Bläddra i källkod

improve error message for untyped vars (#4963)

Khaleel Al-Adhami 2 månader sedan
förälder
incheckning
518d9753e0
4 ändrade filer med 60 tillägg och 7 borttagningar
  1. 3 2
      reflex/components/core/foreach.py
  2. 3 3
      reflex/state.py
  3. 31 1
      reflex/utils/exceptions.py
  4. 23 1
      reflex/vars/base.py

+ 3 - 2
reflex/components/core/foreach.py

@@ -100,8 +100,9 @@ class Foreach(Component):
             component.children = [component._render().render_component()]
         except UntypedVarError as e:
             raise UntypedVarError(
-                f"Could not foreach over var `{iterable!s}` without a type annotation. "
-                "See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
+                iterable,
+                "foreach",
+                "https://reflex.dev/docs/library/dynamic-rendering/foreach/",
             ) from e
         return component
 

+ 3 - 3
reflex/state.py

@@ -1013,9 +1013,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
 
         if not types.is_valid_var_type(prop._var_type):
             raise VarTypeError(
-                "State vars must be primitive Python types, "
-                "Plotly figures, Pandas dataframes, "
-                "or subclasses of rx.Base. "
+                "State vars must be of a serializable type. "
+                "Valid types include strings, numbers, booleans, lists, "
+                "dictionaries, dataclasses, datetime objects, and pydantic models. "
                 f'Found var "{prop._js_expr}" with type {prop._var_type}.'
             )
         cls._set_var(prop)

+ 31 - 1
reflex/utils/exceptions.py

@@ -1,6 +1,11 @@
 """Custom Exceptions."""
 
-from typing import Any
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+    from reflex.vars import Var
 
 
 class ReflexError(Exception):
@@ -78,6 +83,31 @@ class VarAttributeError(ReflexError, AttributeError):
 class UntypedVarError(ReflexError, TypeError):
     """Custom TypeError for untyped var errors."""
 
+    def __init__(self, var: Var, action: str, doc_link: str = ""):
+        """Create an UntypedVarError from a var.
+
+        Args:
+            var: The var.
+            action: The action that caused the error.
+            doc_link: The link to the documentation.
+        """
+        var_data = var._get_all_var_data()
+        is_state_var = (
+            var_data
+            and var_data.state
+            and var_data.field_name
+            and var_data.state + "." + var_data.field_name == str(var)
+        )
+        super().__init__(
+            f"Cannot {action} on untyped var '{var!s}' of type '{var._var_type!s}'."
+            + (
+                " Please add a type annotation to the var in the state class."
+                if is_state_var
+                else " You can call the var's .to(desired_type) method to convert it to the desired type."
+            )
+            + (f" See {doc_link}" if doc_link else "")
+        )
+
 
 class UntypedComputedVarError(ReflexError, TypeError):
     """Custom TypeError for untyped computed var errors."""

+ 23 - 1
reflex/vars/base.py

@@ -1256,6 +1256,27 @@ class Var(Generic[VAR_TYPE]):
 
     if not TYPE_CHECKING:
 
+        def __getitem__(self, key: Any) -> Var:
+            """Get the item from the var.
+
+            Args:
+                key: The key to get.
+
+            Raises:
+                UntypedVarError: If the var type is Any.
+                TypeError: If the var type is Any.
+
+            # noqa: DAR101 self
+            """
+            if self._var_type is Any:
+                raise exceptions.UntypedVarError(
+                    self,
+                    f"access the item '{key}'",
+                )
+            raise TypeError(
+                f"Var of type {self._var_type} does not support item access."
+            )
+
         def __getattr__(self, name: str):
             """Get an attribute of the var.
 
@@ -1281,7 +1302,8 @@ class Var(Generic[VAR_TYPE]):
 
             if self._var_type is Any:
                 raise exceptions.UntypedVarError(
-                    f"You must provide an annotation for the state var `{self!s}`. Annotation cannot be `{self._var_type}`."
+                    self,
+                    f"access the attribute '{name}'",
                 )
 
             raise VarAttributeError(