From 6420fb12526bed1d76e94fdfc1c6fdabbb2c3638 Mon Sep 17 00:00:00 2001
From: Elijah Ahianyo <elijahahianyo@gmail.com>
Date: Tue, 4 Jun 2024 11:50:02 -0700
Subject: [PATCH] [REF-3010] Circular Imports Fix (#3433)

---
 reflex/components/core/html.py             |  2 +-
 reflex/components/el/__init__.pyi          |  3 ++-
 reflex/components/el/elements/__init__.py  |  2 +-
 reflex/components/el/elements/__init__.pyi |  5 +++--
 reflex/utils/format.py                     | 12 ++++++++----
 reflex/utils/serializers.py                |  7 ++++++-
 reflex/utils/types.py                      |  4 +++-
 reflex/vars.py                             | 14 +++++++++++++-
 8 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/reflex/components/core/html.py b/reflex/components/core/html.py
index f4d9ba923..b68761316 100644
--- a/reflex/components/core/html.py
+++ b/reflex/components/core/html.py
@@ -9,7 +9,7 @@ class Html(Div):
     """Render the html.
 
     Returns:
-        The code to render the  html component.
+        The code to render the html component.
     """
 
     # The HTML to render.
diff --git a/reflex/components/el/__init__.pyi b/reflex/components/el/__init__.pyi
index 81b00e37e..0181309eb 100644
--- a/reflex/components/el/__init__.pyi
+++ b/reflex/components/el/__init__.pyi
@@ -185,7 +185,7 @@ from .elements.tables import tfoot as tfoot
 from .elements.tables import th as th
 from .elements.tables import thead as thead
 from .elements.tables import tr as tr
-from .elements.tables import Tbody as Tbody
+from .elements.tables import tbody as tbody
 from .elements.tables import Caption as Caption
 from .elements.tables import Col as Col
 from .elements.tables import Colgroup as Colgroup
@@ -195,6 +195,7 @@ from .elements.tables import Tfoot as Tfoot
 from .elements.tables import Th as Th
 from .elements.tables import Thead as Thead
 from .elements.tables import Tr as Tr
+from .elements.tables import Tbody as Tbody
 from .elements.typography import blockquote as blockquote
 from .elements.typography import dd as dd
 from .elements.typography import div as div
diff --git a/reflex/components/el/elements/__init__.py b/reflex/components/el/elements/__init__.py
index 4a029e7dc..70a7dad4a 100644
--- a/reflex/components/el/elements/__init__.py
+++ b/reflex/components/el/elements/__init__.py
@@ -102,7 +102,7 @@ _MAPPING = {
         "th",
         "thead",
         "tr",
-        "Tbody",
+        "tbody",
     ],
     "typography": [
         "blockquote",
diff --git a/reflex/components/el/elements/__init__.pyi b/reflex/components/el/elements/__init__.pyi
index 9e812790a..adaf63049 100644
--- a/reflex/components/el/elements/__init__.pyi
+++ b/reflex/components/el/elements/__init__.pyi
@@ -183,7 +183,7 @@ from .tables import tfoot as tfoot
 from .tables import th as th
 from .tables import thead as thead
 from .tables import tr as tr
-from .tables import Tbody as Tbody
+from .tables import tbody as tbody
 from .tables import Caption as Caption
 from .tables import Col as Col
 from .tables import Colgroup as Colgroup
@@ -193,6 +193,7 @@ from .tables import Tfoot as Tfoot
 from .tables import Th as Th
 from .tables import Thead as Thead
 from .tables import Tr as Tr
+from .tables import Tbody as Tbody
 from .typography import blockquote as blockquote
 from .typography import dd as dd
 from .typography import div as div
@@ -316,7 +317,7 @@ _MAPPING = {
         "th",
         "thead",
         "tr",
-        "Tbody",
+        "tbody",
     ],
     "typography": [
         "blockquote",
diff --git a/reflex/utils/format.py b/reflex/utils/format.py
index 5a0d1b959..f3c2e63de 100644
--- a/reflex/utils/format.py
+++ b/reflex/utils/format.py
@@ -9,8 +9,7 @@ import re
 from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
 
 from reflex import constants
-from reflex.utils import exceptions, serializers, types
-from reflex.utils.serializers import serialize
+from reflex.utils import exceptions, types
 from reflex.vars import BaseVar, Var
 
 if TYPE_CHECKING:
@@ -400,6 +399,7 @@ def format_prop(
     """
     # import here to avoid circular import.
     from reflex.event import EventChain
+    from reflex.utils import serializers
 
     try:
         # Handle var props.
@@ -687,6 +687,8 @@ def format_state(value: Any, key: Optional[str] = None) -> Any:
     Raises:
         TypeError: If the given value is not a valid state.
     """
+    from reflex.utils import serializers
+
     # Handle dicts.
     if isinstance(value, dict):
         return {k: format_state(v, k) for k, v in value.items()}
@@ -700,7 +702,7 @@ def format_state(value: Any, key: Optional[str] = None) -> Any:
         return value
 
     # Serialize the value.
-    serialized = serialize(value)
+    serialized = serializers.serialize(value)
     if serialized is not None:
         return serialized
 
@@ -803,7 +805,9 @@ def json_dumps(obj: Any) -> str:
     Returns:
         A string
     """
-    return json.dumps(obj, ensure_ascii=False, default=serialize)
+    from reflex.utils import serializers
+
+    return json.dumps(obj, ensure_ascii=False, default=serializers.serialize)
 
 
 def unwrap_vars(value: str) -> str:
diff --git a/reflex/utils/serializers.py b/reflex/utils/serializers.py
index f3f9e635f..aa9b6e484 100644
--- a/reflex/utils/serializers.py
+++ b/reflex/utils/serializers.py
@@ -12,7 +12,7 @@ from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union, get_type_
 
 from reflex.base import Base
 from reflex.constants.colors import Color, format_color
-from reflex.utils import exceptions, format, types
+from reflex.utils import exceptions, types
 
 # Mapping from type to a serializer.
 # The serializer should convert the type to a JSON object.
@@ -154,6 +154,8 @@ def serialize_primitive(value: Union[bool, int, float, None]) -> str:
     Returns:
         The serialized number/bool/None.
     """
+    from reflex.utils import format
+
     return format.json_dumps(value)
 
 
@@ -180,6 +182,8 @@ def serialize_list(value: Union[List, Tuple, Set]) -> str:
     Returns:
         The serialized list.
     """
+    from reflex.utils import format
+
     # Dump the list to a string.
     fprop = format.json_dumps(list(value))
 
@@ -202,6 +206,7 @@ def serialize_dict(prop: Dict[str, Any]) -> str:
     """
     # Import here to avoid circular imports.
     from reflex.event import EventHandler
+    from reflex.utils import format
 
     prop_dict = {}
 
diff --git a/reflex/utils/types.py b/reflex/utils/types.py
index 6dd120e3d..e26904385 100644
--- a/reflex/utils/types.py
+++ b/reflex/utils/types.py
@@ -42,7 +42,7 @@ from sqlalchemy.orm import (
 
 from reflex import constants
 from reflex.base import Base
-from reflex.utils import console, serializers
+from reflex.utils import console
 
 if sys.version_info >= (3, 12):
     from typing import override
@@ -392,6 +392,8 @@ def is_valid_var_type(type_: Type) -> bool:
     Returns:
         Whether the type is a valid prop type.
     """
+    from reflex.utils import serializers
+
     if is_union(type_):
         return all((is_valid_var_type(arg) for arg in get_args(type_)))
     return _issubclass(type_, StateVar) or serializers.has_serializer(type_)
diff --git a/reflex/vars.py b/reflex/vars.py
index cf6f2eed6..cad3d735b 100644
--- a/reflex/vars.py
+++ b/reflex/vars.py
@@ -35,7 +35,7 @@ from typing import (
 
 from reflex import constants
 from reflex.base import Base
-from reflex.utils import console, format, imports, serializers, types
+from reflex.utils import console, imports, serializers, types
 from reflex.utils.exceptions import VarAttributeError, VarTypeError, VarValueError
 
 # This module used to export ImportVar itself, so we still import it for export here
@@ -364,6 +364,8 @@ class Var:
         Raises:
             VarTypeError: If the value is JSON-unserializable.
         """
+        from reflex.utils import format
+
         # Check for none values.
         if value is None:
             return None
@@ -543,6 +545,8 @@ class Var:
         Returns:
             The wrapped var, i.e. {state.var}.
         """
+        from reflex.utils import format
+
         out = (
             self._var_full_name
             if self._var_is_local
@@ -600,6 +604,8 @@ class Var:
         Raises:
             VarTypeError: If the var is not indexable.
         """
+        from reflex.utils import format
+
         # Indexing is only supported for strings, lists, tuples, dicts, and dataframes.
         if not (
             types._issubclass(self._var_type, Union[List, Dict, Tuple, str])
@@ -793,6 +799,8 @@ class Var:
             VarTypeError: If the operation between two operands is invalid.
             VarValueError: If flip is set to true and value of operand is not provided
         """
+        from reflex.utils import format
+
         if isinstance(other, str):
             other = Var.create(json.dumps(other))
         else:
@@ -1671,6 +1679,8 @@ class Var:
         Returns:
             The full name of the var.
         """
+        from reflex.utils import format
+
         if not self._var_full_name_needs_state_prefix:
             return self._var_name
         return (
@@ -1690,6 +1700,8 @@ class Var:
         Returns:
             The var with the set state.
         """
+        from reflex.utils import format
+
         state_name = state if isinstance(state, str) else state.get_full_name()
         new_var_data = VarData(
             state=state_name,