Răsfoiți Sursa

Fix project hash and modernize type annotations (#1704)

Nikhil Rao 1 an în urmă
părinte
comite
1d9f25be6d

+ 2 - 3
reflex/.templates/web/utils/state.js

@@ -9,9 +9,8 @@ import Router, { useRouter } from "next/router";
 
 
 
 
 // Endpoint URLs.
 // Endpoint URLs.
-const PINGURL = env.pingUrl
-const EVENTURL = env.eventUrl
-const UPLOADURL = env.uploadUrl
+const EVENTURL = env.EVENT
+const UPLOADURL = env.UPLOAD
 
 
 // Global variable to hold the token.
 // Global variable to hold the token.
 let token;
 let token;

+ 18 - 17
reflex/app.py

@@ -13,7 +13,6 @@ from typing import (
     Dict,
     Dict,
     List,
     List,
     Optional,
     Optional,
-    Tuple,
     Type,
     Type,
     Union,
     Union,
 )
 )
@@ -210,7 +209,7 @@ class App(Base):
             allow_origins=["*"],
             allow_origins=["*"],
         )
         )
 
 
-    async def preprocess(self, state: State, event: Event) -> Optional[StateUpdate]:
+    async def preprocess(self, state: State, event: Event) -> StateUpdate | None:
         """Preprocess the event.
         """Preprocess the event.
 
 
         This is where middleware can modify the event before it is processed.
         This is where middleware can modify the event before it is processed.
@@ -263,7 +262,7 @@ class App(Base):
                 return out  # type: ignore
                 return out  # type: ignore
         return update
         return update
 
 
-    def add_middleware(self, middleware: Middleware, index: Optional[int] = None):
+    def add_middleware(self, middleware: Middleware, index: int | None = None):
         """Add middleware to the app.
         """Add middleware to the app.
 
 
         Args:
         Args:
@@ -302,16 +301,17 @@ class App(Base):
 
 
     def add_page(
     def add_page(
         self,
         self,
-        component: Union[Component, ComponentCallable],
-        route: Optional[str] = None,
+        component: Component | ComponentCallable,
+        route: str | None = None,
         title: str = constants.DEFAULT_TITLE,
         title: str = constants.DEFAULT_TITLE,
         description: str = constants.DEFAULT_DESCRIPTION,
         description: str = constants.DEFAULT_DESCRIPTION,
         image=constants.DEFAULT_IMAGE,
         image=constants.DEFAULT_IMAGE,
-        on_load: Optional[
-            Union[EventHandler, EventSpec, List[Union[EventHandler, EventSpec]]]
-        ] = None,
-        meta: List[Dict] = constants.DEFAULT_META_LIST,
-        script_tags: Optional[List[Component]] = None,
+        on_load: EventHandler
+        | EventSpec
+        | list[EventHandler | EventSpec]
+        | None = None,
+        meta: list[dict[str, str]] = constants.DEFAULT_META_LIST,
+        script_tags: list[Component] | None = None,
     ):
     ):
         """Add a page to the app.
         """Add a page to the app.
 
 
@@ -379,7 +379,7 @@ class App(Base):
                 on_load = [on_load]
                 on_load = [on_load]
             self.load_events[route] = on_load
             self.load_events[route] = on_load
 
 
-    def get_load_events(self, route: str) -> List[Union[EventHandler, EventSpec]]:
+    def get_load_events(self, route: str) -> list[EventHandler | EventSpec]:
         """Get the load events for a route.
         """Get the load events for a route.
 
 
         Args:
         Args:
@@ -428,14 +428,15 @@ class App(Base):
 
 
     def add_custom_404_page(
     def add_custom_404_page(
         self,
         self,
-        component: Optional[Union[Component, ComponentCallable]] = None,
+        component: Component | ComponentCallable | None = None,
         title: str = constants.TITLE_404,
         title: str = constants.TITLE_404,
         image: str = constants.FAVICON_404,
         image: str = constants.FAVICON_404,
         description: str = constants.DESCRIPTION_404,
         description: str = constants.DESCRIPTION_404,
-        on_load: Optional[
-            Union[EventHandler, EventSpec, List[Union[EventHandler, EventSpec]]]
-        ] = None,
-        meta: List[Dict] = constants.DEFAULT_META_LIST,
+        on_load: EventHandler
+        | EventSpec
+        | list[EventHandler | EventSpec]
+        | None = None,
+        meta: list[dict[str, str]] = constants.DEFAULT_META_LIST,
     ):
     ):
         """Define a custom 404 page for any url having no match.
         """Define a custom 404 page for any url having no match.
 
 
@@ -694,7 +695,7 @@ def upload(app: App):
         # get the current state(parent state/substate)
         # get the current state(parent state/substate)
         path = handler.split(".")[:-1]
         path = handler.split(".")[:-1]
         current_state = state.get_substate(path)
         current_state = state.get_substate(path)
-        handler_upload_param: Tuple = ()
+        handler_upload_param = ()
 
 
         # get handler function
         # get handler function
         func = getattr(current_state, handler.split(".")[-1])
         func = getattr(current_state, handler.split(".")[-1])

+ 2 - 2
reflex/base.py

@@ -1,7 +1,7 @@
 """Define the base Reflex class."""
 """Define the base Reflex class."""
 from __future__ import annotations
 from __future__ import annotations
 
 
