validating 0.0.0__tar.gz → 0.0.1__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.
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: validating
3
+ Version: 0.0.1
4
+ Summary: Provides a lightweight `attr()` descriptor factory that adds runtime validation to dataclass fields.
5
+ Project-URL: Documentation, https://github.com/Chitaoji/validating/blob/main/README.md
6
+ Project-URL: Repository, https://github.com/Chitaoji/validating/
7
+ Author-email: Chitaoji <2360742040@qq.com>
8
+ Maintainer-email: Chitaoji <2360742040@qq.com>
9
+ License-Expression: BSD-3-Clause
10
+ License-File: LICENSE
11
+ Keywords: config
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Python: >=3.13
15
+ Description-Content-Type: text/markdown
16
+
17
+ # validating
18
+
19
+ `validating` is a lightweight runtime validation library focused on making
20
+ `dataclass` fields and function arguments safer and easier to validate.
21
+
22
+ It exposes three main entry points:
23
+
24
+ - `attr(...)`: declare validated fields (type checks, bounds, allow/deny lists, custom validators)
25
+ - `@dataclass(...)`: a compatible enhancement of `dataclasses.dataclass` with automatic validation integration
26
+ - `@validate`: a decorator that validates function arguments using type annotations
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install validating
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```python
37
+ from validating import attr, dataclass
38
+
39
+ @dataclass
40
+ class UserConfig:
41
+ age: int = attr(lb=0)
42
+ role: str = attr(allowlist=["admin", "user"])
43
+
44
+ cfg = UserConfig(age=18, role="admin")
45
+ cfg.age = 20 # ✅
46
+ cfg.role = "user" # ✅
47
+ # cfg.age = -1 # ❌ ValueError
48
+ # cfg.role = "guest" # ❌ ValueError
49
+ ```
50
+
51
+ ## Core API
52
+
53
+ ### `attr(...)`
54
+
55
+ Declares a descriptor-backed field that validates values on initialization and assignment.
56
+
57
+ Common parameters:
58
+
59
+ - `default`: default value
60
+ - `default_factory`: lazy default factory (mutually exclusive with `default`)
61
+ - `allowlist`: whitelist of allowed values
62
+ - `denylist`: blacklist of forbidden values
63
+ - `lb` / `ub`: inclusive lower / upper bounds
64
+ - `slb` / `sub`: exclusive lower / upper bounds
65
+ - `validator`: custom validator function with signature `Callable[[Any], bool]`
66
+ - `init` / `repr` / `hash` / `compare` / `kw_only`: forwarded dataclass field behavior controls
67
+
68
+ Error semantics:
69
+
70
+ - Misconfiguration at class-definition time (for example, default type mismatch) raises `ValidatorError`
71
+ - Invalid runtime values raise `TypeError` or `ValueError`
72
+
73
+ ---
74
+
75
+ ### `@dataclass(...)`
76
+
77
+ `validating.dataclass` is a compatible enhanced wrapper around `dataclasses.dataclass`.
78
+
79
+ Enhancements:
80
+
81
+ 1. **Automatic default promotion**: `x: int = 1` is promoted to `attr(default=1)`
82
+ 2. **Method argument validation**: when `validate_methods=True` (by default `False`), all public methods are wrapped with `validate` (including `@staticmethod` and `@classmethod`)
83
+
84
+ ```python
85
+ from validating import dataclass
86
+
87
+ @dataclass(validate_methods=True)
88
+ class Service:
89
+ retries: int = 3
90
+
91
+ def run(self, timeout: int) -> int:
92
+ return timeout + self.retries
93
+
94
+ svc = Service()
95
+ svc.run(1) # ✅
96
+ # svc.run("1") # ❌ TypeError
97
+ ```
98
+
99
+ ---
100
+
101
+ ### `@validate`
102
+
103
+ Enables call-time argument validation based on type annotations.
104
+
105
+ ```python
106
+ from typing import Literal
107
+ from validating import validate
108
+
109
+ @validate
110
+ def configure(mode: Literal["dev", "prod"], workers: int):
111
+ return mode, workers
112
+
113
+ configure("dev", 4) # ✅
114
+ # configure("test", 4) # ❌ TypeError
115
+ ```
116
+
117
+ `@validate` also handles `assert` statements in validated functions:
118
+
119
+ - `assert <expr>, "custom message"` keeps the original `AssertionError` with your message.
120
+ - `assert <expr>` (without message) is converted to a `ValueError` when `<expr>` is a direct assertion on function arguments, with a message like `expected <expr>, got <value> instead`.
121
+ - Assertions that are not direct checks on function arguments are left as regular `AssertionError`.
122
+
123
+ ```python
124
+ from validating import validate
125
+
126
+ @validate
127
+ def check_score(score: int) -> int:
128
+ assert score >= 60
129
+ return score
130
+
131
+ check_score(80) # ✅
132
+ # check_score(59) # ❌ ValueError: expected score >= 60, got 59 instead
133
+ ```
134
+
135
+ ## More Examples
136
+
137
+ ### 1) `default_factory`
138
+
139
+ ```python
140
+ from validating import attr, dataclass
141
+
142
+ @dataclass
143
+ class Cache:
144
+ items: list[int] = attr(default_factory=list)
145
+ ```
146
+
147
+ ### 2) Complex type hints
148
+
149
+ ```python
150
+ from typing import Literal
151
+ from validating import attr, dataclass
152
+
153
+ @dataclass
154
+ class AppConfig:
155
+ mode: Literal["dev", "prod"] = attr()
156
+ token: int | str = attr()
157
+ mapping: dict[str, int] = attr()
158
+ ```
159
+
160
+ ### 3) Custom validator
161
+
162
+ ```python
163
+ from validating import attr, dataclass
164
+
165
+ @dataclass
166
+ class EvenNumber:
167
+ value: int = attr(validator=lambda x: x % 2 == 0)
168
+ ```
169
+
170
+ ## Notes
171
+
172
+ - Dataclasses with `slots=True` are currently not supported.
173
+ - This project focuses on runtime validation and does not replace static type checking.
174
+
175
+ ## See Also
176
+
177
+ - GitHub: https://github.com/Chitaoji/validating/
178
+ - PyPI: https://pypi.org/project/validating/
179
+
180
+ ## License
181
+ This project falls under the BSD 3-Clause License.
182
+
183
+ ## History
184
+
185
+ ### v0.0.1
186
+
187
+ - Initial release.
@@ -0,0 +1,171 @@
1
+ # validating
2
+
3
+ `validating` is a lightweight runtime validation library focused on making
4
+ `dataclass` fields and function arguments safer and easier to validate.
5
+
6
+ It exposes three main entry points:
7
+
8
+ - `attr(...)`: declare validated fields (type checks, bounds, allow/deny lists, custom validators)
9
+ - `@dataclass(...)`: a compatible enhancement of `dataclasses.dataclass` with automatic validation integration
10
+ - `@validate`: a decorator that validates function arguments using type annotations
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install validating
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```python
21
+ from validating import attr, dataclass
22
+
23
+ @dataclass
24
+ class UserConfig:
25
+ age: int = attr(lb=0)
26
+ role: str = attr(allowlist=["admin", "user"])
27
+
28
+ cfg = UserConfig(age=18, role="admin")
29
+ cfg.age = 20 # ✅
30
+ cfg.role = "user" # ✅
31
+ # cfg.age = -1 # ❌ ValueError
32
+ # cfg.role = "guest" # ❌ ValueError
33
+ ```
34
+
35
+ ## Core API
36
+
37
+ ### `attr(...)`
38
+
39
+ Declares a descriptor-backed field that validates values on initialization and assignment.
40
+
41
+ Common parameters:
42
+
43
+ - `default`: default value
44
+ - `default_factory`: lazy default factory (mutually exclusive with `default`)
45
+ - `allowlist`: whitelist of allowed values
46
+ - `denylist`: blacklist of forbidden values
47
+ - `lb` / `ub`: inclusive lower / upper bounds
48
+ - `slb` / `sub`: exclusive lower / upper bounds
49
+ - `validator`: custom validator function with signature `Callable[[Any], bool]`
50
+ - `init` / `repr` / `hash` / `compare` / `kw_only`: forwarded dataclass field behavior controls
51
+
52
+ Error semantics:
53
+
54
+ - Misconfiguration at class-definition time (for example, default type mismatch) raises `ValidatorError`
55
+ - Invalid runtime values raise `TypeError` or `ValueError`
56
+
57
+ ---
58
+
59
+ ### `@dataclass(...)`
60
+
61
+ `validating.dataclass` is a compatible enhanced wrapper around `dataclasses.dataclass`.
62
+
63
+ Enhancements:
64
+
65
+ 1. **Automatic default promotion**: `x: int = 1` is promoted to `attr(default=1)`
66
+ 2. **Method argument validation**: when `validate_methods=True` (by default `False`), all public methods are wrapped with `validate` (including `@staticmethod` and `@classmethod`)
67
+
68
+ ```python
69
+ from validating import dataclass
70
+
71
+ @dataclass(validate_methods=True)
72
+ class Service:
73
+ retries: int = 3
74
+
75
+ def run(self, timeout: int) -> int:
76
+ return timeout + self.retries
77
+
78
+ svc = Service()
79
+ svc.run(1) # ✅
80
+ # svc.run("1") # ❌ TypeError
81
+ ```
82
+
83
+ ---
84
+
85
+ ### `@validate`
86
+
87
+ Enables call-time argument validation based on type annotations.
88
+
89
+ ```python
90
+ from typing import Literal
91
+ from validating import validate
92
+
93
+ @validate
94
+ def configure(mode: Literal["dev", "prod"], workers: int):
95
+ return mode, workers
96
+
97
+ configure("dev", 4) # ✅
98
+ # configure("test", 4) # ❌ TypeError
99
+ ```
100
+
101
+ `@validate` also handles `assert` statements in validated functions:
102
+
103
+ - `assert <expr>, "custom message"` keeps the original `AssertionError` with your message.
104
+ - `assert <expr>` (without message) is converted to a `ValueError` when `<expr>` is a direct assertion on function arguments, with a message like `expected <expr>, got <value> instead`.
105
+ - Assertions that are not direct checks on function arguments are left as regular `AssertionError`.
106
+
107
+ ```python
108
+ from validating import validate
109
+
110
+ @validate
111
+ def check_score(score: int) -> int:
112
+ assert score >= 60
113
+ return score
114
+
115
+ check_score(80) # ✅
116
+ # check_score(59) # ❌ ValueError: expected score >= 60, got 59 instead
117
+ ```
118
+
119
+ ## More Examples
120
+
121
+ ### 1) `default_factory`
122
+
123
+ ```python
124
+ from validating import attr, dataclass
125
+
126
+ @dataclass
127
+ class Cache:
128
+ items: list[int] = attr(default_factory=list)
129
+ ```
130
+
131
+ ### 2) Complex type hints
132
+
133
+ ```python
134
+ from typing import Literal
135
+ from validating import attr, dataclass
136
+
137
+ @dataclass
138
+ class AppConfig:
139
+ mode: Literal["dev", "prod"] = attr()
140
+ token: int | str = attr()
141
+ mapping: dict[str, int] = attr()
142
+ ```
143
+
144
+ ### 3) Custom validator
145
+
146
+ ```python
147
+ from validating import attr, dataclass
148
+
149
+ @dataclass
150
+ class EvenNumber:
151
+ value: int = attr(validator=lambda x: x % 2 == 0)
152
+ ```
153
+
154
+ ## Notes
155
+
156
+ - Dataclasses with `slots=True` are currently not supported.
157
+ - This project focuses on runtime validation and does not replace static type checking.
158
+
159
+ ## See Also
160
+
161
+ - GitHub: https://github.com/Chitaoji/validating/
162
+ - PyPI: https://pypi.org/project/validating/
163
+
164
+ ## License
165
+ This project falls under the BSD 3-Clause License.
166
+
167
+ ## History
168
+
169
+ ### v0.0.1
170
+
171
+ - Initial release.
@@ -21,7 +21,6 @@ HOMEPAGE: Final[str] = project["urls"]["Repository"]
21
21
  REQUIRES: Final[list[str]] = project["dependencies"]
