From 39952ce70bf92081f49d3f9ccd47aafd7f43bd69 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 29 Oct 2024 16:07:31 -0700 Subject: [PATCH] add type validation for state setattr --- reflex/utils/types.py | 52 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 3d7992011..baedcc5a0 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -510,16 +510,66 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None) raise TypeError(f"Invalid type for issubclass: {cls_base}") from te -def _isinstance(obj: Any, cls: GenericType) -> bool: +def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool: """Check if an object is an instance of a class. Args: obj: The object to check. cls: The class to check against. + nested: Whether the check is nested. Returns: Whether the object is an instance of the class. """ + if cls is Any: + return True + + if cls is None or cls is type(None): + return obj is None + + if is_literal(cls): + return obj in get_args(cls) + + if is_union(cls): + return any(_isinstance(obj, arg) for arg in get_args(cls)) + + origin = get_origin(cls) + + if origin is None: + # cls is a simple class + return isinstance(obj, cls) + + args = get_args(cls) + + if not args: + # cls is a simple generic class + return isinstance(obj, origin) + + if nested and args: + if origin is list: + return isinstance(obj, list) and all( + _isinstance(item, args[0]) for item in obj + ) + if origin is tuple: + if args[-1] is Ellipsis: + return isinstance(obj, tuple) and all( + _isinstance(item, args[0]) for item in obj + ) + return ( + isinstance(obj, tuple) + and len(obj) == len(args) + and all(_isinstance(item, arg) for item, arg in zip(obj, args)) + ) + if origin is dict: + return isinstance(obj, dict) and all( + _isinstance(key, args[0]) and _isinstance(value, args[1]) + for key, value in obj.items() + ) + if origin is set: + return isinstance(obj, set) and all( + _isinstance(item, args[0]) for item in obj + ) + return isinstance(obj, get_base_class(cls))