type_enforced.utils
1import types, re, copy 2from functools import update_wrapper 3 4 5class Partial: 6 """ 7 A special class wrapper to allow for easy partial function wrappings and calls. 8 """ 9 10 def __init__( 11 self, 12 __fn__, 13 *__args__, 14 **__kwargs__, 15 ): 16 update_wrapper(self, __fn__) 17 self.__fn__ = __fn__ 18 self.__args__ = __args__ 19 self.__kwargs__ = __kwargs__ 20 self.__fnArity__ = self.__getFnArity__() 21 self.__arity__ = self.__getArity__(__args__, __kwargs__) 22 23 def __exception__(self, message): 24 pre_message = ( 25 f"({self.__fn__.__module__}.{self.__fn__.__qualname__}_partial): " 26 ) 27 raise Exception(pre_message + message) 28 29 def __call__(self, *args, **kwargs): 30 new_args = self.__args__ + args 31 new_kwargs = {**self.__kwargs__, **kwargs} 32 self.__arity__ = self.__getArity__(new_args, new_kwargs) 33 if self.__arity__ < 0: 34 self.__exception__("Too many arguments were supplied") 35 if self.__arity__ == 0: 36 results = self.__fn__(*new_args, **new_kwargs) 37 return results 38 return Partial( 39 self.__fn__, 40 *new_args, 41 **new_kwargs, 42 ) 43 44 def __repr__(self): 45 return f"<Partial {self.__fn__.__module__}.{self.__fn__.__qualname__} object at {hex(id(self))}>" 46 47 def __getArity__(self, args, kwargs): 48 return self.__fnArity__ - (len(args) + len(kwargs)) 49 50 def __getFnArity__(self): 51 if not isinstance(self.__fn__, (types.MethodType, types.FunctionType)): 52 self.__exception__( 53 "A non function was passed as a function and does not have any arity. See the stack trace above for more information." 54 ) 55 extra_method_input_count = ( 56 1 if isinstance(self.__fn__, (types.MethodType)) else 0 57 ) 58 return self.__fn__.__code__.co_argcount - extra_method_input_count 59 60 61class GenericConstraint: 62 def __init__(self, constraints: dict): 63 """ 64 Creates a generic constraint object that can be used to validate a value against a set of constraints. 65 66 Required Arguments: 67 68 - `constraints`: 69 - What: A dictionary of constraint names and their associated functions. 70 - Type: dict 71 - Note: All values in the dictionary must be functions that take a single argument and return a boolean. 72 - Note: The dictionary keys will be used to identify the failed constraints in the error messages. 73 """ 74 assert all( 75 hasattr(v, "__call__") for v in constraints.values() 76 ), "All constraints must be functions." 77 self.__constraint_checks__ = constraints 78 79 def __validate__(self, varname, value): 80 for check_name, check_func in self.__constraint_checks__.items(): 81 try: 82 if not check_func(value): 83 return f"Constraint `{check_name}` not met with the provided value `{value}`" 84 except Exception as e: 85 return f"An exception was raised when checking the constraint `{check_name}` with the provided value `{value}`. Error: {e}" 86 return True 87 88 89class Constraint(GenericConstraint): 90 def __init__( 91 self, 92 pattern: [str, None] = None, 93 includes: [list, tuple, set, None] = None, 94 excludes: [list, tuple, set, None] = None, 95 gt: [float, int, None] = None, 96 lt: [float, int, None] = None, 97 ge: [float, int, None] = None, 98 le: [float, int, None] = None, 99 eq: [float, int, None] = None, 100 ne: [float, int, None] = None, 101 ): 102 """ 103 Creates a constraint object that can be used to validate a value against a set of constraints. 104 105 Optional Arguments: 106 107 - `pattern`: 108 - What: A regex pattern that the value must match. 109 - Type: str or None 110 - Default: None 111 - `includes`: 112 - What: A list of values that the value must be in. 113 - Type: list, tuple, set or None 114 - Default: None 115 - `excludes`: 116 - What: A list of values that the value must not be in. 117 - Type: list, tuple, set or None 118 - Default: None 119 - `gt`: 120 - What: The value must be greater than this value. 121 - Type: float, int or None 122 - Default: None 123 - `lt`: 124 - What: The value must be less than this value. 125 - Type: float, int or None 126 - Default: None 127 - `ge`: 128 - What: The value must be greater than or equal to this value. 129 - Type: float, int or None 130 - Default: None 131 - `le`: 132 - What: The value must be less than or equal to this value. 133 - Type: float, int or None 134 - Default: None 135 - `eq`: 136 - What: The value must be equal to this value. 137 - Type: float, int or None 138 - Default: None 139 - `ne`: 140 - What: The value must not be equal to this value. 141 - Type: float, int or None 142 - Default: None 143 """ 144 assert any( 145 v is not None 146 for v in [pattern, gt, lt, ge, le, eq, ne, includes, excludes] 147 ), "At least one constraint must be provided." 148 assert isinstance( 149 includes, (list, tuple, set, type(None)) 150 ), "Includes must be a list, tuple, set or None." 151 assert isinstance( 152 excludes, (list, tuple, set, type(None)) 153 ), "Excludes must be a list, tuple, set or None." 154 assert isinstance( 155 pattern, (str, type(None)) 156 ), "Pattern must be a string or None." 157 assert isinstance( 158 gt, (float, int, type(None)) 159 ), "Greater than constraint must be a float, int or None." 160 assert isinstance( 161 lt, (float, int, type(None)) 162 ), "Less than constraint must be a float, int or None." 163 assert isinstance( 164 ge, (float, int, type(None)) 165 ), "Greater or equal to constraint must be a float, int or None." 166 assert isinstance( 167 le, (float, int, type(None)) 168 ), "Less than or equal to constraint must be a float, int or None." 169 assert isinstance( 170 eq, (float, int, type(None)) 171 ), "Equal to constraint must be a float, int or None." 172 assert isinstance( 173 ne, (float, int, type(None)) 174 ), "Not equal to constraint must be a float, int or None." 175 self.__constraint_checks__ = {} 176 if pattern is not None: 177 self.__constraint_checks__["be a string"] = lambda x: isinstance( 178 x, str 179 ) 180 self.__constraint_checks__["Regex Pattern Match"] = lambda x: bool( 181 re.findall(pattern, x) 182 ) 183 if includes is not None: 184 self.__constraint_checks__[f"Includes"] = lambda x: x in includes 185 if excludes is not None: 186 self.__constraint_checks__["Excludes"] = lambda x: x not in excludes 187 if gt is not None: 188 self.__constraint_checks__[f"Greater Than ({gt})"] = ( 189 lambda x: x > gt 190 ) 191 if lt is not None: 192 self.__constraint_checks__[f"Less Than ({lt})"] = lambda x: x < lt 193 if ge is not None: 194 self.__constraint_checks__[f"Greater Than Or Equal To ({ge})"] = ( 195 lambda x: x >= ge 196 ) 197 if le is not None: 198 self.__constraint_checks__[f"Less Than Or Equal To ({le})"] = ( 199 lambda x: x <= le 200 ) 201 if eq is not None: 202 self.__constraint_checks__[f"Equal To ({eq})"] = lambda x: x == eq 203 if ne is not None: 204 self.__constraint_checks__[f"Not Equal To ({ne})"] = ( 205 lambda x: x != ne 206 ) 207 208 209class WithSubclasses: 210 def __init__(self, obj, cache=True): 211 """ 212 A special helper class to allow a class type to be passed and also allow all subclasses of that type. 213 214 This allows delayed evaluation of the subclasses until initial call time such that delayed inherited classes are considered. 215 216 Note: You can not validate that a passed object is a WithSubclasses object as this is a special case. 217 218 Required Arguments: 219 220 - `obj`: 221 - What: An uninitialized class that should also be considered type correct if a subclass is passed. 222 - Type: Any Uninitialized class 223 224 Optional Arguments: 225 226 - `cache`: 227 - What: Whether to cache the calcuation of the subclasses. If set to False, this will recalculate the subclasses on each call. 228 - Type: bool 229 - Default: True 230 """ 231 self.obj = obj 232 self.cache = cache 233 234 @classmethod 235 def __get_subclasses__(cls, obj): 236 """ 237 A special helper method to get all of the subclasses of a provided class object. 238 239 Requires: 240 241 - `obj`: 242 - What: An uninitialized class that should also be considered type correct if a subclass is passed. 243 - Type: Any Uninitialized class 244 245 Returns: 246 247 - `out`: 248 - What: A list of all of the subclasses (recursively parsed) 249 - Type: list of strs 250 251 252 Notes: 253 254 - From a functional perspective, this recursively gets the subclasses for an uninitialised class (type). 255 """ 256 out = [obj] 257 for i in obj.__subclasses__(): 258 out += cls.__get_subclasses__(i) 259 return out 260 261 def get_subclasses(self): 262 """ 263 Returns a list of all of the subclasses of the class that was passed to the WithSubclasses object. 264 265 If already calculated, it will return the cached value. 266 267 Returns: 268 269 - `subclasses`: 270 - What: A list of all of the subclasses of the class that was passed to the WithSubclasses object. 271 - Type: list of strs 272 """ 273 if not hasattr(self, "subclasses") or self.cache == False: 274 self.subclasses = self.__get_subclasses__(self.obj) 275 return self.subclasses 276 277 278def DeepMerge(original: dict, update: dict): 279 """ 280 Merge two dictionaries together, recursively merging any nested dictionaries and extending any nested lists. 281 282 Required Arguments: 283 284 - `original`: 285 - What: The original dictionary to merge the update into. 286 - Type: dict 287 - `update`: 288 - What: The dictionary to merge into the original dictionary. 289 - Type: dict 290 """ 291 original = copy.deepcopy(original) 292 for key, value in update.items(): 293 if ( 294 key in original 295 and isinstance(original[key], dict) 296 and isinstance(value, dict) 297 ): 298 DeepMerge(original[key], value) 299 elif ( 300 key in original 301 and isinstance(original[key], list) 302 and isinstance(value, list) 303 ): 304 original[key].extend(value) 305 else: 306 original[key] = value 307 return original
6class Partial: 7 """ 8 A special class wrapper to allow for easy partial function wrappings and calls. 9 """ 10 11 def __init__( 12 self, 13 __fn__, 14 *__args__, 15 **__kwargs__, 16 ): 17 update_wrapper(self, __fn__) 18 self.__fn__ = __fn__ 19 self.__args__ = __args__ 20 self.__kwargs__ = __kwargs__ 21 self.__fnArity__ = self.__getFnArity__() 22 self.__arity__ = self.__getArity__(__args__, __kwargs__) 23 24 def __exception__(self, message): 25 pre_message = ( 26 f"({self.__fn__.__module__}.{self.__fn__.__qualname__}_partial): " 27 ) 28 raise Exception(pre_message + message) 29 30 def __call__(self, *args, **kwargs): 31 new_args = self.__args__ + args 32 new_kwargs = {**self.__kwargs__, **kwargs} 33 self.__arity__ = self.__getArity__(new_args, new_kwargs) 34 if self.__arity__ < 0: 35 self.__exception__("Too many arguments were supplied") 36 if self.__arity__ == 0: 37 results = self.__fn__(*new_args, **new_kwargs) 38 return results 39 return Partial( 40 self.__fn__, 41 *new_args, 42 **new_kwargs, 43 ) 44 45 def __repr__(self): 46 return f"<Partial {self.__fn__.__module__}.{self.__fn__.__qualname__} object at {hex(id(self))}>" 47 48 def __getArity__(self, args, kwargs): 49 return self.__fnArity__ - (len(args) + len(kwargs)) 50 51 def __getFnArity__(self): 52 if not isinstance(self.__fn__, (types.MethodType, types.FunctionType)): 53 self.__exception__( 54 "A non function was passed as a function and does not have any arity. See the stack trace above for more information." 55 ) 56 extra_method_input_count = ( 57 1 if isinstance(self.__fn__, (types.MethodType)) else 0 58 ) 59 return self.__fn__.__code__.co_argcount - extra_method_input_count
A special class wrapper to allow for easy partial function wrappings and calls.
62class GenericConstraint: 63 def __init__(self, constraints: dict): 64 """ 65 Creates a generic constraint object that can be used to validate a value against a set of constraints. 66 67 Required Arguments: 68 69 - `constraints`: 70 - What: A dictionary of constraint names and their associated functions. 71 - Type: dict 72 - Note: All values in the dictionary must be functions that take a single argument and return a boolean. 73 - Note: The dictionary keys will be used to identify the failed constraints in the error messages. 74 """ 75 assert all( 76 hasattr(v, "__call__") for v in constraints.values() 77 ), "All constraints must be functions." 78 self.__constraint_checks__ = constraints 79 80 def __validate__(self, varname, value): 81 for check_name, check_func in self.__constraint_checks__.items(): 82 try: 83 if not check_func(value): 84 return f"Constraint `{check_name}` not met with the provided value `{value}`" 85 except Exception as e: 86 return f"An exception was raised when checking the constraint `{check_name}` with the provided value `{value}`. Error: {e}" 87 return True
63 def __init__(self, constraints: dict): 64 """ 65 Creates a generic constraint object that can be used to validate a value against a set of constraints. 66 67 Required Arguments: 68 69 - `constraints`: 70 - What: A dictionary of constraint names and their associated functions. 71 - Type: dict 72 - Note: All values in the dictionary must be functions that take a single argument and return a boolean. 73 - Note: The dictionary keys will be used to identify the failed constraints in the error messages. 74 """ 75 assert all( 76 hasattr(v, "__call__") for v in constraints.values() 77 ), "All constraints must be functions." 78 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.
90class Constraint(GenericConstraint): 91 def __init__( 92 self, 93 pattern: [str, None] = None, 94 includes: [list, tuple, set, None] = None, 95 excludes: [list, tuple, set, None] = None, 96 gt: [float, int, None] = None, 97 lt: [float, int, None] = None, 98 ge: [float, int, None] = None, 99 le: [float, int, None] = None, 100 eq: [float, int, None] = None, 101 ne: [float, int, None] = None, 102 ): 103 """ 104 Creates a constraint object that can be used to validate a value against a set of constraints. 105 106 Optional Arguments: 107 108 - `pattern`: 109 - What: A regex pattern that the value must match. 110 - Type: str or None 111 - Default: None 112 - `includes`: 113 - What: A list of values that the value must be in. 114 - Type: list, tuple, set or None 115 - Default: None 116 - `excludes`: 117 - What: A list of values that the value must not be in. 118 - Type: list, tuple, set or None 119 - Default: None 120 - `gt`: 121 - What: The value must be greater than this value. 122 - Type: float, int or None 123 - Default: None 124 - `lt`: 125 - What: The value must be less than this value. 126 - Type: float, int or None 127 - Default: None 128 - `ge`: 129 - What: The value must be greater than or equal to this value. 130 - Type: float, int or None 131 - Default: None 132 - `le`: 133 - What: The value must be less than or equal to this value. 134 - Type: float, int or None 135 - Default: None 136 - `eq`: 137 - What: The value must be equal to this value. 138 - Type: float, int or None 139 - Default: None 140 - `ne`: 141 - What: The value must not be equal to this value. 142 - Type: float, int or None 143 - Default: None 144 """ 145 assert any( 146 v is not None 147 for v in [pattern, gt, lt, ge, le, eq, ne, includes, excludes] 148 ), "At least one constraint must be provided." 149 assert isinstance( 150 includes, (list, tuple, set, type(None)) 151 ), "Includes must be a list, tuple, set or None." 152 assert isinstance( 153 excludes, (list, tuple, set, type(None)) 154 ), "Excludes must be a list, tuple, set or None." 155 assert isinstance( 156 pattern, (str, type(None)) 157 ), "Pattern must be a string or None." 158 assert isinstance( 159 gt, (float, int, type(None)) 160 ), "Greater than constraint must be a float, int or None." 161 assert isinstance( 162 lt, (float, int, type(None)) 163 ), "Less than constraint must be a float, int or None." 164 assert isinstance( 165 ge, (float, int, type(None)) 166 ), "Greater or equal to constraint must be a float, int or None." 167 assert isinstance( 168 le, (float, int, type(None)) 169 ), "Less than or equal to constraint must be a float, int or None." 170 assert isinstance( 171 eq, (float, int, type(None)) 172 ), "Equal to constraint must be a float, int or None." 173 assert isinstance( 174 ne, (float, int, type(None)) 175 ), "Not equal to constraint must be a float, int or None." 176 self.__constraint_checks__ = {} 177 if pattern is not None: 178 self.__constraint_checks__["be a string"] = lambda x: isinstance( 179 x, str 180 ) 181 self.__constraint_checks__["Regex Pattern Match"] = lambda x: bool( 182 re.findall(pattern, x) 183 ) 184 if includes is not None: 185 self.__constraint_checks__[f"Includes"] = lambda x: x in includes 186 if excludes is not None: 187 self.__constraint_checks__["Excludes"] = lambda x: x not in excludes 188 if gt is not None: 189 self.__constraint_checks__[f"Greater Than ({gt})"] = ( 190 lambda x: x > gt 191 ) 192 if lt is not None: 193 self.__constraint_checks__[f"Less Than ({lt})"] = lambda x: x < lt 194 if ge is not None: 195 self.__constraint_checks__[f"Greater Than Or Equal To ({ge})"] = ( 196 lambda x: x >= ge 197 ) 198 if le is not None: 199 self.__constraint_checks__[f"Less Than Or Equal To ({le})"] = ( 200 lambda x: x <= le 201 ) 202 if eq is not None: 203 self.__constraint_checks__[f"Equal To ({eq})"] = lambda x: x == eq 204 if ne is not None: 205 self.__constraint_checks__[f"Not Equal To ({ne})"] = ( 206 lambda x: x != ne 207 )
91 def __init__( 92 self, 93 pattern: [str, None] = None, 94 includes: [list, tuple, set, None] = None, 95 excludes: [list, tuple, set, None] = None, 96 gt: [float, int, None] = None, 97 lt: [float, int, None] = None, 98 ge: [float, int, None] = None, 99 le: [float, int, None] = None, 100 eq: [float, int, None] = None, 101 ne: [float, int, None] = None, 102 ): 103 """ 104 Creates a constraint object that can be used to validate a value against a set of constraints. 105 106 Optional Arguments: 107 108 - `pattern`: 109 - What: A regex pattern that the value must match. 110 - Type: str or None 111 - Default: None 112 - `includes`: 113 - What: A list of values that the value must be in. 114 - Type: list, tuple, set or None 115 - Default: None 116 - `excludes`: 117 - What: A list of values that the value must not be in. 118 - Type: list, tuple, set or None 119 - Default: None 120 - `gt`: 121 - What: The value must be greater than this value. 122 - Type: float, int or None 123 - Default: None 124 - `lt`: 125 - What: The value must be less than this value. 126 - Type: float, int or None 127 - Default: None 128 - `ge`: 129 - What: The value must be greater than or equal to this value. 130 - Type: float, int or None 131 - Default: None 132 - `le`: 133 - What: The value must be less than or equal to this value. 134 - Type: float, int or None 135 - Default: None 136 - `eq`: 137 - What: The value must be equal to this value. 138 - Type: float, int or None 139 - Default: None 140 - `ne`: 141 - What: The value must not be equal to this value. 142 - Type: float, int or None 143 - Default: None 144 """ 145 assert any( 146 v is not None 147 for v in [pattern, gt, lt, ge, le, eq, ne, includes, excludes] 148 ), "At least one constraint must be provided." 149 assert isinstance( 150 includes, (list, tuple, set, type(None)) 151 ), "Includes must be a list, tuple, set or None." 152 assert isinstance( 153 excludes, (list, tuple, set, type(None)) 154 ), "Excludes must be a list, tuple, set or None." 155 assert isinstance( 156 pattern, (str, type(None)) 157 ), "Pattern must be a string or None." 158 assert isinstance( 159 gt, (float, int, type(None)) 160 ), "Greater than constraint must be a float, int or None." 161 assert isinstance( 162 lt, (float, int, type(None)) 163 ), "Less than constraint must be a float, int or None." 164 assert isinstance( 165 ge, (float, int, type(None)) 166 ), "Greater or equal to constraint must be a float, int or None." 167 assert isinstance( 168 le, (float, int, type(None)) 169 ), "Less than or equal to constraint must be a float, int or None." 170 assert isinstance( 171 eq, (float, int, type(None)) 172 ), "Equal to constraint must be a float, int or None." 173 assert isinstance( 174 ne, (float, int, type(None)) 175 ), "Not equal to constraint must be a float, int or None." 176 self.__constraint_checks__ = {} 177 if pattern is not None: 178 self.__constraint_checks__["be a string"] = lambda x: isinstance( 179 x, str 180 ) 181 self.__constraint_checks__["Regex Pattern Match"] = lambda x: bool( 182 re.findall(pattern, x) 183 ) 184 if includes is not None: 185 self.__constraint_checks__[f"Includes"] = lambda x: x in includes 186 if excludes is not None: 187 self.__constraint_checks__["Excludes"] = lambda x: x not in excludes 188 if gt is not None: 189 self.__constraint_checks__[f"Greater Than ({gt})"] = ( 190 lambda x: x > gt 191 ) 192 if lt is not None: 193 self.__constraint_checks__[f"Less Than ({lt})"] = lambda x: x < lt 194 if ge is not None: 195 self.__constraint_checks__[f"Greater Than Or Equal To ({ge})"] = ( 196 lambda x: x >= ge 197 ) 198 if le is not None: 199 self.__constraint_checks__[f"Less Than Or Equal To ({le})"] = ( 200 lambda x: x <= le 201 ) 202 if eq is not None: 203 self.__constraint_checks__[f"Equal To ({eq})"] = lambda x: x == eq 204 if ne is not None: 205 self.__constraint_checks__[f"Not Equal To ({ne})"] = ( 206 lambda x: x != ne 207 )
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
210class WithSubclasses: 211 def __init__(self, obj, cache=True): 212 """ 213 A special helper class to allow a class type to be passed and also allow all subclasses of that type. 214 215 This allows delayed evaluation of the subclasses until initial call time such that delayed inherited classes are considered. 216 217 Note: You can not validate that a passed object is a WithSubclasses object as this is a special case. 218 219 Required Arguments: 220 221 - `obj`: 222 - What: An uninitialized class that should also be considered type correct if a subclass is passed. 223 - Type: Any Uninitialized class 224 225 Optional Arguments: 226 227 - `cache`: 228 - What: Whether to cache the calcuation of the subclasses. If set to False, this will recalculate the subclasses on each call. 229 - Type: bool 230 - Default: True 231 """ 232 self.obj = obj 233 self.cache = cache 234 235 @classmethod 236 def __get_subclasses__(cls, obj): 237 """ 238 A special helper method to get all of the subclasses of a provided class object. 239 240 Requires: 241 242 - `obj`: 243 - What: An uninitialized class that should also be considered type correct if a subclass is passed. 244 - Type: Any Uninitialized class 245 246 Returns: 247 248 - `out`: 249 - What: A list of all of the subclasses (recursively parsed) 250 - Type: list of strs 251 252 253 Notes: 254 255 - From a functional perspective, this recursively gets the subclasses for an uninitialised class (type). 256 """ 257 out = [obj] 258 for i in obj.__subclasses__(): 259 out += cls.__get_subclasses__(i) 260 return out 261 262 def get_subclasses(self): 263 """ 264 Returns a list of all of the subclasses of the class that was passed to the WithSubclasses object. 265 266 If already calculated, it will return the cached value. 267 268 Returns: 269 270 - `subclasses`: 271 - What: A list of all of the subclasses of the class that was passed to the WithSubclasses object. 272 - Type: list of strs 273 """ 274 if not hasattr(self, "subclasses") or self.cache == False: 275 self.subclasses = self.__get_subclasses__(self.obj) 276 return self.subclasses
211 def __init__(self, obj, cache=True): 212 """ 213 A special helper class to allow a class type to be passed and also allow all subclasses of that type. 214 215 This allows delayed evaluation of the subclasses until initial call time such that delayed inherited classes are considered. 216 217 Note: You can not validate that a passed object is a WithSubclasses object as this is a special case. 218 219 Required Arguments: 220 221 - `obj`: 222 - What: An uninitialized class that should also be considered type correct if a subclass is passed. 223 - Type: Any Uninitialized class 224 225 Optional Arguments: 226 227 - `cache`: 228 - What: Whether to cache the calcuation of the subclasses. If set to False, this will recalculate the subclasses on each call. 229 - Type: bool 230 - Default: True 231 """ 232 self.obj = obj 233 self.cache = cache
A special helper class to allow a class type to be passed and also allow all subclasses of that type.
This allows delayed evaluation of the subclasses until initial call time such that delayed inherited classes are considered.
Note: You can not validate that a passed object is a WithSubclasses object as this is a special case.
Required Arguments:
obj
:- What: An uninitialized class that should also be considered type correct if a subclass is passed.
- Type: Any Uninitialized class
Optional Arguments:
cache
:- What: Whether to cache the calcuation of the subclasses. If set to False, this will recalculate the subclasses on each call.
- Type: bool
- Default: True
262 def get_subclasses(self): 263 """ 264 Returns a list of all of the subclasses of the class that was passed to the WithSubclasses object. 265 266 If already calculated, it will return the cached value. 267 268 Returns: 269 270 - `subclasses`: 271 - What: A list of all of the subclasses of the class that was passed to the WithSubclasses object. 272 - Type: list of strs 273 """ 274 if not hasattr(self, "subclasses") or self.cache == False: 275 self.subclasses = self.__get_subclasses__(self.obj) 276 return self.subclasses
Returns a list of all of the subclasses of the class that was passed to the WithSubclasses object.
If already calculated, it will return the cached value.
Returns:
subclasses
:- What: A list of all of the subclasses of the class that was passed to the WithSubclasses object.
- Type: list of strs
279def DeepMerge(original: dict, update: dict): 280 """ 281 Merge two dictionaries together, recursively merging any nested dictionaries and extending any nested lists. 282 283 Required Arguments: 284 285 - `original`: 286 - What: The original dictionary to merge the update into. 287 - Type: dict 288 - `update`: 289 - What: The dictionary to merge into the original dictionary. 290 - Type: dict 291 """ 292 original = copy.deepcopy(original) 293 for key, value in update.items(): 294 if ( 295 key in original 296 and isinstance(original[key], dict) 297 and isinstance(value, dict) 298 ): 299 DeepMerge(original[key], value) 300 elif ( 301 key in original 302 and isinstance(original[key], list) 303 and isinstance(value, list) 304 ): 305 original[key].extend(value) 306 else: 307 original[key] = value 308 return original
Merge two dictionaries together, recursively merging any nested dictionaries and extending any nested lists.
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