Răsfoiți Sursa

Merge branch 'main' into release/reflex-0.7.4

Khaleel Al-Adhami 2 luni în urmă
părinte
comite
e978a42ab2

+ 2 - 1
pyproject.toml

@@ -26,6 +26,7 @@ dependencies = [
   "distro >=1.8.0,<2.0; platform_system == 'Linux'",
   "distro >=1.8.0,<2.0; platform_system == 'Linux'",
   "fastapi >=0.96.0,!=0.111.0,!=0.111.1",
   "fastapi >=0.96.0,!=0.111.0,!=0.111.1",
   "granian[reload] >=2.0.0",
   "granian[reload] >=2.0.0",
+  "gunicorn >=23.0.0,<24.0.0",
   "httpx >=0.25.1,<1.0",
   "httpx >=0.25.1,<1.0",
   "jinja2 >=3.1.2,<4.0",
   "jinja2 >=3.1.2,<4.0",
   "lazy_loader >=0.4",
   "lazy_loader >=0.4",
@@ -46,6 +47,7 @@ dependencies = [
   "twine >=4.0.0,<7.0",
   "twine >=4.0.0,<7.0",
   "typer >=0.15.1,<1.0",
   "typer >=0.15.1,<1.0",
   "typing_extensions >=4.6.0",
   "typing_extensions >=4.6.0",
+  "uvicorn >=0.20.0",
   "wheel >=0.42.0,<1.0",
   "wheel >=0.42.0,<1.0",
   "wrapt >=1.17.0,<2.0",
   "wrapt >=1.17.0,<2.0",
 ]
 ]
@@ -161,5 +163,4 @@ dev = [
   "ruff ==0.11.0",
   "ruff ==0.11.0",
   "selenium >=4.11.0,<5.0",
   "selenium >=4.11.0,<5.0",
   "toml >=0.10.2,<1.0",
   "toml >=0.10.2,<1.0",
-  "uvicorn >=0.20.0",
 ]
 ]

+ 9 - 1
reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js

@@ -1,5 +1,5 @@
 import { useTheme } from "next-themes";
 import { useTheme } from "next-themes";
