From 7565ae15efa83ebe204eaacdad13a613ceebc36f Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 16 Oct 2024 11:31:05 -0700 Subject: [PATCH 1/7] disk is memory is disk (#4185) --- reflex/state.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index 7b338b4d6..0d6eed0ed 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -2566,9 +2566,9 @@ class StateManager(Base, ABC): The state manager (either disk, memory or redis). """ config = get_config() - if config.state_manager_mode == constants.StateManagerMode.DISK: - return StateManagerMemory(state=state) if config.state_manager_mode == constants.StateManagerMode.MEMORY: + return StateManagerMemory(state=state) + if config.state_manager_mode == constants.StateManagerMode.DISK: return StateManagerDisk(state=state) if config.state_manager_mode == constants.StateManagerMode.REDIS: redis = prerequisites.get_redis() From 4422515f4baca8d1a6ef1822f889792cd5cf2f85 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 16 Oct 2024 11:35:09 -0700 Subject: [PATCH 2/7] LiteralEventChainVar becomes an ArgsFunctionOperation (#4174) * LiteralEventChainVar becomes an ArgsFunctionOperation Instead of using the ArgsFunctionOperation to create the string representation of the _js_expr, make the identity of the var an ArgsFunctionOperation so the _args_names and _return_expr remain accessible. Rely on the default behavior of ArgsFunctionOperation to create the _cached_var_name / _js_expr value. This allows the compat shim in `format_event_chain` to remain functional, as it does special handling for ArgsFunctionOperation to retain the previous behavior of that function (this was a regression introduced in 0.6.2). * _var_type is EventChain; fix parent class order * Re-fix LiteralEventChainVar inheritence list w/ comment * [ENG-3942] LiteralEventVar becomes VarCallOperation instead of using `.call` when constructing the `_js_expr`, have the identity of a LiteralEventVar as a VarCallOperation to take advantage of the _var_data carrying. * add event overlords * EventCallback descriptor always returns EventSpec from class Relax actual `__get__` definition to support the multitude of overloads * test case for event related vars carrying _var_data --------- Co-authored-by: Khaleel Al-Adhami --- reflex/event.py | 173 +++++++++++++++++++++++--------------- tests/units/test_event.py | 38 ++++++++- 2 files changed, 138 insertions(+), 73 deletions(-) diff --git a/reflex/event.py b/reflex/event.py index 04879add3..4b0bf96e2 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -22,6 +22,7 @@ from typing import ( TypeVar, Union, get_type_hints, + overload, ) from typing_extensions import ParamSpec, get_args, get_origin @@ -32,14 +33,17 @@ from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch from reflex.utils.types import ArgsSpec, GenericType from reflex.vars import VarData from reflex.vars.base import ( - CachedVarOperation, LiteralNoneVar, LiteralVar, ToOperation, Var, - cached_property_no_lock, ) -from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar, FunctionVar +from reflex.vars.function import ( + ArgsFunctionOperation, + FunctionStringVar, + FunctionVar, + VarOperationCall, +) from reflex.vars.object import ObjectVar try: @@ -1258,7 +1262,7 @@ class EventVar(ObjectVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar): +class LiteralEventVar(VarOperationCall, LiteralVar, EventVar): """A literal event var.""" _var_value: EventSpec = dataclasses.field(default=None) # type: ignore @@ -1271,35 +1275,6 @@ class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar): """ return hash((self.__class__.__name__, self._js_expr)) - @cached_property_no_lock - def _cached_var_name(self) -> str: - """The name of the var. - - Returns: - The name of the var. - """ - return str( - FunctionStringVar("Event").call( - # event handler name - ".".join( - filter( - None, - format.get_event_handler_parts(self._var_value.handler), - ) - ), - # event handler args - {str(name): value for name, value in self._var_value.args}, - # event actions - self._var_value.event_actions, - # client handler name - *( - [self._var_value.client_handler_name] - if self._var_value.client_handler_name - else [] - ), - ) - ) - @classmethod def create( cls, @@ -1320,6 +1295,22 @@ class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar): _var_type=EventSpec, _var_data=_var_data, _var_value=value, + _func=FunctionStringVar("Event"), + _args=( + # event handler name + ".".join( + filter( + None, + format.get_event_handler_parts(value.handler), + ) + ), + # event handler args + {str(name): value for name, value in value.args}, + # event actions + value.event_actions, + # client handler name + *([value.client_handler_name] if value.client_handler_name else []), + ), ) @@ -1332,7 +1323,10 @@ class EventChainVar(FunctionVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar): +# Note: LiteralVar is second in the inheritance list allowing it act like a +# CachedVarOperation (ArgsFunctionOperation) and get the _js_expr from the +# _cached_var_name property. +class LiteralEventChainVar(ArgsFunctionOperation, LiteralVar, EventChainVar): """A literal event chain var.""" _var_value: EventChain = dataclasses.field(default=None) # type: ignore @@ -1345,41 +1339,6 @@ class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar): """ return hash((self.__class__.__name__, self._js_expr)) - @cached_property_no_lock - def _cached_var_name(self) -> str: - """The name of the var. - - Returns: - The name of the var. - """ - sig = inspect.signature(self._var_value.args_spec) # type: ignore - if sig.parameters: - arg_def = tuple((f"_{p}" for p in sig.parameters)) - arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def]) - else: - # add a default argument for addEvents if none were specified in value.args_spec - # used to trigger the preventDefault() on the event. - arg_def = ("...args",) - arg_def_expr = Var(_js_expr="args") - - if self._var_value.invocation is None: - invocation = FunctionStringVar.create("addEvents") - else: - invocation = self._var_value.invocation - - return str( - ArgsFunctionOperation.create( - arg_def, - invocation.call( - LiteralVar.create( - [LiteralVar.create(event) for event in self._var_value.events] - ), - arg_def_expr, - self._var_value.event_actions, - ), - ) - ) - @classmethod def create( cls, @@ -1395,10 +1354,31 @@ class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar): Returns: The created LiteralEventChainVar instance. """ + sig = inspect.signature(value.args_spec) # type: ignore + if sig.parameters: + arg_def = tuple((f"_{p}" for p in sig.parameters)) + arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def]) + else: + # add a default argument for addEvents if none were specified in value.args_spec + # used to trigger the preventDefault() on the event. + arg_def = ("...args",) + arg_def_expr = Var(_js_expr="args") + + if value.invocation is None: + invocation = FunctionStringVar.create("addEvents") + else: + invocation = value.invocation + return cls( _js_expr="", _var_type=EventChain, _var_data=_var_data, + _args_names=arg_def, + _return_expr=invocation.call( + LiteralVar.create([LiteralVar.create(event) for event in value.events]), + arg_def_expr, + value.event_actions, + ), _var_value=value, ) @@ -1437,6 +1417,11 @@ EventType = Union[IndividualEventType[G], List[IndividualEventType[G]]] P = ParamSpec("P") T = TypeVar("T") +V = TypeVar("V") +V2 = TypeVar("V2") +V3 = TypeVar("V3") +V4 = TypeVar("V4") +V5 = TypeVar("V5") if sys.version_info >= (3, 10): from typing import Concatenate @@ -1452,7 +1437,55 @@ if sys.version_info >= (3, 10): """ self.func = func - def __get__(self, instance, owner) -> Callable[P, T]: + @overload + def __get__( + self: EventCallback[[V], T], instance: None, owner + ) -> Callable[[Union[Var[V], V]], EventSpec]: ... + + @overload + def __get__( + self: EventCallback[[V, V2], T], instance: None, owner + ) -> Callable[[Union[Var[V], V], Union[Var[V2], V2]], EventSpec]: ... + + @overload + def __get__( + self: EventCallback[[V, V2, V3], T], instance: None, owner + ) -> Callable[ + [Union[Var[V], V], Union[Var[V2], V2], Union[Var[V3], V3]], + EventSpec, + ]: ... + + @overload + def __get__( + self: EventCallback[[V, V2, V3, V4], T], instance: None, owner + ) -> Callable[ + [ + Union[Var[V], V], + Union[Var[V2], V2], + Union[Var[V3], V3], + Union[Var[V4], V4], + ], + EventSpec, + ]: ... + + @overload + def __get__( + self: EventCallback[[V, V2, V3, V4, V5], T], instance: None, owner + ) -> Callable[ + [ + Union[Var[V], V], + Union[Var[V2], V2], + Union[Var[V3], V3], + Union[Var[V4], V4], + Union[Var[V5], V5], + ], + EventSpec, + ]: ... + + @overload + def __get__(self, instance, owner) -> Callable[P, T]: ... + + def __get__(self, instance, owner) -> Callable: """Get the function with the instance bound to it. Args: diff --git a/tests/units/test_event.py b/tests/units/test_event.py index 3996a6101..d7b7cf7a2 100644 --- a/tests/units/test_event.py +++ b/tests/units/test_event.py @@ -2,11 +2,18 @@ from typing import List import pytest -from reflex import event -from reflex.event import Event, EventHandler, EventSpec, call_event_handler, fix_events +from reflex.event import ( + Event, + EventChain, + EventHandler, + EventSpec, + call_event_handler, + event, + fix_events, +) from reflex.state import BaseState from reflex.utils import format -from reflex.vars.base import LiteralVar, Var +from reflex.vars.base import Field, LiteralVar, Var, field def make_var(value) -> Var: @@ -388,3 +395,28 @@ def test_event_actions_on_state(): assert sp_handler.event_actions == {"stopPropagation": True} # should NOT affect other references to the handler assert not handler.event_actions + + +def test_event_var_data(): + class S(BaseState): + x: Field[int] = field(0) + + @event + def s(self, value: int): + pass + + # Handler doesn't have any _var_data because it's just a str + handler_var = Var.create(S.s) + assert handler_var._get_all_var_data() is None + + # Ensure spec carries _var_data + spec_var = Var.create(S.s(S.x)) + assert spec_var._get_all_var_data() == S.x._get_all_var_data() + + # Needed to instantiate the EventChain + def _args_spec(value: Var[int]) -> tuple[Var[int]]: + return (value,) + + # Ensure chain carries _var_data + chain_var = Var.create(EventChain(events=[S.s(S.x)], args_spec=_args_spec)) + assert chain_var._get_all_var_data() == S.x._get_all_var_data() From da9d7eabddfeda76291f0a1e425b62250e2528e5 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 16 Oct 2024 11:35:27 -0700 Subject: [PATCH 3/7] Arbitrary arg access two levels deep for untyped handler (#4180) * Arbitrary arg access two levels deep for untyped handler Provide drop-in compatibility with existing component wrapping code that was accessing attributes on the default handler arg type. * py3.9 compat --- reflex/event.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reflex/event.py b/reflex/event.py index 4b0bf96e2..58053408d 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -1045,7 +1045,8 @@ def resolve_annotation(annotations: dict[str, Any], arg_name: str): deprecation_version="0.6.3", removal_version="0.7.0", ) - return JavascriptInputEvent + # Allow arbitrary attribute access two levels deep until removed. + return Dict[str, dict] return annotation From 13c909434386f00a3db4669b496da3980b0d4b48 Mon Sep 17 00:00:00 2001 From: Alek Petuskey Date: Wed, 16 Oct 2024 11:35:56 -0700 Subject: [PATCH 4/7] Remove demo command (#4176) * Remove demo command * Format --------- Co-authored-by: Alek Petuskey --- reflex/reflex.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index 4608ed171..bd6904d06 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -4,7 +4,6 @@ from __future__ import annotations import atexit import os -import webbrowser from pathlib import Path from typing import List, Optional @@ -586,18 +585,6 @@ def deploy( ) -@cli.command() -def demo( - frontend_port: str = typer.Option( - "3001", help="Specify a different frontend port." - ), - backend_port: str = typer.Option("8001", help="Specify a different backend port."), -): - """Run the demo app.""" - # Open the demo app in a terminal. - webbrowser.open("https://demo.reflex.run") - - cli.add_typer(db_cli, name="db", help="Subcommands for managing the database schema.") cli.add_typer(script_cli, name="script", help="Subcommands running helper scripts.") cli.add_typer( From d8ea2fc79543d4abaeec09839f83a3e4219415ac Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 16 Oct 2024 13:39:49 -0700 Subject: [PATCH 5/7] fix pyi for untyped event handlers (#4186) * fix pyi for untyped event handlers * no more empty lambdas --- reflex/components/base/error_boundary.pyi | 2 +- reflex/components/component.py | 35 +++++++------- reflex/components/datadisplay/dataeditor.pyi | 16 +++---- reflex/components/react_player/audio.pyi | 2 +- .../components/react_player/react_player.pyi | 2 +- reflex/components/react_player/video.pyi | 2 +- reflex/components/recharts/cartesian.py | 6 +-- reflex/components/recharts/charts.py | 22 ++++----- reflex/components/recharts/polar.py | 48 +++++++++---------- reflex/components/suneditor/editor.pyi | 20 ++++---- reflex/event.py | 10 ++-- reflex/utils/pyi_generator.py | 2 +- 12 files changed, 84 insertions(+), 83 deletions(-) diff --git a/reflex/components/base/error_boundary.pyi b/reflex/components/base/error_boundary.pyi index 65109b0fe..aaf5584e4 100644 --- a/reflex/components/base/error_boundary.pyi +++ b/reflex/components/base/error_boundary.pyi @@ -31,7 +31,7 @@ class ErrorBoundary(Component): on_click: Optional[EventType[[]]] = None, on_context_menu: Optional[EventType[[]]] = None, on_double_click: Optional[EventType[[]]] = None, - on_error: Optional[EventType[[]]] = None, + on_error: Optional[EventType] = None, on_focus: Optional[EventType[[]]] = None, on_mount: Optional[EventType[[]]] = None, on_mouse_down: Optional[EventType[[]]] = None, diff --git a/reflex/components/component.py b/reflex/components/component.py index 364353b9d..a0d9c93b0 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -45,6 +45,7 @@ from reflex.event import ( EventVar, call_event_fn, call_event_handler, + empty_event, get_handler_args, ) from reflex.style import Style, format_as_emotion @@ -623,21 +624,21 @@ class Component(BaseComponent, ABC): """ default_triggers = { - EventTriggers.ON_FOCUS: lambda: [], - EventTriggers.ON_BLUR: lambda: [], - EventTriggers.ON_CLICK: lambda: [], - EventTriggers.ON_CONTEXT_MENU: lambda: [], - EventTriggers.ON_DOUBLE_CLICK: lambda: [], - EventTriggers.ON_MOUSE_DOWN: lambda: [], - EventTriggers.ON_MOUSE_ENTER: lambda: [], - EventTriggers.ON_MOUSE_LEAVE: lambda: [], - EventTriggers.ON_MOUSE_MOVE: lambda: [], - EventTriggers.ON_MOUSE_OUT: lambda: [], - EventTriggers.ON_MOUSE_OVER: lambda: [], - EventTriggers.ON_MOUSE_UP: lambda: [], - EventTriggers.ON_SCROLL: lambda: [], - EventTriggers.ON_MOUNT: lambda: [], - EventTriggers.ON_UNMOUNT: lambda: [], + EventTriggers.ON_FOCUS: empty_event, + EventTriggers.ON_BLUR: empty_event, + EventTriggers.ON_CLICK: empty_event, + EventTriggers.ON_CONTEXT_MENU: empty_event, + EventTriggers.ON_DOUBLE_CLICK: empty_event, + EventTriggers.ON_MOUSE_DOWN: empty_event, + EventTriggers.ON_MOUSE_ENTER: empty_event, + EventTriggers.ON_MOUSE_LEAVE: empty_event, + EventTriggers.ON_MOUSE_MOVE: empty_event, + EventTriggers.ON_MOUSE_OUT: empty_event, + EventTriggers.ON_MOUSE_OVER: empty_event, + EventTriggers.ON_MOUSE_UP: empty_event, + EventTriggers.ON_SCROLL: empty_event, + EventTriggers.ON_MOUNT: empty_event, + EventTriggers.ON_UNMOUNT: empty_event, } # Look for component specific triggers, @@ -648,7 +649,7 @@ class Component(BaseComponent, ABC): annotation = field.annotation if (metadata := getattr(annotation, "__metadata__", None)) is not None: args_spec = metadata[0] - default_triggers[field.name] = args_spec or (lambda: []) + default_triggers[field.name] = args_spec or (empty_event) # type: ignore return default_triggers def __repr__(self) -> str: @@ -1705,7 +1706,7 @@ class CustomComponent(Component): value = self._create_event_chain( value=value, args_spec=event_triggers_in_component_declaration.get( - key, lambda: [] + key, empty_event ), ) self.props[format.to_camel_case(key)] = value diff --git a/reflex/components/datadisplay/dataeditor.pyi b/reflex/components/datadisplay/dataeditor.pyi index b3a9ce2b3..1b8fed287 100644 --- a/reflex/components/datadisplay/dataeditor.pyi +++ b/reflex/components/datadisplay/dataeditor.pyi @@ -139,20 +139,20 @@ class DataEditor(NoSSRComponent): on_cell_activated: Optional[EventType] = None, on_cell_clicked: Optional[EventType] = None, on_cell_context_menu: Optional[EventType] = None, - on_cell_edited: Optional[EventType[[]]] = None, + on_cell_edited: Optional[EventType] = None, on_click: Optional[EventType[[]]] = None, - on_column_resize: Optional[EventType[[]]] = None, + on_column_resize: Optional[EventType] = None, on_context_menu: Optional[EventType[[]]] = None, - on_delete: Optional[EventType[[]]] = None, + on_delete: Optional[EventType] = None, on_double_click: Optional[EventType[[]]] = None, - on_finished_editing: Optional[EventType[[]]] = None, + on_finished_editing: Optional[EventType] = None, on_focus: Optional[EventType[[]]] = None, - on_group_header_clicked: Optional[EventType[[]]] = None, - on_group_header_context_menu: Optional[EventType[[]]] = None, - on_group_header_renamed: Optional[EventType[[]]] = None, + on_group_header_clicked: Optional[EventType] = None, + on_group_header_context_menu: Optional[EventType] = None, + on_group_header_renamed: Optional[EventType] = None, on_header_clicked: Optional[EventType] = None, on_header_context_menu: Optional[EventType] = None, - on_header_menu_click: Optional[EventType[[]]] = None, + on_header_menu_click: Optional[EventType] = None, on_item_hovered: Optional[EventType] = None, on_mount: Optional[EventType[[]]] = None, on_mouse_down: Optional[EventType[[]]] = None, diff --git a/reflex/components/react_player/audio.pyi b/reflex/components/react_player/audio.pyi index 4b566d898..d1f29f508 100644 --- a/reflex/components/react_player/audio.pyi +++ b/reflex/components/react_player/audio.pyi @@ -58,7 +58,7 @@ class Audio(ReactPlayer): on_play: Optional[EventType[[]]] = None, on_playback_quality_change: Optional[EventType[[]]] = None, on_playback_rate_change: Optional[EventType[[]]] = None, - on_progress: Optional[EventType[[]]] = None, + on_progress: Optional[EventType] = None, on_ready: Optional[EventType[[]]] = None, on_scroll: Optional[EventType[[]]] = None, on_seek: Optional[EventType] = None, diff --git a/reflex/components/react_player/react_player.pyi b/reflex/components/react_player/react_player.pyi index 1977eaa00..940b09e51 100644 --- a/reflex/components/react_player/react_player.pyi +++ b/reflex/components/react_player/react_player.pyi @@ -56,7 +56,7 @@ class ReactPlayer(NoSSRComponent): on_play: Optional[EventType[[]]] = None, on_playback_quality_change: Optional[EventType[[]]] = None, on_playback_rate_change: Optional[EventType[[]]] = None, - on_progress: Optional[EventType[[]]] = None, + on_progress: Optional[EventType] = None, on_ready: Optional[EventType[[]]] = None, on_scroll: Optional[EventType[[]]] = None, on_seek: Optional[EventType] = None, diff --git a/reflex/components/react_player/video.pyi b/reflex/components/react_player/video.pyi index 6e4047d06..a50ccf71f 100644 --- a/reflex/components/react_player/video.pyi +++ b/reflex/components/react_player/video.pyi @@ -58,7 +58,7 @@ class Video(ReactPlayer): on_play: Optional[EventType[[]]] = None, on_playback_quality_change: Optional[EventType[[]]] = None, on_playback_rate_change: Optional[EventType[[]]] = None, - on_progress: Optional[EventType[[]]] = None, + on_progress: Optional[EventType] = None, on_ready: Optional[EventType[[]]] = None, on_scroll: Optional[EventType[[]]] = None, on_seek: Optional[EventType] = None, diff --git a/reflex/components/recharts/cartesian.py b/reflex/components/recharts/cartesian.py index 153d3fb2a..865b50a32 100644 --- a/reflex/components/recharts/cartesian.py +++ b/reflex/components/recharts/cartesian.py @@ -252,7 +252,7 @@ class Brush(Recharts): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_CHANGE: lambda: [], + EventTriggers.ON_CHANGE: empty_event, } @@ -293,10 +293,10 @@ class Cartesian(Recharts): name: Var[Union[str, int]] # The customized event handler of animation start - on_animation_start: EventHandler[lambda: []] + on_animation_start: EventHandler[empty_event] # The customized event handler of animation end - on_animation_end: EventHandler[lambda: []] + on_animation_end: EventHandler[empty_event] # The customized event handler of click on the component in this group on_click: EventHandler[empty_event] diff --git a/reflex/components/recharts/charts.py b/reflex/components/recharts/charts.py index d4785f6c4..d7e07b2d8 100644 --- a/reflex/components/recharts/charts.py +++ b/reflex/components/recharts/charts.py @@ -330,9 +330,9 @@ class RadarChart(ChartBase): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_CLICK: lambda: [], - EventTriggers.ON_MOUSE_ENTER: lambda: [], - EventTriggers.ON_MOUSE_LEAVE: lambda: [], + EventTriggers.ON_CLICK: empty_event, + EventTriggers.ON_MOUSE_ENTER: empty_event, + EventTriggers.ON_MOUSE_LEAVE: empty_event, } @@ -419,14 +419,14 @@ class ScatterChart(ChartBase): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_CLICK: lambda: [], - EventTriggers.ON_MOUSE_DOWN: lambda: [], - EventTriggers.ON_MOUSE_UP: lambda: [], - EventTriggers.ON_MOUSE_MOVE: lambda: [], - EventTriggers.ON_MOUSE_OVER: lambda: [], - EventTriggers.ON_MOUSE_OUT: lambda: [], - EventTriggers.ON_MOUSE_ENTER: lambda: [], - EventTriggers.ON_MOUSE_LEAVE: lambda: [], + EventTriggers.ON_CLICK: empty_event, + EventTriggers.ON_MOUSE_DOWN: empty_event, + EventTriggers.ON_MOUSE_UP: empty_event, + EventTriggers.ON_MOUSE_MOVE: empty_event, + EventTriggers.ON_MOUSE_OVER: empty_event, + EventTriggers.ON_MOUSE_OUT: empty_event, + EventTriggers.ON_MOUSE_ENTER: empty_event, + EventTriggers.ON_MOUSE_LEAVE: empty_event, } diff --git a/reflex/components/recharts/polar.py b/reflex/components/recharts/polar.py index bcbd5abd3..ccb96f180 100644 --- a/reflex/components/recharts/polar.py +++ b/reflex/components/recharts/polar.py @@ -103,14 +103,14 @@ class Pie(Recharts): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_ANIMATION_START: lambda: [], - EventTriggers.ON_ANIMATION_END: lambda: [], - EventTriggers.ON_CLICK: lambda: [], - EventTriggers.ON_MOUSE_MOVE: lambda: [], - EventTriggers.ON_MOUSE_OVER: lambda: [], - EventTriggers.ON_MOUSE_OUT: lambda: [], - EventTriggers.ON_MOUSE_ENTER: lambda: [], - EventTriggers.ON_MOUSE_LEAVE: lambda: [], + EventTriggers.ON_ANIMATION_START: empty_event, + EventTriggers.ON_ANIMATION_END: empty_event, + EventTriggers.ON_CLICK: empty_event, + EventTriggers.ON_MOUSE_MOVE: empty_event, + EventTriggers.ON_MOUSE_OVER: empty_event, + EventTriggers.ON_MOUSE_OUT: empty_event, + EventTriggers.ON_MOUSE_ENTER: empty_event, + EventTriggers.ON_MOUSE_LEAVE: empty_event, } @@ -167,8 +167,8 @@ class Radar(Recharts): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_ANIMATION_START: lambda: [], - EventTriggers.ON_ANIMATION_END: lambda: [], + EventTriggers.ON_ANIMATION_START: empty_event, + EventTriggers.ON_ANIMATION_END: empty_event, } @@ -219,14 +219,14 @@ class RadialBar(Recharts): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_CLICK: lambda: [], - EventTriggers.ON_MOUSE_MOVE: lambda: [], - EventTriggers.ON_MOUSE_OVER: lambda: [], - EventTriggers.ON_MOUSE_OUT: lambda: [], - EventTriggers.ON_MOUSE_ENTER: lambda: [], - EventTriggers.ON_MOUSE_LEAVE: lambda: [], - EventTriggers.ON_ANIMATION_START: lambda: [], - EventTriggers.ON_ANIMATION_END: lambda: [], + EventTriggers.ON_CLICK: empty_event, + EventTriggers.ON_MOUSE_MOVE: empty_event, + EventTriggers.ON_MOUSE_OVER: empty_event, + EventTriggers.ON_MOUSE_OUT: empty_event, + EventTriggers.ON_MOUSE_ENTER: empty_event, + EventTriggers.ON_MOUSE_LEAVE: empty_event, + EventTriggers.ON_ANIMATION_START: empty_event, + EventTriggers.ON_ANIMATION_END: empty_event, } @@ -392,12 +392,12 @@ class PolarRadiusAxis(Recharts): A dict mapping the event trigger to the var that is passed to the handler. """ return { - EventTriggers.ON_CLICK: lambda: [], - EventTriggers.ON_MOUSE_MOVE: lambda: [], - EventTriggers.ON_MOUSE_OVER: lambda: [], - EventTriggers.ON_MOUSE_OUT: lambda: [], - EventTriggers.ON_MOUSE_ENTER: lambda: [], - EventTriggers.ON_MOUSE_LEAVE: lambda: [], + EventTriggers.ON_CLICK: empty_event, + EventTriggers.ON_MOUSE_MOVE: empty_event, + EventTriggers.ON_MOUSE_OVER: empty_event, + EventTriggers.ON_MOUSE_OUT: empty_event, + EventTriggers.ON_MOUSE_ENTER: empty_event, + EventTriggers.ON_MOUSE_LEAVE: empty_event, } diff --git a/reflex/components/suneditor/editor.pyi b/reflex/components/suneditor/editor.pyi index bcc0b64ac..f7149a02c 100644 --- a/reflex/components/suneditor/editor.pyi +++ b/reflex/components/suneditor/editor.pyi @@ -122,16 +122,16 @@ class Editor(NoSSRComponent): class_name: Optional[Any] = None, autofocus: Optional[bool] = None, custom_attrs: Optional[Dict[str, Union[Var, str]]] = None, - on_blur: Optional[EventType[[]]] = None, - on_change: Optional[EventType[[]]] = None, + on_blur: Optional[EventType] = None, + on_change: Optional[EventType] = None, on_click: Optional[EventType[[]]] = None, on_context_menu: Optional[EventType[[]]] = None, - on_copy: Optional[EventType[[]]] = None, - on_cut: Optional[EventType[[]]] = None, + on_copy: Optional[EventType] = None, + on_cut: Optional[EventType] = None, on_double_click: Optional[EventType[[]]] = None, on_focus: Optional[EventType[[]]] = None, - on_input: Optional[EventType[[]]] = None, - on_load: Optional[EventType[[]]] = None, + on_input: Optional[EventType] = None, + on_load: Optional[EventType] = None, on_mount: Optional[EventType[[]]] = None, on_mouse_down: Optional[EventType[[]]] = None, on_mouse_enter: Optional[EventType[[]]] = None, @@ -140,12 +140,12 @@ class Editor(NoSSRComponent): on_mouse_out: Optional[EventType[[]]] = None, on_mouse_over: Optional[EventType[[]]] = None, on_mouse_up: Optional[EventType[[]]] = None, - on_paste: Optional[EventType[[]]] = None, - on_resize_editor: Optional[EventType[[]]] = None, + on_paste: Optional[EventType] = None, + on_resize_editor: Optional[EventType] = None, on_scroll: Optional[EventType[[]]] = None, on_unmount: Optional[EventType[[]]] = None, - toggle_code_view: Optional[EventType[[]]] = None, - toggle_full_screen: Optional[EventType[[]]] = None, + toggle_code_view: Optional[EventType] = None, + toggle_full_screen: Optional[EventType] = None, **props, ) -> "Editor": """Create an instance of Editor. No children allowed. diff --git a/reflex/event.py b/reflex/event.py index 58053408d..f93bc63d2 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -399,11 +399,6 @@ class EventChain(EventActionsMixin): invocation: Optional[Var] = dataclasses.field(default=None) -# These chains can be used for their side effects when no other events are desired. -stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation -prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default - - @dataclasses.dataclass( init=True, frozen=True, @@ -467,6 +462,11 @@ def empty_event() -> Tuple[()]: return tuple() # type: ignore +# These chains can be used for their side effects when no other events are desired. +stop_propagation = EventChain(events=[], args_spec=empty_event).stop_propagation +prevent_default = EventChain(events=[], args_spec=empty_event).prevent_default + + T = TypeVar("T") diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py index 1df8e6fa0..fd76576b9 100644 --- a/reflex/utils/pyi_generator.py +++ b/reflex/utils/pyi_generator.py @@ -429,7 +429,7 @@ def _generate_component_create_functiondef( def figure_out_return_type(annotation: Any): if inspect.isclass(annotation) and issubclass(annotation, inspect._empty): - return ast.Name(id="Optional[EventType[[]]]") + return ast.Name(id="Optional[EventType]") if isinstance(annotation, str) and annotation.startswith("Tuple["): inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]") From 35810fe1bd3935e4df1f8246b98163a6517acbd2 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 16 Oct 2024 15:20:51 -0700 Subject: [PATCH 6/7] use larger or equal for node version check (#4189) --- reflex/utils/prerequisites.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 34ed5f53f..44d1f6acc 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -146,14 +146,9 @@ def check_node_version() -> bool: Whether the version of Node.js is valid. """ current_version = get_node_version() - if current_version: - # Compare the version numbers - return ( - current_version >= version.parse(constants.Node.MIN_VERSION) - if constants.IS_WINDOWS or path_ops.use_system_node() - else current_version == version.parse(constants.Node.VERSION) - ) - return False + return current_version is not None and current_version >= version.parse( + constants.Node.MIN_VERSION + ) def get_node_version() -> version.Version | None: From 101fb1b5405e2aa20e91efa21ecb77068e7e3fd4 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 16 Oct 2024 15:21:47 -0700 Subject: [PATCH 7/7] check for none before returning which (#4187) --- reflex/utils/path_ops.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/reflex/utils/path_ops.py b/reflex/utils/path_ops.py index f597e0075..f795e1aa4 100644 --- a/reflex/utils/path_ops.py +++ b/reflex/utils/path_ops.py @@ -185,7 +185,8 @@ def get_node_path() -> str | None: """ node_path = Path(constants.Node.PATH) if use_system_node() or not node_path.exists(): - return str(which("node")) + system_node_path = which("node") + return str(system_node_path) if system_node_path else None return str(node_path) @@ -197,7 +198,8 @@ def get_npm_path() -> str | None: """ npm_path = Path(constants.Node.NPM_PATH) if use_system_node() or not npm_path.exists(): - return str(which("npm")) + system_npm_path = which("npm") + return str(system_npm_path) if system_npm_path else None return str(npm_path)