diff --git a/reflex/app.py b/reflex/app.py index a3d0d8e10c4..18cce69d2f9 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -99,7 +99,15 @@ _substate_key, code_uses_state_contexts, ) -from reflex.utils import codespaces, console, exceptions, format, prerequisites, types +from reflex.utils import ( + codespaces, + console, + exceptions, + format, + path_ops, + prerequisites, + types, +) from reflex.utils.exec import is_prod_mode, is_testing_env from reflex.utils.imports import ImportVar @@ -991,9 +999,10 @@ def get_compilation_time() -> str: should_compile = self._should_compile() if not should_compile: - for route in self._unevaluated_pages: - console.debug(f"Evaluating page: {route}") - self._compile_page(route, save_page=should_compile) + with console.timing("Evaluate Pages (Backend)"): + for route in self._unevaluated_pages: + console.debug(f"Evaluating page: {route}") + self._compile_page(route, save_page=should_compile) # Add the optional endpoints (_upload) self._add_optional_endpoints() @@ -1019,10 +1028,11 @@ def get_compilation_time() -> str: + adhoc_steps_without_executor, ) - for route in self._unevaluated_pages: - console.debug(f"Evaluating page: {route}") - self._compile_page(route, save_page=should_compile) - progress.advance(task) + with console.timing("Evaluate Pages (Frontend)"): + for route in self._unevaluated_pages: + console.debug(f"Evaluating page: {route}") + self._compile_page(route, save_page=should_compile) + progress.advance(task) # Add the optional endpoints (_upload) self._add_optional_endpoints() @@ -1057,13 +1067,13 @@ def get_compilation_time() -> str: custom_components |= component._get_all_custom_components() # Perform auto-memoization of stateful components. - ( - stateful_components_path, - stateful_components_code, - page_components, - ) = compiler.compile_stateful_components(self._pages.values()) - - progress.advance(task) + with console.timing("Auto-memoize StatefulComponents"): + ( + stateful_components_path, + stateful_components_code, + page_components, + ) = compiler.compile_stateful_components(self._pages.values()) + progress.advance(task) # Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State. if code_uses_state_contexts(stateful_components_code) and self._state is None: @@ -1086,6 +1096,17 @@ def get_compilation_time() -> str: progress.advance(task) + # Copy the assets. + assets_src = Path.cwd() / constants.Dirs.APP_ASSETS + if assets_src.is_dir(): + with console.timing("Copy assets"): + path_ops.update_directory_tree( + src=assets_src, + dest=( + Path.cwd() / prerequisites.get_web_dir() / constants.Dirs.PUBLIC + ), + ) + # Use a forking process pool, if possible. Much faster, especially for large sites. # Fallback to ThreadPoolExecutor as something that will always work. executor = None @@ -1138,9 +1159,10 @@ def _submit_work(fn: Callable, *args, **kwargs): _submit_work(compiler.remove_tailwind_from_postcss) # Wait for all compilation tasks to complete. - for future in concurrent.futures.as_completed(result_futures): - compile_results.append(future.result()) - progress.advance(task) + with console.timing("Compile to Javascript"): + for future in concurrent.futures.as_completed(result_futures): + compile_results.append(future.result()) + progress.advance(task) app_root = self._app_root(app_wrappers=app_wrappers) @@ -1175,7 +1197,8 @@ def _submit_work(fn: Callable, *args, **kwargs): progress.stop() # Install frontend packages. - self._get_frontend_packages(all_imports) + with console.timing("Install Frontend Packages"): + self._get_frontend_packages(all_imports) # Setup the next.config.js transpile_packages = [ @@ -1201,8 +1224,9 @@ def _submit_work(fn: Callable, *args, **kwargs): # Remove pages that are no longer in the app. p.unlink() - for output_path, code in compile_results: - compiler_utils.write_page(output_path, code) + with console.timing("Write to Disk"): + for output_path, code in compile_results: + compiler_utils.write_page(output_path, code) @contextlib.asynccontextmanager async def modify_state(self, token: str) -> AsyncIterator[BaseState]: diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py index c797a095fe3..91ee18b8654 100644 --- a/reflex/compiler/utils.py +++ b/reflex/compiler/utils.py @@ -119,24 +119,34 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]: validate_imports(collapsed_import_dict) import_dicts = [] for lib, fields in collapsed_import_dict.items(): - default, rest = compile_import_statement(fields) - # prevent lib from being rendered on the page if all imports are non rendered kind if not any(f.render for f in fields): continue - if not lib: - if default: - raise ValueError("No default field allowed for empty library.") - if rest is None or len(rest) == 0: - raise ValueError("No fields to import.") - import_dicts.extend(get_import_dict(module) for module in sorted(rest)) - continue + lib_paths: dict[str, list[ImportVar]] = {} + + for field in fields: + lib_paths.setdefault(field.package_path, []).append(field) - # remove the version before rendering the package imports - lib = format.format_library_name(lib) + compiled = { + path: compile_import_statement(fields) for path, fields in lib_paths.items() + } + + for path, (default, rest) in compiled.items(): + if not lib: + if default: + raise ValueError("No default field allowed for empty library.") + if rest is None or len(rest) == 0: + raise ValueError("No fields to import.") + import_dicts.extend(get_import_dict(module) for module in sorted(rest)) + continue + + # remove the version before rendering the package imports + formatted_lib = format.format_library_name(lib) + ( + path if path != "/" else "" + ) - import_dicts.append(get_import_dict(lib, default, rest)) + import_dicts.append(get_import_dict(formatted_lib, default, rest)) return import_dicts diff --git a/reflex/components/core/sticky.py b/reflex/components/core/sticky.py index 162bab3cd7b..cbcec00a94e 100644 --- a/reflex/components/core/sticky.py +++ b/reflex/components/core/sticky.py @@ -107,9 +107,7 @@ def add_style(self): default=True, global_ref=False, ) - localhost_hostnames = Var.create( - ["localhost", "127.0.0.1", "[::1]"] - ).guess_type() + localhost_hostnames = Var.create(["localhost", "127.0.0.1", "[::1]"]) is_localhost_expr = localhost_hostnames.contains( Var("window.location.hostname", _var_type=str).guess_type(), ) diff --git a/reflex/components/lucide/icon.py b/reflex/components/lucide/icon.py index 6c7cbede7dd..269ef7f79ae 100644 --- a/reflex/components/lucide/icon.py +++ b/reflex/components/lucide/icon.py @@ -4,7 +4,7 @@ from reflex.utils import format from reflex.utils.imports import ImportVar from reflex.vars.base import LiteralVar, Var -from reflex.vars.sequence import LiteralStringVar +from reflex.vars.sequence import LiteralStringVar, StringVar class LucideIconComponent(Component): @@ -40,7 +40,12 @@ def create(cls, *children, **props) -> Component: The created component. """ if children: - if len(children) == 1 and isinstance(children[0], str): + if len(children) == 1: + child = Var.create(children[0]).guess_type() + if not isinstance(child, StringVar): + raise AttributeError( + f"Icon name must be a string, got {children[0]._var_type if isinstance(children[0], Var) else children[0]}" + ) props["tag"] = children[0] else: raise AttributeError( @@ -56,7 +61,10 @@ def create(cls, *children, **props) -> Component: else: raise TypeError(f"Icon name must be a string, got {type(tag)}") elif isinstance(tag, Var): - return DynamicIcon.create(name=tag, **props) + tag_stringified = tag.guess_type() + if not isinstance(tag_stringified, StringVar): + raise TypeError(f"Icon name must be a string, got {tag._var_type}") + return DynamicIcon.create(name=tag_stringified.replace("_", "-"), **props) if ( not isinstance(tag, str) diff --git a/reflex/components/plotly/__init__.py b/reflex/components/plotly/__init__.py index 5620d5fc48d..8743b31b288 100644 --- a/reflex/components/plotly/__init__.py +++ b/reflex/components/plotly/__init__.py @@ -1,5 +1,32 @@ """Plotly components.""" -from .plotly import Plotly +from reflex.components.component import ComponentNamespace -plotly = Plotly.create +from .plotly import ( + Plotly, + PlotlyBasic, + PlotlyCartesian, + PlotlyFinance, + PlotlyGeo, + PlotlyGl2d, + PlotlyGl3d, + PlotlyMapbox, + PlotlyStrict, +) + + +class PlotlyNamespace(ComponentNamespace): + """Plotly namespace.""" + + __call__ = Plotly.create + basic = PlotlyBasic.create + cartesian = PlotlyCartesian.create + geo = PlotlyGeo.create + gl2d = PlotlyGl2d.create + gl3d = PlotlyGl3d.create + finance = PlotlyFinance.create + mapbox = PlotlyMapbox.create + strict = PlotlyStrict.create + + +plotly = PlotlyNamespace() diff --git a/reflex/components/plotly/plotly.py b/reflex/components/plotly/plotly.py index c85423d35b2..2ddaad8d78f 100644 --- a/reflex/components/plotly/plotly.py +++ b/reflex/components/plotly/plotly.py @@ -10,6 +10,7 @@ from reflex.components.core.cond import color_mode_cond from reflex.event import EventHandler, no_args_event_spec from reflex.utils import console +from reflex.utils.imports import ImportDict, ImportVar from reflex.vars.base import LiteralVar, Var try: @@ -278,3 +279,237 @@ def _render(self): # Spread the figure dict over props, nothing to merge. tag.special_props.append(Var(_js_expr=f"{{...{figure!s}}}")) return tag + + +CREATE_PLOTLY_COMPONENT: ImportDict = { + "react-plotly.js": [ + ImportVar( + tag="createPlotlyComponent", + is_default=True, + package_path="/factory", + ), + ] +} + + +def dynamic_plotly_import(name: str, package: str) -> str: + """Create a dynamic import for a plotly component. + + Args: + name: The name of the component. + package: The package path of the component. + + Returns: + The dynamic import for the plotly component. + """ + return f""" +const {name} = dynamic(() => import('{package}').then(mod => createPlotlyComponent(mod)), {{ssr: false}}) +""" + + +class PlotlyBasic(Plotly): + """Display a basic plotly graph.""" + + tag: str = "BasicPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-basic-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly basic component. + + Returns: + The imports for the plotly basic component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly basic component. + + Returns: + The dynamic imports for the plotly basic component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-basic-dist-min") + + +class PlotlyCartesian(Plotly): + """Display a plotly cartesian graph.""" + + tag: str = "CartesianPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-cartesian-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly cartesian component. + + Returns: + The imports for the plotly cartesian component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly cartesian component. + + Returns: + The dynamic imports for the plotly cartesian component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-cartesian-dist-min") + + +class PlotlyGeo(Plotly): + """Display a plotly geo graph.""" + + tag: str = "GeoPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-geo-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly geo component. + + Returns: + The imports for the plotly geo component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly geo component. + + Returns: + The dynamic imports for the plotly geo component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-geo-dist-min") + + +class PlotlyGl3d(Plotly): + """Display a plotly 3d graph.""" + + tag: str = "Gl3dPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-gl3d-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly 3d component. + + Returns: + The imports for the plotly 3d component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly 3d component. + + Returns: + The dynamic imports for the plotly 3d component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-gl3d-dist-min") + + +class PlotlyGl2d(Plotly): + """Display a plotly 2d graph.""" + + tag: str = "Gl2dPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-gl2d-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly 2d component. + + Returns: + The imports for the plotly 2d component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly 2d component. + + Returns: + The dynamic imports for the plotly 2d component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-gl2d-dist-min") + + +class PlotlyMapbox(Plotly): + """Display a plotly mapbox graph.""" + + tag: str = "MapboxPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-mapbox-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly mapbox component. + + Returns: + The imports for the plotly mapbox component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly mapbox component. + + Returns: + The dynamic imports for the plotly mapbox component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-mapbox-dist-min") + + +class PlotlyFinance(Plotly): + """Display a plotly finance graph.""" + + tag: str = "FinancePlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-finance-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly finance component. + + Returns: + The imports for the plotly finance component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly finance component. + + Returns: + The dynamic imports for the plotly finance component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-finance-dist-min") + + +class PlotlyStrict(Plotly): + """Display a plotly strict graph.""" + + tag: str = "StrictPlotlyPlot" + + library = "react-plotly.js@2.6.0" + + lib_dependencies: list[str] = ["plotly.js-strict-dist-min@3.0.0"] + + def add_imports(self) -> ImportDict | list[ImportDict]: + """Add imports for the plotly strict component. + + Returns: + The imports for the plotly strict component. + """ + return CREATE_PLOTLY_COMPONENT + + def _get_dynamic_imports(self) -> str: + """Get the dynamic imports for the plotly strict component. + + Returns: + The dynamic imports for the plotly strict component. + """ + return dynamic_plotly_import(self.tag, "plotly.js-strict-dist-min") diff --git a/reflex/components/plotly/plotly.pyi b/reflex/components/plotly/plotly.pyi index f60e5a6a41a..c4d8bf64a97 100644 --- a/reflex/components/plotly/plotly.pyi +++ b/reflex/components/plotly/plotly.pyi @@ -11,6 +11,7 @@ from reflex.components.component import NoSSRComponent from reflex.event import EventType from reflex.style import Style from reflex.utils import console +from reflex.utils.imports import ImportDict from reflex.vars.base import Var try: @@ -141,3 +142,767 @@ class Plotly(NoSSRComponent): The Plotly component. """ ... + +CREATE_PLOTLY_COMPONENT: ImportDict + +def dynamic_plotly_import(name: str, package: str) -> str: ... + +class PlotlyBasic(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyBasic": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyCartesian(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyCartesian": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyGeo(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyGeo": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyGl3d(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyGl3d": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyGl2d(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyGl2d": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyMapbox(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyMapbox": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyFinance(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyFinance": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... + +class PlotlyStrict(Plotly): + def add_imports(self) -> ImportDict | list[ImportDict]: ... + @overload + @classmethod + def create( # type: ignore + cls, + *children, + data: Optional[Union[Figure, Var[Figure]]] = None, # type: ignore + layout: Optional[Union[Dict, Var[Dict]]] = None, + template: Optional[Union[Template, Var[Template]]] = None, # type: ignore + config: Optional[Union[Dict, Var[Dict]]] = None, + use_resize_handler: Optional[Union[Var[bool], bool]] = None, + style: Optional[Style] = None, + key: Optional[Any] = None, + id: Optional[Any] = None, + class_name: Optional[Any] = None, + autofocus: Optional[bool] = None, + custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, + on_after_plot: Optional[EventType[()]] = None, + on_animated: Optional[EventType[()]] = None, + on_animating_frame: Optional[EventType[()]] = None, + on_animation_interrupted: Optional[EventType[()]] = None, + on_autosize: Optional[EventType[()]] = None, + on_before_hover: Optional[EventType[()]] = None, + on_blur: Optional[EventType[()]] = None, + on_button_clicked: Optional[EventType[()]] = None, + on_click: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_context_menu: Optional[EventType[()]] = None, + on_deselect: Optional[EventType[()]] = None, + on_double_click: Optional[EventType[()]] = None, + on_focus: Optional[EventType[()]] = None, + on_hover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_mount: Optional[EventType[()]] = None, + on_mouse_down: Optional[EventType[()]] = None, + on_mouse_enter: Optional[EventType[()]] = None, + on_mouse_leave: Optional[EventType[()]] = None, + on_mouse_move: Optional[EventType[()]] = None, + on_mouse_out: Optional[EventType[()]] = None, + on_mouse_over: Optional[EventType[()]] = None, + on_mouse_up: Optional[EventType[()]] = None, + on_redraw: Optional[EventType[()]] = None, + on_relayout: Optional[EventType[()]] = None, + on_relayouting: Optional[EventType[()]] = None, + on_restyle: Optional[EventType[()]] = None, + on_scroll: Optional[EventType[()]] = None, + on_selected: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_selecting: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_transition_interrupted: Optional[EventType[()]] = None, + on_transitioning: Optional[EventType[()]] = None, + on_unhover: Optional[Union[EventType[()], EventType[List[Point]]]] = None, + on_unmount: Optional[EventType[()]] = None, + **props, + ) -> "PlotlyStrict": + """Create the Plotly component. + + Args: + *children: The children of the component. + data: The figure to display. This can be a plotly figure or a plotly data json. + layout: The layout of the graph. + template: The template for visual appearance of the graph. + config: The config of the graph. + use_resize_handler: If true, the graph will resize when the window is resized. + on_after_plot: Fired after the plot is redrawn. + on_animated: Fired after the plot was animated. + on_animating_frame: Fired while animating a single frame (does not currently pass data through). + on_animation_interrupted: Fired when an animation is interrupted (to start a new animation for example). + on_autosize: Fired when the plot is responsively sized. + on_before_hover: Fired whenever mouse moves over a plot. + on_button_clicked: Fired when a plotly UI button is clicked. + on_click: Fired when the plot is clicked. + on_deselect: Fired when a selection is cleared (via double click). + on_double_click: Fired when the plot is double clicked. + on_hover: Fired when a plot element is hovered over. + on_relayout: Fired after the plot is laid out (zoom, pan, etc). + on_relayouting: Fired while the plot is being laid out. + on_restyle: Fired after the plot style is changed. + on_redraw: Fired after the plot is redrawn. + on_selected: Fired after selecting plot elements. + on_selecting: Fired while dragging a selection. + on_transitioning: Fired while an animation is occurring. + on_transition_interrupted: Fired when a transition is stopped early. + on_unhover: Fired when a hovered element is no longer hovered. + style: The style of the component. + key: A unique key for the component. + id: The id for the component. + class_name: The class name for the component. + autofocus: Whether the component should take the focus once the page is loaded + custom_attrs: custom attribute + **props: The properties of the component. + + Returns: + The Plotly component. + """ + ... diff --git a/reflex/config.py b/reflex/config.py index 634a8456acf..a543258f3bb 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -685,7 +685,7 @@ class Config: # pyright: ignore [reportIncompatibleVariableOverride] # Number of gunicorn workers from user gunicorn_workers: Optional[int] = None - # Number of requests before a worker is restarted + # Number of requests before a worker is restarted; set to 0 to disable gunicorn_max_requests: int = 100 # Variance limit for max requests; gunicorn only diff --git a/reflex/event.py b/reflex/event.py index f247047cf9c..c2eb8db3a54 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -26,6 +26,7 @@ from typing_extensions import ( Protocol, + Self, TypeAliasType, TypedDict, TypeVar, @@ -110,7 +111,7 @@ class EventActionsMixin: event_actions: Dict[str, Union[bool, int]] = dataclasses.field(default_factory=dict) @property - def stop_propagation(self): + def stop_propagation(self) -> Self: """Stop the event from bubbling up the DOM tree. Returns: @@ -122,7 +123,7 @@ def stop_propagation(self): ) @property - def prevent_default(self): + def prevent_default(self) -> Self: """Prevent the default behavior of the event. Returns: @@ -133,7 +134,7 @@ def prevent_default(self): event_actions={"preventDefault": True, **self.event_actions}, ) - def throttle(self, limit_ms: int): + def throttle(self, limit_ms: int) -> Self: """Throttle the event handler. Args: @@ -147,7 +148,7 @@ def throttle(self, limit_ms: int): event_actions={"throttle": limit_ms, **self.event_actions}, ) - def debounce(self, delay_ms: int): + def debounce(self, delay_ms: int) -> Self: """Debounce the event handler. Args: @@ -162,7 +163,7 @@ def debounce(self, delay_ms: int): ) @property - def temporal(self): + def temporal(self) -> Self: """Do not queue the event if the backend is down. Returns: @@ -1773,7 +1774,7 @@ def create( V5 = TypeVar("V5") -class EventCallback(Generic[Unpack[P]]): +class EventCallback(Generic[Unpack[P]], EventActionsMixin): """A descriptor that wraps a function to be used as an event.""" def __init__(self, func: Callable[[Any, Unpack[P]], Any]): @@ -1784,24 +1785,6 @@ def __init__(self, func: Callable[[Any, Unpack[P]], Any]): """ self.func = func - @property - def prevent_default(self): - """Prevent default behavior. - - Returns: - The event callback with prevent default behavior. - """ - return self - - @property - def stop_propagation(self): - """Stop event propagation. - - Returns: - The event callback with stop propagation behavior. - """ - return self - @overload def __call__( self: EventCallback[Unpack[Q]], diff --git a/reflex/utils/console.py b/reflex/utils/console.py index d5b7a0d6e14..5c47eee6f9f 100644 --- a/reflex/utils/console.py +++ b/reflex/utils/console.py @@ -2,8 +2,10 @@ from __future__ import annotations +import contextlib import inspect import shutil +import time from pathlib import Path from types import FrameType @@ -317,3 +319,20 @@ def status(*args, **kwargs): A new status. """ return _console.status(*args, **kwargs) + + +@contextlib.contextmanager +def timing(msg: str): + """Create a context manager to time a block of code. + + Args: + msg: The message to display. + + Yields: + None. + """ + start = time.time() + try: + yield + finally: + debug(f"[white]\\[timing] {msg}: {time.time() - start:.2f}s[/white]") diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 67df7ea919e..de326dacc97 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -368,34 +368,49 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel): app_module = get_app_module() - run_backend_prod = f"gunicorn --worker-class {config.gunicorn_worker_class} --max-requests {config.gunicorn_max_requests} --max-requests-jitter {config.gunicorn_max_requests_jitter} --preload --timeout {config.timeout} --log-level critical".split() - run_backend_prod_windows = f"uvicorn --limit-max-requests {config.gunicorn_max_requests} --timeout-keep-alive {config.timeout}".split() command = ( [ - *run_backend_prod_windows, - "--host", - host, - "--port", - str(port), + "uvicorn", + *( + [ + "--limit-max-requests", + str(config.gunicorn_max_requests), + ] + if config.gunicorn_max_requests > 0 + else [] + ), + *("--timeout-keep-alive", str(config.timeout)), + *("--host", host), + *("--port", str(port)), + *("--workers", str(_get_backend_workers())), app_module, ] if constants.IS_WINDOWS else [ - *run_backend_prod, - "--bind", - f"{host}:{port}", - "--threads", - str(_get_backend_workers()), + "gunicorn", + *("--worker-class", config.gunicorn_worker_class), + *( + [ + "--max-requests", + str(config.gunicorn_max_requests), + "--max-requests-jitter", + str(config.gunicorn_max_requests_jitter), + ] + if config.gunicorn_max_requests > 0 + else [] + ), + "--preload", + *("--timeout", str(config.timeout)), + *("--bind", f"{host}:{port}"), + *("--threads", str(_get_backend_workers())), f"{app_module}()", ] ) command += [ - "--log-level", - loglevel.value, - "--workers", - str(_get_backend_workers()), + *("--log-level", loglevel.value), ] + processes.new_process( command, run=True, diff --git a/reflex/utils/imports.py b/reflex/utils/imports.py index 46e8e736239..66ae4b02318 100644 --- a/reflex/utils/imports.py +++ b/reflex/utils/imports.py @@ -109,6 +109,9 @@ class ImportVar: # whether this import should be rendered or not render: Optional[bool] = True + # The path of the package to import from. + package_path: str = "/" + # whether this import package should be added to transpilePackages in next.config.js # https://nextjs.org/docs/app/api-reference/next-config-js/transpilePackages transpile: Optional[bool] = False diff --git a/reflex/utils/path_ops.py b/reflex/utils/path_ops.py index 07a54120105..92557d801c1 100644 --- a/reflex/utils/path_ops.py +++ b/reflex/utils/path_ops.py @@ -260,3 +260,33 @@ def find_replace(directory: str | Path, find: str, replace: str): text = filepath.read_text(encoding="utf-8") text = re.sub(find, replace, text) filepath.write_text(text, encoding="utf-8") + + +def update_directory_tree(src: Path, dest: Path): + """Recursively copies a directory tree from src to dest. + Only copies files if the destination file is missing or modified earlier than the source file. + + Args: + src: Source directory + dest: Destination directory + + Raises: + ValueError: If the source is not a directory + """ + if not src.is_dir(): + raise ValueError(f"Source {src} is not a directory") + + # Ensure the destination directory exists + dest.mkdir(parents=True, exist_ok=True) + + for item in src.iterdir(): + dest_item = dest / item.name + + if item.is_dir(): + # Recursively copy subdirectories + update_directory_tree(item, dest_item) + elif item.is_file() and ( + not dest_item.exists() or item.stat().st_mtime > dest_item.stat().st_mtime + ): + # Copy file if it doesn't exist in the destination or is older than the source + shutil.copy2(item, dest_item) diff --git a/reflex/vars/base.py b/reflex/vars/base.py index c9dd81986ac..a24db4010de 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -75,9 +75,9 @@ if TYPE_CHECKING: from reflex.state import BaseState - from .number import BooleanVar, NumberVar - from .object import ObjectVar - from .sequence import ArrayVar, StringVar + from .number import BooleanVar, LiteralBooleanVar, LiteralNumberVar, NumberVar + from .object import LiteralObjectVar, ObjectVar + from .sequence import ArrayVar, LiteralArrayVar, LiteralStringVar, StringVar VAR_TYPE = TypeVar("VAR_TYPE", covariant=True) @@ -573,13 +573,21 @@ def _replace( return value_with_replaced + @overload + @classmethod + def create( # pyright: ignore[reportOverlappingOverload] + cls, + value: NoReturn, + _var_data: VarData | None = None, + ) -> Var[Any]: ... + @overload @classmethod def create( # pyright: ignore[reportOverlappingOverload] cls, value: bool, _var_data: VarData | None = None, - ) -> BooleanVar: ... + ) -> LiteralBooleanVar: ... @overload @classmethod @@ -587,7 +595,7 @@ def create( cls, value: int, _var_data: VarData | None = None, - ) -> NumberVar[int]: ... + ) -> LiteralNumberVar[int]: ... @overload @classmethod @@ -595,7 +603,15 @@ def create( cls, value: float, _var_data: VarData | None = None, - ) -> NumberVar[float]: ... + ) -> LiteralNumberVar[float]: ... + + @overload + @classmethod + def create( # pyright: ignore [reportOverlappingOverload] + cls, + value: str, + _var_data: VarData | None = None, + ) -> LiteralStringVar: ... @overload @classmethod @@ -611,7 +627,7 @@ def create( # pyright: ignore[reportOverlappingOverload] cls, value: None, _var_data: VarData | None = None, - ) -> NoneVar: ... + ) -> LiteralNoneVar: ... @overload @classmethod @@ -619,7 +635,7 @@ def create( cls, value: MAPPING_TYPE, _var_data: VarData | None = None, - ) -> ObjectVar[MAPPING_TYPE]: ... + ) -> LiteralObjectVar[MAPPING_TYPE]: ... @overload @classmethod @@ -627,7 +643,7 @@ def create( cls, value: SEQUENCE_TYPE, _var_data: VarData | None = None, - ) -> ArrayVar[SEQUENCE_TYPE]: ... + ) -> LiteralArrayVar[SEQUENCE_TYPE]: ... @overload @classmethod @@ -2238,6 +2254,27 @@ def __get__( owner: Type, ) -> ArrayVar[tuple[LIST_INSIDE, ...]]: ... + @overload + def __get__( + self: ComputedVar[BASE_TYPE], + instance: None, + owner: Type, + ) -> ObjectVar[BASE_TYPE]: ... + + @overload + def __get__( + self: ComputedVar[SQLA_TYPE], + instance: None, + owner: Type, + ) -> ObjectVar[SQLA_TYPE]: ... + + if TYPE_CHECKING: + + @overload + def __get__( + self: ComputedVar[DATACLASS_TYPE], instance: None, owner: Any + ) -> ObjectVar[DATACLASS_TYPE]: ... + @overload def __get__(self, instance: None, owner: Type) -> ComputedVar[RETURN_TYPE]: ... @@ -2484,6 +2521,27 @@ def __get__( owner: Type, ) -> ArrayVar[tuple[LIST_INSIDE, ...]]: ... + @overload + def __get__( + self: AsyncComputedVar[BASE_TYPE], + instance: None, + owner: Type, + ) -> ObjectVar[BASE_TYPE]: ... + + @overload + def __get__( + self: AsyncComputedVar[SQLA_TYPE], + instance: None, + owner: Type, + ) -> ObjectVar[SQLA_TYPE]: ... + + if TYPE_CHECKING: + + @overload + def __get__( + self: AsyncComputedVar[DATACLASS_TYPE], instance: None, owner: Any + ) -> ObjectVar[DATACLASS_TYPE]: ... + @overload def __get__(self, instance: None, owner: Type) -> AsyncComputedVar[RETURN_TYPE]: ... diff --git a/reflex/vars/number.py b/reflex/vars/number.py index 35a55490a75..87f1760a6f1 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -974,7 +974,7 @@ def boolean_not_operation(value: BooleanVar): frozen=True, slots=True, ) -class LiteralNumberVar(LiteralVar, NumberVar): +class LiteralNumberVar(LiteralVar, NumberVar[NUMBER_T]): """Base class for immutable literal number vars.""" _var_value: float | int = dataclasses.field(default=0) diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py index fb797b4ec18..0e7b082f982 100644 --- a/reflex/vars/sequence.py +++ b/reflex/vars/sequence.py @@ -372,6 +372,33 @@ def __ge__(self, other: Any): return string_ge_operation(self, other) + @overload + def replace( # pyright: ignore [reportOverlappingOverload] + self, search_value: StringVar | str, new_value: StringVar | str + ) -> StringVar: ... + + @overload + def replace( + self, search_value: Any, new_value: Any + ) -> CustomVarOperationReturn[StringVar]: ... + + def replace(self, search_value: Any, new_value: Any) -> StringVar: # pyright: ignore [reportInconsistentOverload] + """Replace a string with a value. + + Args: + search_value: The string to search. + new_value: The value to be replaced with. + + Returns: + The string replace operation. + """ + if not isinstance(search_value, (StringVar, str)): + raise_unsupported_operand_types("replace", (type(self), type(search_value))) + if not isinstance(new_value, (StringVar, str)): + raise_unsupported_operand_types("replace", (type(self), type(new_value))) + + return string_replace_operation(self, search_value, new_value) + @var_operation def string_lt_operation(lhs: StringVar[Any] | str, rhs: StringVar[Any] | str): @@ -570,7 +597,7 @@ def array_join_operation(array: ArrayVar, sep: StringVar[Any] | str = ""): @var_operation def string_replace_operation( - string: StringVar, search_value: StringVar | str, new_value: StringVar | str + string: StringVar[Any], search_value: StringVar | str, new_value: StringVar | str ): """Replace a string with a value. @@ -583,7 +610,7 @@ def string_replace_operation( The string replace operation. """ return var_operation_return( - js_expression=f"{string}.replace({search_value}, {new_value})", + js_expression=f"{string}.replaceAll({search_value}, {new_value})", var_type=str, ) diff --git a/tests/units/components/datadisplay/test_shiki_code.py b/tests/units/components/datadisplay/test_shiki_code.py index cc05c35b074..e1c7984f1df 100644 --- a/tests/units/components/datadisplay/test_shiki_code.py +++ b/tests/units/components/datadisplay/test_shiki_code.py @@ -11,6 +11,7 @@ from reflex.components.radix.themes.layout.box import Box from reflex.style import Style from reflex.vars import Var +from reflex.vars.base import LiteralVar @pytest.mark.parametrize( @@ -99,7 +100,9 @@ def test_create_shiki_code_block( applied_styles = component.style for key, value in expected_styles.items(): - assert Var.create(applied_styles[key])._var_value == value + var = Var.create(applied_styles[key]) + assert isinstance(var, LiteralVar) + assert var._var_value == value @pytest.mark.parametrize( diff --git a/tests/units/vars/test_object.py b/tests/units/vars/test_object.py index 90e34be96ca..89ace55bb9e 100644 --- a/tests/units/vars/test_object.py +++ b/tests/units/vars/test_object.py @@ -74,11 +74,11 @@ class ObjectState(rx.State): @pytest.mark.parametrize("type_", [Base, Bare, SqlaModel, Dataclass]) -def test_var_create(type_: GenericType) -> None: +def test_var_create(type_: type[Base | Bare | SqlaModel | Dataclass]) -> None: my_object = type_() var = Var.create(my_object) assert var._var_type is type_ - + assert isinstance(var, ObjectVar) quantity = var.quantity assert quantity._var_type is int @@ -94,12 +94,12 @@ def test_literal_create(type_: GenericType) -> None: @pytest.mark.parametrize("type_", [Base, Bare, SqlaModel, Dataclass]) -def test_guess(type_: GenericType) -> None: +def test_guess(type_: type[Base | Bare | SqlaModel | Dataclass]) -> None: my_object = type_() var = Var.create(my_object) var = var.guess_type() assert var._var_type is type_ - + assert isinstance(var, ObjectVar) quantity = var.quantity assert quantity._var_type is int