22
22
  SOURCE = "src"
23
23
  LICENSE = (here / project["license-files"][0]).read_text().partition("\n")[0]
24
- VERSION = project["version"]
25
24
 
26
25
  # Import the README and use it as the long-description.
27
26
  readme_path = here / project["readme"]
@@ -84,10 +83,6 @@ def _quote(readme: str) -> str:
84
83
  return f'"""{readme}"""'
85
84
 
86
85
 
87
- def _version(version: str = VERSION) -> str:
88
- return f'"""Version file."""\n\n__version__ = "{version}"\n'
89
-
90
-
91
86
  class ReadmeFormatError(Exception):
92
87
  """Raised when the README has a wrong format."""
93
88
 
@@ -95,7 +90,6 @@ class ReadmeFormatError(Exception):
95
90
  if __name__ == "__main__":
96
91
  # Import the __init__.py and change the module docstring.
97
92
  init_path = here / SOURCE / NAME / "__init__.py"
98
- version_path = here / SOURCE / NAME / "_version.py"
99
93
  module_file = init_path.read_text(encoding="utf-8")
100
94
  new_doc, long_description = _readme2doc(long_description)
101
95
  module_file = re.sub(
@@ -103,5 +97,4 @@ if __name__ == "__main__":
103
97
  )
104
98
  init_path.write_text(module_file, encoding="utf-8")
