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.
@@ -1,41 +1,46 @@
1
- from .base import ValidationRule
1
+ from .base import Rule
2
2
  from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
3
+ from .basic import *
4
+ from .boolean import AcceptedRule, DeclinedRule
3
5
 
4
- class AnyOfRule(ValidationRule):
6
+ class RequiredIfRule(RequiredRule):
5
7
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
6
- if not params:
7
- return False
8
- return any(self.get_field_value(param, param) == value for param in params)
9
-
10
- def message(self, field: str, params: List[str]) -> str:
11
- return f"The :name must be one of: {', '.join(params)}"
12
-
13
- class ExcludeRule(ValidationRule):
14
- def validate(self, field: str, value: Any, params: List[str]) -> bool:
15
- return False # This rule is typically used to exclude fields from validation
8
+ if len(params) == 1 and callable(params[0]):
9
+ condition_met = params[0](self.validator.data)
10
+ elif len(params) == 1 and isinstance(params[0], bool):
11
+ condition_met = params[0]
12
+ else:
13
+ conditions = list(zip(params[::2], params[1::2]))
14
+
15
+ condition_met = any(
16
+ str(self.get_field_value(field, '')) == str(expected_value)
17
+ for field, expected_value in conditions
18
+ if field and expected_value is not None
19
+ )
20
+
21
+ if condition_met:
22
+ return super().validate(field, value, params)
23
+
24
+ return True
16
25
 
17
- def message(self, field: str, params: List[str]) -> str:
18
- return f"The :name field is excluded."
19
-
20
- class ExcludeIfRule(ValidationRule):
26
+ class RequiredUnlessRule(RequiredRule):
21
27
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
22
- conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
23
-
24
- all_conditions_met = all(
25
- self.get_field_value(f) == v
26
- for f, v in conditions
27
- )
28
+ if len(params) < 2:
29
+ return False
30
+
31
+ other_field, other_value = params[0], params[1]
32
+ actual_value = self.get_field_value(other_field, '')
28
33
 
29
- if all_conditions_met:
30
- self.validator._is_exclude = True
34
+ if actual_value == other_value:
35
+ return True
31
36
 
32
- return True
37
+ return super().validate(field, value, params)
33
38
 
34
- def message(self, field: str, params: List[str]) -> str:
35
- return f"The :name field is excluded when {params[0]} is {params[1]}."
36
-
37
- class ExcludeUnlessRule(ValidationRule):
39
+ class RequiredAllIfRule(RequiredRule):
38
40
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
41
+ if len(params) < 2:
42
+ return False
43
+
39
44
  conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
40
45
 
41
46
  all_conditions_met = all(
@@ -44,170 +49,265 @@ class ExcludeUnlessRule(ValidationRule):
44
49
  )
45
50
 
46
51
  if not all_conditions_met:
47
- self.validator._is_exclude = True
48
-
49
- return True
52
+ return True
50
53
 
51
- def message(self, field: str, params: List[str]) -> str:
52
- return f"The :name field is excluded unless {params[0]} is {params[1]}."
53
-
54
- class ExcludeWithRule(ValidationRule):
54
+ return super().validate(field, value, params)
55
+
56
+ class RequiredWithRule(RequiredRule):
55
57
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
56
- if any(not self.is_empty(self.get_field_value(param, None)) for param in params):
57
- self.validator._is_exclude = True
58
+ if not params:
59
+ return False
58
60
 
61
+ if any(f in self.validator.data for f in params):
62
+ return super().validate(field, value, params)
59
63
  return True
60
-
61
- def message(self, field: str, params: List[str]) -> str:
62
- return f"The :name field is excluded when any of {', '.join(params)} is present."
63
64
 
64
- class ExcludeWithoutRule(ValidationRule):
65
+ class RequiredWithAllRule(RequiredRule):
65
66
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
66
- if any(self.is_empty(self.get_field_value(param, None)) for param in params):
67
- self.validator._is_exclude = True
67
+ if not params:
68
+ return False
68
69
 
70
+ if all(f in self.validator.data for f in params):
71
+ return not self.is_empty(value)
69
72
  return True
70
73
 