-import { useEffect, useState } from "react";
+import { useRef, useEffect, useState } from "react";
 import {
 import {
   ColorModeContext,
   ColorModeContext,
   defaultColorMode,
   defaultColorMode,
@@ -13,6 +13,14 @@ export default function RadixThemesColorModeProvider({ children }) {
   const [resolvedColorMode, setResolvedColorMode] = useState(
   const [resolvedColorMode, setResolvedColorMode] = useState(
     defaultColorMode === "dark" ? "dark" : "light",
     defaultColorMode === "dark" ? "dark" : "light",
   );
   );
+  const firstUpdate = useRef(true);
+  useEffect(() => {
+    if (firstUpdate.current) {
+      firstUpdate.current = false;
+      setRawColorMode(theme);
+      setResolvedColorMode(resolvedTheme);
+    }
+  });
 
 
   useEffect(() => {
   useEffect(() => {
     if (isDevMode) {
     if (isDevMode) {

+ 4 - 2
reflex/app.py

@@ -968,7 +968,7 @@ class App(MiddlewareMixin, LifespanMixin):
         # Check the nocompile file.
         # Check the nocompile file.
         if nocompile.exists():
         if nocompile.exists():
             # Delete the nocompile file
             # Delete the nocompile file
-            nocompile.unlink()
+            nocompile.unlink(missing_ok=True)
             return False
             return False
 
 
         # By default, compile the app.
         # By default, compile the app.
@@ -1258,7 +1258,9 @@ class App(MiddlewareMixin, LifespanMixin):
             compiler.compile_document_root(
             compiler.compile_document_root(
                 self.head_components,
                 self.head_components,
                 html_lang=self.html_lang,
                 html_lang=self.html_lang,
-                html_custom_attrs=self.html_custom_attrs,  # pyright: ignore [reportArgumentType]
+                html_custom_attrs=(
+                    {**self.html_custom_attrs} if self.html_custom_attrs else {}
+                ),
             )
             )
         )
         )
 
 

+ 3 - 3
reflex/base.py

@@ -38,7 +38,7 @@ def validate_field_name(bases: list[Type["BaseModel"]], field_name: str) -> None
 
 
 # monkeypatch pydantic validate_field_name method to skip validating
 # monkeypatch pydantic validate_field_name method to skip validating
 # shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
 # shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
-pydantic_main.validate_field_name = validate_field_name  # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
+pydantic_main.validate_field_name = validate_field_name  # pyright: ignore [reportPrivateImportUsage]
 
 
 if TYPE_CHECKING:
 if TYPE_CHECKING:
     from reflex.vars import Var
     from reflex.vars import Var
@@ -107,7 +107,7 @@ class Base(BaseModel):
             default_value: The default value of the field
             default_value: The default value of the field
         """
         """
         var_name = var._var_field_name
         var_name = var._var_field_name
-        new_field = ModelField.infer(  # pyright: ignore [reportPossiblyUnboundVariable]
+        new_field = ModelField.infer(
             name=var_name,
             name=var_name,
             value=default_value,
             value=default_value,
             annotation=var._var_type,
             annotation=var._var_type,
@@ -128,5 +128,5 @@ class Base(BaseModel):
         if isinstance(key, str):
         if isinstance(key, str):
             # Seems like this function signature was wrong all along?
             # Seems like this function signature was wrong all along?
             # If the user wants a field that we know of, get it and pass it off to _get_value
             # If the user wants a field that we know of, get it and pass it off to _get_value
-            return getattr(self, key, key)
+            return getattr(self, key)
         return key
         return key

+ 5 - 0
reflex/compiler/compiler.py

@@ -20,6 +20,7 @@ from reflex.config import environment, get_config
 from reflex.state import BaseState
 from reflex.state import BaseState
 from reflex.style import SYSTEM_COLOR_MODE
 from reflex.style import SYSTEM_COLOR_MODE
 from reflex.utils import console, path_ops
 from reflex.utils import console, path_ops
+from reflex.utils.exceptions import ReflexError
 from reflex.utils.exec import is_prod_mode
 from reflex.utils.exec import is_prod_mode
 from reflex.utils.imports import ImportVar
 from reflex.utils.imports import ImportVar
 from reflex.utils.prerequisites import get_web_dir
 from reflex.utils.prerequisites import get_web_dir
@@ -651,6 +652,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
         ):
         ):
             return converted
             return converted
     except KeyError as e:
     except KeyError as e:
+        if isinstance(e, ReflexError):
+            raise
         key = e.args[0] if e.args else None
         key = e.args[0] if e.args else None
         if key is not None and isinstance(key, Var):
         if key is not None and isinstance(key, Var):
             raise TypeError(
             raise TypeError(
@@ -658,6 +661,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
             ).with_traceback(e.__traceback__) from None
             ).with_traceback(e.__traceback__) from None
         raise
         raise
     except TypeError as e:
     except TypeError as e:
+        if isinstance(e, ReflexError):
+            raise
         message = e.args[0] if e.args else None
         message = e.args[0] if e.args else None
         if message and isinstance(message, str):
         if message and isinstance(message, str):
             if message.endswith("has no len()") and (
             if message.endswith("has no len()") and (

+ 6 - 3
reflex/components/component.py

@@ -2,6 +2,7 @@
 
 
 from __future__ import annotations
 from __future__ import annotations
 
 
+import contextlib
 import copy
 import copy
 import dataclasses
 import dataclasses
 import functools
 import functools
@@ -1974,13 +1975,15 @@ class NoSSRComponent(Component):
         # Do NOT import the main library/tag statically.
         # Do NOT import the main library/tag statically.
         import_name = self._get_import_name()
         import_name = self._get_import_name()
         if import_name is not None:
         if import_name is not None:
-            _imports[import_name] = [
+            with contextlib.suppress(ValueError):
+                _imports[import_name].remove(self.import_var)
+            _imports[import_name].append(
                 imports.ImportVar(
                 imports.ImportVar(
                     tag=None,
                     tag=None,
                     render=False,
                     render=False,
                     transpile=self._should_transpile(self.library),
                     transpile=self._should_transpile(self.library),
-                ),
-            ]
+                )
+            )
 
 
         return imports.merge_imports(
         return imports.merge_imports(
             dynamic_import,
             dynamic_import,

+ 1 - 1
reflex/config.py

@@ -44,7 +44,7 @@ from reflex.utils.types import (
 )
 )
 
 
 try:
 try:
-    from dotenv import load_dotenv  # pyright: ignore [reportMissingImports]
+    from dotenv import load_dotenv
 except ImportError:
 except ImportError:
     load_dotenv = None
     load_dotenv = None
 
 

+ 8 - 4
reflex/reflex.py

@@ -205,18 +205,22 @@ def _run(
     prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
     prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
 
 
     # Get the app module.
     # Get the app module.
-    app_task = prerequisites.compile_app if frontend else prerequisites.validate_app
+    app_task = prerequisites.compile_or_validate_app
+    args = (frontend,)
 
 
     # Granian fails if the app is already imported.
     # Granian fails if the app is already imported.
     if should_use_granian():
     if should_use_granian():
         import concurrent.futures
         import concurrent.futures
 
 
         compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
         compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
-            app_task
+            app_task,
+            *args,
         )
         )
-        compile_future.result()
+        validation_result = compile_future.result()
     else:
     else:
-        app_task()
+        validation_result = app_task(*args)
+    if not validation_result:
+        raise typer.Exit(1)
 
 
     # Warn if schema is not up to date.
     # Warn if schema is not up to date.
     prerequisites.check_schema_up_to_date()
     prerequisites.check_schema_up_to_date()

+ 39 - 33
reflex/utils/exec.py

@@ -189,9 +189,11 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
 
 
 @once
 @once
 def _warn_user_about_uvicorn():
 def _warn_user_about_uvicorn():
-    console.warn(
-        "Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
-    )
+    # When we eventually switch to Granian by default, we should enable this warning.
+    if False:
+        console.warn(
+            "Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
+        )
 
 
 
 
 def should_use_granian():
 def should_use_granian():
@@ -357,70 +359,74 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
     ).serve()
     ).serve()
 
 
 
 
+def _deprecate_asgi_config(
+    config_name: str,
+    reason: str = "",
+):
+    # When we eventually switch to Granian by default, we should enable this deprecation.
+    if False:
+        console.deprecate(
+            f"config.{config_name}",
+            reason=reason,
+            deprecation_version="0.7.5",
+            removal_version="0.8.0",
+        )
+
+
 @once
 @once
 def _get_backend_workers():
 def _get_backend_workers():
     from reflex.utils import processes
     from reflex.utils import processes
 
 
     config = get_config()
     config = get_config()
 
 
+    gunicorn_workers = config.gunicorn_workers or 0
+
     if config.gunicorn_workers is not None:
     if config.gunicorn_workers is not None:
-        console.deprecate(
-            "config.gunicorn_workers",
-            reason="If you're using Granian, use GRANIAN_WORKERS instead.",
-            deprecation_version="0.7.4",
-            removal_version="0.8.0",
+        _deprecate_asgi_config(
+            "gunicorn_workers",
+            "If you're using Granian, use GRANIAN_WORKERS instead.",
         )
         )
 
 
-    return (
-        processes.get_num_workers()
-        if not config.gunicorn_workers
-        else config.gunicorn_workers
-    )
+    return gunicorn_workers if gunicorn_workers else processes.get_num_workers()
 
 
 
 
 @once
 @once
 def _get_backend_timeout():
 def _get_backend_timeout():
     config = get_config()
     config = get_config()
 
 
+    timeout = config.timeout or 120
+
     if config.timeout is not None:
     if config.timeout is not None:
-        console.deprecate(
-            "config.timeout",
-            reason="If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
-            deprecation_version="0.7.4",
-            removal_version="0.8.0",
+        _deprecate_asgi_config(
+            "timeout",
+            "If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
         )
         )
 
 
-    return config.timeout
+    return timeout
 
 
 
 
 @once
 @once
 def _get_backend_max_requests():
 def _get_backend_max_requests():
     config = get_config()
     config = get_config()
 
 
+    gunicorn_max_requests = config.gunicorn_max_requests or 120
+
     if config.gunicorn_max_requests is not None:
     if config.gunicorn_max_requests is not None:
-        console.deprecate(
-            "config.gunicorn_max_requests",
-            reason="",
-            deprecation_version="0.7.4",
-            removal_version="0.8.0",
-        )
+        _deprecate_asgi_config("gunicorn_max_requests")
 
 
-    return config.gunicorn_max_requests
+    return gunicorn_max_requests
 
 
 
 
 @once
 @once
 def _get_backend_max_requests_jitter():
 def _get_backend_max_requests_jitter():
     config = get_config()
     config = get_config()
 
 
+    gunicorn_max_requests_jitter = config.gunicorn_max_requests_jitter or 25
+
     if config.gunicorn_max_requests_jitter is not None:
     if config.gunicorn_max_requests_jitter is not None:
-        console.deprecate(
-            "config.gunicorn_max_requests_jitter",
-            reason="",
-            deprecation_version="0.7.4",
-            removal_version="0.8.0",
-        )
+        _deprecate_asgi_config("gunicorn_max_requests_jitter")
 
 
-    return config.gunicorn_max_requests_jitter
+    return gunicorn_max_requests_jitter
 
 
 
 
 def run_backend_prod(
 def run_backend_prod(

+ 73 - 2
reflex/utils/prerequisites.py

@@ -8,6 +8,7 @@ import functools
 import importlib
 import importlib
 import importlib.metadata
 import importlib.metadata
 import importlib.util
 import importlib.util
+import io
 import json
 import json
 import os
 import os
 import platform
 import platform
@@ -183,7 +184,7 @@ def get_node_version() -> version.Version | None:
     try:
     try:
         result = processes.new_process([node_path, "-v"], run=True)
         result = processes.new_process([node_path, "-v"], run=True)
         # The output will be in the form "vX.Y.Z", but version.parse() can handle it
         # The output will be in the form "vX.Y.Z", but version.parse() can handle it
-        return version.parse(result.stdout)  # pyright: ignore [reportArgumentType]
+        return version.parse(result.stdout)
     except (FileNotFoundError, TypeError):
     except (FileNotFoundError, TypeError):
         return None
         return None
 
 
@@ -200,7 +201,7 @@ def get_bun_version() -> version.Version | None:
     try:
     try:
         # Run the bun -v command and capture the output
         # Run the bun -v command and capture the output
         result = processes.new_process([str(bun_path), "-v"], run=True)
         result = processes.new_process([str(bun_path), "-v"], run=True)
-        return version.parse(str(result.stdout))  # pyright: ignore [reportArgumentType]
+        return version.parse(str(result.stdout))
     except FileNotFoundError:
     except FileNotFoundError:
         return None
         return None
     except version.InvalidVersion as e:
     except version.InvalidVersion as e:
@@ -449,6 +450,76 @@ def compile_app(reload: bool = False, export: bool = False) -> None:
     get_compiled_app(reload=reload, export=export)
     get_compiled_app(reload=reload, export=export)
 
 
 
 
+def _can_colorize() -> bool:
+    """Check if the output can be colorized.
+
+    Copied from _colorize.can_colorize.
+
+    https://raw.githubusercontent.com/python/cpython/refs/heads/main/Lib/_colorize.py
+
+    Returns:
+        If the output can be colorized
+    """
+    file = sys.stdout
+
+    if not sys.flags.ignore_environment:
+        if os.environ.get("PYTHON_COLORS") == "0":
+            return False
+        if os.environ.get("PYTHON_COLORS") == "1":
+            return True
+    if os.environ.get("NO_COLOR"):
+        return False
+    if os.environ.get("FORCE_COLOR"):
+        return True
+    if os.environ.get("TERM") == "dumb":
+        return False
+
+    if not hasattr(file, "fileno"):
+        return False
+
+    if sys.platform == "win32":
+        try:
+            import nt
+
+            if not nt._supports_virtual_terminal():
+                return False
+        except (ImportError, AttributeError):
+            return False
+
+    try:
+        return os.isatty(file.fileno())
+    except io.UnsupportedOperation:
+        return file.isatty()
+
+
+def compile_or_validate_app(compile: bool = False) -> bool:
+    """Compile or validate the app module based on the default config.
+
+    Args:
+        compile: Whether to compile the app.
+
+    Returns:
+        If the app is compiled successfully.
+    """
+    try:
+        if compile:
+            compile_app()
+        else:
+            validate_app()
+    except Exception as e:
+        import traceback
+
+        sys_exception = sys.exception()
+
+        try:
+            colorize = _can_colorize()
+            traceback.print_exception(e, colorize=colorize)  # pyright: ignore[reportCallIssue]
+        except Exception:
+            traceback.print_exception(sys_exception)
+        return False
+    return True
+
+
 def get_redis() -> Redis | None:
 def get_redis() -> Redis | None:
     """Get the asynchronous redis client.
     """Get the asynchronous redis client.
 
 

+ 48 - 16
reflex/utils/processes.py

@@ -10,7 +10,7 @@ import signal
 import subprocess
 import subprocess
 from concurrent import futures
 from concurrent import futures
 from pathlib import Path
 from pathlib import Path
-from typing import Any, Callable, Generator, Sequence, Tuple
+from typing import Any, Callable, Generator, Literal, Sequence, Tuple, overload
 
 
 import psutil
 import psutil
 import typer
 import typer
@@ -142,12 +142,30 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
         raise typer.Exit()
         raise typer.Exit()
 
 
 
 
+@overload
+def new_process(
+    args: str | list[str] | list[str | None] | list[str | Path | None],
+    run: Literal[False] = False,
+    show_logs: bool = False,
+    **kwargs,
+) -> subprocess.Popen[str]: ...
+
+
+@overload
+def new_process(
+    args: str | list[str] | list[str | None] | list[str | Path | None],
+    run: Literal[True],
+    show_logs: bool = False,
+    **kwargs,
+) -> subprocess.CompletedProcess[str]: ...
+
+
 def new_process(
 def new_process(
     args: str | list[str] | list[str | None] | list[str | Path | None],
     args: str | list[str] | list[str | None] | list[str | Path | None],
     run: bool = False,
     run: bool = False,
     show_logs: bool = False,
     show_logs: bool = False,
     **kwargs,
     **kwargs,
-):
+) -> subprocess.CompletedProcess[str] | subprocess.Popen[str]:
     """Wrapper over subprocess.Popen to unify the launch of child processes.
     """Wrapper over subprocess.Popen to unify the launch of child processes.
 
 
     Args:
     Args:
@@ -163,7 +181,8 @@ def new_process(
         Exit: When attempting to run a command with a None value.
         Exit: When attempting to run a command with a None value.
     """
     """
     # Check for invalid command first.
     # Check for invalid command first.
-    if isinstance(args, list) and None in args:
+    non_empty_args = list(filter(None, args)) if isinstance(args, list) else [args]
+    if isinstance(args, list) and len(non_empty_args) != len(args):
         console.error(f"Invalid command: {args}")
         console.error(f"Invalid command: {args}")
         raise typer.Exit(1)
         raise typer.Exit(1)
 
 
@@ -190,9 +209,15 @@ def new_process(
         "errors": "replace",  # Avoid UnicodeDecodeError in unknown command output
         "errors": "replace",  # Avoid UnicodeDecodeError in unknown command output
         **kwargs,
         **kwargs,
     }
     }
-    console.debug(f"Running command: {args}")
-    fn = subprocess.run if run else subprocess.Popen
-    return fn(args, **kwargs)  # pyright: ignore [reportCallIssue, reportArgumentType]
+    console.debug(f"Running command: {non_empty_args}")
+
+    def subprocess_p_open(args: subprocess._CMD, **kwargs):
+        return subprocess.Popen(args, **kwargs)
+
+    fn: Callable[..., subprocess.CompletedProcess[str] | subprocess.Popen[str]] = (
+        subprocess.run if run else subprocess_p_open
+    )
+    return fn(non_empty_args, **kwargs)
 
 
 
 
 @contextlib.contextmanager
 @contextlib.contextmanager
@@ -311,6 +336,7 @@ def show_status(
     process: subprocess.Popen,
     process: subprocess.Popen,
     suppress_errors: bool = False,
     suppress_errors: bool = False,
     analytics_enabled: bool = False,
     analytics_enabled: bool = False,
+    prior_processes: Tuple[subprocess.Popen, ...] = (),
 ):
 ):
     """Show the status of a process.
     """Show the status of a process.
 
 
@@ -319,15 +345,17 @@ def show_status(
         process: The process.
         process: The process.
         suppress_errors: If True, do not exit if errors are encountered (for fallback).
         suppress_errors: If True, do not exit if errors are encountered (for fallback).
         analytics_enabled: Whether analytics are enabled for this command.
         analytics_enabled: Whether analytics are enabled for this command.
+        prior_processes: The prior processes that have been run.
     """
     """
-    with console.status(message) as status:
-        for line in stream_logs(
-            message,
-            process,
-            suppress_errors=suppress_errors,
-            analytics_enabled=analytics_enabled,
-        ):
-            status.update(f"{message} {line}")
+    for one_process in (*prior_processes, process):
+        with console.status(message) as status:
+            for line in stream_logs(
+                message,
+                one_process,
+                suppress_errors=suppress_errors,
+                analytics_enabled=analytics_enabled,
+            ):
+                status.update(f"{message} {line}")
 
 
 
 
 def show_progress(message: str, process: subprocess.Popen, checkpoints: list[str]):
 def show_progress(message: str, process: subprocess.Popen, checkpoints: list[str]):
@@ -381,6 +409,7 @@ def run_process_with_fallbacks(
     show_status_message: str,
     show_status_message: str,
     fallbacks: str | Sequence[str] | Sequence[Sequence[str]] | None = None,
     fallbacks: str | Sequence[str] | Sequence[Sequence[str]] | None = None,
     analytics_enabled: bool = False,
     analytics_enabled: bool = False,
+    prior_processes: Tuple[subprocess.Popen, ...] = (),
     **kwargs,
     **kwargs,
 ):
 ):
     """Run subprocess and retry using fallback command if initial command fails.
     """Run subprocess and retry using fallback command if initial command fails.
@@ -390,7 +419,8 @@ def run_process_with_fallbacks(
         show_status_message: The status message to be displayed in the console.
         show_status_message: The status message to be displayed in the console.
         fallbacks: The fallback command to run if the initial command fails.
         fallbacks: The fallback command to run if the initial command fails.
         analytics_enabled: Whether analytics are enabled for this command.
         analytics_enabled: Whether analytics are enabled for this command.
-        kwargs: Kwargs to pass to new_process function.
+        prior_processes: The prior processes that have been run.
+        **kwargs: Kwargs to pass to new_process function.
     """
     """
     process = new_process(get_command_with_loglevel(args), **kwargs)
     process = new_process(get_command_with_loglevel(args), **kwargs)
     if not fallbacks:
     if not fallbacks:
@@ -399,6 +429,7 @@ def run_process_with_fallbacks(
             show_status_message,
             show_status_message,
             process,
             process,
             analytics_enabled=analytics_enabled,
             analytics_enabled=analytics_enabled,
+            prior_processes=prior_processes,
         )
         )
     else:
     else:
         # Suppress errors for initial command, because we will try to fallback
         # Suppress errors for initial command, because we will try to fallback
@@ -411,7 +442,7 @@ def run_process_with_fallbacks(
             # retry with fallback command.
             # retry with fallback command.
             fallback_with_args = (
             fallback_with_args = (
                 [current_fallback, *args[1:]]
                 [current_fallback, *args[1:]]
-                if isinstance(fallbacks, str)
+                if isinstance(current_fallback, str)
                 else [*current_fallback, *args[1:]]
                 else [*current_fallback, *args[1:]]
             )
             )
             console.warn(
             console.warn(
@@ -422,6 +453,7 @@ def run_process_with_fallbacks(
                 show_status_message=show_status_message,
                 show_status_message=show_status_message,
                 fallbacks=next_fallbacks,
                 fallbacks=next_fallbacks,
                 analytics_enabled=analytics_enabled,
                 analytics_enabled=analytics_enabled,
+                prior_processes=(*prior_processes, process),
                 **kwargs,
                 **kwargs,
             )
             )
 
 

+ 0 - 35
reflex/vars/base.py

@@ -3016,41 +3016,6 @@ _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
 _global_vars: dict[int, Var] = {}
 _global_vars: dict[int, Var] = {}
 
 
 
 
-def _extract_var_data(value: Iterable) -> list[VarData | None]:
-    """Extract the var imports and hooks from an iterable containing a Var.
-
-    Args:
-        value: The iterable to extract the VarData from
-
-    Returns:
-        The extracted VarDatas.
-    """
-    from reflex.style import Style
-    from reflex.vars import Var
-
-    var_datas = []
-    with contextlib.suppress(TypeError):
-        for sub in value:
-            if isinstance(sub, Var):
-                var_datas.append(sub._var_data)
-            elif not isinstance(sub, str):
-                # Recurse into dict values.
-                if hasattr(sub, "values") and callable(sub.values):
-                    var_datas.extend(_extract_var_data(sub.values()))  # pyright: ignore [reportArgumentType]
-                # Recurse into iterable values (or dict keys).
-                var_datas.extend(_extract_var_data(sub))
-
-    # Style objects should already have _var_data.
-    if isinstance(value, Style):
-        var_datas.append(value._var_data)
-    else:
-        # Recurse when value is a dict itself.
-        values = getattr(value, "values", None)
-        if callable(values):
-            var_datas.extend(_extract_var_data(values()))  # pyright: ignore [reportArgumentType]
-    return var_datas
-
-
 dispatchers: dict[GenericType, Callable[[Var], Var]] = {}
 dispatchers: dict[GenericType, Callable[[Var], Var]] = {}
 
 
 
 

+ 10 - 34
reflex/vars/datetime.py

@@ -4,7 +4,7 @@ from __future__ import annotations
 
 
 import dataclasses
 import dataclasses
 from datetime import date, datetime
 from datetime import date, datetime
-from typing import Any, NoReturn, TypeVar, overload
+from typing import Any, TypeVar
 
 
 from reflex.utils.exceptions import VarTypeError
 from reflex.utils.exceptions import VarTypeError
 from reflex.vars.number import BooleanVar
 from reflex.vars.number import BooleanVar
@@ -35,13 +35,7 @@ def raise_var_type_error():
 class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
 class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
     """A variable that holds a datetime or date object."""
     """A variable that holds a datetime or date object."""
 
 
-    @overload
-    def __lt__(self, other: datetime_types) -> BooleanVar: ...
-
-    @overload
-    def __lt__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __lt__(self, other: Any):
+    def __lt__(self, other: datetime_types | DateTimeVar) -> BooleanVar:
         """Less than comparison.
         """Less than comparison.
 
 
         Args:
         Args:
@@ -54,13 +48,7 @@ class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
             raise_var_type_error()
             raise_var_type_error()
         return date_lt_operation(self, other)
         return date_lt_operation(self, other)
 
 
-    @overload
-    def __le__(self, other: datetime_types) -> BooleanVar: ...
-
-    @overload
-    def __le__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __le__(self, other: Any):
+    def __le__(self, other: datetime_types | DateTimeVar) -> BooleanVar:
         """Less than or equal comparison.
         """Less than or equal comparison.
 
 
         Args:
         Args:
@@ -73,13 +61,7 @@ class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
             raise_var_type_error()
             raise_var_type_error()
         return date_le_operation(self, other)
         return date_le_operation(self, other)
 
 
-    @overload
-    def __gt__(self, other: datetime_types) -> BooleanVar: ...
-
-    @overload
-    def __gt__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __gt__(self, other: Any):
+    def __gt__(self, other: datetime_types | DateTimeVar) -> BooleanVar:
         """Greater than comparison.
         """Greater than comparison.
 
 
         Args:
         Args:
@@ -92,13 +74,7 @@ class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
             raise_var_type_error()
             raise_var_type_error()
         return date_gt_operation(self, other)
         return date_gt_operation(self, other)
 
 
-    @overload
-    def __ge__(self, other: datetime_types) -> BooleanVar: ...
-
-    @overload
-    def __ge__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __ge__(self, other: Any):
+    def __ge__(self, other: datetime_types | DateTimeVar) -> BooleanVar:
         """Greater than or equal comparison.
         """Greater than or equal comparison.
 
 
         Args:
         Args:
@@ -113,7 +89,7 @@ class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
 
 
 
 
 @var_operation
 @var_operation
-def date_gt_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
+def date_gt_operation(lhs: DateTimeVar | Any, rhs: DateTimeVar | Any):
     """Greater than comparison.
     """Greater than comparison.
 
 
     Args:
     Args:
@@ -127,7 +103,7 @@ def date_gt_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationRetur
 
 
 
 
 @var_operation
 @var_operation
-def date_lt_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
+def date_lt_operation(lhs: DateTimeVar | Any, rhs: DateTimeVar | Any):
     """Less than comparison.
     """Less than comparison.
 
 
     Args:
     Args:
@@ -141,7 +117,7 @@ def date_lt_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationRetur
 
 
 
 
 @var_operation
 @var_operation
-def date_le_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
+def date_le_operation(lhs: DateTimeVar | Any, rhs: DateTimeVar | Any):
     """Less than or equal comparison.
     """Less than or equal comparison.
 
 
     Args:
     Args:
@@ -155,7 +131,7 @@ def date_le_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationRetur
 
 
 
 
 @var_operation
 @var_operation
-def date_ge_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
+def date_ge_operation(lhs: DateTimeVar | Any, rhs: DateTimeVar | Any):
     """Greater than or equal comparison.
     """Greater than or equal comparison.
 
 
     Args:
     Args:
@@ -172,7 +148,7 @@ def date_compare_operation(
     lhs: DateTimeVar[DATETIME_T] | Any,
     lhs: DateTimeVar[DATETIME_T] | Any,
     rhs: DateTimeVar[DATETIME_T] | Any,
     rhs: DateTimeVar[DATETIME_T] | Any,
     strict: bool = False,
     strict: bool = False,
-) -> CustomVarOperationReturn:
+) -> CustomVarOperationReturn[bool]:
     """Check if the value is less than the other value.
     """Check if the value is less than the other value.
 
 
     Args:
     Args:

+ 16 - 112
reflex/vars/number.py

@@ -61,13 +61,7 @@ def raise_unsupported_operand_types(
 class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 class NumberVar(Var[NUMBER_T], python_types=(int, float)):
     """Base class for immutable number vars."""
     """Base class for immutable number vars."""
 
 
-    @overload
-    def __add__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __add__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __add__(self, other: Any):
+    def __add__(self, other: number_types) -> NumberVar:
         """Add two numbers.
         """Add two numbers.
 
 
         Args:
         Args:
@@ -80,13 +74,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
             raise_unsupported_operand_types("+", (type(self), type(other)))
             raise_unsupported_operand_types("+", (type(self), type(other)))
         return number_add_operation(self, +other)
         return number_add_operation(self, +other)
 
 
-    @overload
-    def __radd__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __radd__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __radd__(self, other: Any):
+    def __radd__(self, other: number_types) -> NumberVar:
         """Add two numbers.
         """Add two numbers.
 
 
         Args:
         Args:
@@ -99,13 +87,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
             raise_unsupported_operand_types("+", (type(other), type(self)))
             raise_unsupported_operand_types("+", (type(other), type(self)))
         return number_add_operation(+other, self)
         return number_add_operation(+other, self)
 
 
-    @overload
-    def __sub__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __sub__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __sub__(self, other: Any):
+    def __sub__(self, other: number_types) -> NumberVar:
         """Subtract two numbers.
         """Subtract two numbers.
 
 
         Args:
         Args:
@@ -119,13 +101,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_subtract_operation(self, +other)
         return number_subtract_operation(self, +other)
 
 
-    @overload
-    def __rsub__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __rsub__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __rsub__(self, other: Any):
+    def __rsub__(self, other: number_types) -> NumberVar:
         """Subtract two numbers.
         """Subtract two numbers.
 
 
         Args:
         Args:
@@ -201,13 +177,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_multiply_operation(+other, self)
         return number_multiply_operation(+other, self)
 
 
-    @overload
-    def __truediv__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __truediv__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __truediv__(self, other: Any):
+    def __truediv__(self, other: number_types) -> NumberVar:
         """Divide two numbers.
         """Divide two numbers.
 
 
         Args:
         Args:
@@ -221,13 +191,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_true_division_operation(self, +other)
         return number_true_division_operation(self, +other)
 
 
-    @overload
-    def __rtruediv__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __rtruediv__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __rtruediv__(self, other: Any):
+    def __rtruediv__(self, other: number_types) -> NumberVar:
         """Divide two numbers.
         """Divide two numbers.
 
 
         Args:
         Args:
@@ -241,13 +205,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_true_division_operation(+other, self)
         return number_true_division_operation(+other, self)
 
 
-    @overload
-    def __floordiv__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __floordiv__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __floordiv__(self, other: Any):
+    def __floordiv__(self, other: number_types) -> NumberVar:
         """Floor divide two numbers.
         """Floor divide two numbers.
 
 
         Args:
         Args:
@@ -261,13 +219,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_floor_division_operation(self, +other)
         return number_floor_division_operation(self, +other)
 
 
-    @overload
-    def __rfloordiv__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __rfloordiv__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __rfloordiv__(self, other: Any):
+    def __rfloordiv__(self, other: number_types) -> NumberVar:
         """Floor divide two numbers.
         """Floor divide two numbers.
 
 
         Args:
         Args:
@@ -281,13 +233,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_floor_division_operation(+other, self)
         return number_floor_division_operation(+other, self)
 
 
-    @overload
-    def __mod__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __mod__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __mod__(self, other: Any):
+    def __mod__(self, other: number_types) -> NumberVar:
         """Modulo two numbers.
         """Modulo two numbers.
 
 
         Args:
         Args:
@@ -301,13 +247,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_modulo_operation(self, +other)
         return number_modulo_operation(self, +other)
 
 
-    @overload
-    def __rmod__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __rmod__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __rmod__(self, other: Any):
+    def __rmod__(self, other: number_types) -> NumberVar:
         """Modulo two numbers.
         """Modulo two numbers.
 
 
         Args:
         Args:
@@ -321,13 +261,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_modulo_operation(+other, self)
         return number_modulo_operation(+other, self)
 
 
-    @overload
-    def __pow__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __pow__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __pow__(self, other: Any):
+    def __pow__(self, other: number_types) -> NumberVar:
         """Exponentiate two numbers.
         """Exponentiate two numbers.
 
 
         Args:
         Args:
@@ -341,13 +275,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
 
 
         return number_exponent_operation(self, +other)
         return number_exponent_operation(self, +other)
 
 
-    @overload
-    def __rpow__(self, other: number_types) -> NumberVar: ...
-
-    @overload
-    def __rpow__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __rpow__(self, other: Any):
+    def __rpow__(self, other: number_types) -> NumberVar:
         """Exponentiate two numbers.
         """Exponentiate two numbers.
 
 
         Args:
         Args:
@@ -417,13 +345,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
         """
         """
         return number_trunc_operation(self)
         return number_trunc_operation(self)
 
 
-    @overload
-    def __lt__(self, other: number_types) -> BooleanVar: ...
-
-    @overload
-    def __lt__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __lt__(self, other: Any):
+    def __lt__(self, other: number_types) -> BooleanVar:
         """Less than comparison.
         """Less than comparison.
 
 
         Args:
         Args:
@@ -436,13 +358,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
             raise_unsupported_operand_types("<", (type(self), type(other)))
             raise_unsupported_operand_types("<", (type(self), type(other)))
         return less_than_operation(+self, +other)
         return less_than_operation(+self, +other)
 
 
-    @overload
-    def __le__(self, other: number_types) -> BooleanVar: ...
-
-    @overload
-    def __le__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __le__(self, other: Any):
+    def __le__(self, other: number_types) -> BooleanVar:
         """Less than or equal comparison.
         """Less than or equal comparison.
 
 
         Args:
         Args:
@@ -481,13 +397,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
             return not_equal_operation(+self, +other)
             return not_equal_operation(+self, +other)
         return not_equal_operation(self, other)
         return not_equal_operation(self, other)
 
 
-    @overload
-    def __gt__(self, other: number_types) -> BooleanVar: ...
-
-    @overload
-    def __gt__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __gt__(self, other: Any):
+    def __gt__(self, other: number_types) -> BooleanVar:
         """Greater than comparison.
         """Greater than comparison.
 
 
         Args:
         Args:
@@ -500,13 +410,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
             raise_unsupported_operand_types(">", (type(self), type(other)))
             raise_unsupported_operand_types(">", (type(self), type(other)))
         return greater_than_operation(+self, +other)
         return greater_than_operation(+self, +other)
 
 
-    @overload
-    def __ge__(self, other: number_types) -> BooleanVar: ...
-
-    @overload
-    def __ge__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __ge__(self, other: Any):
+    def __ge__(self, other: number_types) -> BooleanVar:
         """Greater than or equal comparison.
         """Greater than or equal comparison.
 
 
         Args:
         Args:

+ 15 - 108
reflex/vars/sequence.py

@@ -14,7 +14,6 @@ from typing import (
     List,
     List,
     Literal,
     Literal,
     Mapping,
     Mapping,
-    NoReturn,
     Sequence,
     Sequence,
     Type,
     Type,
     TypeVar,
     TypeVar,
@@ -76,13 +75,7 @@ VALUE_TYPE = TypeVar("VALUE_TYPE")
 class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)):
 class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)):
     """Base class for immutable array vars."""
     """Base class for immutable array vars."""
 
 
-    @overload
-    def join(self, sep: StringVar | str = "") -> StringVar: ...
-
-    @overload
-    def join(self, sep: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def join(self, sep: Any = "") -> StringVar:
+    def join(self, sep: StringVar | str = "") -> StringVar:
         """Join the elements of the array.
         """Join the elements of the array.
 
 
         Args:
         Args:
@@ -123,13 +116,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)):
         """
         """
         return array_reverse_operation(self)
         return array_reverse_operation(self)
 
 
-    @overload
-    def __add__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> ArrayVar[ARRAY_VAR_TYPE]: ...
-
-    @overload
-    def __add__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __add__(self, other: Any) -> ArrayVar[ARRAY_VAR_TYPE]:
+    def __add__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> ArrayVar[ARRAY_VAR_TYPE]:
         """Concatenate two arrays.
         """Concatenate two arrays.
 
 
         Parameters:
         Parameters:
@@ -352,13 +339,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)):
         """
         """
         return array_pluck_operation(self, field)
         return array_pluck_operation(self, field)
 
 
-    @overload
-    def __mul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]: ...
-
-    @overload
-    def __mul__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __mul__(self, other: Any) -> ArrayVar[ARRAY_VAR_TYPE]:
+    def __mul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]:
         """Multiply the sequence by a number or integer.
         """Multiply the sequence by a number or integer.
 
 
         Parameters:
         Parameters:
@@ -603,13 +584,7 @@ STRING_TYPE = TypingExtensionsTypeVar("STRING_TYPE", default=str)
 class StringVar(Var[STRING_TYPE], python_types=str):
 class StringVar(Var[STRING_TYPE], python_types=str):
     """Base class for immutable string vars."""
     """Base class for immutable string vars."""
 
 
-    @overload
-    def __add__(self, other: StringVar | str) -> ConcatVarOperation: ...
-
-    @overload
-    def __add__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __add__(self, other: Any) -> ConcatVarOperation:
+    def __add__(self, other: StringVar | str) -> ConcatVarOperation:
         """Concatenate two strings.
         """Concatenate two strings.
 
 
         Args:
         Args:
@@ -623,13 +598,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
 
 
         return ConcatVarOperation.create(self, other)
         return ConcatVarOperation.create(self, other)
 
 
-    @overload
-    def __radd__(self, other: StringVar | str) -> ConcatVarOperation: ...
-
-    @overload
-    def __radd__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __radd__(self, other: Any) -> ConcatVarOperation:
+    def __radd__(self, other: StringVar | str) -> ConcatVarOperation:
         """Concatenate two strings.
         """Concatenate two strings.
 
 
         Args:
         Args:
@@ -643,13 +612,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
 
 
         return ConcatVarOperation.create(other, self)
         return ConcatVarOperation.create(other, self)
 
 
-    @overload
-    def __mul__(self, other: NumberVar | int) -> StringVar: ...
-
-    @overload
-    def __mul__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __mul__(self, other: Any) -> StringVar:
+    def __mul__(self, other: NumberVar | int) -> StringVar:
         """Multiply the sequence by a number or an integer.
         """Multiply the sequence by a number or an integer.
 
 
         Args:
         Args:
@@ -663,13 +626,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
 
 
         return (self.split() * other).join()
         return (self.split() * other).join()
 
 
-    @overload
-    def __rmul__(self, other: NumberVar | int) -> StringVar: ...
-
-    @overload
-    def __rmul__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __rmul__(self, other: Any) -> StringVar:
+    def __rmul__(self, other: NumberVar | int) -> StringVar:
         """Multiply the sequence by a number or an integer.
         """Multiply the sequence by a number or an integer.
 
 
         Args:
         Args:
@@ -762,17 +719,9 @@ class StringVar(Var[STRING_TYPE], python_types=str):
         """
         """
         return self.split().reverse().join()
         return self.split().reverse().join()
 
 
-    @overload
     def contains(
     def contains(
         self, other: StringVar | str, field: StringVar | str | None = None
         self, other: StringVar | str, field: StringVar | str | None = None
-    ) -> BooleanVar: ...
-
-    @overload
-    def contains(  # pyright: ignore [reportOverlappingOverload]
-        self, other: NoReturn, field: StringVar | str | None = None
-    ) -> NoReturn: ...
-
-    def contains(self, other: Any, field: Any = None) -> BooleanVar:
+    ) -> BooleanVar:
         """Check if the string contains another string.
         """Check if the string contains another string.
 
 
         Args:
         Args:
@@ -790,13 +739,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
             return string_contains_field_operation(self, other, field)
             return string_contains_field_operation(self, other, field)
         return string_contains_operation(self, other)
         return string_contains_operation(self, other)
 
 
-    @overload
-    def split(self, separator: StringVar | str = "") -> ArrayVar[list[str]]: ...
-
-    @overload
-    def split(self, separator: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def split(self, separator: Any = "") -> ArrayVar[list[str]]:
+    def split(self, separator: StringVar | str = "") -> ArrayVar[list[str]]:
         """Split the string.
         """Split the string.
 
 
         Args:
         Args:
@@ -809,13 +752,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
             raise_unsupported_operand_types("split", (type(self), type(separator)))
             raise_unsupported_operand_types("split", (type(self), type(separator)))
         return string_split_operation(self, separator)
         return string_split_operation(self, separator)
 
 
-    @overload
-    def startswith(self, prefix: StringVar | str) -> BooleanVar: ...
-
-    @overload
-    def startswith(self, prefix: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def startswith(self, prefix: Any) -> BooleanVar:
+    def startswith(self, prefix: StringVar | str) -> BooleanVar:
         """Check if the string starts with a prefix.
         """Check if the string starts with a prefix.
 
 
         Args:
         Args:
@@ -828,13 +765,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
             raise_unsupported_operand_types("startswith", (type(self), type(prefix)))
             raise_unsupported_operand_types("startswith", (type(self), type(prefix)))
         return string_starts_with_operation(self, prefix)
         return string_starts_with_operation(self, prefix)
 
 
-    @overload
-    def endswith(self, suffix: StringVar | str) -> BooleanVar: ...
-
-    @overload
-    def endswith(self, suffix: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def endswith(self, suffix: Any) -> BooleanVar:
+    def endswith(self, suffix: StringVar | str) -> BooleanVar:
         """Check if the string ends with a suffix.
         """Check if the string ends with a suffix.
 
 
         Args:
         Args:
@@ -847,13 +778,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
             raise_unsupported_operand_types("endswith", (type(self), type(suffix)))
             raise_unsupported_operand_types("endswith", (type(self), type(suffix)))
         return string_ends_with_operation(self, suffix)
         return string_ends_with_operation(self, suffix)
 
 
-    @overload
-    def __lt__(self, other: StringVar | str) -> BooleanVar: ...
-
-    @overload
-    def __lt__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __lt__(self, other: Any):
+    def __lt__(self, other: StringVar | str) -> BooleanVar:
         """Check if the string is less than another string.
         """Check if the string is less than another string.
 
 
         Args:
         Args:
@@ -867,13 +792,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
 
 
         return string_lt_operation(self, other)
         return string_lt_operation(self, other)
 
 
-    @overload
-    def __gt__(self, other: StringVar | str) -> BooleanVar: ...
-
-    @overload
-    def __gt__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __gt__(self, other: Any):
+    def __gt__(self, other: StringVar | str) -> BooleanVar:
         """Check if the string is greater than another string.
         """Check if the string is greater than another string.
 
 
         Args:
         Args:
@@ -887,13 +806,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
 
 
         return string_gt_operation(self, other)
         return string_gt_operation(self, other)
 
 
-    @overload
-    def __le__(self, other: StringVar | str) -> BooleanVar: ...
-
-    @overload
-    def __le__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __le__(self, other: Any):
+    def __le__(self, other: StringVar | str) -> BooleanVar:
         """Check if the string is less than or equal to another string.
         """Check if the string is less than or equal to another string.
 
 
         Args:
         Args:
@@ -907,13 +820,7 @@ class StringVar(Var[STRING_TYPE], python_types=str):
 
 
         return string_le_operation(self, other)
         return string_le_operation(self, other)
 
 
-    @overload
-    def __ge__(self, other: StringVar | str) -> BooleanVar: ...
-
-    @overload
-    def __ge__(self, other: NoReturn) -> NoReturn: ...  # pyright: ignore [reportOverlappingOverload]
-
-    def __ge__(self, other: Any):
+    def __ge__(self, other: StringVar | str) -> BooleanVar:
         """Check if the string is greater than or equal to another string.
         """Check if the string is greater than or equal to another string.
 
 
         Args:
         Args:

+ 10 - 10
tests/units/components/core/test_colors.py

@@ -31,37 +31,37 @@ def create_color_var(color):
         (create_color_var(rx.color("mint", 3)), '"var(--mint-3)"', Color),
         (create_color_var(rx.color("mint", 3)), '"var(--mint-3)"', Color),
         (create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"', Color),
         (create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"', Color),
         (
         (
-            create_color_var(rx.color(ColorState.color, ColorState.shade)),  # pyright: ignore [reportArgumentType]
+            create_color_var(rx.color(ColorState.color, ColorState.shade)),
             f'("var(--"+{color_state_name!s}.color+"-"+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")',
             f'("var(--"+{color_state_name!s}.color+"-"+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")',
             Color,
             Color,
         ),
         ),
         (
         (
             create_color_var(
             create_color_var(
-                rx.color(ColorState.color, ColorState.shade, ColorState.alpha)  # pyright: ignore [reportArgumentType]
+                rx.color(ColorState.color, ColorState.shade, ColorState.alpha)
             ),
             ),
             f'("var(--"+{color_state_name!s}.color+"-"+({color_state_name!s}.alpha ? "a" : "")+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")',
             f'("var(--"+{color_state_name!s}.color+"-"+({color_state_name!s}.alpha ? "a" : "")+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")',
             Color,
             Color,
         ),
         ),
         (
         (
-            create_color_var(rx.color(f"{ColorState.color}", f"{ColorState.shade}")),  # pyright: ignore [reportArgumentType]
+            create_color_var(rx.color(f"{ColorState.color}", f"{ColorState.shade}")),
             f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")',
             f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")',
             Color,
             Color,
         ),
         ),
         (
         (
             create_color_var(
             create_color_var(
-                rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}")  # pyright: ignore [reportArgumentType]
+                rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}")
             ),
             ),
             f'("var(--"+({color_state_name!s}.color_part+"ato")+"-"+{color_state_name!s}.shade+")")',
             f'("var(--"+({color_state_name!s}.color_part+"ato")+"-"+{color_state_name!s}.shade+")")',
             Color,
             Color,
         ),
         ),
         (
         (
-            create_color_var(f"{rx.color(ColorState.color, f'{ColorState.shade}')}"),  # pyright: ignore [reportArgumentType]
+            create_color_var(f"{rx.color(ColorState.color, f'{ColorState.shade}')}"),
             f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")',
             f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")',
             str,
             str,
         ),
         ),
         (
         (
             create_color_var(
             create_color_var(
-                f"{rx.color(f'{ColorState.color}', f'{ColorState.shade}')}"  # pyright: ignore [reportArgumentType]
+                f"{rx.color(f'{ColorState.color}', f'{ColorState.shade}')}"
             ),
             ),
             f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")',
             f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")',
             str,
             str,
@@ -89,7 +89,7 @@ def test_color(color, expected, expected_type: Union[Type[str], Type[Color]]):
                 "condition",
                 "condition",
                 ("first", rx.color("mint")),
                 ("first", rx.color("mint")),
                 ("second", rx.color("tomato", 5)),
                 ("second", rx.color("tomato", 5)),
-                rx.color(ColorState.color, 2),  # pyright: ignore [reportArgumentType]
+                rx.color(ColorState.color, 2),
             ),
             ),
             '(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"):  return ("var(--mint-7)");'
             '(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"):  return ("var(--mint-7)");'
             '  break;case JSON.stringify("second"):  return ("var(--tomato-5)");  break;default:  '
             '  break;case JSON.stringify("second"):  return ("var(--tomato-5)");  break;default:  '
@@ -98,9 +98,9 @@ def test_color(color, expected, expected_type: Union[Type[str], Type[Color]]):
         (
         (
             rx.match(
             rx.match(
                 "condition",
                 "condition",
-                ("first", rx.color(ColorState.color)),  # pyright: ignore [reportArgumentType]
-                ("second", rx.color(ColorState.color, 5)),  # pyright: ignore [reportArgumentType]
-                rx.color(ColorState.color, 2),  # pyright: ignore [reportArgumentType]
+                ("first", rx.color(ColorState.color)),
+                ("second", rx.color(ColorState.color, 5)),
+                rx.color(ColorState.color, 2),
             ),
             ),
             '(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"):  '
             '(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"):  '
             f'return (("var(--"+{color_state_name!s}.color+"-7)"));  break;case JSON.stringify("second"):  '
             f'return (("var(--"+{color_state_name!s}.color+"-7)"));  break;case JSON.stringify("second"):  '

+ 16 - 2
uv.lock

@@ -556,6 +556,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 },
     { url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 },
 ]
 ]
 
 
+[[package]]
+name = "gunicorn"
+version = "23.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029 },
+]
+
 [[package]]
 [[package]]
 name = "h11"
 name = "h11"
 version = "0.14.0"
 version = "0.14.0"
@@ -1706,6 +1718,7 @@ dependencies = [
     { name = "distro", marker = "sys_platform == 'linux'" },
     { name = "distro", marker = "sys_platform == 'linux'" },
     { name = "fastapi" },
     { name = "fastapi" },
     { name = "granian", extra = ["reload"] },
     { name = "granian", extra = ["reload"] },
+    { name = "gunicorn" },
     { name = "httpx" },
     { name = "httpx" },
     { name = "jinja2" },
     { name = "jinja2" },
     { name = "lazy-loader" },
     { name = "lazy-loader" },
@@ -1726,6 +1739,7 @@ dependencies = [
     { name = "twine" },
     { name = "twine" },
     { name = "typer" },
     { name = "typer" },
     { name = "typing-extensions" },
     { name = "typing-extensions" },
+    { name = "uvicorn" },
     { name = "wheel" },
     { name = "wheel" },
     { name = "wrapt" },
     { name = "wrapt" },
 ]
 ]
@@ -1757,7 +1771,6 @@ dev = [
     { name = "ruff" },
     { name = "ruff" },
     { name = "selenium" },
     { name = "selenium" },
     { name = "toml" },
     { name = "toml" },
-    { name = "uvicorn" },
 ]
 ]
 
 
 [package.metadata]
 [package.metadata]
@@ -1768,6 +1781,7 @@ requires-dist = [
     { name = "distro", marker = "sys_platform == 'linux'", specifier = ">=1.8.0,<2.0" },
     { name = "distro", marker = "sys_platform == 'linux'", specifier = ">=1.8.0,<2.0" },
     { name = "fastapi", specifier = ">=0.96.0,!=0.111.0,!=0.111.1" },
     { name = "fastapi", specifier = ">=0.96.0,!=0.111.0,!=0.111.1" },
     { name = "granian", extras = ["reload"], specifier = ">=2.0.0" },
     { name = "granian", extras = ["reload"], specifier = ">=2.0.0" },
+    { name = "gunicorn", specifier = ">=23.0.0,<24.0.0" },
     { name = "httpx", specifier = ">=0.25.1,<1.0" },
     { name = "httpx", specifier = ">=0.25.1,<1.0" },
     { name = "jinja2", specifier = ">=3.1.2,<4.0" },
     { name = "jinja2", specifier = ">=3.1.2,<4.0" },
     { name = "lazy-loader", specifier = ">=0.4" },
     { name = "lazy-loader", specifier = ">=0.4" },
@@ -1788,6 +1802,7 @@ requires-dist = [
     { name = "twine", specifier = ">=4.0.0,<7.0" },
     { name = "twine", specifier = ">=4.0.0,<7.0" },
     { name = "typer", specifier = ">=0.15.1,<1.0" },
     { name = "typer", specifier = ">=0.15.1,<1.0" },
     { name = "typing-extensions", specifier = ">=4.6.0" },
     { name = "typing-extensions", specifier = ">=4.6.0" },
+    { name = "uvicorn", specifier = ">=0.20.0" },
     { name = "wheel", specifier = ">=0.42.0,<1.0" },
     { name = "wheel", specifier = ">=0.42.0,<1.0" },
     { name = "wrapt", specifier = ">=1.17.0,<2.0" },
     { name = "wrapt", specifier = ">=1.17.0,<2.0" },
 ]
 ]
@@ -1819,7 +1834,6 @@ dev = [
     { name = "ruff", specifier = "==0.11.0" },
     { name = "ruff", specifier = "==0.11.0" },
     { name = "selenium", specifier = ">=4.11.0,<5.0" },
     { name = "selenium", specifier = ">=4.11.0,<5.0" },
     { name = "toml", specifier = ">=0.10.2,<1.0" },
     { name = "toml", specifier = ">=0.10.2,<1.0" },
-    { name = "uvicorn", specifier = ">=0.20.0" },
 ]
 ]
 
 
 [[package]]
 [[package]]