Merge branch 'main' into lendemor/fix_bun_path

This commit is contained in:
Lendemor 2025-02-10 15:50:38 +01:00
commit 054a5ff3c1
30 changed files with 1471 additions and 163 deletions

View File

@ -99,7 +99,15 @@ from reflex.state import (
_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 @@ class App(MiddlewareMixin, LifespanMixin):
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 @@ class App(MiddlewareMixin, LifespanMixin):
+ 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 @@ class App(MiddlewareMixin, LifespanMixin):
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 @@ class App(MiddlewareMixin, LifespanMixin):
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 @@ class App(MiddlewareMixin, LifespanMixin):
_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 @@ class App(MiddlewareMixin, LifespanMixin):
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 @@ class App(MiddlewareMixin, LifespanMixin):
# 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]:

View File

@ -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]] = {}
# remove the version before rendering the package imports
lib = format.format_library_name(lib)
for field in fields:
lib_paths.setdefault(field.package_path, []).append(field)
import_dicts.append(get_import_dict(lib, default, rest))
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(formatted_lib, default, rest))
return import_dicts

View File

@ -179,6 +179,7 @@ ComponentStyle = Dict[
Union[str, Type[BaseComponent], Callable, ComponentNamespace], Any
]
ComponentChild = Union[types.PrimitiveType, Var, BaseComponent]
ComponentChildTypes = (*types.PrimitiveTypes, Var, BaseComponent)
def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
@ -191,11 +192,7 @@ def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
Returns:
Whether the object satisfies the type hint.
"""
if isinstance(obj, LiteralVar):
return types._isinstance(obj._var_value, type_hint)
if isinstance(obj, Var):
return types._issubclass(obj._var_type, type_hint)
return types._isinstance(obj, type_hint)
return types._isinstance(obj, type_hint, nested=1)
class Component(BaseComponent, ABC):
@ -712,8 +709,8 @@ class Component(BaseComponent, ABC):
validate_children(child)
# Make sure the child is a valid type.
if isinstance(child, dict) or not types._isinstance(
child, ComponentChild
if isinstance(child, dict) or not isinstance(
child, ComponentChildTypes
):
raise ChildrenTypeError(component=cls.__name__, child=child)
@ -1771,9 +1768,7 @@ class CustomComponent(Component):
return [
Var(
_js_expr=name,
_var_type=(
prop._var_type if types._isinstance(prop, Var) else type(prop)
),
_var_type=(prop._var_type if isinstance(prop, Var) else type(prop)),
).guess_type()
for name, prop in self.props.items()
]

View File

@ -54,9 +54,10 @@ class Foreach(Component):
TypeError: If the render function is a ComponentState.
UntypedVarError: If the iterable is of type Any without a type annotation.
"""
from reflex.vars.object import ObjectVar
from reflex.vars import ArrayVar, ObjectVar, StringVar
iterable = LiteralVar.create(iterable).guess_type()
iterable = LiteralVar.create(iterable)
if iterable._var_type == Any:
raise ForeachVarError(
f"Could not foreach over var `{iterable!s}` of type Any. "
@ -75,6 +76,15 @@ class Foreach(Component):
if isinstance(iterable, ObjectVar):
iterable = iterable.entries()
if isinstance(iterable, StringVar):
iterable = iterable.split()
if not isinstance(iterable, ArrayVar):
raise ForeachVarError(
f"Could not foreach over var `{iterable!s}` of type {iterable._var_type}. "
"See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
)
component = cls(
iterable=iterable,
render_fn=render_fn,

View File

@ -178,9 +178,9 @@ class Match(MemoizationLeaf):
first_case_return = match_cases[0][-1]
return_type = type(first_case_return)
if types._isinstance(first_case_return, BaseComponent):
if isinstance(first_case_return, BaseComponent):
return_type = BaseComponent
elif types._isinstance(first_case_return, Var):
elif isinstance(first_case_return, Var):
return_type = Var
for index, case in enumerate(match_cases):
@ -228,8 +228,8 @@ class Match(MemoizationLeaf):
# Validate the match cases (as well as the default case) to have Var return types.
if any(
case for case in match_cases if not types._isinstance(case[-1], Var)
) or not types._isinstance(default, Var):
case for case in match_cases if not isinstance(case[-1], Var)
) or not isinstance(default, Var):
raise ValueError("Return types of match cases should be Vars.")
return Var(

View File

@ -107,9 +107,7 @@ class StickyBadge(A):
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(),
)

View File

@ -3,6 +3,7 @@
from __future__ import annotations
import dataclasses
import typing
from typing import ClassVar, Dict, Literal, Optional, Union
from reflex.components.component import Component, ComponentNamespace
@ -503,7 +504,7 @@ class CodeBlock(Component, MarkdownComponentMap):
return ["can_copy", "copy_button"]
@classmethod
def _get_language_registration_hook(cls, language_var: Var = _LANGUAGE) -> str:
def _get_language_registration_hook(cls, language_var: Var = _LANGUAGE) -> Var:
"""Get the hook to register the language.
Args:
@ -514,21 +515,46 @@ class CodeBlock(Component, MarkdownComponentMap):
Returns:
The hook to register the language.
"""
return f"""
if ({language_var!s}) {{
(async () => {{
try {{
language_in_there = Var.create(typing.get_args(LiteralCodeLanguage)).contains(
language_var
)
async_load = f"""
(async () => {{
try {{
const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{{language_var!s}}}`);
SyntaxHighlighter.registerLanguage({language_var!s}, module.default);
}} catch (error) {{
console.error(`Error importing language module for ${{{language_var!s}}}:`, error);
}}
}})();
}} catch (error) {{
console.error(`Language ${{{language_var!s}}} is not supported for code blocks inside of markdown: `, error);
}}
}})();
"""
return Var(
f"""
if ({language_var!s}) {{
if (!{language_in_there!s}) {{
console.warn(`Language \\`${{{language_var!s}}}\\` is not supported for code blocks inside of markdown.`);
{language_var!s} = '';
}} else {{
{async_load!s}
}}
}}
"""
if not isinstance(language_var, LiteralVar)
else f"""
if ({language_var!s}) {{
{async_load!s}
}}""",
_var_data=VarData(
imports={
cls.__fields__["library"].default: [
ImportVar(tag="PrismAsyncLight", alias="SyntaxHighlighter")
]
},
),
)
@classmethod
def get_component_map_custom_code(cls) -> str:
def get_component_map_custom_code(cls) -> Var:
"""Get the custom code for the component.
Returns:

View File

@ -984,7 +984,7 @@ class CodeBlock(Component, MarkdownComponentMap):
def add_style(self): ...
@classmethod
def get_component_map_custom_code(cls) -> str: ...
def get_component_map_custom_code(cls) -> Var: ...
def add_hooks(self) -> list[str | Var]: ...
class CodeblockNamespace(ComponentNamespace):

View File

@ -4,7 +4,7 @@ from reflex.components.component import Component
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 @@ class Icon(LucideIconComponent):
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 @@ class Icon(LucideIconComponent):
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)

View File

@ -6,13 +6,12 @@ import dataclasses
import textwrap
from functools import lru_cache
from hashlib import md5
from typing import Any, Callable, Dict, Sequence, Union
from typing import Any, Callable, Dict, Sequence
from reflex.components.component import BaseComponent, Component, CustomComponent
from reflex.components.tags.tag import Tag
from reflex.utils import types
from reflex.utils.imports import ImportDict, ImportVar
from reflex.vars.base import LiteralVar, Var
from reflex.vars.base import LiteralVar, Var, VarData
from reflex.vars.function import ARRAY_ISARRAY, ArgsFunctionOperation, DestructuredArg
from reflex.vars.number import ternary_operation
@ -83,13 +82,13 @@ class MarkdownComponentMap:
_explicit_return: bool = dataclasses.field(default=False)
@classmethod
def get_component_map_custom_code(cls) -> str:
def get_component_map_custom_code(cls) -> Var:
"""Get the custom code for the component map.
Returns:
The custom code for the component map.
"""
return ""
return Var("")
@classmethod
def create_map_fn_var(
@ -97,6 +96,7 @@ class MarkdownComponentMap:
fn_body: Var | None = None,
fn_args: Sequence[str] | None = None,
explicit_return: bool | None = None,
var_data: VarData | None = None,
) -> Var:
"""Create a function Var for the component map.
@ -104,6 +104,7 @@ class MarkdownComponentMap:
fn_body: The formatted component as a string.
fn_args: The function arguments.
explicit_return: Whether to use explicit return syntax.
var_data: The var data for the function.
Returns:
The function Var for the component map.
@ -116,6 +117,7 @@ class MarkdownComponentMap:
args_names=(DestructuredArg(fields=tuple(fn_args)),),
return_expr=fn_body,
explicit_return=explicit_return,
_var_data=var_data,
)
@classmethod
@ -166,7 +168,7 @@ class Markdown(Component):
Returns:
The markdown component.
"""
if len(children) != 1 or not types._isinstance(children[0], Union[str, Var]):
if len(children) != 1 or not isinstance(children[0], (str, Var)):
raise ValueError(
"Markdown component must have exactly one child containing the markdown source."
)
@ -239,6 +241,15 @@ class Markdown(Component):
component(_MOCK_ARG)._get_all_imports()
for component in self.component_map.values()
],
*(
[inline_code_var_data.old_school_imports()]
if (
inline_code_var_data
:= self._get_inline_code_fn_var()._get_all_var_data()
)
is not None
else []
),
]
def _get_tag_map_fn_var(self, tag: str) -> Var:
@ -278,12 +289,20 @@ class Markdown(Component):
self._get_map_fn_custom_code_from_children(self.get_component("code"))
)
codeblock_custom_code = "\n".join(custom_code_list)
var_data = VarData.merge(
*[
code._get_all_var_data()
for code in custom_code_list
if isinstance(code, Var)
]
)
codeblock_custom_code = "\n".join(map(str, custom_code_list))
# Format the code to handle inline and block code.
formatted_code = f"""
const match = (className || '').match(/language-(?<lang>.*)/);
const {_LANGUAGE!s} = match ? match[1] : '';
let {_LANGUAGE!s} = match ? match[1] : '';
{codeblock_custom_code};
return inline ? (
{self.format_component("code")}
@ -302,6 +321,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
),
fn_body=Var(_js_expr=formatted_code),
explicit_return=True,
var_data=var_data,
)
def get_component(self, tag: str, **props) -> Component:
@ -381,7 +401,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
def _get_map_fn_custom_code_from_children(
self, component: BaseComponent
) -> list[str]:
) -> list[str | Var]:
"""Recursively get markdown custom code from children components.
Args:
@ -390,7 +410,7 @@ const {_LANGUAGE!s} = match ? match[1] : '';
Returns:
A list of markdown custom code strings.
"""
custom_code_list = []
custom_code_list: list[str | Var] = []
if isinstance(component, MarkdownComponentMap):
custom_code_list.append(component.get_component_map_custom_code())

View File

@ -11,7 +11,7 @@ from reflex.components.component import Component
from reflex.event import EventType
from reflex.style import Style
from reflex.utils.imports import ImportDict
from reflex.vars.base import LiteralVar, Var
from reflex.vars.base import LiteralVar, Var, VarData
_CHILDREN = Var(_js_expr="children", _var_type=str)
_PROPS = Var(_js_expr="...props")
@ -32,13 +32,14 @@ def get_base_component_map() -> dict[str, Callable]: ...
@dataclasses.dataclass()
class MarkdownComponentMap:
@classmethod
def get_component_map_custom_code(cls) -> str: ...
def get_component_map_custom_code(cls) -> Var: ...
@classmethod
def create_map_fn_var(
cls,
fn_body: Var | None = None,
fn_args: Sequence[str] | None = None,
explicit_return: bool | None = None,
var_data: VarData | None = None,
) -> Var: ...
@classmethod
def get_fn_args(cls) -> Sequence[str]: ...

View File

@ -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()

View File

@ -10,6 +10,7 @@ from reflex.components.component import Component, NoSSRComponent
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 @@ const extractPoints = (points) => {
# 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")

View File

@ -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.
"""
...

View File

@ -3,7 +3,7 @@
from __future__ import annotations
import dataclasses
from typing import Any, Dict, List, Optional, Sequence, Union
from typing import Any, Dict, List, Mapping, Optional, Sequence
from reflex.event import EventChain
from reflex.utils import format, types
@ -103,7 +103,7 @@ class Tag:
{
format.to_camel_case(name, allow_hyphens=True): (
prop
if types._isinstance(prop, Union[EventChain, dict])
if types._isinstance(prop, (EventChain, Mapping))
else LiteralVar.create(prop)
) # rx.color is always a string
for name, prop in kwargs.items()

View File

@ -679,7 +679,7 @@ class Config(Base):
# 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

View File

@ -26,6 +26,7 @@ from typing import (
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 @@ class EventActionsMixin:
)
@property
def prevent_default(self):
def prevent_default(self) -> Self:
"""Prevent the default behavior of the event.
Returns:
@ -133,7 +134,7 @@ class EventActionsMixin:
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 @@ class EventActionsMixin:
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 @@ class EventActionsMixin:
)
@property
def temporal(self):
def temporal(self) -> Self:
"""Do not queue the event if the backend is down.
Returns:
@ -1773,7 +1774,7 @@ V4 = TypeVar("V4")
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 @@ class EventCallback(Generic[Unpack[P]]):
"""
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]],

View File

@ -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]")

View File

@ -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,

View File

@ -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

View File

@ -276,3 +276,33 @@ def samefile(file1: Path, file2: Path) -> bool:
return file1.samefile(file2)
return False
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)

View File

@ -95,6 +95,7 @@ GenericType = Union[Type, _GenericAlias]
# Valid state var types.
JSONType = {str, int, float, bool}
PrimitiveType = Union[int, float, bool, str, list, dict, set, tuple]
PrimitiveTypes = (int, float, bool, str, list, dict, set, tuple)
StateVar = Union[PrimitiveType, Base, None]
StateIterVar = Union[list, set, tuple]
@ -551,13 +552,13 @@ def does_obj_satisfy_typed_dict(obj: Any, cls: GenericType) -> bool:
return required_keys.issubset(required_keys)
def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
def _isinstance(obj: Any, cls: GenericType, nested: int = 0) -> bool:
"""Check if an object is an instance of a class.
Args:
obj: The object to check.
cls: The class to check against.
nested: Whether the check is nested.
nested: How many levels deep to check.
Returns:
Whether the object is an instance of the class.
@ -565,15 +566,24 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
if cls is Any:
return True
from reflex.vars import LiteralVar, Var
if cls is Var:
return isinstance(obj, Var)
if isinstance(obj, LiteralVar):
return _isinstance(obj._var_value, cls, nested=nested)
if isinstance(obj, Var):
return _issubclass(obj._var_type, cls)
if cls is None or cls is type(None):
return obj is None
if cls and is_union(cls):
return any(_isinstance(obj, arg, nested=nested) for arg in get_args(cls))
if is_literal(cls):
return obj in get_args(cls)
if is_union(cls):
return any(_isinstance(obj, arg) for arg in get_args(cls))
origin = get_origin(cls)
if origin is None:
@ -596,38 +606,40 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
# cls is a simple generic class
return isinstance(obj, origin)
if nested and args:
if nested > 0 and args:
if origin is list:
return isinstance(obj, list) and all(
_isinstance(item, args[0]) for item in obj
_isinstance(item, args[0], nested=nested - 1) for item in obj
)
if origin is tuple:
if args[-1] is Ellipsis:
return isinstance(obj, tuple) and all(
_isinstance(item, args[0]) for item in obj
_isinstance(item, args[0], nested=nested - 1) for item in obj
)
return (
isinstance(obj, tuple)
and len(obj) == len(args)
and all(
_isinstance(item, arg) for item, arg in zip(obj, args, strict=True)
_isinstance(item, arg, nested=nested - 1)
for item, arg in zip(obj, args, strict=True)
)
)
if origin in (dict, Breakpoints):
return isinstance(obj, dict) and all(
_isinstance(key, args[0]) and _isinstance(value, args[1])
if origin in (dict, Mapping, Breakpoints):
return isinstance(obj, Mapping) and all(
_isinstance(key, args[0], nested=nested - 1)
and _isinstance(value, args[1], nested=nested - 1)
for key, value in obj.items()
)
if origin is set:
return isinstance(obj, set) and all(
_isinstance(item, args[0]) for item in obj
_isinstance(item, args[0], nested=nested - 1) for item in obj
)
if args:
from reflex.vars import Field
if origin is Field:
return _isinstance(obj, args[0])
return _isinstance(obj, args[0], nested=nested)
return isinstance(obj, get_base_class(cls))
@ -749,7 +761,7 @@ def check_prop_in_allowed_types(prop: Any, allowed_types: Iterable) -> bool:
"""
from reflex.vars import Var
type_ = prop._var_type if _isinstance(prop, Var) else type(prop)
type_ = prop._var_type if isinstance(prop, Var) else type(prop)
return type_ in allowed_types

View File

@ -75,9 +75,9 @@ from reflex.utils.types import (
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 @@ class Var(Generic[VAR_TYPE]):
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 @@ class Var(Generic[VAR_TYPE]):
cls,
value: int,
_var_data: VarData | None = None,
) -> NumberVar[int]: ...
) -> LiteralNumberVar[int]: ...
@overload
@classmethod
@ -595,7 +603,15 @@ class Var(Generic[VAR_TYPE]):
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 @@ class Var(Generic[VAR_TYPE]):
cls,
value: None,
_var_data: VarData | None = None,
) -> NoneVar: ...
) -> LiteralNoneVar: ...
@overload
@classmethod
@ -619,7 +635,7 @@ class Var(Generic[VAR_TYPE]):
cls,
value: MAPPING_TYPE,
_var_data: VarData | None = None,
) -> ObjectVar[MAPPING_TYPE]: ...
) -> LiteralObjectVar[MAPPING_TYPE]: ...
@overload
@classmethod
@ -627,7 +643,7 @@ class Var(Generic[VAR_TYPE]):
cls,
value: SEQUENCE_TYPE,
_var_data: VarData | None = None,
) -> ArrayVar[SEQUENCE_TYPE]: ...
) -> LiteralArrayVar[SEQUENCE_TYPE]: ...
@overload
@classmethod
@ -2238,6 +2254,27 @@ class ComputedVar(Var[RETURN_TYPE]):
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 @@ class AsyncComputedVar(ComputedVar[RETURN_TYPE]):
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]: ...

View File

@ -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)

View File

@ -22,7 +22,12 @@ from typing_extensions import is_typeddict
from reflex.utils import types
from reflex.utils.exceptions import VarAttributeError
from reflex.utils.types import GenericType, get_attribute_access_type, get_origin
from reflex.utils.types import (
GenericType,
get_attribute_access_type,
get_origin,
safe_issubclass,
)
from .base import (
CachedVarOperation,
@ -187,10 +192,14 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=Mapping):
Returns:
The item from the object.
"""
from .sequence import LiteralStringVar
if not isinstance(key, (StringVar, str, int, NumberVar)) or (
isinstance(key, NumberVar) and key._is_strict_float()
):
raise_unsupported_operand_types("[]", (type(self), type(key)))
if isinstance(key, str) and isinstance(Var.create(key), LiteralStringVar):
return self.__getattr__(key)
return ObjectItemOperation.create(self, key).guess_type()
# NoReturn is used here to catch when key value is Any
@ -260,12 +269,12 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=Mapping):
if types.is_optional(var_type):
var_type = get_args(var_type)[0]
fixed_type = var_type if isclass(var_type) else get_origin(var_type)
fixed_type = get_origin(var_type) or var_type
if (
(isclass(fixed_type) and not issubclass(fixed_type, Mapping))
is_typeddict(fixed_type)
or (isclass(fixed_type) and not safe_issubclass(fixed_type, Mapping))
or (fixed_type in types.UnionTypes)
or is_typeddict(fixed_type)
):
attribute_type = get_attribute_access_type(var_type, name)
if attribute_type is None:

View File

@ -372,6 +372,33 @@ class StringVar(Var[STRING_TYPE], python_types=str):
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,
)

View File

@ -10,6 +10,8 @@ from reflex.testing import AppHarness
def VarOperations():
"""App with var operations."""
from typing import TypedDict
import reflex as rx
from reflex.vars.base import LiteralVar
from reflex.vars.sequence import ArrayVar
@ -17,6 +19,10 @@ def VarOperations():
class Object(rx.Base):
name: str = "hello"
class Person(TypedDict):
name: str
age: int
class VarOperationState(rx.State):
int_var1: rx.Field[int] = rx.field(10)
int_var2: rx.Field[int] = rx.field(5)
@ -34,6 +40,9 @@ def VarOperations():
dict1: rx.Field[dict[int, int]] = rx.field({1: 2})
dict2: rx.Field[dict[int, int]] = rx.field({3: 4})
html_str: rx.Field[str] = rx.field("<div>hello</div>")
people: rx.Field[list[Person]] = rx.field(
[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]
)
app = rx.App(_state=rx.State)
@ -619,6 +628,23 @@ def VarOperations():
),
id="dict_in_foreach3",
),
rx.box(
rx.foreach("abcdef", lambda x: rx.text.span(x + " ")),
id="str_in_foreach",
),
rx.box(
rx.foreach(VarOperationState.str_var1, lambda x: rx.text.span(x + " ")),
id="str_var_in_foreach",
),
rx.box(
rx.foreach(
VarOperationState.people,
lambda person: rx.text.span(
"Hello " + person["name"], person["age"] + 3
),
),
id="typed_dict_in_foreach",
),
)
@ -826,6 +852,9 @@ def test_var_operations(driver, var_operations: AppHarness):
("dict_in_foreach1", "a1b2"),
("dict_in_foreach2", "12"),
("dict_in_foreach3", "1234"),
("str_in_foreach", "a b c d e f"),
("str_var_in_foreach", "f i r s t"),
("typed_dict_in_foreach", "Hello Alice33Hello Bob28"),
]
for tag, expected in tests:

View File

@ -11,6 +11,7 @@ from reflex.components.lucide.icon import Icon
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(

View File

@ -148,7 +148,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe
(
"code",
{},
"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; if (_language) { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Error importing language module for ${_language}:`, error); } })(); } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <SyntaxHighlighter children={((Array.isArray(children)) ? children.join("\\n") : children)} css={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} customStyle={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} language={_language} style={((resolvedColorMode === "light") ? oneLight : oneDark)} wrapLongLines={true} {...props}/> ); })""",
r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); let _language = match ? match[1] : ''; if (_language) { if (!["abap", "abnf", "actionscript", "ada", "agda", "al", "antlr4", "apacheconf", "apex", "apl", "applescript", "aql", "arduino", "arff", "asciidoc", "asm6502", "asmatmel", "aspnet", "autohotkey", "autoit", "avisynth", "avro-idl", "bash", "basic", "batch", "bbcode", "bicep", "birb", "bison", "bnf", "brainfuck", "brightscript", "bro", "bsl", "c", "cfscript", "chaiscript", "cil", "clike", "clojure", "cmake", "cobol", "coffeescript", "concurnas", "coq", "core", "cpp", "crystal", "csharp", "cshtml", "csp", "css", "css-extras", "csv", "cypher", "d", "dart", "dataweave", "dax", "dhall", "diff", "django", "dns-zone-file", "docker", "dot", "ebnf", "editorconfig", "eiffel", "ejs", "elixir", "elm", "erb", "erlang", "etlua", "excel-formula", "factor", "false", "firestore-security-rules", "flow", "fortran", "fsharp", "ftl", "gap", "gcode", "gdscript", "gedcom", "gherkin", "git", "glsl", "gml", "gn", "go", "go-module", "graphql", "groovy", "haml", "handlebars", "haskell", "haxe", "hcl", "hlsl", "hoon", "hpkp", "hsts", "http", "ichigojam", "icon", "icu-message-format", "idris", "iecst", "ignore", "index", "inform7", "ini", "io", "j", "java", "javadoc", "javadoclike", "javascript", "javastacktrace", "jexl", "jolie", "jq", "js-extras", "js-templates", "jsdoc", "json", "json5", "jsonp", "jsstacktrace", "jsx", "julia", "keepalived", "keyman", "kotlin", "kumir", "kusto", "latex", "latte", "less", "lilypond", "liquid", "lisp", "livescript", "llvm", "log", "lolcode", "lua", "magma", "makefile", "markdown", "markup", "markup-templating", "matlab", "maxscript", "mel", "mermaid", "mizar", "mongodb", "monkey", "moonscript", "n1ql", "n4js", "nand2tetris-hdl", "naniscript", "nasm", "neon", "nevod", "nginx", "nim", "nix", "nsis", "objectivec", "ocaml", "opencl", "openqasm", "oz", "parigp", "parser", "pascal", "pascaligo", "pcaxis", "peoplecode", "perl", "php", "php-extras", "phpdoc", "plsql", "powerquery", "powershell", "processing", "prolog", "promql", "properties", "protobuf", "psl", "pug", "puppet", "pure", "purebasic", "purescript", "python", "q", "qml", "qore", "qsharp", "r", "racket", "reason", "regex", "rego", "renpy", "rest", "rip", "roboconf", "robotframework", "ruby", "rust", "sas", "sass", "scala", "scheme", "scss", "shell-session", "smali", "smalltalk", "smarty", "sml", "solidity", "solution-file", "soy", "sparql", "splunk-spl", "sqf", "sql", "squirrel", "stan", "stylus", "swift", "systemd", "t4-cs", "t4-templating", "t4-vb", "tap", "tcl", "textile", "toml", "tremor", "tsx", "tt2", "turtle", "twig", "typescript", "typoscript", "unrealscript", "uorazor", "uri", "v", "vala", "vbnet", "velocity", "verilog", "vhdl", "vim", "visual-basic", "warpscript", "wasm", "web-idl", "wiki", "wolfram", "wren", "xeora", "xml-doc", "xojo", "xquery", "yaml", "yang", "zig"].includes(_language)) { console.warn(`Language \`${_language}\` is not supported for code blocks inside of markdown.`); _language = ''; } else { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Language ${_language} is not supported for code blocks inside of markdown: `, error); } })(); } } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <SyntaxHighlighter children={((Array.isArray(children)) ? children.join("\n") : children)} css={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} customStyle={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} language={_language} style={((resolvedColorMode === "light") ? oneLight : oneDark)} wrapLongLines={true} {...props}/> ); })""",
),
(
"code",
@ -157,7 +157,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe
value, **props
)
},
"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <RadixThemesBox css={({ ["pre"] : ({ ["margin"] : "0", ["padding"] : "24px", ["background"] : "transparent", ["overflow-x"] : "auto", ["border-radius"] : "6px" }) })} {...props}><ShikiCode code={((Array.isArray(children)) ? children.join("\\n") : children)} decorations={[]} language={_language} theme={((resolvedColorMode === "light") ? "one-light" : "one-dark-pro")} transformers={[]}/></RadixThemesBox> ); })""",
r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); let _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <RadixThemesBox css={({ ["pre"] : ({ ["margin"] : "0", ["padding"] : "24px", ["background"] : "transparent", ["overflow-x"] : "auto", ["border-radius"] : "6px" }) })} {...props}><ShikiCode code={((Array.isArray(children)) ? children.join("\n") : children)} decorations={[]} language={_language} theme={((resolvedColorMode === "light") ? "one-light" : "one-dark-pro")} transformers={[]}/></RadixThemesBox> ); })""",
),
(
"h1",
@ -171,7 +171,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe
(
"code",
{"codeblock": syntax_highlighter_memoized_component(CodeBlock)},
"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; if (_language) { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Error importing language module for ${_language}:`, error); } })(); } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={((Array.isArray(children)) ? children.join("\\n") : children)} language={_language} {...props}/> ); })""",
r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); let _language = match ? match[1] : ''; if (_language) { if (!["abap", "abnf", "actionscript", "ada", "agda", "al", "antlr4", "apacheconf", "apex", "apl", "applescript", "aql", "arduino", "arff", "asciidoc", "asm6502", "asmatmel", "aspnet", "autohotkey", "autoit", "avisynth", "avro-idl", "bash", "basic", "batch", "bbcode", "bicep", "birb", "bison", "bnf", "brainfuck", "brightscript", "bro", "bsl", "c", "cfscript", "chaiscript", "cil", "clike", "clojure", "cmake", "cobol", "coffeescript", "concurnas", "coq", "core", "cpp", "crystal", "csharp", "cshtml", "csp", "css", "css-extras", "csv", "cypher", "d", "dart", "dataweave", "dax", "dhall", "diff", "django", "dns-zone-file", "docker", "dot", "ebnf", "editorconfig", "eiffel", "ejs", "elixir", "elm", "erb", "erlang", "etlua", "excel-formula", "factor", "false", "firestore-security-rules", "flow", "fortran", "fsharp", "ftl", "gap", "gcode", "gdscript", "gedcom", "gherkin", "git", "glsl", "gml", "gn", "go", "go-module", "graphql", "groovy", "haml", "handlebars", "haskell", "haxe", "hcl", "hlsl", "hoon", "hpkp", "hsts", "http", "ichigojam", "icon", "icu-message-format", "idris", "iecst", "ignore", "index", "inform7", "ini", "io", "j", "java", "javadoc", "javadoclike", "javascript", "javastacktrace", "jexl", "jolie", "jq", "js-extras", "js-templates", "jsdoc", "json", "json5", "jsonp", "jsstacktrace", "jsx", "julia", "keepalived", "keyman", "kotlin", "kumir", "kusto", "latex", "latte", "less", "lilypond", "liquid", "lisp", "livescript", "llvm", "log", "lolcode", "lua", "magma", "makefile", "markdown", "markup", "markup-templating", "matlab", "maxscript", "mel", "mermaid", "mizar", "mongodb", "monkey", "moonscript", "n1ql", "n4js", "nand2tetris-hdl", "naniscript", "nasm", "neon", "nevod", "nginx", "nim", "nix", "nsis", "objectivec", "ocaml", "opencl", "openqasm", "oz", "parigp", "parser", "pascal", "pascaligo", "pcaxis", "peoplecode", "perl", "php", "php-extras", "phpdoc", "plsql", "powerquery", "powershell", "processing", "prolog", "promql", "properties", "protobuf", "psl", "pug", "puppet", "pure", "purebasic", "purescript", "python", "q", "qml", "qore", "qsharp", "r", "racket", "reason", "regex", "rego", "renpy", "rest", "rip", "roboconf", "robotframework", "ruby", "rust", "sas", "sass", "scala", "scheme", "scss", "shell-session", "smali", "smalltalk", "smarty", "sml", "solidity", "solution-file", "soy", "sparql", "splunk-spl", "sqf", "sql", "squirrel", "stan", "stylus", "swift", "systemd", "t4-cs", "t4-templating", "t4-vb", "tap", "tcl", "textile", "toml", "tremor", "tsx", "tt2", "turtle", "twig", "typescript", "typoscript", "unrealscript", "uorazor", "uri", "v", "vala", "vbnet", "velocity", "verilog", "vhdl", "vim", "visual-basic", "warpscript", "wasm", "web-idl", "wiki", "wolfram", "wren", "xeora", "xml-doc", "xojo", "xquery", "yaml", "yang", "zig"].includes(_language)) { console.warn(`Language \`${_language}\` is not supported for code blocks inside of markdown.`); _language = ''; } else { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Language ${_language} is not supported for code blocks inside of markdown: `, error); } })(); } } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={((Array.isArray(children)) ? children.join("\n") : children)} language={_language} {...props}/> ); })""",
),
(
"code",
@ -180,11 +180,12 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe
ShikiHighLevelCodeBlock
)
},
"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={((Array.isArray(children)) ? children.join("\\n") : children)} language={_language} {...props}/> ); })""",
r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); let _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={((Array.isArray(children)) ? children.join("\n") : children)} language={_language} {...props}/> ); })""",
),
],
)
def test_markdown_format_component(key, component_map, expected):
markdown = Markdown.create("# header", component_map=component_map)
result = markdown.format_component_map()
print(str(result[key]))
assert str(result[key]) == expected

View File

@ -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