-from typing import Any, Dict
+from typing import Any
 
 
 import pydantic
 import pydantic
 from pydantic.fields import ModelField
 from pydantic.fields import ModelField
@@ -46,7 +46,7 @@ class Base(pydantic.BaseModel):
         return self
         return self
 
 
     @classmethod
     @classmethod
-    def get_fields(cls) -> Dict[str, Any]:
+    def get_fields(cls) -> dict[str, Any]:
         """Get the fields of the object.
         """Get the fields of the object.
 
 
         Returns:
         Returns:

+ 4 - 2
reflex/components/base/meta.py

@@ -1,6 +1,8 @@
 """Display the title of the current page."""
 """Display the title of the current page."""
 
 
-from typing import Dict, Optional
+from __future__ import annotations
+
+from typing import Optional
 
 
 from reflex.components.base.bare import Bare
 from reflex.components.base.bare import Bare
 from reflex.components.component import Component
 from reflex.components.component import Component
@@ -11,7 +13,7 @@ class Title(Component):
 
 
     tag = "title"
     tag = "title"
 
 
-    def render(self) -> Dict:
+    def render(self) -> dict:
         """Render the title component.
         """Render the title component.
 
 
         Returns:
         Returns:

+ 2 - 2
reflex/components/base/script.py

@@ -2,7 +2,7 @@
 
 
 https://nextjs.org/docs/app/api-reference/components/script
 https://nextjs.org/docs/app/api-reference/components/script
 """
 """
-from typing import Set
+from __future__ import annotations
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.event import EventChain
 from reflex.event import EventChain
@@ -57,7 +57,7 @@ class Script(Component):
             raise ValueError("Must provide inline script or `src` prop.")
             raise ValueError("Must provide inline script or `src` prop.")
         return super().create(*children, **props)
         return super().create(*children, **props)
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_triggers(self) -> set[str]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:

+ 7 - 7
reflex/config.py

@@ -28,9 +28,9 @@ class DBConfig(Base):
         cls,
         cls,
         database: str,
         database: str,
         username: str,
         username: str,
-        password: Optional[str] = None,
-        host: Optional[str] = None,
-        port: Optional[int] = 5432,
+        password: str | None = None,
+        host: str | None = None,
+        port: int | None = 5432,
     ) -> DBConfig:
     ) -> DBConfig:
         """Create an instance with postgresql engine.
         """Create an instance with postgresql engine.
 
 
@@ -58,9 +58,9 @@ class DBConfig(Base):
         cls,
         cls,
         database: str,
         database: str,
         username: str,
         username: str,
-        password: Optional[str] = None,
-        host: Optional[str] = None,
-        port: Optional[int] = 5432,
+        password: str | None = None,
+        host: str | None = None,
+        port: int | None = 5432,
     ) -> DBConfig:
     ) -> DBConfig:
         """Create an instance with postgresql+psycopg2 engine.
         """Create an instance with postgresql+psycopg2 engine.
 
 
@@ -259,7 +259,7 @@ class Config(Base):
                 # Set the value.
                 # Set the value.
                 setattr(self, key, env_var)
                 setattr(self, key, env_var)
 
 
-    def get_event_namespace(self) -> Optional[str]:
+    def get_event_namespace(self) -> str | None:
         """Get the websocket event namespace.
         """Get the websocket event namespace.
 
 
         Returns:
         Returns:

+ 1 - 2
reflex/constants.py

@@ -6,7 +6,6 @@ import platform
 import re
 import re
 from enum import Enum
 from enum import Enum
 from types import SimpleNamespace
 from types import SimpleNamespace
-from typing import Optional
 
 
 from platformdirs import PlatformDirs
 from platformdirs import PlatformDirs
 
 
@@ -19,7 +18,7 @@ except ImportError:
 IS_WINDOWS = platform.system() == "Windows"
 IS_WINDOWS = platform.system() == "Windows"
 
 
 
 
-def get_fnm_name() -> Optional[str]:
+def get_fnm_name() -> str | None:
     """Get the appropriate fnm executable name based on the current platform.
     """Get the appropriate fnm executable name based on the current platform.
 
 
     Returns:
     Returns:

+ 9 - 11
reflex/event.py

@@ -2,7 +2,7 @@
 from __future__ import annotations
 from __future__ import annotations
 
 
 import inspect
 import inspect
-from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
+from typing import Any, Callable, Dict, List, Tuple
 
 
 from reflex import constants
 from reflex import constants
 from reflex.base import Base
 from reflex.base import Base
@@ -162,7 +162,7 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
     )
     )
 
 
 
 
-def redirect(path: Union[str, Var[str]]) -> EventSpec:
+def redirect(path: str | Var[str]) -> EventSpec:
     """Redirect to a new path.
     """Redirect to a new path.
 
 
     Args:
     Args:
@@ -174,7 +174,7 @@ def redirect(path: Union[str, Var[str]]) -> EventSpec:
     return server_side("_redirect", get_fn_signature(redirect), path=path)
     return server_side("_redirect", get_fn_signature(redirect), path=path)
 
 
 
 
