type_enforced.utils
1import types, re, copy 2from functools import update_wrapper 3from typing import Union 4 5 6class Partial: 7 """ 8 A special class wrapper to allow for easy partial function wrappings and calls. 9 """ 10 11 __slots__ = ( 12 "__fn__", 13 "__args__", 14 "__kwargs__", 15 "__fnArity__", 16 "__arity__", 17 "__fn_var_keys__", 18 "__fn_arg_keys__", 19 "__fn_arg_default_keys__", 20 "__wrapped__", 21 "__name__", 22 "__qualname__", 23 "__dict__", 24 ) 25 26 def __init__( 27 self, 28 __fn__, 29 *__args__, 30 **__kwargs__, 31 ): 32 update_wrapper(self, __fn__) 33 self.__fn__ = __fn__ 34 self.__args__ = __args__ 35 self.__kwargs__ = __kwargs__ 36 self.__fnArity__ = self.__getFnArity__() 37 self.__arity__ = self.__getArity__(__args__, __kwargs__) 38 self.__get_fn_arg_default_keys__() 39 40 def __exception__(self, message): 41 pre_message = ( 42 f"({self.__fn__.__module__}.{self.__fn__.__qualname__}_partial): " 43 ) 44 raise Exception(pre_message + message) 45 46 def __call__(self, *args, **kwargs): 47 new_args = self.__args__ + args 48 new_kwargs = {**self.__kwargs__, **kwargs} 49 # Create a comprehensive set of assigned variable names to determine arity 50 assigned_vars = set(self.__fn_arg_default_keys__) 51 assigned_vars.update(self.__fn_arg_keys__[: len(new_args)]) 52 assigned_vars.update(new_kwargs) 53 arity = self.__fnArity__ - len(assigned_vars) 54 if arity < 0: 55 self.__exception__("Too many arguments were supplied") 56 if arity == 0: 57 return self.__fn__(*new_args, **new_kwargs) 58 return Partial( 59 self.__fn__, 60 *new_args, 61 **new_kwargs, 62 ) 63 64 def __get_fn_arg_default_keys__(self): 65 """ 66 Get the default values of the passed function or method and store them in `self.__fn_defaults__`. 67 """ 68 co = self.__fn__.__code__ 69 self.__fn_var_keys__ = co.co_varnames 70 self.__fn_arg_keys__ = co.co_varnames[: co.co_argcount] 71 if self.__fn__.__defaults__ is not None: 72 self.__fn_arg_default_keys__ = list( 73 self.__fn_arg_keys__[-len(self.__fn__.__defaults__) :] 74 ) 75 else: 76 self.__fn_arg_default_keys__ = [] 77 if self.__fn__.__kwdefaults__ is not None: 78 self.__fn_arg_default_keys__.extend(self.__fn__.__kwdefaults__) 79 80 def __get__(self, instance, owner): 81 def bind(*args, **kwargs): 82 if instance is not None and self.__arity__ == self.__fnArity__: 83 return self.__call__(instance, *args, **kwargs) 84 else: 85 return self.__call__(*args, **kwargs) 86 87 return bind 88 89 def __repr__(self): 90 return f"<Partial {self.__fn__.__module__}.{self.__fn__.__qualname__} object at {hex(id(self))}>" 91 92 def __getArity__(self, args, kwargs): 93 return self.__fnArity__ - (len(args) + len(kwargs)) 94 95 def __getFnArity__(self): 96 if not isinstance(self.__fn__, (types.MethodType, types.FunctionType)): 97 self.__exception__( 98 "A non function was passed as a function and does not have any arity. See the stack trace above for more information." 99 ) 100 extra_method_input_count = ( 101 1 if isinstance(self.__fn__, types.MethodType) else 0 102 ) 103 return self.__fn__.__code__.co_argcount - extra_method_input_count 104 105 106class GenericConstraint: 107 def __init__(self, constraints: dict): 108 """ 109 Creates a generic constraint object that can be used to validate a value against a set of constraints. 110 111 Required Arguments: 112 113 - `constraints`: 114 - What: A dictionary of constraint names and their associated functions. 115 - Type: dict 116 - Note: All values in the dictionary must be functions that take a single argument and return a boolean. 117 - Note: The dictionary keys will be used to identify the failed constraints in the error messages. 118 """ 119 assert all( 120 hasattr(v, "__call__") for v in constraints.values() 121 ), "All constraints must be functions." 122 self.__constraint_checks__ = constraints 123 124 def __validate__(self, varname, value): 125 for check_name, check_func in self.__constraint_checks__.items(): 126 try: 127 if not check_func(value): 128 return f"Constraint `{check_name}` not met with the provided value `{value}`" 129 except Exception as e: 130 return f"An exception was raised when checking the constraint `{check_name}` with the provided value `{value}`. Error: {e}" 131 return True 132 133 def __ror__(self, other): 134 """ 135 Allows the use of | operator to combine GenericConstraints via a union. 136 """ 137 return Union[other, self] 138 139 140class Constraint(GenericConstraint): 141 def __init__( 142 self, 143 pattern: str | None = None, 144 includes: list | tuple | set | None = None, 145 excludes: list | tuple | set | None = None, 146 gt: float | int | None = None, 147 lt: float | int | None = None, 148 ge: float | int | None = None, 149 le: float | int | None = None, 150 eq: float | int | None = None, 151 ne: float | int | None = None, 152 ): 153 """ 154 Creates a constraint object that can be used to validate a value against a set of constraints. 155 156 Optional Arguments: 157 158 - `pattern`: 159 - What: A regex pattern that the value must match. 160 - Type: str or None 161 - Default: None 162 - `includes`: 163 - What: A list of values that the value must be in. 164 - Type: list, tuple, set or None 165 - Default: None 166 - `excludes`: 167 - What: A list of values that the value must not be in. 168 - Type: list, tuple, set or None 169 - Default: None 170 - `gt`: 171 - What: The value must be greater than this value. 172 - Type: float, int or None 173 - Default: None 174 - `lt`: 175 - What: The value must be less than this value. 176 - Type: float, int or None 177 - Default: None 178 - `ge`: 179 - What: The value must be greater than or equal to this value. 180 - Type: float, int or None 181 - Default: None 182 - `le`: 183 - What: The value must be less than or equal to this value. 184 - Type: float, int or None 185 - Default: None 186 - `eq`: 187 - What: The value must be equal to this value. 188 - Type: float, int or None 189 - Default: None 190 - `ne`: 191 - What: The value must not be equal to this value. 192 - Type: float, int or None 193 - Default: None 194 """ 195 assert any( 196 v is not None 197 for v in [pattern, gt, lt, ge, le, eq, ne, includes, excludes] 198 ), "At least one constraint must be provided." 199 assert isinstance( 200 includes, (list, tuple, set, type(None)) 201 ), "Includes must be a list, tuple, set or None." 202 assert isinstance( 203 excludes, (list, tuple, set, type(None)) 204 ), "Excludes must be a list, tuple, set or None." 205 assert isinstance( 206 pattern, (str, type(None)) 207 ), "Pattern must be a string or None." 208 assert isinstance( 209 gt, (float, int, type(None)) 210 ), "Greater than constraint must be a float, int or None." 211 assert isinstance( 212 lt, (float, int, type(None)) 213 ), "Less than constraint must be a float, int or None." 214 assert isinstance( 215 ge, (float, int, type(None)) 216 ), "Greater or equal to constraint must be a float, int or None." 217 assert isinstance( 218 le, (float, int, type(None)) 219 ), "Less than or equal to constraint must be a float, int or None." 220 assert isinstance( 221 eq, (float, int, type(None)) 222 ), "Equal to constraint must be a float, int or None." 223 assert isinstance( 224 ne, (float, int, type(None)) 225 ), "Not equal to constraint must be a float, int or None." 226 self.__constraint_checks__ = {} 227 if pattern is not None: 228 self.__constraint_checks__["be a string"] = lambda x: isinstance( 229 x, str 230 ) 231 self.__constraint_checks__["Regex Pattern Match"] = lambda x: bool( 232 re.search(pattern, x) 233 ) 234 if includes is not None: 235 self.__constraint_checks__[f"Includes"] = lambda x: x in includes 236 if excludes is not None: 237 self.__constraint_checks__["Excludes"] = lambda x: x not in excludes 238 if gt is not None: 239 self.__constraint_checks__[f"Greater Than ({gt})"] = ( 240 lambda x: x > gt 241 ) 242 if lt is not None: 243 self.__constraint_checks__[f"Less Than ({lt})"] = lambda x: x < lt 244 if ge is not None: 245 self.__constraint_checks__[f"Greater Than Or Equal To ({ge})"] = ( 246 lambda x: x >= ge 247 ) 248 if le is not None: 249 self.__constraint_checks__[f"Less Than Or Equal To ({le})"] = ( 250 lambda x: x <= le 251 ) 252 if eq is not None: 253 self.__constraint_checks__[f"Equal To ({eq})"] = lambda x: x == eq 254 if ne is not None: 255 self.__constraint_checks__[f"Not Equal To ({ne})"] = ( 256 lambda x: x != ne 257 ) 258 259 260iterable_types = frozenset({list, tuple, set, dict}) 261 262 263def merge_type_dicts(target, source): 264 """Merge source type dict into target in-place. 265 266 Preserves multiple schema variants for collection types (list, tuple, dict, set) 267 when distinct collection schemas are united. 268 """ 269 for key, value in source.items(): 270 if key not in target: 271 target[key] = value 272 elif key == "__extra__": 273 if isinstance(target[key], dict) and isinstance(value, dict): 274 for ek, ev in value.items(): 275 if ek not in target[key]: 276 target[key][ek] = ev 277 elif isinstance(target[key][ek], list) and isinstance( 278 ev, list 279 ): 280 target[key][ek] = list( 281 dict.fromkeys(target[key][ek] + ev) 282 ) 283 elif target[key] == value: 284 continue 285 elif key in iterable_types: 286 if isinstance(target[key], list): 287 if isinstance(value, list): 288 for v in value: 289 if v not in target[key]: 290 target[key].append(v) 291 else: 292 if value not in target[key]: 293 target[key].append(value) 294 else: 295 if isinstance(value, list): 296 new_list = [target[key]] 297 for v in value: 298 if v not in new_list: 299 new_list.append(v) 300 target[key] = new_list 301 else: 302 target[key] = [target[key], value] 303 elif isinstance(target[key], dict) and isinstance(value, dict): 304 merge_type_dicts(target[key], value) 305 else: 306 target[key] = value 307 308 309def DeepMerge(original: dict, update: dict): 310 """ 311 Merge two dictionaries together, recursively merging any nested dictionaries and preserving collection variant schemas. 312 313 Required Arguments: 314 315 - `original`: 316 - What: The original dictionary to merge the update into. 317 - Type: dict 318 - `update`: 319 - What: The dictionary to merge into the original dictionary. 320 - Type: dict 321 """ 322 original = copy.deepcopy(original) 323 merge_type_dicts(original, update) 324 return original 325 326 327def WithSubclasses(cls): 328 """ 329 A utility class to preserve backwards compatibility 330 with the older versions of type_enforced. 331 332 By default subclasses of all classes are now enforced by type_enforced. 333 334 It is slated to be removed in the next major version. 335 """ 336 # TODO: Remove this in the next major version of type_enforced 337 return cls 338 339 340def has_cpp(): 341 try: 342 from type_enforced.cpp import create_validator # noqa: F401 343 344 return True 345 except ImportError: 346 return False 347 348 349def cpp_check(): 350 try: 351 from type_enforced.cpp import create_validator # noqa: F401 352 353 print("Using C++ & Python implementation of type_enforced.") 354 except ImportError: 355 print("Using Pure Python implementation of type_enforced.")
7class Partial: 8 """ 9 A special class wrapper to allow for easy partial function wrappings and calls. 10 """ 11 12 __slots__ = ( 13 "__fn__", 14 "__args__", 15 "__kwargs__", 16 "__fnArity__", 17 "__arity__", 18 "__fn_var_keys__", 19 "__fn_arg_keys__", 20 "__fn_arg_default_keys__", 21 "__wrapped__", 22 "__name__", 23 "__qualname__", 24 "__dict__", 25 ) 26 27 def __init__( 28 self, 29 __fn__, 30 *__args__, 31 **__kwargs__, 32 ): 33 update_wrapper(self, __fn__) 34 self.__fn__ = __fn__ 35 self.__args__ = __args__ 36 self.__kwargs__ = __kwargs__ 37 self.__fnArity__ = self.__getFnArity__() 38 self.__arity__ = self.__getArity__(__args__, __kwargs__) 39 self.__get_fn_arg_default_keys__() 40 41 def __exception__(self, message): 42 pre_message = ( 43 f"({self.__fn__.__module__}.{self.__fn__.__qualname__}_partial): " 44 ) 45 raise Exception(pre_message + message) 46 47 def __call__(self, *args, **kwargs): 48 new_args = self.__args__ + args 49 new_kwargs = {**self.__kwargs__, **kwargs} 50 # Create a comprehensive set of assigned variable names to determine arity 51 assigned_vars = set(self.__fn_arg_default_keys__) 52 assigned_vars.update(self.__fn_arg_keys__[: len(new_args)]) 53 assigned_vars.update(new_kwargs) 54 arity = self.__fnArity__ - len(assigned_vars) 55 if arity < 0: 56 self.__exception__("Too many arguments were supplied") 57 if arity == 0: 58 return self.__fn__(*new_args, **new_kwargs) 59 return Partial( 60 self.__fn__, 61 *new_args, 62 **new_kwargs, 63 ) 64 65 def __get_fn_arg_default_keys__(self): 66 """ 67 Get the default values of the passed function or method and store them in `self.__fn_defaults__`. 68 """ 69 co = self.__fn__.__code__ 70 self.__fn_var_keys__ = co.co_varnames 71 self.__fn_arg_keys__ = co.co_varnames[: co.co_argcount] 72 if self.__fn__.__defaults__ is not None: 73 self.__fn_arg_default_keys__ = list( 74 self.__fn_arg_keys__[-len(self.__fn__.__defaults__) :] 75 ) 76 else: 77 self.__fn_arg_default_keys__ = [] 78 if self.__fn__.__kwdefaults__ is not None: 79 self.__fn_arg_default_keys__.extend(self.__fn__.__kwdefaults__) 80 81 def __get__(self, instance, owner): 82 def bind(*args, **kwargs): 83 if instance is not None and self.__arity__ == self.__fnArity__: 84 return self.__call__(instance, *args, **kwargs) 85 else: 86 return self.__call__(*args, **kwargs) 87 88 return bind 89 90 def __repr__(self): 91 return f"<Partial {self.__fn__.__module__}.{self.__fn__.__qualname__} object at {hex(id(self))}>" 92 93 def __getArity__(self, args, kwargs): 94 return self.__fnArity__ - (len(args) + len(kwargs)) 95 96 def __getFnArity__(self): 97 if not isinstance(self.__fn__, (types.MethodType, types.FunctionType)): 98 self.__exception__( 99 "A non function was passed as a function and does not have any arity. See the stack trace above for more information." 100 ) 101 extra_method_input_count = ( 102 1 if isinstance(self.__fn__, types.MethodType) else 0 103 ) 104 return self.__fn__.__code__.co_argcount - extra_method_input_count
A special class wrapper to allow for easy partial function wrappings and calls.
27 def __init__( 28 self, 29 __fn__, 30 *__args__, 31 **__kwargs__, 32 ): 33 update_wrapper(self, __fn__) 34 self.__fn__ = __fn__ 35 self.__args__ = __args__ 36 self.__kwargs__ = __kwargs__ 37 self.__fnArity__ = self.__getFnArity__() 38 self.__arity__ = self.__getArity__(__args__, __kwargs__) 39 self.__get_fn_arg_default_keys__()
107class GenericConstraint: 108 def __init__(self, constraints: dict): 109 """ 110 Creates a generic constraint object that can be used to validate a value against a set of constraints. 111 112 Required Arguments: 113 114 - `constraints`: 115 - What: A dictionary of constraint names and their associated functions. 116 - Type: dict 117 - Note: All values in the dictionary must be functions that take a single argument and return a boolean. 118 - Note: The dictionary keys will be used to identify the failed constraints in the error messages. 119 """ 120 assert all( 121 hasattr(v, "__call__") for v in constraints.values() 122 ), "All constraints must be functions." 123 self.__constraint_checks__ = constraints 124 125 def __validate__(self, varname, value): 126 for check_name, check_func in self.__constraint_checks__.items(): 127 try: 128 if not check_func(value): 129 return f"Constraint `{check_name}` not met with the provided value `{value}`" 130 except Exception as e: 131 return f"An exception was raised when checking the constraint `{check_name}` with the provided value `{value}`. Error: {e}" 132 return True 133 134 def __ror__(self, other): 135 """ 136 Allows the use of | operator to combine GenericConstraints via a union. 137 """ 138 return Union[other, self]
108 def __init__(self, constraints: dict): 109 """ 110 Creates a generic constraint object that can be used to validate a value against a set of constraints. 111 112 Required Arguments: 113 114 - `constraints`: 115 - What: A dictionary of constraint names and their associated functions. 116 - Type: dict 117 - Note: All values in the dictionary must be functions that take a single argument and return a boolean. 118 - Note: The dictionary keys will be used to identify the failed constraints in the error messages. 119 """ 120 assert all( 121 hasattr(v, "__call__") for v in constraints.values() 122 ), "All constraints must be functions." 123 self.__constraint_checks__ = constraints
Creates a generic constraint object that can be used to validate a value against a set of constraints.
Required Arguments:
constraints:- What: A dictionary of constraint names and their associated functions.
- Type: dict
- Note: All values in the dictionary must be functions that take a single argument and return a boolean.
- Note: The dictionary keys will be used to identify the failed constraints in the error messages.
141class Constraint(GenericConstraint): 142 def __init__( 143 self, 144 pattern: str | None = None, 145 includes: list | tuple | set | None = None, 146 excludes: list | tuple | set | None = None, 147 gt: float | int | None = None, 148 lt: float | int | None = None, 149 ge: float | int | None = None, 150 le: float | int | None = None, 151 eq: float | int | None = None, 152 ne: float | int | None = None, 153 ): 154 """ 155 Creates a constraint object that can be used to validate a value against a set of constraints. 156 157 Optional Arguments: 158 159 - `pattern`: 160 - What: A regex pattern that the value must match. 161 - Type: str or None 162 - Default: None 163 - `includes`: 164 - What: A list of values that the value must be in. 165 - Type: list, tuple, set or None 166 - Default: None 167 - `excludes`: 168 - What: A list of values that the value must not be in. 169 - Type: list, tuple, set or None 170 - Default: None 171 - `gt`: 172 - What: The value must be greater than this value. 173 - Type: float, int or None 174 - Default: None 175 - `lt`: 176 - What: The value must be less than this value. 177 - Type: float, int or None 178 - Default: None 179 - `ge`: 180 - What: The value must be greater than or equal to this value. 181 - Type: float, int or None 182 - Default: None 183 - `le`: 184 - What: The value must be less than or equal to this value. 185 - Type: float, int or None 186 - Default: None 187 - `eq`: 188 - What: The value must be equal to this value. 189 - Type: float, int or None 190 - Default: None 191 - `ne`: 192 - What: The value must not be equal to this value. 193 - Type: float, int or None 194 - Default: None 195 """ 196 assert any( 197 v is not None 198 for v in [pattern, gt, lt, ge, le, eq, ne, includes, excludes] 199 ), "At least one constraint must be provided." 200 assert isinstance( 201 includes, (list, tuple, set, type(None)) 202 ), "Includes must be a list, tuple, set or None." 203 assert isinstance( 204 excludes, (list, tuple, set, type(None)) 205 ), "Excludes must be a list, tuple, set or None." 206 assert isinstance( 207 pattern, (str, type(None)) 208 ), "Pattern must be a string or None." 209 assert isinstance( 210 gt, (float, int, type(None)) 211 ), "Greater than constraint must be a float, int or None." 212 assert isinstance( 213 lt, (float, int, type(None)) 214 ), "Less than constraint must be a float, int or None." 215 assert isinstance( 216 ge, (float, int, type(None)) 217 ), "Greater or equal to constraint must be a float, int or None." 218 assert isinstance( 219 le, (float, int, type(None)) 220 ), "Less than or equal to constraint must be a float, int or None." 221 assert isinstance( 222 eq, (float, int, type(None)) 223 ), "Equal to constraint must be a float, int or None." 224 assert isinstance( 225 ne, (float, int, type(None)) 226 ), "Not equal to constraint must be a float, int or None." 227 self.__constraint_checks__ = {} 228 if pattern is not None: 229 self.__constraint_checks__["be a string"] = lambda x: isinstance( 230 x, str 231 ) 232 self.__constraint_checks__["Regex Pattern Match"] = lambda x: bool( 233 re.search(pattern, x) 234 ) 235 if includes is not None: 236 self.__constraint_checks__[f"Includes"] = lambda x: x in includes 237 if excludes is not None: 238 self.__constraint_checks__["Excludes"] = lambda x: x not in excludes 239 if gt is not None: 240 self.__constraint_checks__[f"Greater Than ({gt})"] = ( 241 lambda x: x > gt 242 ) 243 if lt is not None: 244 self.__constraint_checks__[f"Less Than ({lt})"] = lambda x: x < lt 245 if ge is not None: 246 self.__constraint_checks__[f"Greater Than Or Equal To ({ge})"] = ( 247 lambda x: x >= ge 248 ) 249 if le is not None: 250 self.__constraint_checks__[f"Less Than Or Equal To ({le})"] = ( 251 lambda x: x <= le 252 ) 253 if eq is not None: 254 self.__constraint_checks__[f"Equal To ({eq})"] = lambda x: x == eq 255 if ne is not None: 256 self.__constraint_checks__[f"Not Equal To ({ne})"] = ( 257 lambda x: x != ne 258 )
142 def __init__( 143 self, 144 pattern: str | None = None, 145 includes: list | tuple | set | None = None, 146 excludes: list | tuple | set | None = None, 147 gt: float | int | None = None, 148 lt: float | int | None = None, 149 ge: float | int | None = None, 150 le: float | int | None = None, 151 eq: float | int | None = None, 152 ne: float | int | None = None, 153 ): 154 """ 155 Creates a constraint object that can be used to validate a value against a set of constraints. 156 157 Optional Arguments: 158 159 - `pattern`: 160 - What: A regex pattern that the value must match. 161 - Type: str or None 162 - Default: None 163 - `includes`: 164 - What: A list of values that the value must be in. 165 - Type: list, tuple, set or None 166 - Default: None 167 - `excludes`: 168 - What: A list of values that the value must not be in. 169 - Type: list, tuple, set or None 170 - Default: None 171 - `gt`: 172 - What: The value must be greater than this value. 173 - Type: float, int or None 174 - Default: None 175 - `lt`: 176 - What: The value must be less than this value. 177 - Type: float, int or None 178 - Default: None 179 - `ge`: 180 - What: The value must be greater than or equal to this value. 181 - Type: float, int or None 182 - Default: None 183 - `le`: 184 - What: The value must be less than or equal to this value. 185 - Type: float, int or None 186 - Default: None 187 - `eq`: 188 - What: The value must be equal to this value. 189 - Type: float, int or None 190 - Default: None 191 - `ne`: 192 - What: The value must not be equal to this value. 193 - Type: float, int or None 194 - Default: None 195 """ 196 assert any( 197 v is not None 198 for v in [pattern, gt, lt, ge, le, eq, ne, includes, excludes] 199 ), "At least one constraint must be provided." 200 assert isinstance( 201 includes, (list, tuple, set, type(None)) 202 ), "Includes must be a list, tuple, set or None." 203 assert isinstance( 204 excludes, (list, tuple, set, type(None)) 205 ), "Excludes must be a list, tuple, set or None." 206 assert isinstance( 207 pattern, (str, type(None)) 208 ), "Pattern must be a string or None." 209 assert isinstance( 210 gt, (float, int, type(None)) 211 ), "Greater than constraint must be a float, int or None." 212 assert isinstance( 213 lt, (float, int, type(None)) 214 ), "Less than constraint must be a float, int or None." 215 assert isinstance( 216 ge, (float, int, type(None)) 217 ), "Greater or equal to constraint must be a float, int or None." 218 assert isinstance( 219 le, (float, int, type(None)) 220 ), "Less than or equal to constraint must be a float, int or None." 221 assert isinstance( 222 eq, (float, int, type(None)) 223 ), "Equal to constraint must be a float, int or None." 224 assert isinstance( 225 ne, (float, int, type(None)) 226 ), "Not equal to constraint must be a float, int or None." 227 self.__constraint_checks__ = {} 228 if pattern is not None: 229 self.__constraint_checks__["be a string"] = lambda x: isinstance( 230 x, str 231 ) 232 self.__constraint_checks__["Regex Pattern Match"] = lambda x: bool( 233 re.search(pattern, x) 234 ) 235 if includes is not None: 236 self.__constraint_checks__[f"Includes"] = lambda x: x in includes 237 if excludes is not None: 238 self.__constraint_checks__["Excludes"] = lambda x: x not in excludes 239 if gt is not None: 240 self.__constraint_checks__[f"Greater Than ({gt})"] = ( 241 lambda x: x > gt 242 ) 243 if lt is not None: 244 self.__constraint_checks__[f"Less Than ({lt})"] = lambda x: x < lt 245 if ge is not None: 246 self.__constraint_checks__[f"Greater Than Or Equal To ({ge})"] = ( 247 lambda x: x >= ge 248 ) 249 if le is not None: 250 self.__constraint_checks__[f"Less Than Or Equal To ({le})"] = ( 251 lambda x: x <= le 252 ) 253 if eq is not None: 254 self.__constraint_checks__[f"Equal To ({eq})"] = lambda x: x == eq 255 if ne is not None: 256 self.__constraint_checks__[f"Not Equal To ({ne})"] = ( 257 lambda x: x != ne 258 )
Creates a constraint object that can be used to validate a value against a set of constraints.
Optional Arguments:
pattern:- What: A regex pattern that the value must match.
- Type: str or None
- Default: None
includes:- What: A list of values that the value must be in.
- Type: list, tuple, set or None
- Default: None
excludes:- What: A list of values that the value must not be in.
- Type: list, tuple, set or None
- Default: None
gt:- What: The value must be greater than this value.
- Type: float, int or None
- Default: None
lt:- What: The value must be less than this value.
- Type: float, int or None
- Default: None
ge:- What: The value must be greater than or equal to this value.
- Type: float, int or None
- Default: None
le:- What: The value must be less than or equal to this value.
- Type: float, int or None
- Default: None
eq:- What: The value must be equal to this value.
- Type: float, int or None
- Default: None
ne:- What: The value must not be equal to this value.
- Type: float, int or None
- Default: None
264def merge_type_dicts(target, source): 265 """Merge source type dict into target in-place. 266 267 Preserves multiple schema variants for collection types (list, tuple, dict, set) 268 when distinct collection schemas are united. 269 """ 270 for key, value in source.items(): 271 if key not in target: 272 target[key] = value 273 elif key == "__extra__": 274 if isinstance(target[key], dict) and isinstance(value, dict): 275 for ek, ev in value.items(): 276 if ek not in target[key]: 277 target[key][ek] = ev 278 elif isinstance(target[key][ek], list) and isinstance( 279 ev, list 280 ): 281 target[key][ek] = list( 282 dict.fromkeys(target[key][ek] + ev) 283 ) 284 elif target[key] == value: 285 continue 286 elif key in iterable_types: 287 if isinstance(target[key], list): 288 if isinstance(value, list): 289 for v in value: 290 if v not in target[key]: 291 target[key].append(v) 292 else: 293 if value not in target[key]: 294 target[key].append(value) 295 else: 296 if isinstance(value, list): 297 new_list = [target[key]] 298 for v in value: 299 if v not in new_list: 300 new_list.append(v) 301 target[key] = new_list 302 else: 303 target[key] = [target[key], value] 304 elif isinstance(target[key], dict) and isinstance(value, dict): 305 merge_type_dicts(target[key], value) 306 else: 307 target[key] = value
Merge source type dict into target in-place.
Preserves multiple schema variants for collection types (list, tuple, dict, set) when distinct collection schemas are united.
310def DeepMerge(original: dict, update: dict): 311 """ 312 Merge two dictionaries together, recursively merging any nested dictionaries and preserving collection variant schemas. 313 314 Required Arguments: 315 316 - `original`: 317 - What: The original dictionary to merge the update into. 318 - Type: dict 319 - `update`: 320 - What: The dictionary to merge into the original dictionary. 321 - Type: dict 322 """ 323 original = copy.deepcopy(original) 324 merge_type_dicts(original, update) 325 return original
Merge two dictionaries together, recursively merging any nested dictionaries and preserving collection variant schemas.
Required Arguments:
original:- What: The original dictionary to merge the update into.
- Type: dict
update:- What: The dictionary to merge into the original dictionary.
- Type: dict
328def WithSubclasses(cls): 329 """ 330 A utility class to preserve backwards compatibility 331 with the older versions of type_enforced. 332 333 By default subclasses of all classes are now enforced by type_enforced. 334 335 It is slated to be removed in the next major version. 336 """ 337 # TODO: Remove this in the next major version of type_enforced 338 return cls
A utility class to preserve backwards compatibility with the older versions of type_enforced.
By default subclasses of all classes are now enforced by type_enforced.
It is slated to be removed in the next major version.