safeshield 1.2.2__py3-none-any.whl → 1.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/METADATA +9 -1
- safeshield-1.4.2.dist-info/RECORD +31 -0
- validator/core/validator.py +10 -10
- validator/factory.py +4 -4
- validator/rules/__init__.py +6 -8
- validator/rules/array.py +27 -34
- validator/rules/base.py +32 -8
- validator/rules/basic.py +105 -10
- validator/rules/boolean.py +157 -0
- validator/rules/comparison.py +130 -40
- validator/rules/date.py +36 -20
- validator/rules/files.py +179 -67
- validator/rules/format.py +122 -31
- validator/rules/numeric.py +188 -0
- validator/rules/string.py +71 -19
- validator/rules/utilities.py +233 -133
- validator/services/rule_conflict.py +2 -2
- validator/services/rule_error_handler.py +221 -24
- validator/services/rule_preparer.py +12 -25
- safeshield-1.2.2.dist-info/RECORD +0 -31
- validator/rules/conditional.py +0 -332
- validator/rules/type.py +0 -42
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/LICENSE +0 -0
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/WHEEL +0 -0
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/top_level.txt +0 -0
validator/rules/conditional.py
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
from .base import ValidationRule
|
|
2
|
-
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
3
|
-
from enum import Enum
|
|
4
|
-
import re
|
|
5
|
-
import inspect
|
|
6
|
-
from collections.abc import Iterable
|
|
7
|
-
|
|
8
|
-
# =============================================
|
|
9
|
-
# CONDITIONAL VALIDATION RULES
|
|
10
|
-
# =============================================
|
|
11
|
-
|
|
12
|
-
class RequiredIfRule(ValidationRule):
|
|
13
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
14
|
-
if len(params) < 2 or len(params) % 2 != 0:
|
|
15
|
-
return True
|
|
16
|
-
|
|
17
|
-
conditions = list(zip(params[::2], params[1::2]))
|
|
18
|
-
|
|
19
|
-
condition_met = False
|
|
20
|
-
for other_field, expected_value in conditions:
|
|
21
|
-
if not other_field or expected_value is None:
|
|
22
|
-
continue
|
|
23
|
-
|
|
24
|
-
actual_value = self.get_field_value(other_field, '')
|
|
25
|
-
if actual_value == expected_value:
|
|
26
|
-
condition_met = True
|
|
27
|
-
break
|
|
28
|
-
|
|
29
|
-
if not condition_met:
|
|
30
|
-
return True
|
|
31
|
-
|
|
32
|
-
return not self.is_empty(value)
|
|
33
|
-
|
|
34
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
35
|
-
valid_conditions = []
|
|
36
|
-
if len(params) >= 2 and len(params) % 2 == 0:
|
|
37
|
-
valid_conditions = [
|
|
38
|
-
f"{params[i]} = {params[i+1]}"
|
|
39
|
-
for i in range(0, len(params), 2)
|
|
40
|
-
if params[i] and params[i+1] is not None
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
if not valid_conditions:
|
|
44
|
-
return f"Invalid required_if rule configuration for {field}"
|
|
45
|
-
|
|
46
|
-
return f"The :name field is required when any of these are true: {', '.join(valid_conditions)}"
|
|
47
|
-
|
|
48
|
-
class RequiredAllIfRule(ValidationRule):
|
|
49
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
50
|
-
if len(params) < 2:
|
|
51
|
-
return False
|
|
52
|
-
|
|
53
|
-
conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
|
|
54
|
-
|
|
55
|
-
all_conditions_met = all(
|
|
56
|
-
self.get_field_value(f) == v
|
|
57
|
-
for f, v in conditions
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
if not all_conditions_met:
|
|
61
|
-
return True
|
|
62
|
-
|
|
63
|
-
return not self.is_empty(value)
|
|
64
|
-
|
|
65
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
66
|
-
conditions = " AND ".join(f"{f} = {v}" for f, v in zip(params[::2], params[1::2]))
|
|
67
|
-
return f"The :name field is required when ALL conditions are met: {conditions}"
|
|
68
|
-
|
|
69
|
-
class RequiredUnlessRule(ValidationRule):
|
|
70
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
71
|
-
if len(params) < 2:
|
|
72
|
-
return False
|
|
73
|
-
|
|
74
|
-
other_field, other_value = params[0], params[1]
|
|
75
|
-
actual_value = self.get_field_value(other_field, '')
|
|
76
|
-
|
|
77
|
-
if actual_value == other_value:
|
|
78
|
-
return True
|
|
79
|
-
|
|
80
|
-
return not self.is_empty(value)
|
|
81
|
-
|
|
82
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
83
|
-
return f"The :name field is required unless {params[0]} is {params[1]}."
|
|
84
|
-
|
|
85
|
-
class RequiredWithRule(ValidationRule):
|
|
86
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
87
|
-
if not params:
|
|
88
|
-
return False
|
|
89
|
-
|
|
90
|
-
if any(f in self.validator.data for f in params):
|
|
91
|
-
return not self.is_empty(value)
|
|
92
|
-
return True
|
|
93
|
-
|
|
94
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
95
|
-
return f"The :name field is required when {', '.join(params)} is present."
|
|
96
|
-
|
|
97
|
-
class RequiredWithAllRule(ValidationRule):
|
|
98
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
99
|
-
if not params:
|
|
100
|
-
return False
|
|
101
|
-
|
|
102
|
-
if all(f in self.validator.data for f in params):
|
|
103
|
-
return not self.is_empty(value)
|
|
104
|
-
return True
|
|
105
|
-
|
|
106
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
107
|
-
return f"The :name field is required when all of {', '.join(params)} are present."
|
|
108
|
-
|
|
109
|
-
class RequiredWithoutRule(ValidationRule):
|
|
110
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
111
|
-
if not params:
|
|
112
|
-
return False
|
|
113
|
-
|
|
114
|
-
if any(f not in self.validator.data for f in params):
|
|
115
|
-
return not self.is_empty(value)
|
|
116
|
-
return True
|
|
117
|
-
|
|
118
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
119
|
-
return f"The :name field is required when {', '.join(params)} is not present."
|
|
120
|
-
|
|
121
|
-
class RequiredWithoutAllRule(ValidationRule):
|
|
122
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
123
|
-
if not params:
|
|
124
|
-
return False
|
|
125
|
-
|
|
126
|
-
if all(f not in self.validator.data for f in params):
|
|
127
|
-
return not self.is_empty(value)
|
|
128
|
-
return True
|
|
129
|
-
|
|
130
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
131
|
-
return f"The :name field is required when none of {', '.join(params)} are present."
|
|
132
|
-
|
|
133
|
-
class ProhibitedIfRule(ValidationRule):
|
|
134
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
135
|
-
if len(params) < 2:
|
|
136
|
-
return False
|
|
137
|
-
|
|
138
|
-
other_field, other_value = params[0], params[1]
|
|
139
|
-
actual_value = self.get_field_value(other_field, '')
|
|
140
|
-
|
|
141
|
-
if actual_value != other_value:
|
|
142
|
-
return True
|
|
143
|
-
|
|
144
|
-
return self.is_empty(value)
|
|
145
|
-
|
|
146
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
147
|
-
return f"The :name field is prohibited when {params[0]} is {params[1]}."
|
|
148
|
-
|
|
149
|
-
class ProhibitedUnlessRule(ValidationRule):
|
|
150
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
151
|
-
if len(params) < 2:
|
|
152
|
-
return False
|
|
153
|
-
|
|
154
|
-
other_field, other_value = params[0], params[1]
|
|
155
|
-
actual_value = self.get_field_value(other_field, '')
|
|
156
|
-
|
|
157
|
-
if actual_value == other_value:
|
|
158
|
-
return True
|
|
159
|
-
|
|
160
|
-
return self.is_empty(value)
|
|
161
|
-
|
|
162
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
163
|
-
return f"The :name field is prohibited unless {params[0]} is {params[1]}."
|
|
164
|
-
|
|
165
|
-
class FilledIfRule(ValidationRule):
|
|
166
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
167
|
-
if len(params) < 2:
|
|
168
|
-
return False
|
|
169
|
-
|
|
170
|
-
other_field, other_value = params[0], params[1]
|
|
171
|
-
actual_value = self.get_field_value(other_field, '')
|
|
172
|
-
|
|
173
|
-
if actual_value != other_value:
|
|
174
|
-
return True
|
|
175
|
-
|
|
176
|
-
return value not in ('', None)
|
|
177
|
-
|
|
178
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
179
|
-
return f"The :name field must be filled when {params[0]} is {params[1]}."
|
|
180
|
-
|
|
181
|
-
class RegexRule(ValidationRule):
|
|
182
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
183
|
-
if not params or not isinstance(value, str):
|
|
184
|
-
return False
|
|
185
|
-
try:
|
|
186
|
-
return bool(re.fullmatch(params[0], value))
|
|
187
|
-
except re.error:
|
|
188
|
-
return False
|
|
189
|
-
|
|
190
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
191
|
-
return f"The :name format is invalid."
|
|
192
|
-
|
|
193
|
-
class NotRegexRule(ValidationRule):
|
|
194
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
195
|
-
if not params or not isinstance(value, str):
|
|
196
|
-
return True
|
|
197
|
-
print(not bool(re.search(params[0], value)))
|
|
198
|
-
try:
|
|
199
|
-
return not bool(re.search(params[0], value))
|
|
200
|
-
except re.error:
|
|
201
|
-
return True
|
|
202
|
-
|
|
203
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
204
|
-
return f"The :name format is invalid."
|
|
205
|
-
|
|
206
|
-
class InRule(ValidationRule):
|
|
207
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
208
|
-
allowed_values = self._parse_option_values(field, params)
|
|
209
|
-
return (str(value) in allowed_values or value in allowed_values)
|
|
210
|
-
|
|
211
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
212
|
-
allowed_values = self._parse_option_values(field, params)
|
|
213
|
-
return f"The selected :name must be in : {', '.join(map(str, allowed_values))}"
|
|
214
|
-
|
|
215
|
-
class NotInRule(ValidationRule):
|
|
216
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
217
|
-
not_allowed_values = self._parse_option_values(field, params)
|
|
218
|
-
return str(value) not in not_allowed_values
|
|
219
|
-
|
|
220
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
221
|
-
not_allowed_values = self._parse_option_values(field, params)
|
|
222
|
-
return f"The selected :name must be not in : {', '.join(map(str, not_allowed_values))}"
|
|
223
|
-
|
|
224
|
-
class EnumRule(ValidationRule):
|
|
225
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
226
|
-
allowed_values = self._parse_option_values(field, params)
|
|
227
|
-
return (str(value) in allowed_values or value in allowed_values)
|
|
228
|
-
|
|
229
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
230
|
-
allowed_values = self._parse_option_values(field, params)
|
|
231
|
-
return f"The :name must be one of: {', '.join(map(str, allowed_values))}"
|
|
232
|
-
|
|
233
|
-
class UniqueRule(ValidationRule):
|
|
234
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
235
|
-
if not params or not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
236
|
-
return False
|
|
237
|
-
|
|
238
|
-
table = params[0]
|
|
239
|
-
column = field if len(params) == 1 else params[1]
|
|
240
|
-
|
|
241
|
-
try:
|
|
242
|
-
# Optional: handle ignore case (id)
|
|
243
|
-
ignore_id = None
|
|
244
|
-
if len(params) > 2 and params[2].startswith('ignore:'):
|
|
245
|
-
ignore_field = params[2].split(':')[1]
|
|
246
|
-
ignore_id = self.get_field_value(ignore_field)
|
|
247
|
-
return self.validator.db_manager.is_unique(table, column, value, ignore_id)
|
|
248
|
-
except Exception as e:
|
|
249
|
-
print(f"Database error in UniqueRule: {e}")
|
|
250
|
-
return False
|
|
251
|
-
|
|
252
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
253
|
-
return f"The :name has already been taken."
|
|
254
|
-
|
|
255
|
-
class ExistsRule(ValidationRule):
|
|
256
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
257
|
-
if not params or not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
258
|
-
return False
|
|
259
|
-
|
|
260
|
-
table = params[0]
|
|
261
|
-
column = field if len(params) == 1 else params[1]
|
|
262
|
-
|
|
263
|
-
try:
|
|
264
|
-
return self.validator.db_manager.exists(table, column, value)
|
|
265
|
-
except Exception as e:
|
|
266
|
-
print(f"Database error in ExistsRule: {e}")
|
|
267
|
-
return False
|
|
268
|
-
|
|
269
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
270
|
-
return f"The selected :name is invalid."
|
|
271
|
-
|
|
272
|
-
class ConfirmedRule(ValidationRule):
|
|
273
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
274
|
-
confirmation_field = f"{field}_confirmation"
|
|
275
|
-
|
|
276
|
-
return value == self.get_field_value(confirmation_field, '')
|
|
277
|
-
|
|
278
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
279
|
-
return f"The :name confirmation does not match."
|
|
280
|
-
|
|
281
|
-
class SameRule(ValidationRule):
|
|
282
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
283
|
-
if not params:
|
|
284
|
-
return False
|
|
285
|
-
return value == self.get_field_value(params[0])
|
|
286
|
-
|
|
287
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
288
|
-
return f"The :name and {params[0]} must match."
|
|
289
|
-
|
|
290
|
-
class DifferentRule(ValidationRule):
|
|
291
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
292
|
-
if not params:
|
|
293
|
-
return False
|
|
294
|
-
return value != self.get_field_value(params[0])
|
|
295
|
-
|
|
296
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
297
|
-
return f"The :name and {params[0]} must be different."
|
|
298
|
-
|
|
299
|
-
class AcceptedRule(ValidationRule):
|
|
300
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
301
|
-
if isinstance(value, str):
|
|
302
|
-
return value.lower() in ['yes', 'on', '1', 'true']
|
|
303
|
-
if isinstance(value, int):
|
|
304
|
-
return value == 1
|
|
305
|
-
if isinstance(value, bool):
|
|
306
|
-
return value
|
|
307
|
-
return False
|
|
308
|
-
|
|
309
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
310
|
-
return f"The :name must be accepted."
|
|
311
|
-
|
|
312
|
-
class DeclinedRule(ValidationRule):
|
|
313
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
314
|
-
if isinstance(value, str):
|
|
315
|
-
return value.lower() in ['no', 'off', '0', 'false']
|
|
316
|
-
if isinstance(value, int):
|
|
317
|
-
return value == 0
|
|
318
|
-
if isinstance(value, bool):
|
|
319
|
-
return not value
|
|
320
|
-
return False
|
|
321
|
-
|
|
322
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
323
|
-
return f"The :name must be declined."
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
class BailRule(ValidationRule):
|
|
327
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
328
|
-
self.validator._stop_on_first_failure = True
|
|
329
|
-
return True
|
|
330
|
-
|
|
331
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
332
|
-
return ""
|
validator/rules/type.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from .base import ValidationRule
|
|
2
|
-
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
|
|
5
|
-
# =============================================
|
|
6
|
-
# TYPE DATA VALIDATION RULES
|
|
7
|
-
# =============================================
|
|
8
|
-
|
|
9
|
-
class NumericRule(ValidationRule):
|
|
10
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
11
|
-
if isinstance(value, (int, float)):
|
|
12
|
-
return True
|
|
13
|
-
if not isinstance(value, str):
|
|
14
|
-
return False
|
|
15
|
-
return value.replace('.', '', 1).isdigit()
|
|
16
|
-
|
|
17
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
18
|
-
return f"The :name must be a number."
|
|
19
|
-
|
|
20
|
-
class IntegerRule(ValidationRule):
|
|
21
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
22
|
-
if isinstance(value, int):
|
|
23
|
-
return True
|
|
24
|
-
if not isinstance(value, str):
|
|
25
|
-
return False
|
|
26
|
-
return value.isdigit()
|
|
27
|
-
|
|
28
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
29
|
-
return f"The :name must be an integer."
|
|
30
|
-
|
|
31
|
-
class BooleanRule(ValidationRule):
|
|
32
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
33
|
-
if isinstance(value, bool):
|
|
34
|
-
return True
|
|
35
|
-
if isinstance(value, str):
|
|
36
|
-
return value.lower() in ['true', 'false', '1', '0', 'yes', 'no', 'on', 'off']
|
|
37
|
-
if isinstance(value, int):
|
|
38
|
-
return value in [0, 1]
|
|
39
|
-
return False
|
|
40
|
-
|
|
41
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
42
|
-
return f"The :name field must be true or false."
|
|
File without changes
|
|
File without changes
|
|
File without changes
|