safeshield 1.0.0__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.
Potentially problematic release.
This version of safeshield might be problematic. Click here for more details.
- safeshield-1.0.0.dist-info/LICENSE +21 -0
- safeshield-1.0.0.dist-info/METADATA +32 -0
- safeshield-1.0.0.dist-info/RECORD +29 -0
- safeshield-1.0.0.dist-info/WHEEL +5 -0
- safeshield-1.0.0.dist-info/top_level.txt +1 -0
- validator/__init__.py +7 -0
- validator/core/__init__.py +3 -0
- validator/core/validator.py +299 -0
- validator/database/__init__.py +5 -0
- validator/database/detector.py +250 -0
- validator/database/manager.py +162 -0
- validator/exceptions.py +10 -0
- validator/factory.py +26 -0
- validator/rules/__init__.py +27 -0
- validator/rules/array.py +77 -0
- validator/rules/base.py +84 -0
- validator/rules/basic.py +41 -0
- validator/rules/comparison.py +240 -0
- validator/rules/conditional.py +332 -0
- validator/rules/date.py +154 -0
- validator/rules/files.py +167 -0
- validator/rules/format.py +105 -0
- validator/rules/string.py +74 -0
- validator/rules/type.py +42 -0
- validator/rules/utilities.py +213 -0
- validator/services/__init__.py +5 -0
- validator/services/rule_conflict.py +133 -0
- validator/services/rule_error_handler.py +42 -0
- validator/services/rule_preparer.py +120 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from validator.factory import RuleFactory
|
|
2
|
+
from validator.services.rule_conflict import RuleConflictChecker
|
|
3
|
+
from validator.rules import ValidationRule
|
|
4
|
+
from typing import Dict, List, Union, Tuple
|
|
5
|
+
from validator.exceptions import RuleNotFoundException
|
|
6
|
+
from collections.abc import Iterable, Sequence
|
|
7
|
+
from numbers import Number
|
|
8
|
+
from enum import Enum
|
|
9
|
+
import inspect
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
class RulePreparer:
|
|
13
|
+
"""Handles rule preparation and parsing"""
|
|
14
|
+
def __init__(self, rule_factory: RuleFactory):
|
|
15
|
+
self.rule_factory = rule_factory
|
|
16
|
+
|
|
17
|
+
def prepare(self, raw_rules: Dict[str, Union[str, List[Union[str, ValidationRule]]]]) -> Dict[str, List[ValidationRule]]:
|
|
18
|
+
"""Convert raw rules to prepared validation rules"""
|
|
19
|
+
prepared_rules = {}
|
|
20
|
+
for field, rule_input in raw_rules.items():
|
|
21
|
+
if not rule_input:
|
|
22
|
+
continue
|
|
23
|
+
rules = self._convert_to_rules(rule_input)
|
|
24
|
+
RuleConflictChecker.check_conflicts(rules)
|
|
25
|
+
prepared_rules[field] = self._deduplicate_rules(rules)
|
|
26
|
+
return prepared_rules
|
|
27
|
+
|
|
28
|
+
def _convert_to_rules(self, rule_input: Union[str, List[Union[str, ValidationRule]], ValidationRule, Tuple[Union[str, ValidationRule], str], Tuple[Union[str, ValidationRule], str]]) -> List[ValidationRule]:
|
|
29
|
+
"""Convert mixed rule input to list of ValidationRule objects"""
|
|
30
|
+
if rule_input is None:
|
|
31
|
+
return []
|
|
32
|
+
if isinstance(rule_input, ValidationRule):
|
|
33
|
+
return [rule_input]
|
|
34
|
+
if isinstance(rule_input, list):
|
|
35
|
+
rules = []
|
|
36
|
+
for r in rule_input:
|
|
37
|
+
if isinstance(r, str):
|
|
38
|
+
rules.extend(self._parse_rule_string(r))
|
|
39
|
+
elif isinstance(r, ValidationRule):
|
|
40
|
+
rules.append(r)
|
|
41
|
+
elif isinstance(r, (tuple, list)):
|
|
42
|
+
if len(r) == 0:
|
|
43
|
+
continue
|
|
44
|
+
try:
|
|
45
|
+
# Handle tuple/list format
|
|
46
|
+
rule_name = r[0]
|
|
47
|
+
params = r[1:] if len(r) > 1 else []
|
|
48
|
+
params = self._parse_params(params)
|
|
49
|
+
|
|
50
|
+
if isinstance(rule_name, str):
|
|
51
|
+
rule = RuleFactory.create_rule(rule_name)
|
|
52
|
+
rule.params = params
|
|
53
|
+
elif isinstance(rule_name, ValidationRule):
|
|
54
|
+
rule = rule_name
|
|
55
|
+
if params:
|
|
56
|
+
warnings.warn(f"Parameters {params} are ignored for ValidationRule instance")
|
|
57
|
+
else:
|
|
58
|
+
raise ValueError(f"Invalid rule name type in {r}")
|
|
59
|
+
|
|
60
|
+
rules.append(rule)
|
|
61
|
+
except Exception as e:
|
|
62
|
+
raise ValueError(f"Invalid rule format {r}: {str(e)}")
|
|
63
|
+
return rules
|
|
64
|
+
if isinstance(rule_input, str):
|
|
65
|
+
return self._parse_rule_string(rule_input)
|
|
66
|
+
raise ValueError(f"Invalid rule input type: {type(rule_input)}")
|
|
67
|
+
|
|
68
|
+
def _parse_rule_string(self, rule_str: str) -> List[ValidationRule]:
|
|
69
|
+
"""Parse rule string into ValidationRule objects"""
|
|
70
|
+
rules = []
|
|
71
|
+
for rule_part in rule_str.split('|'):
|
|
72
|
+
rule_part = rule_part.strip()
|
|
73
|
+
if not rule_part:
|
|
74
|
+
continue
|
|
75
|
+
rule_name, params = self._parse_rule_part(rule_part)
|
|
76
|
+
try:
|
|
77
|
+
rule = self.rule_factory.create_rule(rule_name)
|
|
78
|
+
if params:
|
|
79
|
+
rule.params = params
|
|
80
|
+
rules.append(rule)
|
|
81
|
+
except RuleNotFoundException as e:
|
|
82
|
+
warnings.warn(str(e))
|
|
83
|
+
return rules
|
|
84
|
+
|
|
85
|
+
def _parse_rule_part(self, rule_part: str) -> Tuple[str, List[str]]:
|
|
86
|
+
"""Parse single rule part into name and parameters"""
|
|
87
|
+
if ':' not in rule_part:
|
|
88
|
+
return rule_part, []
|
|
89
|
+
rule_name, param_str = rule_part.split(':', 1)
|
|
90
|
+
|
|
91
|
+
if rule_name in {'regex', 'not_regex', 'dimensions'}:
|
|
92
|
+
return rule_name, [param_str]
|
|
93
|
+
return rule_name, [p.strip() for p in param_str.split(',') if p.strip()]
|
|
94
|
+
|
|
95
|
+
def _parse_params(self, params: Union[Tuple, List, str, Enum]):
|
|
96
|
+
all_params = []
|
|
97
|
+
# seen = set()
|
|
98
|
+
# for param in params:
|
|
99
|
+
# if isinstance(param, Iterable) and not isinstance(param, str | bytes) and not inspect.isclass(param):
|
|
100
|
+
# for item in param:
|
|
101
|
+
# if item not in seen and item not in (None, '', [], {}) and (isinstance(item, (Number, Sequence)) or inspect.isclass(item)):
|
|
102
|
+
# seen.add(item)
|
|
103
|
+
# all_params.append(item)
|
|
104
|
+
# else:
|
|
105
|
+
# if param not in seen and param not in (None, '', [], {}) and (isinstance(param, (Number, Sequence)) or inspect.isclass(param)):
|
|
106
|
+
# seen.add(param)
|
|
107
|
+
# all_params.append(param)
|
|
108
|
+
|
|
109
|
+
return set(tuple(x) if isinstance(x, list) else x for x in params)
|
|
110
|
+
|
|
111
|
+
def _deduplicate_rules(self, rules: List[ValidationRule]) -> List[ValidationRule]:
|
|
112
|
+
"""Remove duplicate rules based on name and parameters"""
|
|
113
|
+
seen = set()
|
|
114
|
+
unique = []
|
|
115
|
+
for rule in rules:
|
|
116
|
+
identifier = (rule.rule_name, tuple(rule.params))
|
|
117
|
+
if identifier not in seen:
|
|
118
|
+
seen.add(identifier)
|
|
119
|
+
unique.append(rule)
|
|
120
|
+
return unique
|