diff --git a/.github/actions/setup_build_env/action.yml b/.github/actions/setup_build_env/action.yml index a25f0ae44..d983a4daa 100644 --- a/.github/actions/setup_build_env/action.yml +++ b/.github/actions/setup_build_env/action.yml @@ -6,7 +6,7 @@ # # Exit conditions: # - Python of version `python-version` is ready to be invoked as `python`. -# - Poetry of version `poetry-version` is ready ot be invoked as `poetry`. +# - Poetry of version `poetry-version` is ready to be invoked as `poetry`. # - If `run-poetry-install` is true, deps as defined in `pyproject.toml` will have been installed into the venv at `create-venv-at-path`. name: 'Setup Reflex build environment' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1acf9ecb8..ac25a335e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,6 +11,12 @@ repos: args: ["--fix", "--exit-non-zero-on-fix"] exclude: '^integration/benchmarks/' + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + args: ["reflex"] + # Run pyi check before pyright because pyright can fail if pyi files are wrong. - repo: local hooks: diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 253076695..d22d91973 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -5,7 +5,7 @@ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, +identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. diff --git a/README.md b/README.md index 527cca980..5e098b2d3 100644 --- a/README.md +++ b/README.md @@ -249,7 +249,7 @@ We welcome contributions of any size! Below are some good ways to get started in - **GitHub Discussions**: A great way to talk about features you want added or things that are confusing/need clarification. - **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) are an excellent way to report bugs. Additionally, you can try and solve an existing issue and submit a PR. -We are actively looking for contributors, no matter your skill level or experience. To contribute check out [CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) +We are actively looking for contributors, no matter your skill level or experience. To contribute check out [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) ## All Thanks To Our Contributors: diff --git a/benchmarks/benchmark_package_size.py b/benchmarks/benchmark_package_size.py index 778b52769..6a0c37821 100644 --- a/benchmarks/benchmark_package_size.py +++ b/benchmarks/benchmark_package_size.py @@ -21,7 +21,7 @@ def get_package_size(venv_path: Path, os_name): ValueError: when venv does not exist or python version is None. """ python_version = get_python_version(venv_path, os_name) - print("Python version:", python_version) + print("Python version:", python_version) # noqa: T201 if python_version is None: raise ValueError("Error: Failed to determine Python version.") diff --git a/docker-example/production-app-platform/Dockerfile b/docker-example/production-app-platform/Dockerfile index 7bf71943b..284c9eab8 100644 --- a/docker-example/production-app-platform/Dockerfile +++ b/docker-example/production-app-platform/Dockerfile @@ -27,7 +27,7 @@ FROM python:3.13 as init ARG uv=/root/.local/bin/uv -# Install `uv` for faster package boostrapping +# Install `uv` for faster package bootstrapping ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh RUN /install.sh && rm /install.sh diff --git a/docker-example/production-compose/Dockerfile b/docker-example/production-compose/Dockerfile index 9e69c1778..196e135a7 100644 --- a/docker-example/production-compose/Dockerfile +++ b/docker-example/production-compose/Dockerfile @@ -6,7 +6,7 @@ FROM python:3.13 as init ARG uv=/root/.local/bin/uv -# Install `uv` for faster package boostrapping +# Install `uv` for faster package bootstrapping ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh RUN /install.sh && rm /install.sh diff --git a/pyproject.toml b/pyproject.toml index 636abe6d1..e50ef88bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "reflex" -version = "0.6.7dev1" +version = "0.6.8dev1" description = "Web apps in pure Python." license = "Apache-2.0" authors = [ @@ -92,13 +92,13 @@ build-backend = "poetry.core.masonry.api" target-version = "py39" output-format = "concise" lint.isort.split-on-trailing-comma = false -lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PERF", "PTH", "RUF", "SIM", "W"] +lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PERF", "PTH", "RUF", "SIM", "T", "W"] lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"] lint.pydocstyle.convention = "google" [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] -"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF"] +"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T"] "reflex/.templates/*.py" = ["D100", "D103", "D104"] "*.pyi" = ["D301", "D415", "D417", "D418", "E742"] "*/blank.py" = ["I001"] @@ -106,3 +106,7 @@ lint.pydocstyle.convention = "google" [tool.pytest.ini_options] asyncio_default_fixture_loop_scope = "function" asyncio_mode = "auto" + +[tool.codespell] +skip = "docs/*,*.html,examples/*, *.pyi" +ignore-words-list = "te, TreeE" \ No newline at end of file diff --git a/reflex/.templates/jinja/web/utils/context.js.jinja2 b/reflex/.templates/jinja/web/utils/context.js.jinja2 index 2428cfa9d..32be61ebb 100644 --- a/reflex/.templates/jinja/web/utils/context.js.jinja2 +++ b/reflex/.templates/jinja/web/utils/context.js.jinja2 @@ -28,7 +28,7 @@ export const state_name = "{{state_name}}" export const exception_state_name = "{{const.frontend_exception_state}}" -// Theses events are triggered on initial load and each page navigation. +// These events are triggered on initial load and each page navigation. export const onLoadInternalEvent = () => { const internal_events = []; diff --git a/reflex/app.py b/reflex/app.py index ffb995bb7..259fcca29 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -1362,20 +1362,22 @@ async def health() -> JSONResponse: health_status = {"status": True} status_code = 200 - db_status, redis_status = await asyncio.gather( - get_db_status(), prerequisites.get_redis_status() - ) + tasks = [] - health_status["db"] = db_status + if prerequisites.check_db_used(): + tasks.append(get_db_status()) + if prerequisites.check_redis_used(): + tasks.append(prerequisites.get_redis_status()) - if redis_status is None: + results = await asyncio.gather(*tasks) + + for result in results: + health_status |= result + + if "redis" in health_status and health_status["redis"] is None: health_status["redis"] = False - else: - health_status["redis"] = redis_status - if not health_status["db"] or ( - not health_status["redis"] and redis_status is not None - ): + if not all(health_status.values()): health_status["status"] = False status_code = 503 diff --git a/reflex/components/component.py b/reflex/components/component.py index 34800ab6e..c1d4cbc80 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -23,6 +23,8 @@ from typing import ( Union, ) +from typing_extensions import deprecated + import reflex.state from reflex.base import Base from reflex.compiler.templates import STATEFUL_COMPONENT @@ -43,17 +45,13 @@ from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.event import ( EventCallback, EventChain, - EventChainVar, EventHandler, EventSpec, EventVar, - call_event_fn, - call_event_handler, - get_handler_args, no_args_event_spec, ) from reflex.style import Style, format_as_emotion -from reflex.utils import format, imports, types +from reflex.utils import console, format, imports, types from reflex.utils.imports import ( ImmutableParsedImportDict, ImportDict, @@ -493,8 +491,7 @@ class Component(BaseComponent, ABC): ) # Check if the key is an event trigger. if key in component_specific_triggers: - # Temporarily disable full control for event triggers. - kwargs["event_triggers"][key] = self._create_event_chain( + kwargs["event_triggers"][key] = EventChain.create( value=value, # type: ignore args_spec=component_specific_triggers[key], key=key, @@ -548,6 +545,7 @@ class Component(BaseComponent, ABC): # Construct the component. super().__init__(*args, **kwargs) + @deprecated("Use rx.EventChain.create instead.") def _create_event_chain( self, args_spec: types.ArgsSpec | Sequence[types.ArgsSpec], @@ -569,82 +567,18 @@ class Component(BaseComponent, ABC): Returns: The event chain. - - Raises: - ValueError: If the value is not a valid event chain. """ - # If it's an event chain var, return it. - if isinstance(value, Var): - if isinstance(value, EventChainVar): - return value - elif isinstance(value, EventVar): - value = [value] - elif issubclass(value._var_type, (EventChain, EventSpec)): - return self._create_event_chain(args_spec, value.guess_type(), key=key) - else: - raise ValueError( - f"Invalid event chain: {value!s} of type {value._var_type}" - ) - elif isinstance(value, EventChain): - # Trust that the caller knows what they're doing passing an EventChain directly - return value - - # If the input is a single event handler, wrap it in a list. - if isinstance(value, (EventHandler, EventSpec)): - value = [value] - - # If the input is a list of event handlers, create an event chain. - if isinstance(value, List): - events: List[Union[EventSpec, EventVar]] = [] - for v in value: - if isinstance(v, (EventHandler, EventSpec)): - # Call the event handler to get the event. - events.append(call_event_handler(v, args_spec, key=key)) - elif isinstance(v, Callable): - # Call the lambda to get the event chain. - result = call_event_fn(v, args_spec, key=key) - if isinstance(result, Var): - raise ValueError( - f"Invalid event chain: {v}. Cannot use a Var-returning " - "lambda inside an EventChain list." - ) - events.extend(result) - elif isinstance(v, EventVar): - events.append(v) - else: - raise ValueError(f"Invalid event: {v}") - - # If the input is a callable, create an event chain. - elif isinstance(value, Callable): - result = call_event_fn(value, args_spec, key=key) - if isinstance(result, Var): - # Recursively call this function if the lambda returned an EventChain Var. - return self._create_event_chain(args_spec, result, key=key) - events = [*result] - - # Otherwise, raise an error. - else: - raise ValueError(f"Invalid event chain: {value}") - - # Add args to the event specs if necessary. - events = [ - (e.with_args(get_handler_args(e)) if isinstance(e, EventSpec) else e) - for e in events - ] - - # Return the event chain. - if isinstance(args_spec, Var): - return EventChain( - events=events, - args_spec=None, - event_actions={}, - ) - else: - return EventChain( - events=events, - args_spec=args_spec, - event_actions={}, - ) + console.deprecate( + "Component._create_event_chain", + "Use rx.EventChain.create instead.", + deprecation_version="0.6.8", + removal_version="0.7.0", + ) + return EventChain.create( + value=value, # type: ignore + args_spec=args_spec, + key=key, + ) def get_event_triggers( self, @@ -1737,7 +1671,7 @@ class CustomComponent(Component): # Handle event chains. if types._issubclass(type_, EventChain): - value = self._create_event_chain( + value = EventChain.create( value=value, args_spec=event_triggers_in_component_declaration.get( key, no_args_event_spec diff --git a/reflex/components/core/banner.py b/reflex/components/core/banner.py index a5553800d..b7b6fae6c 100644 --- a/reflex/components/core/banner.py +++ b/reflex/components/core/banner.py @@ -241,7 +241,7 @@ class WifiOffPulse(Icon): size=props.pop("size", 32), z_index=props.pop("z_index", 9999), position=props.pop("position", "fixed"), - bottom=props.pop("botton", "33px"), + bottom=props.pop("bottom", "33px"), right=props.pop("right", "33px"), animation=LiteralVar.create(f"{pulse_var} 1s infinite"), **props, diff --git a/reflex/components/core/breakpoints.py b/reflex/components/core/breakpoints.py index 4b2372a70..25396ecd9 100644 --- a/reflex/components/core/breakpoints.py +++ b/reflex/components/core/breakpoints.py @@ -58,7 +58,7 @@ class Breakpoints(Dict[K, V]): Args: custom: Custom mapping using CSS values or variables. - initial: Styling when in the inital width + initial: Styling when in the initial width xs: Styling when in the extra-small width sm: Styling when in the small width md: Styling when in the medium width diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index 195aa6b66..2d5dfc625 100644 --- a/reflex/components/datadisplay/code.py +++ b/reflex/components/datadisplay/code.py @@ -445,7 +445,7 @@ class CodeBlock(Component, MarkdownComponentMap): dark=Theme.one_dark, ) - # react-syntax-highlighter doesnt have an explicit "light" or "dark" theme so we use one-light and one-dark + # react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark # themes respectively to ensure code compatibility. if "theme" in props and not isinstance(props["theme"], Var): props["theme"] = getattr(Theme, format.to_snake_case(props["theme"])) # type: ignore diff --git a/reflex/components/datadisplay/dataeditor.py b/reflex/components/datadisplay/dataeditor.py index 2b80720ea..f71f97713 100644 --- a/reflex/components/datadisplay/dataeditor.py +++ b/reflex/components/datadisplay/dataeditor.py @@ -219,7 +219,7 @@ class DataEditor(NoSSRComponent): # The minimum width a column can be resized to. min_column_width: Var[int] - # Determins the height of each row. + # Determines the height of each row. row_height: Var[int] # Kind of row markers. diff --git a/reflex/components/datadisplay/dataeditor.pyi b/reflex/components/datadisplay/dataeditor.pyi index 17272d8dc..d930fe256 100644 --- a/reflex/components/datadisplay/dataeditor.pyi +++ b/reflex/components/datadisplay/dataeditor.pyi @@ -291,7 +291,7 @@ class DataEditor(NoSSRComponent): max_column_auto_width: The maximum width a column can be automatically sized to. max_column_width: The maximum width a column can be resized to. min_column_width: The minimum width a column can be resized to. - row_height: Determins the height of each row. + row_height: Determines the height of each row. row_markers: Kind of row markers. row_marker_start_index: Changes the starting index for row markers. row_marker_width: Sets the width of row markers in pixels, if unset row markers will automatically size. diff --git a/reflex/components/el/elements/metadata.py b/reflex/components/el/elements/metadata.py index 458253a01..8e0fbcd4d 100644 --- a/reflex/components/el/elements/metadata.py +++ b/reflex/components/el/elements/metadata.py @@ -81,7 +81,7 @@ class Title(Element): tag = "title" -# Had to be named with an underscore so it doesnt conflict with reflex.style Style in pyi +# Had to be named with an underscore so it doesn't conflict with reflex.style Style in pyi class StyleEl(Element): """Display the style element.""" diff --git a/reflex/components/lucide/icon.py b/reflex/components/lucide/icon.py index b32fb8de3..6b7692643 100644 --- a/reflex/components/lucide/icon.py +++ b/reflex/components/lucide/icon.py @@ -8,7 +8,7 @@ from reflex.vars.base import Var class LucideIconComponent(Component): """Lucide Icon Component.""" - library = "lucide-react@0.359.0" + library = "lucide-react@0.469.0" class Icon(LucideIconComponent): @@ -106,6 +106,7 @@ LUCIDE_ICON_LIST = [ "ambulance", "ampersand", "ampersands", + "amphora", "anchor", "angry", "annoyed", @@ -193,6 +194,7 @@ LUCIDE_ICON_LIST = [ "baggage_claim", "ban", "banana", + "bandage", "banknote", "bar_chart", "bar_chart_2", @@ -230,8 +232,10 @@ LUCIDE_ICON_LIST = [ "between_horizontal_start", "between_vertical_end", "between_vertical_start", + "biceps_flexed", "bike", "binary", + "binoculars", "biohazard", "bird", "bitcoin", @@ -278,6 +282,7 @@ LUCIDE_ICON_LIST = [ "boom_box", "bot", "bot_message_square", + "bot_off", "box", "box_select", "boxes", @@ -289,6 +294,7 @@ LUCIDE_ICON_LIST = [ "brick_wall", "briefcase", "briefcase_business", + "briefcase_conveyor_belt", "briefcase_medical", "bring_to_front", "brush", @@ -305,9 +311,13 @@ LUCIDE_ICON_LIST = [ "cake_slice", "calculator", "calendar", + "calendar_1", + "calendar_arrow_down", + "calendar_arrow_up", "calendar_check", "calendar_check_2", "calendar_clock", + "calendar_cog", "calendar_days", "calendar_fold", "calendar_heart", @@ -318,6 +328,7 @@ LUCIDE_ICON_LIST = [ "calendar_plus_2", "calendar_range", "calendar_search", + "calendar_sync", "calendar_x", "calendar_x_2", "camera", @@ -342,6 +353,29 @@ LUCIDE_ICON_LIST = [ "castle", "cat", "cctv", + "chart_area", + "chart_bar", + "chart_bar_big", + "chart_bar_decreasing", + "chart_bar_increasing", + "chart_bar_stacked", + "chart_candlestick", + "chart_column", + "chart_column_big", + "chart_column_decreasing", + "chart_column_increasing", + "chart_column_stacked", + "chart_gantt", + "chart_line", + "chart_network", + "chart_no_axes_column", + "chart_no_axes_column_decreasing", + "chart_no_axes_column_increasing", + "chart_no_axes_combined", + "chart_no_axes_gantt", + "chart_pie", + "chart_scatter", + "chart_spline", "check", "check_check", "chef_hat", @@ -356,6 +390,7 @@ LUCIDE_ICON_LIST = [ "chevrons_down_up", "chevrons_left", "chevrons_left_right", + "chevrons_left_right_ellipsis", "chevrons_right", "chevrons_right_left", "chevrons_up", @@ -374,8 +409,8 @@ LUCIDE_ICON_LIST = [ "circle_arrow_out_up_right", "circle_arrow_right", "circle_arrow_up", - "circle_check_big", "circle_check", + "circle_check_big", "circle_chevron_down", "circle_chevron_left", "circle_chevron_right", @@ -387,13 +422,14 @@ LUCIDE_ICON_LIST = [ "circle_dot_dashed", "circle_ellipsis", "circle_equal", + "circle_fading_arrow_up", "circle_fading_plus", "circle_gauge", "circle_help", "circle_minus", "circle_off", - "circle_parking_off", "circle_parking", + "circle_parking_off", "circle_pause", "circle_percent", "circle_play", @@ -432,7 +468,11 @@ LUCIDE_ICON_LIST = [ "clock_7", "clock_8", "clock_9", + "clock_alert", + "clock_arrow_down", + "clock_arrow_up", "cloud", + "cloud_alert", "cloud_cog", "cloud_download", "cloud_drizzle", @@ -503,6 +543,7 @@ LUCIDE_ICON_LIST = [ "cup_soda", "currency", "cylinder", + "dam", "database", "database_backup", "database_zap", @@ -510,7 +551,9 @@ LUCIDE_ICON_LIST = [ "dessert", "diameter", "diamond", + "diamond_minus", "diamond_percent", + "diamond_plus", "dice_1", "dice_2", "dice_3", @@ -539,6 +582,7 @@ LUCIDE_ICON_LIST = [ "dribbble", "drill", "droplet", + "droplet_off", "droplets", "drum", "drumstick", @@ -554,12 +598,15 @@ LUCIDE_ICON_LIST = [ "ellipsis", "ellipsis_vertical", "equal", + "equal_approximately", "equal_not", "eraser", + "ethernet_port", "euro", "expand", "external_link", "eye", + "eye_closed", "eye_off", "facebook", "factory", @@ -579,6 +626,10 @@ LUCIDE_ICON_LIST = [ "file_bar_chart", "file_bar_chart_2", "file_box", + "file_chart_column", + "file_chart_column_increasing", + "file_chart_line", + "file_chart_pie", "file_check", "file_check_2", "file_clock", @@ -620,6 +671,7 @@ LUCIDE_ICON_LIST = [ "file_type", "file_type_2", "file_up", + "file_user", "file_video", "file_video_2", "file_volume", @@ -661,6 +713,7 @@ LUCIDE_ICON_LIST = [ "folder_check", "folder_clock", "folder_closed", + "folder_code", "folder_cog", "folder_dot", "folder_down", @@ -733,7 +786,12 @@ LUCIDE_ICON_LIST = [ "graduation_cap", "grape", "grid_2x2", + "grid_2x_2", + "grid_2x_2_check", + "grid_2x_2_plus", + "grid_2x_2_x", "grid_3x3", + "grid_3x_3", "grip", "grip_horizontal", "grip_vertical", @@ -762,6 +820,7 @@ LUCIDE_ICON_LIST = [ "heading_4", "heading_5", "heading_6", + "headphone_off", "headphones", "headset", "heart", @@ -779,14 +838,20 @@ LUCIDE_ICON_LIST = [ "hospital", "hotel", "hourglass", + "house", + "house_plug", + "house_plus", "ice_cream_bowl", "ice_cream_cone", + "id_card", "image", "image_down", "image_minus", "image_off", + "image_play", "image_plus", "image_up", + "image_upscale", "images", "import", "inbox", @@ -808,6 +873,7 @@ LUCIDE_ICON_LIST = [ "key_square", "keyboard", "keyboard_music", + "keyboard_off", "lamp", "lamp_ceiling", "lamp_desk", @@ -817,8 +883,9 @@ LUCIDE_ICON_LIST = [ "land_plot", "landmark", "languages", - "laptop_minimal", "laptop", + "laptop_minimal", + "laptop_minimal_check", "lasso", "lasso_select", "laugh", @@ -833,6 +900,8 @@ LUCIDE_ICON_LIST = [ "layout_template", "leaf", "leafy_green", + "lectern", + "letter_text", "library", "library_big", "life_buoy", @@ -845,10 +914,12 @@ LUCIDE_ICON_LIST = [ "link_2_off", "linkedin", "list", + "list_check", "list_checks", "list_collapse", "list_end", "list_filter", + "list_filter_plus", "list_minus", "list_music", "list_ordered", @@ -861,15 +932,17 @@ LUCIDE_ICON_LIST = [ "list_x", "loader", "loader_circle", + "loader_pinwheel", "locate", "locate_fixed", "locate_off", "lock", - "lock_keyhole_open", "lock_keyhole", + "lock_keyhole_open", "lock_open", "log_in", "log_out", + "logs", "lollipop", "luggage", "magnet", @@ -886,7 +959,16 @@ LUCIDE_ICON_LIST = [ "mails", "map", "map_pin", + "map_pin_check", + "map_pin_check_inside", + "map_pin_house", + "map_pin_minus", + "map_pin_minus_inside", "map_pin_off", + "map_pin_plus", + "map_pin_plus_inside", + "map_pin_x", + "map_pin_x_inside", "map_pinned", "martini", "maximize", @@ -915,6 +997,7 @@ LUCIDE_ICON_LIST = [ "message_square_diff", "message_square_dot", "message_square_heart", + "message_square_lock", "message_square_more", "message_square_off", "message_square_plus", @@ -926,8 +1009,9 @@ LUCIDE_ICON_LIST = [ "message_square_x", "messages_square", "mic", - "mic_vocal", "mic_off", + "mic_vocal", + "microchip", "microscope", "microwave", "milestone", @@ -938,6 +1022,7 @@ LUCIDE_ICON_LIST = [ "minus", "monitor", "monitor_check", + "monitor_cog", "monitor_dot", "monitor_down", "monitor_off", @@ -953,8 +1038,10 @@ LUCIDE_ICON_LIST = [ "mountain", "mountain_snow", "mouse", + "mouse_off", "mouse_pointer", "mouse_pointer_2", + "mouse_pointer_ban", "mouse_pointer_click", "move", "move_3d", @@ -991,10 +1078,13 @@ LUCIDE_ICON_LIST = [ "nut_off", "octagon", "octagon_alert", + "octagon_minus", "octagon_pause", "octagon_x", + "omega", "option", "orbit", + "origami", "package", "package_2", "package_check", @@ -1007,6 +1097,7 @@ LUCIDE_ICON_LIST = [ "paint_roller", "paintbrush", "paintbrush_2", + "paintbrush_vertical", "palette", "panel_bottom", "panel_bottom_close", @@ -1036,13 +1127,16 @@ LUCIDE_ICON_LIST = [ "pc_case", "pen", "pen_line", + "pen_off", "pen_tool", "pencil", "pencil_line", + "pencil_off", "pencil_ruler", "pentagon", "percent", "person_standing", + "philippine_peso", "phone", "phone_call", "phone_forwarded", @@ -1058,7 +1152,10 @@ LUCIDE_ICON_LIST = [ "pie_chart", "piggy_bank", "pilcrow", + "pilcrow_left", + "pilcrow_right", "pill", + "pill_bottle", "pin", "pin_off", "pipette", @@ -1084,6 +1181,7 @@ LUCIDE_ICON_LIST = [ "power_off", "presentation", "printer", + "printer_check", "projector", "proportions", "puzzle", @@ -1158,6 +1256,7 @@ LUCIDE_ICON_LIST = [ "satellite_dish", "save", "save_all", + "save_off", "scale", "scale_3d", "scaling", @@ -1165,7 +1264,9 @@ LUCIDE_ICON_LIST = [ "scan_barcode", "scan_eye", "scan_face", + "scan_heart", "scan_line", + "scan_qr_code", "scan_search", "scan_text", "scatter_chart", @@ -1181,6 +1282,7 @@ LUCIDE_ICON_LIST = [ "search_code", "search_slash", "search_x", + "section", "send", "send_horizontal", "send_to_back", @@ -1225,6 +1327,7 @@ LUCIDE_ICON_LIST = [ "signal_low", "signal_medium", "signal_zero", + "signature", "signpost", "signpost_big", "siren", @@ -1234,8 +1337,8 @@ LUCIDE_ICON_LIST = [ "slack", "slash", "slice", - "sliders_vertical", "sliders_horizontal", + "sliders_vertical", "smartphone", "smartphone_charging", "smartphone_nfc", @@ -1259,29 +1362,31 @@ LUCIDE_ICON_LIST = [ "sprout", "square", "square_activity", + "square_arrow_down", "square_arrow_down_left", "square_arrow_down_right", - "square_arrow_down", "square_arrow_left", "square_arrow_out_down_left", "square_arrow_out_down_right", "square_arrow_out_up_left", "square_arrow_out_up_right", "square_arrow_right", + "square_arrow_up", "square_arrow_up_left", "square_arrow_up_right", - "square_arrow_up", "square_asterisk", "square_bottom_dashed_scissors", - "square_check_big", + "square_chart_gantt", "square_check", + "square_check_big", "square_chevron_down", "square_chevron_left", "square_chevron_right", "square_chevron_up", "square_code", - "square_dashed_bottom_code", + "square_dashed", "square_dashed_bottom", + "square_dashed_bottom_code", "square_dashed_kanban", "square_dashed_mouse_pointer", "square_divide", @@ -1295,8 +1400,8 @@ LUCIDE_ICON_LIST = [ "square_menu", "square_minus", "square_mouse_pointer", - "square_parking_off", "square_parking", + "square_parking_off", "square_pen", "square_percent", "square_pi", @@ -1310,10 +1415,11 @@ LUCIDE_ICON_LIST = [ "square_slash", "square_split_horizontal", "square_split_vertical", + "square_square", "square_stack", "square_terminal", - "square_user_round", "square_user", + "square_user_round", "square_x", "squircle", "squirrel", @@ -1350,6 +1456,7 @@ LUCIDE_ICON_LIST = [ "table_cells_merge", "table_cells_split", "table_columns_split", + "table_of_contents", "table_properties", "table_rows_split", "tablet", @@ -1365,11 +1472,11 @@ LUCIDE_ICON_LIST = [ "tangent", "target", "telescope", + "tent", "tent_tree", "terminal", - "test_tube_diagonal", "test_tube", - "tent", + "test_tube_diagonal", "test_tubes", "text", "text_cursor", @@ -1390,11 +1497,14 @@ LUCIDE_ICON_LIST = [ "ticket_plus", "ticket_slash", "ticket_x", + "tickets", + "tickets_plane", "timer", "timer_off", "timer_reset", "toggle_left", "toggle_right", + "toilet", "tornado", "torus", "touchpad", @@ -1416,17 +1526,21 @@ LUCIDE_ICON_LIST = [ "trello", "trending_down", "trending_up", + "trending_up_down", "triangle", - "triangle_right", "triangle_alert", + "triangle_right", "trophy", "truck", "turtle", "tv", "tv_2", + "tv_minimal", + "tv_minimal_play", "twitch", "twitter", "type", + "type_outline", "umbrella", "umbrella_off", "underline", @@ -1437,8 +1551,8 @@ LUCIDE_ICON_LIST = [ "unfold_vertical", "ungroup", "university", - "unlink_2", "unlink", + "unlink_2", "unplug", "upload", "usb", @@ -1446,11 +1560,13 @@ LUCIDE_ICON_LIST = [ "user_check", "user_cog", "user_minus", + "user_pen", "user_plus", "user_round", "user_round_check", "user_round_cog", "user_round_minus", + "user_round_pen", "user_round_plus", "user_round_search", "user_round_x", @@ -1472,14 +1588,16 @@ LUCIDE_ICON_LIST = [ "videotape", "view", "voicemail", + "volleyball", "volume", "volume_1", "volume_2", + "volume_off", "volume_x", "vote", "wallet", - "wallet_minimal", "wallet_cards", + "wallet_minimal", "wallpaper", "wand", "wand_sparkles", @@ -1487,17 +1605,22 @@ LUCIDE_ICON_LIST = [ "washing_machine", "watch", "waves", + "waves_ladder", "waypoints", "webcam", - "webhook_off", "webhook", + "webhook_off", "weight", "wheat", "wheat_off", "whole_word", "wifi", + "wifi_high", + "wifi_low", "wifi_off", + "wifi_zero", "wind", + "wind_arrow_down", "wine", "wine_off", "workflow", diff --git a/reflex/components/lucide/icon.pyi b/reflex/components/lucide/icon.pyi index 7f59edec5..61697aa2a 100644 --- a/reflex/components/lucide/icon.pyi +++ b/reflex/components/lucide/icon.pyi @@ -154,6 +154,7 @@ LUCIDE_ICON_LIST = [ "ambulance", "ampersand", "ampersands", + "amphora", "anchor", "angry", "annoyed", @@ -241,6 +242,7 @@ LUCIDE_ICON_LIST = [ "baggage_claim", "ban", "banana", + "bandage", "banknote", "bar_chart", "bar_chart_2", @@ -278,8 +280,10 @@ LUCIDE_ICON_LIST = [ "between_horizontal_start", "between_vertical_end", "between_vertical_start", + "biceps_flexed", "bike", "binary", + "binoculars", "biohazard", "bird", "bitcoin", @@ -326,6 +330,7 @@ LUCIDE_ICON_LIST = [ "boom_box", "bot", "bot_message_square", + "bot_off", "box", "box_select", "boxes", @@ -337,6 +342,7 @@ LUCIDE_ICON_LIST = [ "brick_wall", "briefcase", "briefcase_business", + "briefcase_conveyor_belt", "briefcase_medical", "bring_to_front", "brush", @@ -353,9 +359,13 @@ LUCIDE_ICON_LIST = [ "cake_slice", "calculator", "calendar", + "calendar_1", + "calendar_arrow_down", + "calendar_arrow_up", "calendar_check", "calendar_check_2", "calendar_clock", + "calendar_cog", "calendar_days", "calendar_fold", "calendar_heart", @@ -366,6 +376,7 @@ LUCIDE_ICON_LIST = [ "calendar_plus_2", "calendar_range", "calendar_search", + "calendar_sync", "calendar_x", "calendar_x_2", "camera", @@ -390,6 +401,29 @@ LUCIDE_ICON_LIST = [ "castle", "cat", "cctv", + "chart_area", + "chart_bar", + "chart_bar_big", + "chart_bar_decreasing", + "chart_bar_increasing", + "chart_bar_stacked", + "chart_candlestick", + "chart_column", + "chart_column_big", + "chart_column_decreasing", + "chart_column_increasing", + "chart_column_stacked", + "chart_gantt", + "chart_line", + "chart_network", + "chart_no_axes_column", + "chart_no_axes_column_decreasing", + "chart_no_axes_column_increasing", + "chart_no_axes_combined", + "chart_no_axes_gantt", + "chart_pie", + "chart_scatter", + "chart_spline", "check", "check_check", "chef_hat", @@ -404,6 +438,7 @@ LUCIDE_ICON_LIST = [ "chevrons_down_up", "chevrons_left", "chevrons_left_right", + "chevrons_left_right_ellipsis", "chevrons_right", "chevrons_right_left", "chevrons_up", @@ -422,8 +457,8 @@ LUCIDE_ICON_LIST = [ "circle_arrow_out_up_right", "circle_arrow_right", "circle_arrow_up", - "circle_check_big", "circle_check", + "circle_check_big", "circle_chevron_down", "circle_chevron_left", "circle_chevron_right", @@ -435,13 +470,14 @@ LUCIDE_ICON_LIST = [ "circle_dot_dashed", "circle_ellipsis", "circle_equal", + "circle_fading_arrow_up", "circle_fading_plus", "circle_gauge", "circle_help", "circle_minus", "circle_off", - "circle_parking_off", "circle_parking", + "circle_parking_off", "circle_pause", "circle_percent", "circle_play", @@ -480,7 +516,11 @@ LUCIDE_ICON_LIST = [ "clock_7", "clock_8", "clock_9", + "clock_alert", + "clock_arrow_down", + "clock_arrow_up", "cloud", + "cloud_alert", "cloud_cog", "cloud_download", "cloud_drizzle", @@ -551,6 +591,7 @@ LUCIDE_ICON_LIST = [ "cup_soda", "currency", "cylinder", + "dam", "database", "database_backup", "database_zap", @@ -558,7 +599,9 @@ LUCIDE_ICON_LIST = [ "dessert", "diameter", "diamond", + "diamond_minus", "diamond_percent", + "diamond_plus", "dice_1", "dice_2", "dice_3", @@ -587,6 +630,7 @@ LUCIDE_ICON_LIST = [ "dribbble", "drill", "droplet", + "droplet_off", "droplets", "drum", "drumstick", @@ -602,12 +646,15 @@ LUCIDE_ICON_LIST = [ "ellipsis", "ellipsis_vertical", "equal", + "equal_approximately", "equal_not", "eraser", + "ethernet_port", "euro", "expand", "external_link", "eye", + "eye_closed", "eye_off", "facebook", "factory", @@ -627,6 +674,10 @@ LUCIDE_ICON_LIST = [ "file_bar_chart", "file_bar_chart_2", "file_box", + "file_chart_column", + "file_chart_column_increasing", + "file_chart_line", + "file_chart_pie", "file_check", "file_check_2", "file_clock", @@ -668,6 +719,7 @@ LUCIDE_ICON_LIST = [ "file_type", "file_type_2", "file_up", + "file_user", "file_video", "file_video_2", "file_volume", @@ -709,6 +761,7 @@ LUCIDE_ICON_LIST = [ "folder_check", "folder_clock", "folder_closed", + "folder_code", "folder_cog", "folder_dot", "folder_down", @@ -781,7 +834,12 @@ LUCIDE_ICON_LIST = [ "graduation_cap", "grape", "grid_2x2", + "grid_2x_2", + "grid_2x_2_check", + "grid_2x_2_plus", + "grid_2x_2_x", "grid_3x3", + "grid_3x_3", "grip", "grip_horizontal", "grip_vertical", @@ -810,6 +868,7 @@ LUCIDE_ICON_LIST = [ "heading_4", "heading_5", "heading_6", + "headphone_off", "headphones", "headset", "heart", @@ -827,14 +886,20 @@ LUCIDE_ICON_LIST = [ "hospital", "hotel", "hourglass", + "house", + "house_plug", + "house_plus", "ice_cream_bowl", "ice_cream_cone", + "id_card", "image", "image_down", "image_minus", "image_off", + "image_play", "image_plus", "image_up", + "image_upscale", "images", "import", "inbox", @@ -856,6 +921,7 @@ LUCIDE_ICON_LIST = [ "key_square", "keyboard", "keyboard_music", + "keyboard_off", "lamp", "lamp_ceiling", "lamp_desk", @@ -865,8 +931,9 @@ LUCIDE_ICON_LIST = [ "land_plot", "landmark", "languages", - "laptop_minimal", "laptop", + "laptop_minimal", + "laptop_minimal_check", "lasso", "lasso_select", "laugh", @@ -881,6 +948,8 @@ LUCIDE_ICON_LIST = [ "layout_template", "leaf", "leafy_green", + "lectern", + "letter_text", "library", "library_big", "life_buoy", @@ -893,10 +962,12 @@ LUCIDE_ICON_LIST = [ "link_2_off", "linkedin", "list", + "list_check", "list_checks", "list_collapse", "list_end", "list_filter", + "list_filter_plus", "list_minus", "list_music", "list_ordered", @@ -909,15 +980,17 @@ LUCIDE_ICON_LIST = [ "list_x", "loader", "loader_circle", + "loader_pinwheel", "locate", "locate_fixed", "locate_off", "lock", - "lock_keyhole_open", "lock_keyhole", + "lock_keyhole_open", "lock_open", "log_in", "log_out", + "logs", "lollipop", "luggage", "magnet", @@ -934,7 +1007,16 @@ LUCIDE_ICON_LIST = [ "mails", "map", "map_pin", + "map_pin_check", + "map_pin_check_inside", + "map_pin_house", + "map_pin_minus", + "map_pin_minus_inside", "map_pin_off", + "map_pin_plus", + "map_pin_plus_inside", + "map_pin_x", + "map_pin_x_inside", "map_pinned", "martini", "maximize", @@ -963,6 +1045,7 @@ LUCIDE_ICON_LIST = [ "message_square_diff", "message_square_dot", "message_square_heart", + "message_square_lock", "message_square_more", "message_square_off", "message_square_plus", @@ -974,8 +1057,9 @@ LUCIDE_ICON_LIST = [ "message_square_x", "messages_square", "mic", - "mic_vocal", "mic_off", + "mic_vocal", + "microchip", "microscope", "microwave", "milestone", @@ -986,6 +1070,7 @@ LUCIDE_ICON_LIST = [ "minus", "monitor", "monitor_check", + "monitor_cog", "monitor_dot", "monitor_down", "monitor_off", @@ -1001,8 +1086,10 @@ LUCIDE_ICON_LIST = [ "mountain", "mountain_snow", "mouse", + "mouse_off", "mouse_pointer", "mouse_pointer_2", + "mouse_pointer_ban", "mouse_pointer_click", "move", "move_3d", @@ -1039,10 +1126,13 @@ LUCIDE_ICON_LIST = [ "nut_off", "octagon", "octagon_alert", + "octagon_minus", "octagon_pause", "octagon_x", + "omega", "option", "orbit", + "origami", "package", "package_2", "package_check", @@ -1055,6 +1145,7 @@ LUCIDE_ICON_LIST = [ "paint_roller", "paintbrush", "paintbrush_2", + "paintbrush_vertical", "palette", "panel_bottom", "panel_bottom_close", @@ -1084,13 +1175,16 @@ LUCIDE_ICON_LIST = [ "pc_case", "pen", "pen_line", + "pen_off", "pen_tool", "pencil", "pencil_line", + "pencil_off", "pencil_ruler", "pentagon", "percent", "person_standing", + "philippine_peso", "phone", "phone_call", "phone_forwarded", @@ -1106,7 +1200,10 @@ LUCIDE_ICON_LIST = [ "pie_chart", "piggy_bank", "pilcrow", + "pilcrow_left", + "pilcrow_right", "pill", + "pill_bottle", "pin", "pin_off", "pipette", @@ -1132,6 +1229,7 @@ LUCIDE_ICON_LIST = [ "power_off", "presentation", "printer", + "printer_check", "projector", "proportions", "puzzle", @@ -1206,6 +1304,7 @@ LUCIDE_ICON_LIST = [ "satellite_dish", "save", "save_all", + "save_off", "scale", "scale_3d", "scaling", @@ -1213,7 +1312,9 @@ LUCIDE_ICON_LIST = [ "scan_barcode", "scan_eye", "scan_face", + "scan_heart", "scan_line", + "scan_qr_code", "scan_search", "scan_text", "scatter_chart", @@ -1229,6 +1330,7 @@ LUCIDE_ICON_LIST = [ "search_code", "search_slash", "search_x", + "section", "send", "send_horizontal", "send_to_back", @@ -1273,6 +1375,7 @@ LUCIDE_ICON_LIST = [ "signal_low", "signal_medium", "signal_zero", + "signature", "signpost", "signpost_big", "siren", @@ -1282,8 +1385,8 @@ LUCIDE_ICON_LIST = [ "slack", "slash", "slice", - "sliders_vertical", "sliders_horizontal", + "sliders_vertical", "smartphone", "smartphone_charging", "smartphone_nfc", @@ -1307,29 +1410,31 @@ LUCIDE_ICON_LIST = [ "sprout", "square", "square_activity", + "square_arrow_down", "square_arrow_down_left", "square_arrow_down_right", - "square_arrow_down", "square_arrow_left", "square_arrow_out_down_left", "square_arrow_out_down_right", "square_arrow_out_up_left", "square_arrow_out_up_right", "square_arrow_right", + "square_arrow_up", "square_arrow_up_left", "square_arrow_up_right", - "square_arrow_up", "square_asterisk", "square_bottom_dashed_scissors", - "square_check_big", + "square_chart_gantt", "square_check", + "square_check_big", "square_chevron_down", "square_chevron_left", "square_chevron_right", "square_chevron_up", "square_code", - "square_dashed_bottom_code", + "square_dashed", "square_dashed_bottom", + "square_dashed_bottom_code", "square_dashed_kanban", "square_dashed_mouse_pointer", "square_divide", @@ -1343,8 +1448,8 @@ LUCIDE_ICON_LIST = [ "square_menu", "square_minus", "square_mouse_pointer", - "square_parking_off", "square_parking", + "square_parking_off", "square_pen", "square_percent", "square_pi", @@ -1358,10 +1463,11 @@ LUCIDE_ICON_LIST = [ "square_slash", "square_split_horizontal", "square_split_vertical", + "square_square", "square_stack", "square_terminal", - "square_user_round", "square_user", + "square_user_round", "square_x", "squircle", "squirrel", @@ -1398,6 +1504,7 @@ LUCIDE_ICON_LIST = [ "table_cells_merge", "table_cells_split", "table_columns_split", + "table_of_contents", "table_properties", "table_rows_split", "tablet", @@ -1413,11 +1520,11 @@ LUCIDE_ICON_LIST = [ "tangent", "target", "telescope", + "tent", "tent_tree", "terminal", - "test_tube_diagonal", "test_tube", - "tent", + "test_tube_diagonal", "test_tubes", "text", "text_cursor", @@ -1438,11 +1545,14 @@ LUCIDE_ICON_LIST = [ "ticket_plus", "ticket_slash", "ticket_x", + "tickets", + "tickets_plane", "timer", "timer_off", "timer_reset", "toggle_left", "toggle_right", + "toilet", "tornado", "torus", "touchpad", @@ -1464,17 +1574,21 @@ LUCIDE_ICON_LIST = [ "trello", "trending_down", "trending_up", + "trending_up_down", "triangle", - "triangle_right", "triangle_alert", + "triangle_right", "trophy", "truck", "turtle", "tv", "tv_2", + "tv_minimal", + "tv_minimal_play", "twitch", "twitter", "type", + "type_outline", "umbrella", "umbrella_off", "underline", @@ -1485,8 +1599,8 @@ LUCIDE_ICON_LIST = [ "unfold_vertical", "ungroup", "university", - "unlink_2", "unlink", + "unlink_2", "unplug", "upload", "usb", @@ -1494,11 +1608,13 @@ LUCIDE_ICON_LIST = [ "user_check", "user_cog", "user_minus", + "user_pen", "user_plus", "user_round", "user_round_check", "user_round_cog", "user_round_minus", + "user_round_pen", "user_round_plus", "user_round_search", "user_round_x", @@ -1520,14 +1636,16 @@ LUCIDE_ICON_LIST = [ "videotape", "view", "voicemail", + "volleyball", "volume", "volume_1", "volume_2", + "volume_off", "volume_x", "vote", "wallet", - "wallet_minimal", "wallet_cards", + "wallet_minimal", "wallpaper", "wand", "wand_sparkles", @@ -1535,17 +1653,22 @@ LUCIDE_ICON_LIST = [ "washing_machine", "watch", "waves", + "waves_ladder", "waypoints", "webcam", - "webhook_off", "webhook", + "webhook_off", "weight", "wheat", "wheat_off", "whole_word", "wifi", + "wifi_high", + "wifi_low", "wifi_off", + "wifi_zero", "wind", + "wind_arrow_down", "wine", "wine_off", "workflow", diff --git a/reflex/components/plotly/plotly.py b/reflex/components/plotly/plotly.py index d69070ed3..3bdef7875 100644 --- a/reflex/components/plotly/plotly.py +++ b/reflex/components/plotly/plotly.py @@ -149,10 +149,10 @@ class Plotly(NoSSRComponent): # Fired when a plot element is hovered over. on_hover: EventHandler[_event_points_data_signature] - # Fired after the plot is layed out (zoom, pan, etc). + # Fired after the plot is laid out (zoom, pan, etc). on_relayout: EventHandler[no_args_event_spec] - # Fired while the plot is being layed out. + # Fired while the plot is being laid out. on_relayouting: EventHandler[no_args_event_spec] # Fired after the plot style is changed. @@ -167,7 +167,7 @@ class Plotly(NoSSRComponent): # Fired while dragging a selection. on_selecting: EventHandler[_event_points_data_signature] - # Fired while an animation is occuring. + # Fired while an animation is occurring. on_transitioning: EventHandler[no_args_event_spec] # Fired when a transition is stopped early. diff --git a/reflex/components/plotly/plotly.pyi b/reflex/components/plotly/plotly.pyi index 2d606b8a2..ca1ddef39 100644 --- a/reflex/components/plotly/plotly.pyi +++ b/reflex/components/plotly/plotly.pyi @@ -130,13 +130,13 @@ class Plotly(NoSSRComponent): 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 layed out (zoom, pan, etc). - on_relayouting: Fired while the plot is being layed out. + 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 occuring. + 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. diff --git a/reflex/components/radix/primitives/slider.py b/reflex/components/radix/primitives/slider.py index 90d0920bd..68f39e32c 100644 --- a/reflex/components/radix/primitives/slider.py +++ b/reflex/components/radix/primitives/slider.py @@ -34,7 +34,7 @@ def on_value_event_spec( class SliderRoot(SliderComponent): - """The Slider component comtaining all slider parts.""" + """The Slider component containing all slider parts.""" tag = "Root" alias = "RadixSliderRoot" diff --git a/reflex/components/radix/themes/layout/center.pyi b/reflex/components/radix/themes/layout/center.pyi index c166b4c26..59062b293 100644 --- a/reflex/components/radix/themes/layout/center.pyi +++ b/reflex/components/radix/themes/layout/center.pyi @@ -150,7 +150,7 @@ class Center(Flex): Args: *children: Child components. as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. - direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" diff --git a/reflex/components/radix/themes/layout/flex.py b/reflex/components/radix/themes/layout/flex.py index 4403a9542..39982e4f4 100644 --- a/reflex/components/radix/themes/layout/flex.py +++ b/reflex/components/radix/themes/layout/flex.py @@ -22,7 +22,7 @@ class Flex(elements.Div, RadixThemesComponent): # Change the default rendered element for the one passed as a child, merging their props and behavior. as_child: Var[bool] - # How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + # How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" direction: Var[Responsive[LiteralFlexDirection]] # Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" diff --git a/reflex/components/radix/themes/layout/flex.pyi b/reflex/components/radix/themes/layout/flex.pyi index 43f42107d..dafa91c6c 100644 --- a/reflex/components/radix/themes/layout/flex.pyi +++ b/reflex/components/radix/themes/layout/flex.pyi @@ -153,7 +153,7 @@ class Flex(elements.Div, RadixThemesComponent): Args: *children: Child components. as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. - direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" diff --git a/reflex/components/radix/themes/layout/grid.py b/reflex/components/radix/themes/layout/grid.py index 3601e213a..133e19d10 100644 --- a/reflex/components/radix/themes/layout/grid.py +++ b/reflex/components/radix/themes/layout/grid.py @@ -27,7 +27,7 @@ class Grid(elements.Div, RadixThemesComponent): # Number of rows rows: Var[Responsive[str]] - # How the grid items are layed out: "row" | "column" | "dense" | "row-dense" | "column-dense" + # How the grid items are laid out: "row" | "column" | "dense" | "row-dense" | "column-dense" flow: Var[Responsive[LiteralGridFlow]] # Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" diff --git a/reflex/components/radix/themes/layout/grid.pyi b/reflex/components/radix/themes/layout/grid.pyi index 2b0e13365..55153fca3 100644 --- a/reflex/components/radix/themes/layout/grid.pyi +++ b/reflex/components/radix/themes/layout/grid.pyi @@ -184,7 +184,7 @@ class Grid(elements.Div, RadixThemesComponent): as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. columns: Number of columns rows: Number of rows - flow: How the grid items are layed out: "row" | "column" | "dense" | "row-dense" | "column-dense" + flow: How the grid items are laid out: "row" | "column" | "dense" | "row-dense" | "column-dense" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" spacing: Gap between children: "0" - "9" diff --git a/reflex/components/radix/themes/layout/spacer.pyi b/reflex/components/radix/themes/layout/spacer.pyi index 8fb756741..9854aa1ba 100644 --- a/reflex/components/radix/themes/layout/spacer.pyi +++ b/reflex/components/radix/themes/layout/spacer.pyi @@ -150,7 +150,7 @@ class Spacer(Flex): Args: *children: Child components. as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. - direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" diff --git a/reflex/components/radix/themes/layout/stack.pyi b/reflex/components/radix/themes/layout/stack.pyi index cd4b90952..d96c72504 100644 --- a/reflex/components/radix/themes/layout/stack.pyi +++ b/reflex/components/radix/themes/layout/stack.pyi @@ -126,7 +126,7 @@ class Stack(Flex): spacing: Gap between children: "0" - "9" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. - direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" access_key: Provides a hint for generating a keyboard shortcut for the current element. @@ -258,7 +258,7 @@ class VStack(Stack): Args: *children: The children of the stack. - direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" spacing: Gap between children: "0" - "9" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. @@ -393,7 +393,7 @@ class HStack(Stack): Args: *children: The children of the stack. - direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" + direction: How child items are laid out: "row" | "column" | "row-reverse" | "column-reverse" spacing: Gap between children: "0" - "9" align: Alignment of children along the main axis: "start" | "center" | "end" | "baseline" | "stretch" as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. diff --git a/reflex/components/recharts/cartesian.py b/reflex/components/recharts/cartesian.py index 7fc9a27a1..9f6bf672b 100644 --- a/reflex/components/recharts/cartesian.py +++ b/reflex/components/recharts/cartesian.py @@ -42,7 +42,7 @@ class Axis(Recharts): # The width of axis which is usually calculated internally. width: Var[Union[str, int]] - # The height of axis, which can be setted by user. + # The height of axis, which can be set by user. height: Var[Union[str, int]] # The type of axis 'number' | 'category' @@ -60,7 +60,7 @@ class Axis(Recharts): # Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True allow_duplicated_category: Var[bool] - # The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"] + # The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"] domain: Var[List] # If set false, no axis line will be drawn. Default: True diff --git a/reflex/components/recharts/cartesian.pyi b/reflex/components/recharts/cartesian.pyi index 84f16661d..64921ec55 100644 --- a/reflex/components/recharts/cartesian.pyi +++ b/reflex/components/recharts/cartesian.pyi @@ -144,13 +144,13 @@ class Axis(Recharts): data_key: The key of data displayed in the axis. hide: If set true, the axis do not display in the chart. Default: False width: The width of axis which is usually calculated internally. - height: The height of axis, which can be setted by user. + height: The height of axis, which can be set by user. type_: The type of axis 'number' | 'category' interval: If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. Default: "preserveEnd" allow_decimals: Allow the ticks of Axis to be decimals or not. Default: True allow_data_overflow: When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. Default: False allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True - domain: The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"] + domain: The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"] axis_line: If set false, no axis line will be drawn. Default: True mirror: If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. Default: False reversed: Reverse the ticks or not. Default: False @@ -330,13 +330,13 @@ class XAxis(Axis): data_key: The key of data displayed in the axis. hide: If set true, the axis do not display in the chart. Default: False width: The width of axis which is usually calculated internally. - height: The height of axis, which can be setted by user. + height: The height of axis, which can be set by user. type_: The type of axis 'number' | 'category' interval: If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. Default: "preserveEnd" allow_decimals: Allow the ticks of Axis to be decimals or not. Default: True allow_data_overflow: When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. Default: False allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True - domain: The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"] + domain: The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"] axis_line: If set false, no axis line will be drawn. Default: True mirror: If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. Default: False reversed: Reverse the ticks or not. Default: False @@ -512,13 +512,13 @@ class YAxis(Axis): data_key: The key of data displayed in the axis. hide: If set true, the axis do not display in the chart. Default: False width: The width of axis which is usually calculated internally. - height: The height of axis, which can be setted by user. + height: The height of axis, which can be set by user. type_: The type of axis 'number' | 'category' interval: If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. Default: "preserveEnd" allow_decimals: Allow the ticks of Axis to be decimals or not. Default: True allow_data_overflow: When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. Default: False allow_duplicated_category: Allow the axis has duplicated categorys or not when the type of axis is "category". Default: True - domain: The range of the axis. Work best in conjuction with allow_data_overflow. Default: [0, "auto"] + domain: The range of the axis. Work best in conjunction with allow_data_overflow. Default: [0, "auto"] axis_line: If set false, no axis line will be drawn. Default: True mirror: If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. Default: False reversed: Reverse the ticks or not. Default: False diff --git a/reflex/components/recharts/polar.py b/reflex/components/recharts/polar.py index dea42af7b..1f4974d4c 100644 --- a/reflex/components/recharts/polar.py +++ b/reflex/components/recharts/polar.py @@ -124,7 +124,7 @@ class Radar(Recharts): # The key of a group of data which should be unique in a radar chart. data_key: Var[Union[str, int]] - # The coordinates of all the vertexes of the radar shape, like [{ x, y }]. + # The coordinates of all the vertices of the radar shape, like [{ x, y }]. points: Var[List[Dict[str, Any]]] # If false set, dots will not be drawn. Default: True @@ -373,7 +373,7 @@ class PolarRadiusAxis(Recharts): # The count of axis ticks. Not used if 'type' is 'category'. Default: 5 tick_count: Var[int] - # If 'auto' set, the scale funtion is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto" + # If 'auto' set, the scale function is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto" scale: Var[LiteralScale] # Valid children components diff --git a/reflex/components/recharts/polar.pyi b/reflex/components/recharts/polar.pyi index da0602fb0..5388fbcf2 100644 --- a/reflex/components/recharts/polar.pyi +++ b/reflex/components/recharts/polar.pyi @@ -200,7 +200,7 @@ class Radar(Recharts): Args: *children: The children of the component. data_key: The key of a group of data which should be unique in a radar chart. - points: The coordinates of all the vertexes of the radar shape, like [{ x, y }]. + points: The coordinates of all the vertices of the radar shape, like [{ x, y }]. dot: If false set, dots will not be drawn. Default: True stroke: Stoke color. Default: rx.color("accent", 9) fill: Fill color. Default: rx.color("accent", 3) @@ -574,7 +574,7 @@ class PolarRadiusAxis(Recharts): axis_line: If false set, axis line will not be drawn. If true set, axis line will be drawn which have the props calculated internally. If object set, axis line will be drawn which have the props mergered by the internal calculated props and the option. Default: True tick: If false set, ticks will not be drawn. If true set, ticks will be drawn which have the props calculated internally. If object set, ticks will be drawn which have the props mergered by the internal calculated props and the option. Default: True tick_count: The count of axis ticks. Not used if 'type' is 'category'. Default: 5 - scale: If 'auto' set, the scale funtion is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto" + scale: If 'auto' set, the scale function is linear scale. 'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' | 'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utc' | 'sequential' | 'threshold'. Default: "auto" domain: The domain of the polar radius axis, specifying the minimum and maximum values. Default: [0, "auto"] stroke: The stroke color of axis. Default: rx.color("gray", 10) style: The style of the component. diff --git a/reflex/components/sonner/toast.py b/reflex/components/sonner/toast.py index 836c19bf9..b978409ab 100644 --- a/reflex/components/sonner/toast.py +++ b/reflex/components/sonner/toast.py @@ -167,7 +167,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps): class Toaster(Component): """A Toaster Component for displaying toast notifications.""" - library: str = "sonner@1.5.0" + library: str = "sonner@1.7.1" tag = "Toaster" diff --git a/reflex/constants/base.py b/reflex/constants/base.py index 3266043c5..af96583ad 100644 --- a/reflex/constants/base.py +++ b/reflex/constants/base.py @@ -27,7 +27,7 @@ class Dirs(SimpleNamespace): UPLOADED_FILES = "uploaded_files" # The name of the assets directory. APP_ASSETS = "assets" - # The name of the assets directory for external ressource (a subfolder of APP_ASSETS). + # The name of the assets directory for external resources (a subfolder of APP_ASSETS). EXTERNAL_APP_ASSETS = "external" # The name of the utils file. UTILS = "utils" diff --git a/reflex/event.py b/reflex/event.py index e4ca55c70..0a4a01837 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -431,6 +431,96 @@ class EventChain(EventActionsMixin): invocation: Optional[Var] = dataclasses.field(default=None) + @classmethod + def create( + cls, + value: EventType, + args_spec: ArgsSpec | Sequence[ArgsSpec], + key: Optional[str] = None, + ) -> Union[EventChain, Var]: + """Create an event chain from a variety of input types. + + Args: + value: The value to create the event chain from. + args_spec: The args_spec of the event trigger being bound. + key: The key of the event trigger being bound. + + Returns: + The event chain. + + Raises: + ValueError: If the value is not a valid event chain. + """ + # If it's an event chain var, return it. + if isinstance(value, Var): + if isinstance(value, EventChainVar): + return value + elif isinstance(value, EventVar): + value = [value] + elif issubclass(value._var_type, (EventChain, EventSpec)): + return cls.create( + value=value.guess_type(), + args_spec=args_spec, + key=key, + ) + else: + raise ValueError( + f"Invalid event chain: {value!s} of type {value._var_type}" + ) + elif isinstance(value, EventChain): + # Trust that the caller knows what they're doing passing an EventChain directly + return value + + # If the input is a single event handler, wrap it in a list. + if isinstance(value, (EventHandler, EventSpec)): + value = [value] + + # If the input is a list of event handlers, create an event chain. + if isinstance(value, List): + events: List[Union[EventSpec, EventVar]] = [] + for v in value: + if isinstance(v, (EventHandler, EventSpec)): + # Call the event handler to get the event. + events.append(call_event_handler(v, args_spec, key=key)) + elif isinstance(v, Callable): + # Call the lambda to get the event chain. + result = call_event_fn(v, args_spec, key=key) + if isinstance(result, Var): + raise ValueError( + f"Invalid event chain: {v}. Cannot use a Var-returning " + "lambda inside an EventChain list." + ) + events.extend(result) + elif isinstance(v, EventVar): + events.append(v) + else: + raise ValueError(f"Invalid event: {v}") + + # If the input is a callable, create an event chain. + elif isinstance(value, Callable): + result = call_event_fn(value, args_spec, key=key) + if isinstance(result, Var): + # Recursively call this function if the lambda returned an EventChain Var. + return cls.create(value=result, args_spec=args_spec, key=key) + events = [*result] + + # Otherwise, raise an error. + else: + raise ValueError(f"Invalid event chain: {value}") + + # Add args to the event specs if necessary. + events = [ + (e.with_args(get_handler_args(e)) if isinstance(e, EventSpec) else e) + for e in events + ] + + # Return the event chain. + return cls( + events=events, + args_spec=args_spec, + event_actions={}, + ) + @dataclasses.dataclass( init=True, diff --git a/reflex/istate/data.py b/reflex/istate/data.py index 9f6e3b3f4..987921889 100644 --- a/reflex/istate/data.py +++ b/reflex/istate/data.py @@ -26,7 +26,7 @@ class HeaderData: accept_language: str = "" def __init__(self, router_data: Optional[dict] = None): - """Initalize the HeaderData object based on router_data. + """Initialize the HeaderData object based on router_data. Args: router_data: the router_data dict. @@ -51,7 +51,7 @@ class PageData: params: dict = dataclasses.field(default_factory=dict) def __init__(self, router_data: Optional[dict] = None): - """Initalize the PageData object based on router_data. + """Initialize the PageData object based on router_data. Args: router_data: the router_data dict. @@ -91,7 +91,7 @@ class SessionData: session_id: str = "" def __init__(self, router_data: Optional[dict] = None): - """Initalize the SessionData object based on router_data. + """Initialize the SessionData object based on router_data. Args: router_data: the router_data dict. diff --git a/reflex/model.py b/reflex/model.py index cb8bed29b..295159de0 100644 --- a/reflex/model.py +++ b/reflex/model.py @@ -141,15 +141,13 @@ def get_async_engine(url: str | None) -> sqlalchemy.ext.asyncio.AsyncEngine: return _ASYNC_ENGINE[url] -async def get_db_status() -> bool: +async def get_db_status() -> dict[str, bool]: """Checks the status of the database connection. Attempts to connect to the database and execute a simple query to verify connectivity. Returns: - bool: The status of the database connection: - - True: The database is accessible. - - False: The database is not accessible. + The status of the database connection. """ status = True try: @@ -159,7 +157,7 @@ async def get_db_status() -> bool: except sqlalchemy.exc.OperationalError: status = False - return status + return {"db": status} SQLModelOrSqlAlchemy = Union[ @@ -535,6 +533,7 @@ def asession(url: str | None = None) -> AsyncSession: _AsyncSessionLocal[url] = sqlalchemy.ext.asyncio.async_sessionmaker( bind=get_async_engine(url), class_=AsyncSession, + expire_on_commit=False, autocommit=False, autoflush=False, ) diff --git a/reflex/page.py b/reflex/page.py index 8cc031757..44ca6ab31 100644 --- a/reflex/page.py +++ b/reflex/page.py @@ -70,7 +70,7 @@ def get_decorated_pages(omit_implicit_routes=True) -> list[dict[str, Any]]: """Get the decorated pages. Args: - omit_implicit_routes: Whether to omit pages where the route will be implicitely guessed later. + omit_implicit_routes: Whether to omit pages where the route will be implicitly guessed later. Returns: The decorated pages. diff --git a/reflex/reflex.py b/reflex/reflex.py index 20866941f..e333bfbd1 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -329,13 +329,14 @@ def export( @cli.command() def login(loglevel: constants.LogLevel = typer.Option(config.loglevel)): - """Authenicate with experimental Reflex hosting service.""" + """Authenticate with experimental Reflex hosting service.""" from reflex_cli.v2 import cli as hosting_cli check_version() validated_info = hosting_cli.login() if validated_info is not None: + _skip_compile() # Allow running outside of an app dir telemetry.send("login", user_uuid=validated_info.get("user_id")) diff --git a/reflex/state.py b/reflex/state.py index e7e6bcf32..c30a4038d 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1193,6 +1193,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): continue dynamic_vars[param] = DynamicRouteVar( fget=func, + auto_deps=False, + deps=["router"], cache=True, _js_expr=param, _var_data=VarData.from_state(cls), @@ -1240,13 +1242,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if not super().__getattribute__("__dict__"): return super().__getattribute__(name) - inherited_vars = { - **super().__getattribute__("inherited_vars"), - **super().__getattribute__("inherited_backend_vars"), - } + # Fast path for dunder + if name.startswith("__"): + return super().__getattribute__(name) # For now, handle router_data updates as a special case. - if name in inherited_vars or name == constants.ROUTER_DATA: + if ( + name == constants.ROUTER_DATA + or name in super().__getattribute__("inherited_vars") + or name in super().__getattribute__("inherited_backend_vars") + ): parent_state = super().__getattribute__("parent_state") if parent_state is not None: return getattr(parent_state, name) @@ -1301,8 +1306,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): value = value.__wrapped__ # Set the var on the parent state. - inherited_vars = {**self.inherited_vars, **self.inherited_backend_vars} - if name in inherited_vars: + if name in self.inherited_vars or name in self.inherited_backend_vars: setattr(self.parent_state, name, value) return diff --git a/reflex/testing.py b/reflex/testing.py index 29884ac77..582d7f8c9 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -53,6 +53,7 @@ from reflex.state import ( StateManagerRedis, reload_state_module, ) +from reflex.utils import console try: from selenium import webdriver # pyright: ignore [reportMissingImports] @@ -392,7 +393,7 @@ class AppHarness: ) if not line: break - print(line) # for pytest diagnosis + print(line) # for pytest diagnosis #noqa: T201 m = re.search(reflex.constants.Next.FRONTEND_LISTENING_REGEX, line) if m is not None: self.frontend_url = m.group(1) @@ -411,11 +412,10 @@ class AppHarness: ) # catch I/O operation on closed file. except ValueError as e: - print(e) + console.error(str(e)) break if not line: break - print(line) self.frontend_output_thread = threading.Thread(target=consume_frontend_output) self.frontend_output_thread.start() diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 25e753d09..797d28701 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -109,7 +109,7 @@ def check_latest_package_version(package_name: str): console.warn( f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'" ) - # Check for depreacted python versions + # Check for deprecated python versions _python_version_check() except Exception: pass @@ -372,16 +372,13 @@ def parse_redis_url() -> str | dict | None: return config.redis_url -async def get_redis_status() -> bool | None: +async def get_redis_status() -> dict[str, bool | None]: """Checks the status of the Redis connection. Attempts to connect to Redis and send a ping command to verify connectivity. Returns: - bool or None: The status of the Redis connection: - - True: Redis is accessible and responding. - - False: Redis is not accessible due to a connection error. - - None: Redis not used i.e redis_url is not set in rxconfig. + The status of the Redis connection. """ try: status = True @@ -393,7 +390,7 @@ async def get_redis_status() -> bool | None: except exceptions.RedisError: status = False - return status + return {"redis": status} def validate_app_name(app_name: str | None = None) -> str: @@ -594,7 +591,7 @@ def initialize_web_directory(): """Initialize the web directory on reflex init.""" console.log("Initializing the web directory.") - # Re-use the hash if one is already created, so we don't over-write it when running reflex init + # Reuse the hash if one is already created, so we don't over-write it when running reflex init project_hash = get_project_hash() path_ops.cp(constants.Templates.Dirs.WEB_TEMPLATE, str(get_web_dir())) @@ -647,7 +644,7 @@ def initialize_bun_config(): def init_reflex_json(project_hash: int | None): """Write the hash of the Reflex project to a REFLEX_JSON. - Re-use the hash if one is already created, therefore do not + Reuse the hash if one is already created, therefore do not overwrite it every time we run the reflex init command . @@ -1177,6 +1174,24 @@ def initialize_frontend_dependencies(): initialize_web_directory() +def check_db_used() -> bool: + """Check if the database is used. + + Returns: + True if the database is used. + """ + return bool(get_config().db_url) + + +def check_redis_used() -> bool: + """Check if Redis is used. + + Returns: + True if Redis is used. + """ + return bool(get_config().redis_url) + + def check_db_initialized() -> bool: """Check if the database migrations are initialized. diff --git a/reflex/utils/processes.py b/reflex/utils/processes.py index ef2d36401..871b5f323 100644 --- a/reflex/utils/processes.py +++ b/reflex/utils/processes.py @@ -118,7 +118,7 @@ def handle_port(service_name: str, port: str, default_port: str) -> str: """Change port if the specified port is in use and is not explicitly specified as a CLI arg or config arg. otherwise tell the user the port is in use and exit the app. - We make an assumption that when port is the default port,then it hasnt been explicitly set since its not straightforward + We make an assumption that when port is the default port,then it hasn't been explicitly set since its not straightforward to know whether a port was explicitly provided by the user unless its any other than the default. Args: @@ -351,7 +351,7 @@ def atexit_handler(): def get_command_with_loglevel(command: list[str]) -> list[str]: """Add the right loglevel flag to the designated command. - npm uses --loglevel , Bun doesnt use the --loglevel flag and + npm uses --loglevel , Bun doesn't use the --loglevel flag and runs in debug mode by default. Args: diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py index c3a7b0ed1..152c06949 100644 --- a/reflex/utils/pyi_generator.py +++ b/reflex/utils/pyi_generator.py @@ -1023,7 +1023,7 @@ class InitStubGenerator(StubGenerator): class PyiGenerator: """A .pyi file generator that will scan all defined Component in Reflex and - generate the approriate stub. + generate the appropriate stub. """ modules: list = [] @@ -1202,4 +1202,4 @@ class PyiGenerator: or "Var[Template]" in line ): line = line.rstrip() + " # type: ignore\n" - print(line, end="") + print(line, end="") # noqa: T201 diff --git a/reflex/utils/telemetry.py b/reflex/utils/telemetry.py index b24b4d3bf..fc90932a6 100644 --- a/reflex/utils/telemetry.py +++ b/reflex/utils/telemetry.py @@ -7,6 +7,7 @@ import dataclasses import multiprocessing import platform import warnings +from contextlib import suppress from reflex.config import environment @@ -171,10 +172,11 @@ def _send(event, telemetry_enabled, **kwargs): if not telemetry_enabled: return False - event_data = _prepare_event(event, **kwargs) - if not event_data: - return False - return _send_event(event_data) + with suppress(Exception): + event_data = _prepare_event(event, **kwargs) + if not event_data: + return False + return _send_event(event_data) def send(event: str, telemetry_enabled: bool | None = None, **kwargs): diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py index 476c1e32c..5864e70b9 100644 --- a/reflex/vars/sequence.py +++ b/reflex/vars/sequence.py @@ -271,6 +271,25 @@ class StringVar(Var[STRING_TYPE], python_types=str): raise_unsupported_operand_types("startswith", (type(self), type(prefix))) return string_starts_with_operation(self, prefix) + @overload + def endswith(self, suffix: StringVar | str) -> BooleanVar: ... + + @overload + def endswith(self, suffix: NoReturn) -> NoReturn: ... + + def endswith(self, suffix: Any) -> BooleanVar: + """Check if the string ends with a suffix. + + Args: + suffix: The suffix. + + Returns: + The string ends with operation. + """ + if not isinstance(suffix, (StringVar, str)): + raise_unsupported_operand_types("endswith", (type(self), type(suffix))) + return string_ends_with_operation(self, suffix) + @overload def __lt__(self, other: StringVar | str) -> BooleanVar: ... @@ -501,6 +520,24 @@ def string_starts_with_operation( ) +@var_operation +def string_ends_with_operation( + full_string: StringVar[Any], suffix: StringVar[Any] | str +): + """Check if a string ends with a suffix. + + Args: + full_string: The full string. + suffix: The suffix. + + Returns: + Whether the string ends with the suffix. + """ + return var_operation_return( + js_expression=f"{full_string}.endsWith({suffix})", var_type=bool + ) + + @var_operation def string_item_operation(string: StringVar[Any], index: NumberVar | int): """Get an item from a string. diff --git a/scripts/wait_for_listening_port.py b/scripts/wait_for_listening_port.py index cd8cea224..71b6dd8b2 100644 --- a/scripts/wait_for_listening_port.py +++ b/scripts/wait_for_listening_port.py @@ -28,7 +28,7 @@ def _pid_exists(pid): # Not really used anymore now that we actually check the HTTP response. def _wait_for_port(port, server_pid, timeout) -> Tuple[bool, str]: start = time.time() - print(f"Waiting for up to {timeout} seconds for port {port} to start listening.") + print(f"Waiting for up to {timeout} seconds for port {port} to start listening.") # noqa: T201 while True: if not _pid_exists(server_pid): return False, f"Server PID {server_pid} is not running." @@ -51,7 +51,7 @@ def _wait_for_http_response(port, server_pid, timeout, path) -> Tuple[bool, str, # which mangles it https://stackoverflow.com/a/49013604 path = "/" + path url = f"http://localhost:{port}{path}" - print(f"Waiting for up to {timeout} seconds for {url} to return HTTP response.") + print(f"Waiting for up to {timeout} seconds for {url} to return HTTP response.") # noqa: T201 while True: try: if not _pid_exists(server_pid): @@ -97,7 +97,7 @@ def main(): for f in as_completed(futures): ok, msg, content = f.result() if ok: - print(f"OK: {msg}") + print(f"OK: {msg}") # noqa: T201 if base_content is None: base_content = content else: @@ -105,9 +105,9 @@ def main(): content == base_content ), f"HTTP responses are not equal {content!r} != {base_content!r}." else: - print(f"FAIL: {msg}") + print(f"FAIL: {msg}") # noqa: T201 exit(1) - print(f"OK: All HTTP responses are equal after {time.time() - start} sec.") + print(f"OK: All HTTP responses are equal after {time.time() - start} sec.") # noqa: T201 if __name__ == "__main__": diff --git a/tests/units/components/core/test_cond.py b/tests/units/components/core/test_cond.py index 8ad51158e..e88f35c9a 100644 --- a/tests/units/components/core/test_cond.py +++ b/tests/units/components/core/test_cond.py @@ -135,7 +135,7 @@ def test_cond_computed_var(): comp = cond(True, CondStateComputed.computed_int, CondStateComputed.computed_str) - # TODO: shouln't this be a ComputedVar? + # TODO: shouldn't this be a ComputedVar? assert isinstance(comp, Var) state_name = format_state_name(CondStateComputed.get_full_name()) diff --git a/tests/units/test_health_endpoint.py b/tests/units/test_health_endpoint.py index fe350266f..6d12d79d6 100644 --- a/tests/units/test_health_endpoint.py +++ b/tests/units/test_health_endpoint.py @@ -15,11 +15,11 @@ from reflex.utils.prerequisites import get_redis_status "mock_redis_client, expected_status", [ # Case 1: Redis client is available and responds to ping - (Mock(ping=lambda: None), True), + (Mock(ping=lambda: None), {"redis": True}), # Case 2: Redis client raises RedisError - (Mock(ping=lambda: (_ for _ in ()).throw(RedisError)), False), + (Mock(ping=lambda: (_ for _ in ()).throw(RedisError)), {"redis": False}), # Case 3: Redis client is not used - (None, None), + (None, {"redis": None}), ], ) async def test_get_redis_status(mock_redis_client, expected_status, mocker): @@ -41,12 +41,12 @@ async def test_get_redis_status(mock_redis_client, expected_status, mocker): "mock_engine, execute_side_effect, expected_status", [ # Case 1: Database is accessible - (MagicMock(), None, True), + (MagicMock(), None, {"db": True}), # Case 2: Database connection error (OperationalError) ( MagicMock(), sqlalchemy.exc.OperationalError("error", "error", "error"), - False, + {"db": False}, ), ], ) @@ -74,25 +74,49 @@ async def test_get_db_status(mock_engine, execute_side_effect, expected_status, @pytest.mark.asyncio @pytest.mark.parametrize( - "db_status, redis_status, expected_status, expected_code", + "db_enabled, redis_enabled, db_status, redis_status, expected_status, expected_code", [ # Case 1: Both services are connected - (True, True, {"status": True, "db": True, "redis": True}, 200), + (True, True, True, True, {"status": True, "db": True, "redis": True}, 200), # Case 2: Database not connected, Redis connected - (False, True, {"status": False, "db": False, "redis": True}, 503), + (True, True, False, True, {"status": False, "db": False, "redis": True}, 503), # Case 3: Database connected, Redis not connected - (True, False, {"status": False, "db": True, "redis": False}, 503), + (True, True, True, False, {"status": False, "db": True, "redis": False}, 503), # Case 4: Both services not connected - (False, False, {"status": False, "db": False, "redis": False}, 503), + (True, True, False, False, {"status": False, "db": False, "redis": False}, 503), # Case 5: Database Connected, Redis not used - (True, None, {"status": True, "db": True, "redis": False}, 200), + (True, False, True, None, {"status": True, "db": True}, 200), + # Case 6: Database not used, Redis Connected + (False, True, None, True, {"status": True, "redis": True}, 200), + # Case 7: Both services not used + (False, False, None, None, {"status": True}, 200), ], ) -async def test_health(db_status, redis_status, expected_status, expected_code, mocker): +async def test_health( + db_enabled, + redis_enabled, + db_status, + redis_status, + expected_status, + expected_code, + mocker, +): # Mock get_db_status and get_redis_status - mocker.patch("reflex.app.get_db_status", return_value=db_status) mocker.patch( - "reflex.utils.prerequisites.get_redis_status", return_value=redis_status + "reflex.utils.prerequisites.check_db_used", + return_value=db_enabled, + ) + mocker.patch( + "reflex.utils.prerequisites.check_redis_used", + return_value=redis_enabled, + ) + mocker.patch( + "reflex.app.get_db_status", + return_value={"db": db_status}, + ) + mocker.patch( + "reflex.utils.prerequisites.get_redis_status", + return_value={"redis": redis_status}, ) # Call the async health function diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 912d72f4f..39484752c 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -976,7 +976,7 @@ class InterdependentState(BaseState): """A state with 3 vars and 3 computed vars. x: a variable that no computed var depends on - v1: a varable that one computed var directly depeneds on + v1: a variable that one computed var directly depends on _v2: a backend variable that one computed var directly depends on v1x2: a computed var that depends on v1 @@ -2685,7 +2685,7 @@ class Custom1(Base): self.foo = val def double_foo(self) -> str: - """Concantenate foo with foo. + """Concatenate foo with foo. Returns: foo + foo @@ -3267,9 +3267,9 @@ async def test_setvar(mock_app: rx.App, token: str): print(update) assert state.array == [43] - # Cannot setvar for non-existant var + # Cannot setvar for non-existent var with pytest.raises(AttributeError): - TestState.setvar("non_existant_var") + TestState.setvar("non_existent_var") # Cannot setvar for computed vars with pytest.raises(AttributeError): diff --git a/tests/units/test_var.py b/tests/units/test_var.py index 1072fca1b..bfa8aa35a 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -515,7 +515,7 @@ def test_var_indexing_types(var, type_): """Test that indexing returns valid types. Args: - var : The list, typle base var. + var : The list, tuple base var. type_ : The type on indexed object. """ diff --git a/tests/units/utils/test_format.py b/tests/units/utils/test_format.py index cd1d0179d..2a2aa8259 100644 --- a/tests/units/utils/test_format.py +++ b/tests/units/utils/test_format.py @@ -262,7 +262,7 @@ def test_to_kebab_case(input: str, output: str): ], ) def test_format_string(input: str, output: str): - """Test formating the input as JS string literal. + """Test formatting the input as JS string literal. Args: input: the input string. @@ -680,7 +680,7 @@ def test_format_array_ref(input, output): ], ) def test_format_library_name(input: str, output: str): - """Test formating a library name to remove the @version part. + """Test formatting a library name to remove the @version part. Args: input: the input string.