105
99
  readme_path.write_text(long_description.strip(), encoding="utf-8")
106
- version_path.write_text(_version())
107
100
  os.system(f"cd {here} && python -m build")
@@ -4,28 +4,25 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "validating"
7
- version = "0.0.0"
7
+ version = "0.0.1"
8
8
  dependencies = []
9
- requires-python = ">=3.12"
9
+ requires-python = ">=3.13"
10
10
  authors = [
11
11
  {name = "Chitaoji", email = "2360742040@qq.com"},
12
12
  ]
13
13
  maintainers = [
14
14
  {name = "Chitaoji", email = "2360742040@qq.com"}
15
15
  ]
16
- description = "For test"
16
+ description = "Provides a lightweight `attr()` descriptor factory that adds runtime validation to dataclass fields."
17
17
  readme = "README.md"
18
18
  license = "BSD-3-Clause"
19
19
  license-files = ["LICENSE"]
20
20
  keywords = ["config"]
21
21
  classifiers = [
22
22
  "Programming Language :: Python :: 3",
23
- "Programming Language :: Python :: 3.12"
23
+ "Programming Language :: Python :: 3.13"
24
24
  ]
25
25
 
26
26
  [project.urls]
27
27
  Documentation = "https://github.com/Chitaoji/validating/blob/main/README.md"