71
- def message(self, field: str, params: List[str]) -> str:
72
- return f"The :name field is excluded when any of {', '.join(params)} is missing."
73
-
74
- class MissingRule(ValidationRule):
75
- def validate(self, field: str, value: Any, params: List[str]) -> bool:
76
- return value is None
77
-
78
- def message(self, field: str, params: List[str]) -> str:
79
- return f"The :name field must be missing."
80
-
81
- class MissingIfRule(ValidationRule):
74
+ class RequiredWithoutRule(RequiredRule):
82
75
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
83
- if len(params) < 2:
76
+ if not params:
84
77
  return False
85
- other_field, other_value = params[0], params[1]
86
- return value is None if self.get_field_value(other_field, None) == other_value else True
78
+
79
+ if any(f not in self.validator.data for f in params):
80
+ return super().validate(field, value, params)
81
+ return True
87
82
 
88
- def message(self, field: str, params: List[str]) -> str:
89
- return f"The :name field must be missing when {params[0]} is {params[1]}."
90
-
91
- class MissingUnlessRule(ValidationRule):
83
+ class RequiredWithoutAllRule(RequiredRule):
92
84
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
93
- if len(params) < 2:
85
+ if not params:
94
86
  return False
95
- other_field, other_value = params[0], params[1]
96
- return value is None if self.get_field_value(other_field, None) != other_value else True
87
+
88
+ if all(f not in self.validator.data for f in params):
89
+ return super().validate(field, value, params)
90
+ return True
97
91
 
98
- def message(self, field: str, params: List[str]) -> str:
99
- return f"The :name field must be missing unless {params[0]} is {params[1]}."
100
-
101
- class MissingWithRule(ValidationRule):
92
+ class RequiredIfAcceptedRule(RequiredRule, AcceptedRule):
102
93
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
103
94
  if not params:
104
95
  return False
105
- return value is None if any(self.get_field_value(param, None) is not None for param in params) else True
96
+
97
+ if AcceptedRule.validate(self, field, params[0], params):
98
+ return super().validate(field, value, params)
99
+
100
+ return True
106
101
 
107
- def message(self, field: str, params: List[str]) -> str:
108
- return f"The :name field must be missing when any of {', '.join(params)} is present."
109
-
110
- class MissingWithAllRule(ValidationRule):
102
+ class RequiredIfDeclinedRule(RequiredRule, DeclinedRule):
111
103
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
112
104
  if not params:
113
105
  return False
114
- return value is None if all(self.get_field_value(param, None) is not None for param in params) else True
106
+
107
+ if DeclinedRule.validate(self, field, params[0], params):
108
+ return super().validate(field, value, params)
109
+
110
+ return True
115
111
 
116
- def message(self, field: str, params: List[str]) -> str:
117
- return f"The :name field must be missing when all of {', '.join(params)} are present."
118
-
119
- class PresentIfRule(ValidationRule):
112
+ class RequiredArrayKeysRule(Rule):
120
113
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
121
- if len(params) < 2:
114
+ if not isinstance(value, dict) or not params:
122
115
  return False
123
- other_field, other_value = params[0], params[1]
124
- return value is not None if self.get_field_value(other_field, None) == other_value else True
116
+ return all(key in value for key in params)
125
117
 
126
118
  def message(self, field: str, params: List[str]) -> str:
127
- return f"The :name field must be present when {params[0]} is {params[1]}."
128
-
129
- class PresentUnlessRule(ValidationRule):
119
+ return f"The :attribute must contain all required keys: {', '.join(params)}"
120
+
121
+ class ProhibitedIfRule(ProhibitedRule):
122
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
123
+ if len(params) == 1 and callable(params[0]):
124
+ condition_met = params[0](self.validator.data)
125
+ elif len(params) == 1 and isinstance(params[0], bool):
126
+ condition_met = params[0]
127
+ else:
128
+ other_field, other_value = params[0], params[1]
129
+ actual_value = self.get_field_value(other_field, '')
130
+
131
+ condition_met = actual_value == other_value
132
+
133
+ if condition_met:
134
+ return super().validate(field, value, params)
135
+ return True
136
+
137
+ class ProhibitedUnlessRule(ProhibitedRule):
130
138
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
131
139
  if len(params) < 2:
132
140
  return False
141
+
133
142
  other_field, other_value = params[0], params[1]
134
- return value is not None if self.get_field_value(other_field, None) != other_value else True
143
+ actual_value = self.get_field_value(other_field, '')
144
+
145
+ if actual_value == other_value:
146
+ return True
147
+
148
+ return super().validate(field, value, params)
135
149
 