-def console_log(message: Union[str, Var[str]]) -> EventSpec:
+def console_log(message: str | Var[str]) -> EventSpec:
     """Do a console.log on the browser.
     """Do a console.log on the browser.
 
 
     Args:
     Args:
@@ -186,7 +186,7 @@ def console_log(message: Union[str, Var[str]]) -> EventSpec:
     return server_side("_console", get_fn_signature(console_log), message=message)
     return server_side("_console", get_fn_signature(console_log), message=message)
 
 
 
 
-def window_alert(message: Union[str, Var[str]]) -> EventSpec:
+def window_alert(message: str | Var[str]) -> EventSpec:
     """Create a window alert on the browser.
     """Create a window alert on the browser.
 
 
     Args:
     Args:
@@ -250,7 +250,7 @@ def set_cookie(key: str, value: str) -> EventSpec:
     )
     )
 
 
 
 
-def remove_cookie(key: str, options: Dict[str, Any] = {}) -> EventSpec:  # noqa: B006
+def remove_cookie(key: str, options: dict[str, Any] = {}) -> EventSpec:  # noqa: B006
     """Remove a cookie on the frontend.
     """Remove a cookie on the frontend.
 
 
     Args:
     Args:
@@ -378,7 +378,7 @@ def call_event_handler(event_handler: EventHandler, arg: Var) -> EventSpec:
     return event_handler(arg)
     return event_handler(arg)
 
 
 
 
-def call_event_fn(fn: Callable, arg: Var) -> List[EventSpec]:
+def call_event_fn(fn: Callable, arg: Var) -> list[EventSpec]:
     """Call a function to a list of event specs.
     """Call a function to a list of event specs.
 
 
     The function should return either a single EventSpec or a list of EventSpecs.
     The function should return either a single EventSpec or a list of EventSpecs.
@@ -434,7 +434,7 @@ def call_event_fn(fn: Callable, arg: Var) -> List[EventSpec]:
     return events
     return events
 
 
 
 
-def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[Var, Var], ...]:
+def get_handler_args(event_spec: EventSpec, arg: Var) -> tuple[tuple[Var, Var], ...]:
     """Get the handler args for the given event spec.
     """Get the handler args for the given event spec.
 
 
     Args:
     Args:
@@ -449,9 +449,7 @@ def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[Var, Var],
     return event_spec.args if len(args) > 1 else tuple()
     return event_spec.args if len(args) > 1 else tuple()
 
 
 
 
-def fix_events(
-    events: Optional[List[Union[EventHandler, EventSpec]]], token: str
-) -> List[Event]:
+def fix_events(events: list[EventHandler | EventSpec], token: str) -> list[Event]:
     """Fix a list of events returned by an event handler.
     """Fix a list of events returned by an event handler.
 
 
     Args:
     Args:
@@ -510,7 +508,7 @@ def get_fn_signature(fn: Callable) -> inspect.Signature:
 
 
 
 
 # A set of common event triggers.
 # A set of common event triggers.
