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
260def DeepMerge(original: dict, update: dict):
261    """
262    Merge two dictionaries together, recursively merging any nested dictionaries and extending any nested lists.
263
264    Required Arguments:
265
266    - `original`:
267        - What: The original dictionary to merge the update into.
268        - Type: dict
269    - `update`:
270        - What: The dictionary to merge into the original dictionary.
271        - Type: dict
272    """
273    original = copy.deepcopy(original)
274    for key, value in update.items():
275        if (
276            key in original
277            and isinstance(original[key], dict)
278            and isinstance(value, dict)
279        ):
280            original[key] = DeepMerge(original[key], value)
281        elif (
282            key in original
283            and isinstance(original[key], list)
284            and isinstance(value, list)
285        ):
286            original[key].extend(value)
287        else:
288            original[key] = value
289    return original
290
291
292def merge_type_dicts(target, source):
293    """Merge source type dict into target in-place.
294
295    Like DeepMerge but without copy.deepcopy
296    Safe because both dicts are freshly created during type parsing.
297    """
298    for key, value in source.items():
299        if key not in target:
300            target[key] = value
301        elif isinstance(target[key], dict) and isinstance(value, dict):
302            merge_type_dicts(target[key], value)
303        elif isinstance(target[key], list) and isinstance(value, list):
304            target[key].extend(value)
305        else:
306            target[key] = value
307
308
309def WithSubclasses(cls):
310    """
311    A utility class to preserve backwards compatibility
312    with the older versions of type_enforced.
313
314    By default subclasses of all classes are now enforced by type_enforced.
315
316    It is slated to be removed in the next major version.
317    """
318    # TODO: Remove this in the next major version of type_enforced
319    return cls
320
321
322iterable_types = frozenset({list, tuple, set, dict})
class Partial:
  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.

Partial(__fn__, *__args__, **__kwargs__)
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__()
class GenericConstraint:
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]
GenericConstraint(constraints: dict)
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.
class Constraint(GenericConstraint):
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            )
Constraint( pattern: str | None = None, includes: list | tuple | set | None = None, excludes: list | tuple | set | None = None, gt: float | int | None = None, lt: float | int | None = None, ge: float | int | None = None, le: float | int | None = None, eq: float | int | None = None, ne: float | int | None = None)
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
def DeepMerge(original: dict, update: dict):
261def DeepMerge(original: dict, update: dict):
262    """
263    Merge two dictionaries together, recursively merging any nested dictionaries and extending any nested lists.
264
265    Required Arguments:
266
267    - `original`:
268        - What: The original dictionary to merge the update into.
269        - Type: dict
270    - `update`:
271        - What: The dictionary to merge into the original dictionary.
272        - Type: dict
273    """
274    original = copy.deepcopy(original)
275    for key, value in update.items():
276        if (
277            key in original
278            and isinstance(original[key], dict)
279            and isinstance(value, dict)
280        ):
281            original[key] = DeepMerge(original[key], value)
282        elif (
283            key in original
284            and isinstance(original[key], list)
285            and isinstance(value, list)
286        ):
287            original[key].extend(value)
288        else:
289            original[key] = value
290    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
def merge_type_dicts(target, source):
293def merge_type_dicts(target, source):
294    """Merge source type dict into target in-place.
295
296    Like DeepMerge but without copy.deepcopy
297    Safe because both dicts are freshly created during type parsing.
298    """
299    for key, value in source.items():
300        if key not in target:
301            target[key] = value
302        elif isinstance(target[key], dict) and isinstance(value, dict):
303            merge_type_dicts(target[key], value)
304        elif isinstance(target[key], list) and isinstance(value, list):
305            target[key].extend(value)
306        else:
307            target[key] = value

Merge source type dict into target in-place.

Like DeepMerge but without copy.deepcopy Safe because both dicts are freshly created during type parsing.

def WithSubclasses(cls):
310def WithSubclasses(cls):
311    """
312    A utility class to preserve backwards compatibility
313    with the older versions of type_enforced.
314
315    By default subclasses of all classes are now enforced by type_enforced.
316
317    It is slated to be removed in the next major version.
318    """
319    # TODO: Remove this in the next major version of type_enforced
320    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.

iterable_types = frozenset({<class 'list'>, <class 'set'>, <class 'tuple'>, <class 'dict'>})