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.

@@ -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