-EVENT_TRIGGERS: Set[str] = {
+EVENT_TRIGGERS: set[str] = {
     "on_focus",
     "on_focus",
     "on_blur",
     "on_blur",
     "on_click",
     "on_click",

+ 6 - 4
reflex/model.py

@@ -1,5 +1,7 @@
 """Database built into Reflex."""
 """Database built into Reflex."""
 
 
+from __future__ import annotations
+
 import os
 import os
 from collections import defaultdict
 from collections import defaultdict
 from pathlib import Path
 from pathlib import Path
@@ -21,7 +23,7 @@ from reflex.config import get_config
 from reflex.utils import console
 from reflex.utils import console
 
 
 
 
-def get_engine(url: Optional[str] = None):
+def get_engine(url: str | None = None):
     """Get the database engine.
     """Get the database engine.
 
 
     Args:
     Args:
@@ -142,7 +144,7 @@ class Model(Base, sqlmodel.SQLModel):
     def alembic_autogenerate(
     def alembic_autogenerate(
         cls,
         cls,
         connection: sqlalchemy.engine.Connection,
         connection: sqlalchemy.engine.Connection,
-        message: Optional[str] = None,
+        message: str | None = None,
         write_migration_scripts: bool = True,
         write_migration_scripts: bool = True,
     ) -> bool:
     ) -> bool:
         """Generate migration scripts for alembic-detectable changes.
         """Generate migration scripts for alembic-detectable changes.
@@ -233,7 +235,7 @@ class Model(Base, sqlmodel.SQLModel):
             env.run_migrations()
             env.run_migrations()
 
 
     @classmethod
     @classmethod
-    def migrate(cls, autogenerate: bool = False) -> Optional[bool]:
+    def migrate(cls, autogenerate: bool = False) -> bool | None:
         """Execute alembic migrations for all sqlmodel Model classes.
         """Execute alembic migrations for all sqlmodel Model classes.
 
 
         If alembic is not installed or has not been initialized for the project,
         If alembic is not installed or has not been initialized for the project,
@@ -277,7 +279,7 @@ class Model(Base, sqlmodel.SQLModel):
         return sqlmodel.select(cls)
         return sqlmodel.select(cls)
 
 
 
 
-def session(url: Optional[str] = None) -> sqlmodel.Session:
+def session(url: str | None = None) -> sqlmodel.Session:
     """Get a session to interact with the database.
     """Get a session to interact with the database.
 
 
     Args:
     Args:

+ 7 - 10
reflex/page.py

@@ -2,8 +2,6 @@
 
 
 from __future__ import annotations
 from __future__ import annotations
 
 
-from typing import List, Optional, Union
-
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.event import EventHandler
 from reflex.event import EventHandler
 
 
@@ -11,13 +9,13 @@ DECORATED_PAGES = []
 
 
 
 
 def page(
 def page(
-    route: Optional[str] = None,
-    title: Optional[str] = None,
-    image: Optional[str] = None,
-    description: Optional[str] = None,
-    meta: Optional[str] = None,
-    script_tags: Optional[List[Component]] = None,
-    on_load: Optional[Union[EventHandler, List[EventHandler]]] = None,
+    route: str | None = None,
+    title: str | None = None,
+    image: str | None = None,
+    description: str | None = None,
+    meta: str | None = None,
+    script_tags: list[Component] | None = None,
+    on_load: EventHandler | list[EventHandler] | None = None,
 ):
 ):
     """Decorate a function as a page.
     """Decorate a function as a page.
 
 
@@ -40,7 +38,6 @@ def page(
     Returns:
     Returns:
         The decorated function.
         The decorated function.
     """
     """
-    ...
 
 
     def decorator(render_fn):
     def decorator(render_fn):
         kwargs = {}
         kwargs = {}

+ 0 - 1
reflex/reflex.py

@@ -81,7 +81,6 @@ def init(
     if not os.path.exists(constants.CONFIG_FILE):
     if not os.path.exists(constants.CONFIG_FILE):
         prerequisites.create_config(app_name)
         prerequisites.create_config(app_name)
         prerequisites.initialize_app_directory(app_name, template)
         prerequisites.initialize_app_directory(app_name, template)
-        build.set_reflex_project_hash()
         telemetry.send("init", config.telemetry_enabled)
         telemetry.send("init", config.telemetry_enabled)
     else:
     else:
         telemetry.send("reinit", config.telemetry_enabled)
         telemetry.send("reinit", config.telemetry_enabled)

+ 6 - 7
reflex/route.py

@@ -3,7 +3,6 @@
 from __future__ import annotations
 from __future__ import annotations
 
 
 import re
 import re
-from typing import Dict, List, Optional, Union
 
 
 from reflex import constants
 from reflex import constants
 from reflex.event import EventHandler
 from reflex.event import EventHandler
@@ -12,11 +11,11 @@ from reflex.utils.console import deprecate
 
 
 
 
 def route(
 def route(
-    route: Optional[str] = None,
-    title: Optional[str] = None,
-    image: Optional[str] = None,
-    description: Optional[str] = None,
-    on_load: Optional[Union[EventHandler, List[EventHandler]]] = None,
+    route: str | None = None,
+    title: str | None = None,
+    image: str | None = None,
+    description: str | None = None,
+    on_load: EventHandler | list[EventHandler] | None = None,
 ):
 ):
     """Decorate a function as a page.
     """Decorate a function as a page.
 
 
@@ -62,7 +61,7 @@ def verify_route_validity(route: str) -> None:
         raise ValueError(f"Catch-all must be the last part of the URL: {route}")
         raise ValueError(f"Catch-all must be the last part of the URL: {route}")
 
 
 
 
-def get_route_args(route: str) -> Dict[str, str]:
+def get_route_args(route: str) -> dict[str, str]:
     """Get the dynamic arguments for the given route.
     """Get the dynamic arguments for the given route.
 
 
     Args:
     Args:

+ 12 - 13
reflex/state.py

@@ -21,7 +21,6 @@ from typing import (
     Optional,
     Optional,
     Sequence,
     Sequence,
     Set,
     Set,
-    Tuple,
     Type,
     Type,
     Union,
     Union,
 )
 )
@@ -87,7 +86,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
     # Per-instance copy of backend variable values
     # Per-instance copy of backend variable values
     _backend_vars: Dict[str, Any] = {}
     _backend_vars: Dict[str, Any] = {}
 
 
-    def __init__(self, *args, parent_state: Optional[State] = None, **kwargs):
+    def __init__(self, *args, parent_state: State | None = None, **kwargs):
         """Initialize the state.
         """Initialize the state.
 
 
         Args:
         Args:
@@ -287,7 +286,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
             )
             )
 
 
     @classmethod
     @classmethod
-    def get_skip_vars(cls) -> Set[str]:
+    def get_skip_vars(cls) -> set[str]:
         """Get the vars to skip when serializing.
         """Get the vars to skip when serializing.
 
 
         Returns:
         Returns:
@@ -306,7 +305,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
 
 
     @classmethod
     @classmethod
     @functools.lru_cache()
     @functools.lru_cache()
-    def get_parent_state(cls) -> Optional[Type[State]]:
+    def get_parent_state(cls) -> Type[State] | None:
         """Get the parent state.
         """Get the parent state.
 
 
         Returns:
         Returns:
@@ -322,7 +321,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
 
 
     @classmethod
     @classmethod
     @functools.lru_cache()
     @functools.lru_cache()
-    def get_substates(cls) -> Set[Type[State]]:
+    def get_substates(cls) -> set[Type[State]]:
         """Get the substates of the state.
         """Get the substates of the state.
 
 
         Returns:
         Returns:
@@ -493,7 +492,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
             field.default = default_value
             field.default = default_value
 
 
     @staticmethod
     @staticmethod
-    def _get_base_functions() -> Dict[str, FunctionType]:
+    def _get_base_functions() -> dict[str, FunctionType]:
         """Get all functions of the state class excluding dunder methods.
         """Get all functions of the state class excluding dunder methods.
 
 
         Returns:
         Returns:
@@ -551,7 +550,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
         else:
         else:
             return self.router_data.get(constants.RouteVar.PATH, "")
             return self.router_data.get(constants.RouteVar.PATH, "")
 
 
-    def get_query_params(self) -> Dict[str, str]:
+    def get_query_params(self) -> dict[str, str]:
         """Obtain the query parameters for the queried page.
         """Obtain the query parameters for the queried page.
 
 
         The query object contains both the URI parameters and the GET parameters.
         The query object contains both the URI parameters and the GET parameters.
@@ -561,7 +560,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
         """
         """
         return self.router_data.get(constants.RouteVar.QUERY, {})
         return self.router_data.get(constants.RouteVar.QUERY, {})
 
 
-    def get_cookies(self) -> Dict[str, str]:
+    def get_cookies(self) -> dict[str, str]:
         """Obtain the cookies of the client stored in the browser.
         """Obtain the cookies of the client stored in the browser.
 
 
         Returns:
         Returns:
@@ -712,7 +711,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
         for substate in self.substates.values():
         for substate in self.substates.values():
             substate._reset_client_storage()
             substate._reset_client_storage()
 
 
-    def get_substate(self, path: Sequence[str]) -> Optional[State]:
+    def get_substate(self, path: Sequence[str]) -> State | None:
         """Get the substate.
         """Get the substate.
 
 
         Args:
         Args:
@@ -812,7 +811,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
 
 
     async def _process_event(
     async def _process_event(
         self, handler: EventHandler, state: State, payload: Dict
         self, handler: EventHandler, state: State, payload: Dict
-    ) -> AsyncIterator[Tuple[Optional[List[EventSpec]], bool]]:
+    ) -> AsyncIterator[tuple[list[EventSpec] | None, bool]]:
         """Process event.
         """Process event.
 
 
         Args:
         Args:
@@ -865,7 +864,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
             print(error)
             print(error)
             yield [window_alert("An error occurred. See logs for details.")], True
             yield [window_alert("An error occurred. See logs for details.")], True
 
 
-    def _always_dirty_computed_vars(self) -> Set[str]:
+    def _always_dirty_computed_vars(self) -> set[str]:
         """The set of ComputedVars that always need to be recalculated.
         """The set of ComputedVars that always need to be recalculated.
 
 
         Returns:
         Returns:
@@ -889,7 +888,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
                 if actual_var:
                 if actual_var:
                     actual_var.mark_dirty(instance=self)
                     actual_var.mark_dirty(instance=self)
 
 
-    def _dirty_computed_vars(self, from_vars: Optional[Set[str]] = None) -> Set[str]:
+    def _dirty_computed_vars(self, from_vars: set[str] | None = None) -> set[str]:
         """Determine ComputedVars that need to be recalculated based on the given vars.
         """Determine ComputedVars that need to be recalculated based on the given vars.
 
 
         Args:
         Args:
@@ -976,7 +975,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
         self.dirty_vars = set()
         self.dirty_vars = set()
         self.dirty_substates = set()
         self.dirty_substates = set()
 
 
-    def dict(self, include_computed: bool = True, **kwargs) -> Dict[str, Any]:
+    def dict(self, include_computed: bool = True, **kwargs) -> dict[str, Any]:
         """Convert the object to a dictionary.
         """Convert the object to a dictionary.
 
 
         Args:
         Args:

+ 2 - 2
reflex/style.py

@@ -1,6 +1,6 @@
 """Handle styling."""
 """Handle styling."""
 
 
-from typing import Optional
+from __future__ import annotations
 
 
 from reflex import constants
 from reflex import constants
 from reflex.event import EventChain
 from reflex.event import EventChain
@@ -35,7 +35,7 @@ def convert(style_dict):
 class Style(dict):
 class Style(dict):
     """A style dictionary."""
     """A style dictionary."""
 
 
-    def __init__(self, style_dict: Optional[dict] = None):
+    def __init__(self, style_dict: dict | None = None):
         """Initialize the style.
         """Initialize the style.
 
 
         Args:
         Args:

+ 3 - 36
reflex/utils/build.py

@@ -4,12 +4,10 @@ from __future__ import annotations
 
 
 import json
 import json
 import os
 import os
-import random
 import subprocess
 import subprocess
 import zipfile
 import zipfile
 from enum import Enum
 from enum import Enum
 from pathlib import Path
 from pathlib import Path
-from typing import Optional, Union
 
 
 from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
 from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
 
 
@@ -18,42 +16,11 @@ from reflex.config import get_config
 from reflex.utils import console, path_ops, prerequisites, processes
 from reflex.utils import console, path_ops, prerequisites, processes
 
 
 
 
-def update_json_file(file_path: str, update_dict: dict[str, Union[int, str]]):
-    """Update the contents of a json file.
-
-    Args:
-        file_path: the path to the JSON file.
-        update_dict: object to update json.
-    """
-    fp = Path(file_path)
-    # create file if it doesn't exist
-    fp.touch(exist_ok=True)
-    # create an empty json object if file is empty
-    fp.write_text("{}") if fp.stat().st_size == 0 else None
-
-    with open(fp) as f:  # type: ignore
-        json_object: dict = json.load(f)
-        json_object.update(update_dict)
-    with open(fp, "w") as f:
-        json.dump(json_object, f, ensure_ascii=False)
-
-
-def set_reflex_project_hash():
-    """Write the hash of the Reflex project to a REFLEX_JSON."""
-    project_hash = random.getrandbits(128)
-    console.debug(f"Setting project hash to {project_hash}.")
-    update_json_file(constants.REFLEX_JSON, {"project_hash": project_hash})
-
-
 def set_env_json():
 def set_env_json():
     """Write the upload url to a REFLEX_JSON."""
     """Write the upload url to a REFLEX_JSON."""
-    update_json_file(
+    path_ops.update_json_file(
         constants.ENV_JSON,
         constants.ENV_JSON,
-        {
-            "uploadUrl": constants.Endpoint.UPLOAD.get_url(),
-            "eventUrl": constants.Endpoint.EVENT.get_url(),
-            "pingUrl": constants.Endpoint.PING.get_url(),
-        },
+        {endpoint.name: endpoint.get_url() for endpoint in constants.Endpoint},
     )
     )
 
 
 
 
@@ -152,7 +119,7 @@ def export(
     backend: bool = True,
     backend: bool = True,
     frontend: bool = True,
     frontend: bool = True,
     zip: bool = False,
     zip: bool = False,
-    deploy_url: Optional[str] = None,
+    deploy_url: str | None = None,
 ):
 ):
     """Export the app for deployment.
     """Export the app for deployment.
 
 

