From 6979d2353ab6cdfa5c9a1a8bd28ef05ea1e0485d Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Thu, 10 Jul 2025 17:36:53 -0700 Subject: [PATCH 1/2] do not force import event and page --- pyi_hashes.json | 2 +- reflex/__init__.py | 11 ++------ reflex/event.py | 68 ++++++++++++++++++++++++++++++++++++---------- reflex/page.py | 66 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 118 insertions(+), 29 deletions(-) diff --git a/pyi_hashes.json b/pyi_hashes.json index fc25c93b890..84469bf1ce1 100644 --- a/pyi_hashes.json +++ b/pyi_hashes.json @@ -1,5 +1,5 @@ { - "reflex/__init__.pyi": "c69e4120c505941af8087b9c18df6121", + "reflex/__init__.pyi": "19f58e6bbb6846d14ccdd4364afb957c", "reflex/components/__init__.pyi": "ac05995852baa81062ba3d18fbc489fb", "reflex/components/base/__init__.pyi": "16e47bf19e0d62835a605baa3d039c5a", "reflex/components/base/app_wrap.pyi": "ae600e2cc9d70f2ce613bdd6c1da3b16", diff --git a/reflex/__init__.py b/reflex/__init__.py index 58dabbd02f0..6a002dae978 100644 --- a/reflex/__init__.py +++ b/reflex/__init__.py @@ -84,20 +84,11 @@ from __future__ import annotations -from types import ModuleType -from typing import Any - from reflex.utils import ( compat, # for side-effects lazy_loader, ) -from .event import event as event - -# import this here explicitly to avoid returning the page module since page attr has the -# same name as page module(page.py) -from .page import page as page - # Remove the `compat` name from the namespace, it was imported for side-effects only. del compat @@ -300,6 +291,7 @@ "constants": ["Env"], "constants.colors": ["Color"], "event": [ + "event", "EventChain", "EventHandler", "call_script", @@ -330,6 +322,7 @@ ], "middleware": ["middleware", "Middleware"], "model": ["asession", "session", "Model"], + "page": ["page"], "state": [ "var", "ComponentState", diff --git a/reflex/event.py b/reflex/event.py index f0dc035c282..b8630d53c57 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -2,6 +2,7 @@ import dataclasses import inspect +import sys import types import urllib.parse from base64 import b64encode @@ -403,7 +404,7 @@ def __init__(self, fn: Callable[..., EventSpec] | None = None, **kwargs): Args: fn: The function to decorate. - **kwargs: The kwargs to pass to pydantic initializer + **kwargs: The kwargs to pass to the EventSpec constructor. """ if fn is not None: default_event_spec = fn() @@ -1243,19 +1244,6 @@ def download( ) -# This function seems unused. Check if we still need it. If not, remove in 0.7.0 -def _callback_arg_spec(eval_result: Any): - """ArgSpec for call_script callback function. - - Args: - eval_result: The result of the javascript execution. - - Returns: - Args for the callback function - """ - return [eval_result] - - def call_script( javascript_code: str | Var[str], callback: "EventType[Any] | None" = None, @@ -2197,7 +2185,9 @@ def __call__(self, *args: Var) -> Any: class EventNamespace: """A namespace for event related classes.""" + # Core Event Classes Event = Event + EventActionsMixin = EventActionsMixin EventHandler = EventHandler EventSpec = EventSpec CallableEventSpec = CallableEventSpec @@ -2206,8 +2196,43 @@ class EventNamespace: LiteralEventVar = LiteralEventVar EventChainVar = EventChainVar LiteralEventChainVar = LiteralEventChainVar - EventType = EventType EventCallback = EventCallback + LambdaEventCallback = LambdaEventCallback + + # Javascript Event Classes + JavascriptHTMLInputElement = JavascriptHTMLInputElement + JavascriptInputEvent = JavascriptInputEvent + JavasciptKeyboardEvent = JavasciptKeyboardEvent + JavascriptMouseEvent = JavascriptMouseEvent + JavascriptPointerEvent = JavascriptPointerEvent + + # Type Info Classes + KeyInputInfo = KeyInputInfo + MouseEventInfo = MouseEventInfo + PointerEventInfo = PointerEventInfo + IdentityEventReturn = IdentityEventReturn + + # File Upload + FileUpload = FileUpload + + # Type Aliases + EventType = EventType + LAMBDA_OR_STATE = LAMBDA_OR_STATE + BASIC_EVENT_TYPES = BASIC_EVENT_TYPES + IndividualEventType = IndividualEventType + + # Constants + BACKGROUND_TASK_MARKER = BACKGROUND_TASK_MARKER + _EVENT_FIELDS = _EVENT_FIELDS + upload_files = upload_files + stop_propagation = stop_propagation + prevent_default = prevent_default + + # Private/Internal Functions + _values_returned_from_event = staticmethod(_values_returned_from_event) + _check_event_args_subclass_of_callback = staticmethod( + _check_event_args_subclass_of_callback + ) @overload def __new__( @@ -2298,10 +2323,20 @@ def wrapper( check_fn_match_arg_spec = staticmethod(check_fn_match_arg_spec) resolve_annotation = staticmethod(resolve_annotation) parse_args_spec = staticmethod(parse_args_spec) + unwrap_var_annotation = staticmethod(unwrap_var_annotation) + get_fn_signature = staticmethod(get_fn_signature) + + # Event Spec Functions passthrough_event_spec = staticmethod(passthrough_event_spec) input_event = staticmethod(input_event) + int_input_event = staticmethod(int_input_event) + float_input_event = staticmethod(float_input_event) + checked_input_event = staticmethod(checked_input_event) key_event = staticmethod(key_event) + pointer_event_spec = staticmethod(pointer_event_spec) no_args_event_spec = staticmethod(no_args_event_spec) + + # Server Side Events server_side = staticmethod(server_side) redirect = staticmethod(redirect) console_log = staticmethod(console_log) @@ -2322,6 +2357,9 @@ def wrapper( call_script = staticmethod(call_script) call_function = staticmethod(call_function) run_script = staticmethod(run_script) + __file__ = __file__ event = EventNamespace +event.event = event # pyright: ignore[reportAttributeAccessIssue] +sys.modules[__name__] = event # pyright: ignore[reportArgumentType] diff --git a/reflex/page.py b/reflex/page.py index a2907ca2546..9b09682436f 100644 --- a/reflex/page.py +++ b/reflex/page.py @@ -2,12 +2,15 @@ from __future__ import annotations +import sys from collections import defaultdict -from collections.abc import Callable -from typing import Any +from typing import TYPE_CHECKING -from reflex.config import get_config -from reflex.event import EventType +if TYPE_CHECKING: + from collections.abc import Callable + from typing import Any + + from reflex.event import EventType DECORATED_PAGES: dict[str, list] = defaultdict(list) @@ -42,6 +45,7 @@ def page( Returns: The decorated function. """ + from reflex.config import get_config def decorator(render_fn: Callable): kwargs = {} @@ -65,3 +69,57 @@ def decorator(render_fn: Callable): return render_fn return decorator + + +class PageNamespace: + """A namespace for page names.""" + + DECORATED_PAGES = DECORATED_PAGES + + def __new__( + cls, + route: str | None = None, + title: str | None = None, + image: str | None = None, + description: str | None = None, + meta: list[Any] | None = None, + script_tags: list[Any] | None = None, + on_load: EventType[()] | None = None, + ): + """Decorate a function as a page. + + rx.App() will automatically call add_page() for any method decorated with page + when App.compile is called. + + All defaults are None because they will use the one from add_page(). + + Note: the decorated functions still need to be imported. + + Args: + route: The route to reach the page. + title: The title of the page. + image: The favicon of the page. + description: The description of the page. + meta: Additional meta to add to the page. + on_load: The event handler(s) called when the page load. + script_tags: scripts to attach to the page + + Returns: + The decorated function. + """ + return page( + route=route, + title=title, + image=image, + description=description, + meta=meta, + script_tags=script_tags, + on_load=on_load, + ) + + page = staticmethod(page) + __file__ = __file__ + + +page_namespace = PageNamespace +sys.modules[__name__] = page_namespace # pyright: ignore[reportArgumentType] From b267083e737db3497cb330ceb7abf88d30454ccf Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Mon, 21 Jul 2025 17:53:01 -0700 Subject: [PATCH 2/2] post merge --- pyi_hashes.json | 2 +- reflex/event.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyi_hashes.json b/pyi_hashes.json index e6c4e28fe57..7d69cdc9565 100644 --- a/pyi_hashes.json +++ b/pyi_hashes.json @@ -1,5 +1,5 @@ { - "reflex/__init__.pyi": "19f58e6bbb6846d14ccdd4364afb957c", + "reflex/__init__.pyi": "e9f08e115b1e1dd89beabacade84a589", "reflex/components/__init__.pyi": "ac05995852baa81062ba3d18fbc489fb", "reflex/components/base/__init__.pyi": "16e47bf19e0d62835a605baa3d039c5a", "reflex/components/base/app_wrap.pyi": "ae600e2cc9d70f2ce613bdd6c1da3b16", diff --git a/reflex/event.py b/reflex/event.py index e86d82da3bb..1ab9d57af51 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -2202,7 +2202,7 @@ class EventNamespace: # Javascript Event Classes JavascriptHTMLInputElement = JavascriptHTMLInputElement JavascriptInputEvent = JavascriptInputEvent - JavasciptKeyboardEvent = JavasciptKeyboardEvent + JavascriptKeyboardEvent = JavascriptKeyboardEvent JavascriptMouseEvent = JavascriptMouseEvent JavascriptPointerEvent = JavascriptPointerEvent