136
- def message(self, field: str, params: List[str]) -> str:
137
- return f"The :name field must be present unless {params[0]} is {params[1]}."
138
-
139
- class PresentWithRule(ValidationRule):
150
+ class ProhibitedIfAcceptedRule(ProhibitedRule, AcceptedRule):
140
151
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
141
152
  if not params:
142
153
  return False
143
- return value is not None if any(self.get_field_value(param, None) is not None for param in params) else True
144
-
145
- def message(self, field: str, params: List[str]) -> str:
146
- return f"The :name field must be present when any of {', '.join(params)} is present."
154
+
155
+ if AcceptedRule.validate(self, field, params[0], params):
156
+ return super().validate(field, value, params)
157
+ return True
147
158
 
148
- class PresentWithAllRule(ValidationRule):
159
+ class ProhibitedIfDeclinedRule(ProhibitedRule, DeclinedRule):
149
160
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
150
161
  if not params:
151
162
  return False
152
- return value is not None if all(self.get_field_value(param, None) is not None for param in params) else True
163
+
164
+ if DeclinedRule.validate(self, field, params[0], params):
165
+ return super().validate(field, value, params)
166
+
167
+ return True
153
168
 
154
- def message(self, field: str, params: List[str]) -> str:
155
- return f"The :name field must be present when all of {', '.join(params)} are present."
156
-
157
- class ProhibitedIfAcceptedRule(ValidationRule):
169
+ class PresentIfRule(PresentRule):
158
170
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
159
- if not params:
171
+ condition_met = False
172
+
173
+ if len(params) == 1 and callable(params[0]):
174
+ condition_met = params[0](self.validator.data)
175
+ elif len(params) == 1 and isinstance(params[0], bool):
176
+ condition_met = params[0]
177
+ else:
178
+ conditions = list(zip(params[::2], params[1::2]))
179
+ for other_field, expected_value in conditions:
180
+ if self.get_field_value(other_field, None) == expected_value:
181
+ condition_met = True
182
+ break
183
+
184
+ if condition_met:
185
+ return super().validate(field, value, params)
186
+
187
+ return True
188
+
189
+ class PresentUnlessRule(PresentRule):
190
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
191
+ if len(params) < 2:
160
192
  return False
161
- other_field = params[0]
162
- return value is None if self.get_field_value(other_field, None) in ['yes', 'on', '1', 1, True, 'true', 'True'] else True
193
+ other_field, other_value = params[0], params[1]
194
+
195
+ if self.get_field_value(other_field, None) != other_value:
196
+ return super().validate(field, value, params)
197
+
198
+ return True
163
199
 
164
- def message(self, field: str, params: List[str]) -> str:
165
- return f"The :name field is prohibited when {params[0]} is accepted."
166
-
167
- class ProhibitedIfDeclinedRule(ValidationRule):
200
+ class PresentWithRule(PresentRule):
168
201
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
169
202
  if not params:
170
203
  return False
171
- other_field = params[0]
172
- return value is None if self.get_field_value(other_field, None) in ['no', 'off', '0', 0, False, 'false', 'False'] else True
204
+ if any(self.get_field_value(param, None) is not None for param in params):
205
+ return super().validate(field, value, params)
206
+
207
+ return True
173
208
 
174
- def message(self, field: str, params: List[str]) -> str:
175
- return f"The :name field is prohibited when {params[0]} is declined."
209
+ class PresentWithAllRule(PresentRule):
210
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
211
+ if not params:
212
+ return False
213
+
214
+ if all(self.get_field_value(param, None) is not None for param in params):
215
+ return super().validate(field, value, params)
176
216
 
177
- class ProhibitsRule(ValidationRule):
217
+ class MissingIfRule(MissingRule):
178
218
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
179
- if not params or value is None:
180
- return True
181
- return all(self.get_field_value(param, param) in (None, 'None') for param in params)
219
+ condition_met = False
220
+
221
+ if len(params) == 1 and callable(params[0]):
222
+ condition_met = params[0](self.validator.data)
223
+ elif len(params) == 1 and isinstance(params[0], bool):
224
+ condition_met = params[0]
225
+ else:
226
+ conditions = list(zip(params[::2], params[1::2]))
227
+ for other_field, expected_value in conditions:
228
+ if self.get_field_value(other_field, None) == expected_value:
229
+ condition_met = True
230
+ break
231
+
232
+ if condition_met:
233
+ return super().validate(field, value, params)
234
+
235
+ return True
182
236
 