+ 7 - 7
reflex/utils/format.py

@@ -9,7 +9,7 @@ import os
 import os.path as op
 import os.path as op
 import re
 import re
 import sys
 import sys
-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type
+from typing import TYPE_CHECKING, Any, Type
 
 
 import plotly.graph_objects as go
 import plotly.graph_objects as go
 from plotly.io import to_json
 from plotly.io import to_json
@@ -33,7 +33,7 @@ WRAP_MAP = {
 }
 }
 
 
 
 
-def get_close_char(open: str, close: Optional[str] = None) -> str:
+def get_close_char(open: str, close: str | None = None) -> str:
     """Check if the given character is a valid brace.
     """Check if the given character is a valid brace.
 
 
     Args:
     Args:
@@ -53,7 +53,7 @@ def get_close_char(open: str, close: Optional[str] = None) -> str:
     return WRAP_MAP[open]
     return WRAP_MAP[open]
 
 
 
 
-def is_wrapped(text: str, open: str, close: Optional[str] = None) -> bool:
+def is_wrapped(text: str, open: str, close: str | None = None) -> bool:
     """Check if the given text is wrapped in the given open and close characters.
     """Check if the given text is wrapped in the given open and close characters.
 
 
     Args:
     Args:
@@ -71,7 +71,7 @@ def is_wrapped(text: str, open: str, close: Optional[str] = None) -> bool:
 def wrap(
 def wrap(
     text: str,
     text: str,
     open: str,
     open: str,
-    close: Optional[str] = None,
+    close: str | None = None,
     check_first: bool = True,
     check_first: bool = True,
     num: int = 1,
     num: int = 1,
 ) -> str:
 ) -> str:
