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
|
@@ -1,41 +1,238 @@
|
|
|
1
|
-
from typing import Dict, List, Any
|
|
1
|
+
from typing import Dict, List, Any, Optional, Union
|
|
2
|
+
import re
|
|
2
3
|
|
|
3
4
|
class RuleErrorHandler:
|
|
4
|
-
"""
|
|
5
|
+
"""Enhanced validation error handler with complete Laravel-style placeholder support,
|
|
6
|
+
including field-value pair parameters (field1,value1,field2,value2)"""
|
|
7
|
+
|
|
5
8
|
def __init__(self, messages: Dict[str, str], custom_attributes: Dict[str, str]):
|
|
6
9
|
self.messages = messages or {}
|
|
7
10
|
self.custom_attributes = custom_attributes or {}
|
|
8
11
|
self.errors: Dict[str, List[str]] = {}
|
|
12
|
+
self._current_rule: Optional[str] = None
|
|
13
|
+
self._current_params: Optional[List[str]] = None
|
|
14
|
+
self._current_value: Optional[Any] = None
|
|
9
15
|
|
|
10
|
-
def add_error(self, field: str, rule_name: str, default_message: str, value: Any):
|
|
11
|
-
"""Add formatted error message"""
|
|
12
|
-
|
|
16
|
+
def add_error(self, field: str, rule_name: str, rule_params: List[str], default_message: str, value: Any) -> None:
|
|
17
|
+
"""Add a formatted error message with complete placeholder support"""
|
|
18
|
+
self._current_rule = rule_name
|
|
19
|
+
self._current_params = rule_params
|
|
20
|
+
self._current_value = value
|
|
13
21
|
|
|
14
|
-
|
|
22
|
+
message = self._format_message(field, rule_name, default_message, value)
|
|
15
23
|
self.errors.setdefault(field, []).append(message)
|
|
16
24
|
|
|
17
25
|
def _format_message(self, field: str, rule_name: str, default_message: str, value: Any) -> str:
|
|
18
|
-
"""Format error message with placeholders"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
"""Format error message with all supported placeholders"""
|
|
27
|
+
attribute = self._get_attribute_name(field)
|
|
28
|
+
value_str = self._stringify_value(value)
|
|
29
|
+
|
|
30
|
+
# Get the most specific message available
|
|
31
|
+
message = self._get_message(field, rule_name, attribute, default_message)
|
|
32
|
+
|
|
33
|
+
# Prepare all possible replacements
|
|
34
|
+
replacements = self._prepare_replacements(attribute, value_str)
|
|
35
|
+
|
|
36
|
+
# Apply replacements safely
|
|
37
|
+
return self._apply_replacements(message, replacements)
|
|
38
|
+
|
|
39
|
+
def _get_attribute_name(self, field: str) -> str:
|
|
40
|
+
"""Get the display name for a field with nested field support"""
|
|
41
|
+
# Check for exact match first
|
|
42
|
+
if field in self.custom_attributes:
|
|
43
|
+
return self.custom_attributes[field]
|
|
44
|
+
|
|
45
|
+
# Handle nested fields (e.g., 'user.profile.name')
|
|
46
|
+
parts = field.split('.')
|
|
47
|
+
for i in range(len(parts), 0, -1):
|
|
48
|
+
wildcard_key = '.'.join(parts[:i]) + '.*'
|
|
49
|
+
if wildcard_key in self.custom_attributes:
|
|
50
|
+
return self.custom_attributes[wildcard_key]
|
|
32
51
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
52
|
+
# Fallback to last part or field itself
|
|
53
|
+
return self.custom_attributes.get(parts[-1], field.replace('_', ' ').title())
|
|
54
|
+
|
|
55
|
+
def _stringify_value(self, value: Any) -> str:
|
|
56
|
+
"""Convert any value to a string representation"""
|
|
57
|
+
if value is None:
|
|
58
|
+
return ''
|
|
59
|
+
if isinstance(value, (list, dict, set)):
|
|
60
|
+
return ', '.join(str(v) for v in value) if value else ''
|
|
61
|
+
return str(value)
|
|
62
|
+
|
|
63
|
+
def _get_message(self, field: str, rule_name: str, attribute: str, default: str) -> str:
|
|
64
|
+
"""Get the most specific error message available"""
|
|
65
|
+
return (
|
|
66
|
+
self.messages.get(f"{field}.{rule_name}") or # Field-specific rule message
|
|
67
|
+
self.messages.get(field) or # Field-specific default
|
|
68
|
+
self.messages.get(rule_name) or # Rule-specific default
|
|
69
|
+
default # Fallback
|
|
37
70
|
)
|
|
38
71
|
|
|
72
|
+
def _prepare_replacements(self, attribute: str, value_str: str) -> Dict[str, str]:
|
|
73
|
+
"""Prepare all placeholder replacements including field-value pairs"""
|
|
74
|
+
replacements = {
|
|
75
|
+
':attribute': attribute,
|
|
76
|
+
':input': value_str,
|
|
77
|
+
':value': value_str,
|
|
78
|
+
':values': self._get_values_param(),
|
|
79
|
+
':min': self._get_min_param(),
|
|
80
|
+
':max': self._get_max_param(),
|
|
81
|
+
':size': self._get_size_param(),
|
|
82
|
+
':other': self._get_other_param_display(),
|
|
83
|
+
':date': self._get_date_param(),
|
|
84
|
+
':format': self._get_format_param(),
|
|
85
|
+
':param': self._get_first_param(),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Add numbered placeholders for field-value pairs (e.g., :other1, :value1, :other2, :value2)
|
|
89
|
+
if self._is_field_value_rule() and self._current_params:
|
|
90
|
+
field_value_pairs = self._get_field_value_pairs()
|
|
91
|
+
if field_value_pairs:
|
|
92
|
+
first_field, first_value = field_value_pairs[0]
|
|
93
|
+
replacements[':other'] = self._get_attribute_name(first_field)
|
|
94
|
+
replacements[':value'] = first_value
|
|
95
|
+
|
|
96
|
+
for i, (field, val) in enumerate(field_value_pairs[1:], start=2):
|
|
97
|
+
replacements[f':other{i}'] = self._get_attribute_name(field)
|
|
98
|
+
replacements[f':value{i}'] = val
|
|
99
|
+
|
|
100
|
+
return replacements
|
|
101
|
+
|
|
102
|
+
def _is_field_value_rule(self) -> bool:
|
|
103
|
+
"""Check if the current rule uses field-value pairs"""
|
|
104
|
+
return self._current_rule and self._current_rule.lower() in {
|
|
105
|
+
'required_if', 'required_unless',
|
|
106
|
+
'exclude_if', 'exclude_unless',
|
|
107
|
+
'missing_if', 'missing_unless',
|
|
108
|
+
'present_if', 'present_unless'
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def _get_field_value_pairs(self) -> List[tuple]:
|
|
112
|
+
"""Extract field-value pairs from parameters"""
|
|
113
|
+
if not self._current_params:
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
pairs = []
|
|
117
|
+
params = list(self._current_params).copy()
|
|
118
|
+
|
|
119
|
+
# Process parameters in pairs (field, value)
|
|
120
|
+
while len(params) >= 2:
|
|
121
|
+
field = params.pop(0)
|
|
122
|
+
value = params.pop(0)
|
|
123
|
+
pairs.append((field, value))
|
|
124
|
+
|
|
125
|
+
return pairs
|
|
126
|
+
|
|
127
|
+
def _apply_replacements(self, message: str, replacements: Dict[str, str]) -> str:
|
|
128
|
+
"""Safely apply all replacements to the message"""
|
|
129
|
+
for placeholder, replacement in replacements.items():
|
|
130
|
+
if replacement is not None:
|
|
131
|
+
# Use regex to avoid partial replacements
|
|
132
|
+
message = re.sub(
|
|
133
|
+
re.escape(placeholder) + r'(?![a-zA-Z0-9_])',
|
|
134
|
+
str(replacement),
|
|
135
|
+
message
|
|
136
|
+
)
|
|
137
|
+
return message
|
|
138
|
+
|
|
139
|
+
def _get_other_param_display(self) -> Optional[str]:
|
|
140
|
+
"""Get display names for other fields with proper formatting"""
|
|
141
|
+
other_fields = self._get_raw_other_fields()
|
|
142
|
+
if not other_fields:
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
display_names = [self._get_attribute_name(f) for f in other_fields]
|
|
146
|
+
|
|
147
|
+
if len(display_names) == 1:
|
|
148
|
+
return display_names[0]
|
|
149
|
+
if len(display_names) == 2:
|
|
150
|
+
return f"{display_names[0]} and {display_names[1]}"
|
|
151
|
+
return f"{', '.join(display_names[:-1])}, and {display_names[-1]}"
|
|
152
|
+
|
|
153
|
+
def _get_raw_other_fields(self) -> List[str]:
|
|
154
|
+
"""Extract field references from rule parameters"""
|
|
155
|
+
if not self._current_rule or not self._current_params:
|
|
156
|
+
return []
|
|
157
|
+
|
|
158
|
+
rule = self._current_rule.lower()
|
|
159
|
+
|
|
160
|
+
# Rules with field-value pairs (field1,value1,field2,value2,...)
|
|
161
|
+
if rule in {
|
|
162
|
+
'required_if', 'required_unless', 'exclude_if', 'exclude_unless',
|
|
163
|
+
'missing_if', 'missing_unless', 'present_if', 'present_unless'
|
|
164
|
+
}:
|
|
165
|
+
return self._current_params[::2] # Take every even index
|
|
166
|
+
|
|
167
|
+
# Rules with just field references
|
|
168
|
+
if rule in {
|
|
169
|
+
'prohibits', 'exclude_with', 'exclude_without',
|
|
170
|
+
'missing_with', 'missing_with_all',
|
|
171
|
+
'present_with', 'present_with_all'
|
|
172
|
+
}:
|
|
173
|
+
return self._current_params
|
|
174
|
+
|
|
175
|
+
# Single field rules
|
|
176
|
+
if rule in {
|
|
177
|
+
'required_if_accepted', 'required_if_declined',
|
|
178
|
+
'prohibited_if_accepted', 'prohibited_if_declined'
|
|
179
|
+
}:
|
|
180
|
+
return [self._current_params[0]] if self._current_params else []
|
|
181
|
+
|
|
182
|
+
return []
|
|
183
|
+
|
|
184
|
+
def _get_min_param(self) -> Optional[str]:
|
|
185
|
+
"""Get min parameter from rule"""
|
|
186
|
+
if not self._current_params:
|
|
187
|
+
return None
|
|
188
|
+
|
|
189
|
+
if self._current_rule and self._current_rule.startswith(('min', 'between', 'digits_between')):
|
|
190
|
+
return self._current_params[0]
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
def _get_max_param(self) -> Optional[str]:
|
|
194
|
+
"""Get max parameter from rule"""
|
|
195
|
+
if not self._current_params or len(self._current_params) < 2:
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
if self._current_rule and self._current_rule.startswith(('max', 'between', 'digits_between')):
|
|
199
|
+
return self._current_params[1] if self._current_rule.startswith('between') else self._current_params[0]
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
def _get_size_param(self) -> Optional[str]:
|
|
203
|
+
"""Get size parameter from rule"""
|
|
204
|
+
if self._current_rule and self._current_rule.startswith('size') and self._current_params:
|
|
205
|
+
return self._current_params[0]
|
|
206
|
+
return None
|
|
207
|
+
|
|
208
|
+
def _get_values_param(self) -> Optional[str]:
|
|
209
|
+
"""Get values list for in/not_in rules"""
|
|
210
|
+
if (self._current_rule and
|
|
211
|
+
self._current_rule.startswith(('in', 'not_in')) and
|
|
212
|
+
self._current_params):
|
|
213
|
+
return ', '.join(self._current_params)
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
def _get_date_param(self) -> Optional[str]:
|
|
217
|
+
"""Get date parameter for date rules"""
|
|
218
|
+
if (self._current_rule and
|
|
219
|
+
self._current_rule.startswith(('after', 'before', 'after_or_equal', 'before_or_equal')) and
|
|
220
|
+
self._current_params):
|
|
221
|
+
return self._current_params[0]
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
def _get_format_param(self) -> Optional[str]:
|
|
225
|
+
"""Get format parameter"""
|
|
226
|
+
if (self._current_rule and
|
|
227
|
+
self._current_rule.startswith('date_format') and
|
|
228
|
+
self._current_params):
|
|
229
|
+
return self._current_params[0]
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
def _get_first_param(self) -> Optional[str]:
|
|
233
|
+
"""Get first parameter from rule"""
|
|
234
|
+
return self._current_params[0] if self._current_params else None
|
|
235
|
+
|
|
39
236
|
@property
|
|
40
237
|
def has_errors(self) -> bool:
|
|
41
238
|
"""Check if any errors exist"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from validator.factory import RuleFactory
|
|
2
2
|
from validator.services.rule_conflict import RuleConflictChecker
|
|
3
|
-
from validator.rules import
|
|
3
|
+
from validator.rules import Rule
|
|
4
4
|
from typing import Dict, List, Union, Tuple
|
|
5
5
|
from validator.exceptions import RuleNotFoundException
|
|
6
6
|
from collections.abc import Iterable, Sequence
|
|
@@ -14,7 +14,7 @@ class RulePreparer:
|
|
|
14
14
|
def __init__(self, rule_factory: RuleFactory):
|
|
15
15
|
self.rule_factory = rule_factory
|
|
16
16
|
|
|
17
|
-
def prepare(self, raw_rules: Dict[str, Union[str, List[Union[str,
|
|
17
|
+
def prepare(self, raw_rules: Dict[str, Union[str, List[Union[str, Rule]]]]) -> Dict[str, List[Rule]]:
|
|
18
18
|
"""Convert raw rules to prepared validation rules"""
|
|
19
19
|
prepared_rules = {}
|
|
20
20
|
for field, rule_input in raw_rules.items():
|
|
@@ -25,18 +25,18 @@ class RulePreparer:
|
|
|
25
25
|
prepared_rules[field] = self._deduplicate_rules(rules)
|
|
26
26
|
return prepared_rules
|
|
27
27
|
|
|
28
|
-
def _convert_to_rules(self, rule_input: Union[str, List[Union[str,
|
|
29
|
-
"""Convert mixed rule input to list of
|
|
28
|
+
def _convert_to_rules(self, rule_input: Union[str, List[Union[str, Rule]], Rule, Tuple[Union[str, Rule], str], Tuple[Union[str, Rule], str]]) -> List[Rule]:
|
|
29
|
+
"""Convert mixed rule input to list of Rule objects"""
|
|
30
30
|
if rule_input is None:
|
|
31
31
|
return []
|
|
32
|
-
if isinstance(rule_input,
|
|
32
|
+
if isinstance(rule_input, Rule):
|
|
33
33
|
return [rule_input]
|
|
34
|
-
if isinstance(rule_input, list):
|
|
34
|
+
if isinstance(rule_input, list | tuple):
|
|
35
35
|
rules = []
|
|
36
36
|
for r in rule_input:
|
|
37
37
|
if isinstance(r, str):
|
|
38
38
|
rules.extend(self._parse_rule_string(r))
|
|
39
|
-
elif isinstance(r,
|
|
39
|
+
elif isinstance(r, Rule):
|
|
40
40
|
rules.append(r)
|
|
41
41
|
elif isinstance(r, (tuple, list)):
|
|
42
42
|
if len(r) == 0:
|
|
@@ -50,10 +50,10 @@ class RulePreparer:
|
|
|
50
50
|
if isinstance(rule_name, str):
|
|
51
51
|
rule = RuleFactory.create_rule(rule_name)
|
|
52
52
|
rule.params = params
|
|
53
|
-
elif isinstance(rule_name,
|
|
53
|
+
elif isinstance(rule_name, Rule):
|
|
54
54
|
rule = rule_name
|
|
55
55
|
if params:
|
|
56
|
-
warnings.warn(f"Parameters {params} are ignored for
|
|
56
|
+
warnings.warn(f"Parameters {params} are ignored for Rule instance")
|
|
57
57
|
else:
|
|
58
58
|
raise ValueError(f"Invalid rule name type in {r}")
|
|
59
59
|
|
|
@@ -65,8 +65,8 @@ class RulePreparer:
|
|
|
65
65
|
return self._parse_rule_string(rule_input)
|
|
66
66
|
raise ValueError(f"Invalid rule input type: {type(rule_input)}")
|
|
67
67
|
|
|
68
|
-
def _parse_rule_string(self, rule_str: str) -> List[
|
|
69
|
-
"""Parse rule string into
|
|
68
|
+
def _parse_rule_string(self, rule_str: str) -> List[Rule]:
|
|
69
|
+
"""Parse rule string into Rule objects"""
|
|
70
70
|
rules = []
|
|
71
71
|
for rule_part in rule_str.split('|'):
|
|
72
72
|
rule_part = rule_part.strip()
|
|
@@ -93,22 +93,9 @@ class RulePreparer:
|
|
|
93
93
|
return rule_name, [p.strip() for p in param_str.split(',') if p.strip()]
|
|
94
94
|
|
|
95
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
96
|
return set(tuple(x) if isinstance(x, list) else x for x in params)
|
|
110
97
|
|
|
111
|
-
def _deduplicate_rules(self, rules: List[
|
|
98
|
+
def _deduplicate_rules(self, rules: List[Rule]) -> List[Rule]:
|
|
112
99
|
"""Remove duplicate rules based on name and parameters"""
|
|
113
100
|
seen = set()
|
|
114
101
|
unique = []
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
validator/__init__.py,sha256=udxDzUicPfxBOAQvzsnl3pHur9VUppKbWMgg35hpiww,244
|
|
2
|
-
validator/exceptions.py,sha256=y2v7CaXmeGFHWcnigtLl4U-sFta_jMiXkGKXWIIVglY,366
|
|
3
|
-
validator/factory.py,sha256=bImQNLhEJg5VTxtHiMYVb2EbHWvimTDqHq-UcA8uolw,812
|
|
4
|
-
validator/core/__init__.py,sha256=ZcqlXJSk03i_CVzmIN-nVe1UOyvwwO5jhbEj7f62Y_o,59
|
|
5
|
-
validator/core/validator.py,sha256=00qVnbH-EJC5KALlaoUBLAfsszAFLcoSxfRbmy0amyk,12751
|
|
6
|
-
validator/database/__init__.py,sha256=O-cB6-MhNapJ3iwe5jvifbMfr1dPjXLtEdfNTKIu0hc,171
|
|
7
|
-
validator/database/detector.py,sha256=Vac7oVL26GjU6expGo01-6mgUtXqldr-jirzpYokZBM,9597
|
|
8
|
-
validator/database/manager.py,sha256=XJM_I0WaWfZWV710duAc32p1gtiP2or-MAj75WPw1oM,6478
|
|
9
|
-
validator/rules/__init__.py,sha256=nDE3qoI82qJTCbILLUWkXuwsMOmsDtB1m-3IGIvRfpY,919
|
|
10
|
-
validator/rules/array.py,sha256=tx8FCDqn-27Vs7tgtjeoCE9ceDMVrdBEb2-pq-lNLuo,2809
|
|
11
|
-
validator/rules/base.py,sha256=hrGESfkdvqZrQ1yIK_ftVVOMUuyvNFoz-_qaqUucSy8,3474
|
|
12
|
-
validator/rules/basic.py,sha256=fMk0s5_IEQu27X1wndP_ocNyOZ1upXJCn7fR9YYbI74,1527
|
|
13
|
-
validator/rules/comparison.py,sha256=9xb2mO5GiThR1iO8867ex2o7olQC2Bnew6MBdD2UtEo,9402
|
|
14
|
-
validator/rules/conditional.py,sha256=8_O1etzCyCGeD8lmfhegJ1uzhkBSjTEVdufbZmkqgP4,12993
|
|
15
|
-
validator/rules/date.py,sha256=18JIKTO5nzFtCnJEMXm4OUbneqTMB7HGPN6jUkxGU4Y,5278
|
|
16
|
-
validator/rules/files.py,sha256=vu_TZFffDPzDojyTsFXSQ6MmQm3WU6ppFfz7-wuDy98,6550
|
|
17
|
-
validator/rules/format.py,sha256=UeeIAkFn0CdzC5bS9tI78_lbPYRgcpaUujxdmyCSdzE,3744
|
|
18
|
-
validator/rules/string.py,sha256=vYzu4ICKY9FCuGahmsQCoJLmnlBF7uNvVazFj9DQ438,3178
|
|
19
|
-
validator/rules/type.py,sha256=Tu-EOBkTtxkcCe0ANXavurZC449n63iE_VXVzc3BIiM,1596
|
|
20
|
-
validator/rules/utilities.py,sha256=AIm9JRGYf6cTCSkivg3gTj3U5DnXlCAJ5ej1yUSa1dU,9724
|
|
21
|
-
validator/services/__init__.py,sha256=zzKTmqL7v4niFGWHJBfWLqgJ0iTaW_69OzYZN8uInzQ,210
|
|
22
|
-
validator/services/rule_conflict.py,sha256=s1RJNUY5d0WtSMHkrKulBCgJ2BZL2GE0Eu5pdAoiIbM,4943
|
|
23
|
-
validator/services/rule_error_handler.py,sha256=MGvvkP6hbZLpVXxC3xpzg15OmVdPlk7l0M2Srmy5VfM,1729
|
|
24
|
-
validator/services/rule_preparer.py,sha256=jRcMNjqq2xyZjO64Pim8jWmja5DmTzf0V_uuHG0lJTg,5621
|
|
25
|
-
validator/utils/__init__.py,sha256=Yzo-xv285Be-a233M4duDdYtscuHiuBbPSX_C8yViJI,20
|
|
26
|
-
validator/utils/string.py,sha256=0YACzeEaWNEOR9_7O9A8D1ItIbtWfOJ8IfrzcB8VMYA,515
|
|
27
|
-
safeshield-1.2.2.dist-info/LICENSE,sha256=qugtRyKckyaks6hd2xyxOFSOYM6au1N80pMXuMTPvC4,1090
|
|
28
|
-
safeshield-1.2.2.dist-info/METADATA,sha256=Da-A5dUfizYqEpszV6KlIwRLJLgKj7KThQ_990k2wNg,1912
|
|
29
|
-
safeshield-1.2.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
30
|
-
safeshield-1.2.2.dist-info/top_level.txt,sha256=iUtV3dlHOIiMfLuY4pruY00lFni8JzOkQ3Nh1II19OE,10
|
|
31
|
-
safeshield-1.2.2.dist-info/RECORD,,
|