183
- def message(self, field: str, params: List[str]) -> str:
184
- return f"When :name is present, {', '.join(params)} must be absent."
237
+ class MissingUnlessRule(MissingRule):
238
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
239
+ if len(params) < 2:
240
+ return False
241
+ other_field, other_value = params[0], params[1]
242
+ if self.get_field_value(other_field, None) != other_value:
243
+ return super().validate(field, value, params)
185
244
 
186
- class RequiredIfAcceptedRule(ValidationRule):
245
+ return True
246
+
247
+ class MissingWithRule(MissingRule):
187
248
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
188
249
  if not params:
189
250
  return False
190
- other_field = params[0]
191
- return value is not None if self.get_field_value(other_field, None) in ['yes', 'on', '1', 1, True, 'true', 'True'] else True
251
+
252
+ if any(self.get_field_value(param, None) is not None for param in params):
253
+ return super().validate(field, value, params)
254
+
255
+ return True
192
256
 
193
- def message(self, field: str, params: List[str]) -> str:
194
- return f"The :name field is required when {params[0]} is accepted."
195
-
196
- class RequiredIfDeclinedRule(ValidationRule):
257
+ class MissingWithAllRule(MissingRule):
197
258
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
198
259
  if not params:
199
260
  return False
200
- other_field = params[0]
201
- return value is not None if self.get_field_value(other_field, other_field) in ['no', 'off', '0', 0, False, 'false', 'False'] else True
261
+
262
+ if all(self.get_field_value(param, None) is not None for param in params):
263
+ return super().validate(field, value, params)
264
+
265
+ return True
202
266
 
267
+ class ExcludeIfRule(ExcludeRule):
268
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
269
+ if len(params) == 1 and callable(params[0]):
270
+ condition_met = params[0](self.validator.data)
271
+ elif len(params) == 1 and isinstance(params[0], bool):
272
+ condition_met = params[0]
273
+ else:
274
+ conditions = list(zip(params[::2], params[1::2]))
275
+ condition_met = all(
276
+ str(self.get_field_value(f)) == str(v)
277
+ for f, v in conditions
278
+ )
279
+
280
+ if condition_met:
281
+ return super().validate(field, value, params)
282
+ return True
283
+
284
+ class ExcludeUnlessRule(ExcludeRule):
285
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
286
+ conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
287
+
288
+ all_conditions_met = all(
289
+ self.get_field_value(f) == v
290
+ for f, v in conditions
291
+ )
292
+
293
+ if not all_conditions_met:
294
+ return super().validate(field, value, params)
295
+
296
+ return True
297
+
203
298
  def message(self, field: str, params: List[str]) -> str:
204
- return f"The :name field is required when {params[0]} is declined."
299
+ return f"The :attribute field is excluded unless {params[0]} is {params[1]}."
205
300
 
206
- class RequiredArrayKeysRule(ValidationRule):
301
+ class ExcludeWithRule(ExcludeRule):
207
302
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
208
- if not isinstance(value, dict) or not params:
209
- return False
210
- return all(key in value for key in params)
303
+ if any(not self.is_empty(self.get_field_value(param, None)) for param in params):
304
+ return super().validate(field, value, params)
305
+
306
+ return True
211
307
 
212
- def message(self, field: str, params: List[str]) -> str:
213
- return f"The :name must contain all required keys: {', '.join(params)}"
308
+ class ExcludeWithoutRule(ExcludeRule):
309
+ def validate(self, field: str, value: Any, params: List[str]) -> bool:
310
+ if any(self.is_empty(self.get_field_value(param, None)) for param in params):
311
+ return super().validate(field, value, params)
312
+
313
+ return True
@@ -58,11 +58,11 @@ class RuleConflictChecker:
58
58
  }
59
59
 
60
60
  @classmethod
61
- def check_conflicts(cls, rules: List['ValidationRule']) -> None:
61
+ def check_conflicts(cls, rules: List['Rule']) -> None:
62
62
  """Main method untuk mengecek semua jenis konflik.
63
63
 
64
64
  Args:
65
- rules: List of ValidationRule objects to check
65
+ rules: List of Rule objects to check
66
66
 
67
67
  Raises:
68
68
  ValueError: Untuk konflik kritis