@@ -258,7 +258,7 @@ def format_cond(
     return wrap(f"{cond} ? {true_value} : {false_value}", "{")
     return wrap(f"{cond} ? {true_value} : {false_value}", "{")
 
 
 
 
-def get_event_handler_parts(handler: EventHandler) -> Tuple[str, str]:
+def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:
     """Get the state and function name of an event handler.
     """Get the state and function name of an event handler.
 
 
     Args:
     Args:
@@ -370,7 +370,7 @@ def format_event_chain(
     )
     )
 
 
 
 
-def format_query_params(router_data: Dict[str, Any]) -> Dict[str, str]:
+def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
     """Convert back query params name to python-friendly case.
     """Convert back query params name to python-friendly case.
 
 
     Args:
     Args:
@@ -383,7 +383,7 @@ def format_query_params(router_data: Dict[str, Any]) -> Dict[str, str]:
     return {k.replace("-", "_"): v for k, v in params.items()}
     return {k.replace("-", "_"): v for k, v in params.items()}
 
 
 
 
-def format_dataframe_values(value: Type) -> List[Any]:
+def format_dataframe_values(value: Type) -> list[Any]:
     """Format dataframe values.
     """Format dataframe values.
 
 
     Args:
     Args:

+ 2 - 0
reflex/utils/imports.py

@@ -1,5 +1,7 @@
 """Import operations."""
 """Import operations."""
 
 
+from __future__ import annotations
+
 from collections import defaultdict
 from collections import defaultdict
 from typing import Dict, Set
 from typing import Dict, Set
 
 

+ 34 - 5
reflex/utils/path_ops.py

@@ -2,10 +2,10 @@
 
 
 from __future__ import annotations
 from __future__ import annotations
 
 