28
- Repository = "https://github.com/Chitaoji/validating/"
29
-
30
- [project.scripts]
31
- cfg = "template.__main__:run"
28
+ Repository = "https://github.com/Chitaoji/validating/"
@@ -0,0 +1,179 @@
1
+ """
2
+ # validating
3
+
4
+ `validating` is a lightweight runtime validation library focused on making
5
+ `dataclass` fields and function arguments safer and easier to validate.
6
+
7
+ It exposes three main entry points:
8
+
9
+ - `attr(...)`: declare validated fields (type checks, bounds, allow/deny lists, custom
10
+ validators)
11
+ - `@dataclass(...)`: a compatible enhancement of `dataclasses.dataclass` with automatic
12
+ validation integration
13
+ - `@validate`: a decorator that validates function arguments using type annotations
14
+
15
+ ## Quick Start
16
+
17
+ ```python
18
+ from validating import attr, dataclass
19
+
20
+ @dataclass
21
+ class UserConfig:
22
+ age: int = attr(lb=0)
23
+ role: str = attr(allowlist=["admin", "user"])
24
+
25
+ cfg = UserConfig(age=18, role="admin")
26
+ cfg.age = 20 # ✅
27
+ cfg.role = "user" # ✅
28
+ # cfg.age = -1 # ❌ ValueError
29
+ # cfg.role = "guest" # ❌ ValueError
30
+ ```
31
+
32
+ ## Core API
33
+
34
+ ### `attr(...)`
35
+
36
+ Declares a descriptor-backed field that validates values on initialization and
37
+ assignment.
38
+
39
+ Common parameters:
40
+
41
+ - `default`: default value
42
+ - `default_factory`: lazy default factory (mutually exclusive with `default`)
43
+ - `allowlist`: whitelist of allowed values
44
+ - `denylist`: blacklist of forbidden values
45
+ - `lb` / `ub`: inclusive lower / upper bounds
46
+ - `slb` / `sub`: exclusive lower / upper bounds
47
+ - `validator`: custom validator function with signature `Callable[[Any], bool]`
48
+ - `init` / `repr` / `hash` / `compare` / `kw_only`: forwarded dataclass field behavior
49
+ controls
50
+
51
+ Error semantics:
52
+
53
+ - Misconfiguration at class-definition time (for example, default type mismatch) raises
54
+ `ValidatorError`
55
+ - Invalid runtime values raise `TypeError` or `ValueError`
56
+
57
+ ---
58
+
59
+ ### `@dataclass(...)`
60
+
61
+ `validating.dataclass` is a compatible enhanced wrapper around `dataclasses.dataclass`.
62
+
63
+ Enhancements:
64
+
65
+ 1. **Automatic default promotion**: `x: int = 1` is promoted to `attr(default=1)`
66
+ 2. **Method argument validation**: when `validate_methods=True` (by default `False`),
67
+ all public methods are wrapped with `validate` (including `@staticmethod` and
68
+ `@classmethod`)
69
+
70
+ ```python
71
+ from validating import dataclass
72
+
73
+ @dataclass(validate_methods=True)
74
+ class Service:
75
+ retries: int = 3
76
+
77
+ def run(self, timeout: int) -> int:
78
+ return timeout + self.retries
79
+
80
+ svc = Service()
81
+ svc.run(1) # ✅
82
+ # svc.run("1") # ❌ TypeError
83
+ ```
84
+
85
+ ---
86
+
87
+ ### `@validate`
88
+
89
+ Enables call-time argument validation based on type annotations.
90
+
91
+ ```python
92
+ from typing import Literal
93
+ from validating import validate
94
+
95
+ @validate
96
+ def configure(mode: Literal["dev", "prod"], workers: int):
97
+ return mode, workers
98
+
99
+ configure("dev", 4) # ✅
100
+ # configure("test", 4) # ❌ TypeError
101
+ ```
102
+
103
+ `@validate` also handles `assert` statements in validated functions:
104
+
105
+ - `assert <expr>, "custom message"` keeps the original `AssertionError` with your
106
+ message.
107
+ - `assert <expr>` (without message) is converted to a `ValueError` when `<expr>` is a
108
+ direct assertion on function arguments, with a message like `expected <expr>, got
109
+ <value> instead`.
110
+ - Assertions that are not direct checks on function arguments are left as regular
111
+ `AssertionError`.
112
+
113
+ ```python
114
+ from validating import validate
115
+
116
+ @validate
117
+ def check_score(score: int) -> int:
118
+ assert score >= 60
119
+ return score
120
+
121
+ check_score(80) # ✅
122
+ # check_score(59) # ❌ ValueError: expected score >= 60, got 59 instead
123
+ ```
124
+
125
+ ## More Examples
126
+
127
+ ### 1) `default_factory`
128
+
129
+ ```python
130
+ from validating import attr, dataclass
131
+
132
+ @dataclass
133
+ class Cache:
134
+ items: list[int] = attr(default_factory=list)
135
+ ```
136
+
137
+ ### 2) Complex type hints
138
+
139
+ ```python
140
+ from typing import Literal
141
+ from validating import attr, dataclass
142
+
143
+ @dataclass
144
+ class AppConfig:
145
+ mode: Literal["dev", "prod"] = attr()
146
+ token: int | str = attr()
147
+ mapping: dict[str, int] = attr()
148
+ ```
149
+
150
+ ### 3) Custom validator
151
+
152
+ ```python
153
+ from validating import attr, dataclass
154
+
155
+ @dataclass
156
+ class EvenNumber:
157
+ value: int = attr(validator=lambda x: x % 2 == 0)
158
+ ```
159
+
160
+ ## Notes
161
+
162
+ - Dataclasses with `slots=True` are currently not supported.
163
+ - This project focuses on runtime validation and does not replace static type checking.
164
+
165
+ ## See Also
166
+
167
+ - GitHub: https://github.com/Chitaoji/validating/
168
+ - PyPI: https://pypi.org/project/validating/
169
+
170
+ ## License
171
+ This project falls under the BSD 3-Clause License.
172
+
173
+ """
174
+
175
+ from . import core
176
+ from .core import *
177
+
178
+ __all__: list[str] = []
179
+ __all__.extend(core.__all__)
@@ -0,0 +1,13 @@
1
+ """
2
+ Contains the core of validating: attr(), dataclass(), validate(), etc.
3
+
4
+ NOTE: this module is private. All functions and objects are available in the main
5
+ :mod:`validating` namespace - use that instead.
6
+
7
+ """
8
+
9
+ from .datacls import dataclass
10
+ from .valid_attr import ValidatorError, attr
11
+ from .valid_func import validate
12
+
13
+ __all__ = ["attr", "dataclass", "validate", "ValidatorError"]