+import json
 import os
 import os
 import shutil
 import shutil
 from pathlib import Path
 from pathlib import Path
-from typing import Optional
 
 
 from reflex import constants
 from reflex import constants
 
 
@@ -100,7 +100,7 @@ def ln(src: str, dest: str, overwrite: bool = False) -> bool:
     return True
     return True
 
 
 
 
-def which(program: str) -> Optional[str]:
+def which(program: str) -> str | None:
     """Find the path to an executable.
     """Find the path to an executable.
 
 
     Args:
     Args:
@@ -112,7 +112,7 @@ def which(program: str) -> Optional[str]:
     return shutil.which(program)
     return shutil.which(program)
 
 
 
 
-def get_node_bin_path() -> Optional[str]:
+def get_node_bin_path() -> str | None:
     """Get the node binary dir path.
     """Get the node binary dir path.
 
 
     Returns:
     Returns:
@@ -124,7 +124,7 @@ def get_node_bin_path() -> Optional[str]:
     return constants.NODE_BIN_PATH
     return constants.NODE_BIN_PATH
 
 
 
 
-def get_node_path() -> Optional[str]:
+def get_node_path() -> str | None:
     """Get the node binary path.
     """Get the node binary path.
 
 
     Returns:
     Returns:
@@ -135,7 +135,7 @@ def get_node_path() -> Optional[str]:
     return constants.NODE_PATH
     return constants.NODE_PATH
 
 
 
 
-def get_npm_path() -> Optional[str]:
+def get_npm_path() -> str | None:
     """Get npm binary path.
     """Get npm binary path.
 
 
     Returns:
     Returns:
@@ -144,3 +144,32 @@ def get_npm_path() -> Optional[str]:
     if not os.path.exists(constants.NODE_PATH):
     if not os.path.exists(constants.NODE_PATH):
         return which("npm")
         return which("npm")
     return constants.NPM_PATH
     return constants.NPM_PATH
+
+
+def update_json_file(file_path: str, update_dict: dict[str, int | str]):
+    """Update the contents of a json file.
+
+    Args:
+        file_path: the path to the JSON file.
+        update_dict: object to update json.
+    """
+    fp = Path(file_path)
+
+    # Create the file if it doesn't exist.
+    fp.touch(exist_ok=True)
+
+    # Create an empty json object if file is empty
+    fp.write_text("{}") if fp.stat().st_size == 0 else None
+
+    # Read the existing json object from the file.
+    json_object = {}
+    if fp.stat().st_size == 0:
+        with open(fp) as f:
+            json_object = json.load(f)
+
+    # Update the json object with the new data.
+    json_object.update(update_dict)
+
+    # Write the updated json object to the file
+    with open(fp, "w") as f:
+        json.dump(json_object, f, ensure_ascii=False)

+ 24 - 12
reflex/utils/prerequisites.py

@@ -6,6 +6,7 @@ import glob
 import json
 import json
 import os
 import os
 import platform
 import platform
+import random
 import re
 import re
 import stat
 import stat
 import sys
 import sys
@@ -14,7 +15,6 @@ import zipfile
 from fileinput import FileInput
 from fileinput import FileInput
 from pathlib import Path
 from pathlib import Path
 from types import ModuleType
 from types import ModuleType
-from typing import List, Optional
 
 
 import httpx
 import httpx
 import typer
 import typer
@@ -44,7 +44,7 @@ def check_node_version() -> bool:
     return False
     return False
 
 
 
 
-def get_node_version() -> Optional[version.Version]:
+def get_node_version() -> version.Version | None:
     """Get the version of node.
     """Get the version of node.
 
 
     Returns:
     Returns:
@@ -58,7 +58,7 @@ def get_node_version() -> Optional[version.Version]:
         return None
         return None
 
 
 
 
-def get_bun_version() -> Optional[version.Version]:
+def get_bun_version() -> version.Version | None:
     """Get the version of bun.
     """Get the version of bun.
 
 
     Returns:
     Returns:
@@ -72,7 +72,7 @@ def get_bun_version() -> Optional[version.Version]:
         return None
         return None
 
 
 
 
-def get_install_package_manager() -> Optional[str]:
+def get_install_package_manager() -> str | None:
     """Get the package manager executable for installation.
     """Get the package manager executable for installation.
       Currently on unix systems, bun is used for installation only.
       Currently on unix systems, bun is used for installation only.
 
 
@@ -87,7 +87,7 @@ def get_install_package_manager() -> Optional[str]:
     return get_config().bun_path
     return get_config().bun_path
 
 
 
 
-def get_package_manager() -> Optional[str]:
+def get_package_manager() -> str | None:
     """Get the package manager executable for running app.
     """Get the package manager executable for running app.
       Currently on unix systems, npm is used for running the app only.
       Currently on unix systems, npm is used for running the app only.
 
 
@@ -109,7 +109,7 @@ def get_app() -> ModuleType:
     return __import__(module, fromlist=(constants.APP_VAR,))
     return __import__(module, fromlist=(constants.APP_VAR,))
 
 
 
 
-def get_redis() -> Optional[Redis]:
+def get_redis() -> Redis | None:
     """Get the redis client.
     """Get the redis client.
 
 
     Returns:
     Returns:
@@ -227,10 +227,22 @@ def initialize_web_directory():
     with open(next_config_file, "w") as file:
     with open(next_config_file, "w") as file:
         file.writelines(lines)
         file.writelines(lines)
 
 
-    # Write the current version of distributed reflex package to a REFLEX_JSON."""
-    with open(constants.REFLEX_JSON, "w") as f:
-        reflex_json = {"version": constants.VERSION}
-        json.dump(reflex_json, f, ensure_ascii=False)
+    # Initialize the reflex json file.
+    init_reflex_json()
+
+
+def init_reflex_json():
+    """Write the hash of the Reflex project to a REFLEX_JSON."""
+    # Get a random project hash.
+    project_hash = random.getrandbits(128)
+    console.debug(f"Setting project hash to {project_hash}.")
+
+    # Write the hash and version to the reflex json file.
+    reflex_json = {
+        "version": constants.VERSION,
+        "project_hash": project_hash,
+    }
+    path_ops.update_json_file(constants.REFLEX_JSON, reflex_json)
 
 
 
 
 def remove_existing_bun_installation():
 def remove_existing_bun_installation():
@@ -376,11 +388,11 @@ def install_bun():
     )
     )
 
 
 
 
-def install_frontend_packages(packages: List[str]):
+def install_frontend_packages(packages: list[str]):
     """Installs the base and custom frontend packages.
     """Installs the base and custom frontend packages.
 
 
     Args:
     Args:
-        packages (List[str]): A list of package names to be installed.
+        packages: A list of package names to be installed.
 
 
     Example:
     Example:
         >>> install_frontend_packages(["react", "react-dom"])
         >>> install_frontend_packages(["react", "react-dom"])

+ 2 - 2
reflex/utils/types.py

@@ -4,7 +4,7 @@ from __future__ import annotations
 
 
 import contextlib
 import contextlib
 import typing
 import typing
-from typing import Any, Callable, Tuple, Type, Union, _GenericAlias  # type: ignore
+from typing import Any, Callable, Type, Union, _GenericAlias  # type: ignore
 
 
 from reflex.base import Base
 from reflex.base import Base
 
 
@@ -17,7 +17,7 @@ StateVar = Union[PrimitiveType, Base, None]
 StateIterVar = Union[list, set, tuple]
 StateIterVar = Union[list, set, tuple]
 
 
 
 
-def get_args(alias: _GenericAlias) -> Tuple[Type, ...]:
+def get_args(alias: _GenericAlias) -> tuple[Type, ...]:
     """Get the arguments of a type alias.
     """Get the arguments of a type alias.
 
 
     Args:
     Args:

+ 7 - 9
reflex/vars.py

@@ -73,7 +73,7 @@ class Var(ABC):
     @classmethod
     @classmethod
     def create(
     def create(
         cls, value: Any, is_local: bool = True, is_string: bool = False
         cls, value: Any, is_local: bool = True, is_string: bool = False
-    ) -> Optional[Var]:
+    ) -> Var | None:
         """Create a var from a value.
         """Create a var from a value.
 
 
         Args:
         Args:
@@ -358,10 +358,10 @@ class Var(ABC):
     def operation(
     def operation(
         self,
         self,
         op: str = "",
         op: str = "",
-        other: Optional[Var] = None,
-        type_: Optional[Type] = None,
+        other: Var | None = None,
+        type_: Type | None = None,
         flip: bool = False,
         flip: bool = False,
-        fn: Optional[str] = None,
+        fn: str | None = None,
     ) -> Var:
     ) -> Var:
         """Perform an operation on a var.
         """Perform an operation on a var.
 
 
@@ -983,8 +983,8 @@ class ComputedVar(Var, property):
     def deps(
     def deps(
         self,
         self,
         objclass: Type,
         objclass: Type,
-        obj: Optional[FunctionType] = None,
-    ) -> Set[str]:
+        obj: FunctionType | None = None,
+    ) -> set[str]:
         """Determine var dependencies of this ComputedVar.
         """Determine var dependencies of this ComputedVar.
 
 
         Save references to attributes accessed on "self".  Recursively called
         Save references to attributes accessed on "self".  Recursively called
@@ -1375,10 +1375,8 @@ class ImportVar(Base):
 class NoRenderImportVar(ImportVar):
 class NoRenderImportVar(ImportVar):
     """A import that doesn't need to be rendered."""
     """A import that doesn't need to be rendered."""
 
 
-    ...
 
 
-
-def get_local_storage(key: Optional[Union[Var, str]] = None) -> BaseVar:
+def get_local_storage(key: Var | str | None = None) -> BaseVar:
     """Provide a base var as payload to get local storage item(s).
     """Provide a base var as payload to get local storage item(s).
 
 
     Args:
     Args:

+ 3 - 0
reflex/vars.pyi

@@ -160,4 +160,7 @@ class ImportVar(Base):
     def name(self) -> str: ...
     def name(self) -> str: ...
     def __hash__(self) -> int: ...
     def __hash__(self) -> int: ...
 
 
+class NoRenderImportVar(ImportVar):
+    """A import that doesn't need to be rendered."""
+
 def get_local_storage(key: Optional[Union[Var, str]] = ...) -> BaseVar: ...
 def get_local_storage(key: Optional[Union[Var, str]] = ...) -> BaseVar: ...