From e56d7702cd5aa15b33de7dfe65959d6205f27870 Mon Sep 17 00:00:00 2001 From: Lendemor Date: Mon, 20 Jan 2025 23:09:07 +0100 Subject: [PATCH] enable N rules for naming conventions --- benchmarks/benchmark_package_size.py | 2 +- pyproject.toml | 9 ++- reflex/app.py | 8 +-- reflex/app_mixins/lifespan.py | 6 +- reflex/components/core/html.py | 2 +- reflex/components/dynamic.py | 8 ++- reflex/components/next/image.py | 5 +- reflex/components/next/image.pyi | 6 +- .../components/radix/primitives/accordion.py | 8 +-- reflex/components/radix/primitives/drawer.py | 2 +- reflex/components/radix/primitives/drawer.pyi | 8 +-- .../radix/themes/components/icon_button.py | 4 +- .../radix/themes/components/icon_button.pyi | 1 + .../radix/themes/components/tooltip.py | 4 +- .../radix/themes/components/tooltip.pyi | 57 ++++++++++--------- reflex/components/recharts/polar.py | 2 +- reflex/components/recharts/recharts.py | 4 +- reflex/config.py | 8 +-- reflex/event.py | 21 ++++--- reflex/experimental/hooks.py | 8 +-- reflex/state.py | 47 ++++++++------- reflex/testing.py | 2 +- reflex/utils/codespaces.py | 5 +- reflex/utils/exceptions.py | 24 ++++---- reflex/utils/exec.py | 8 +-- reflex/utils/prerequisites.py | 6 +- reflex/vars/base.py | 2 +- reflex/vars/number.py | 6 +- tests/units/components/test_component.py | 12 ++-- tests/units/conftest.py | 31 +--------- tests/units/test_var.py | 4 +- 31 files changed, 151 insertions(+), 169 deletions(-) diff --git a/benchmarks/benchmark_package_size.py b/benchmarks/benchmark_package_size.py index 6a0c37821..778b52769 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) # noqa: T201 + print("Python version:", python_version) if python_version is None: raise ValueError("Error: Failed to determine Python version.") diff --git a/pyproject.toml b/pyproject.toml index eccf21230..56d78d18f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,15 +86,18 @@ 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", "T", "W"] +lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "N", "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", "T"] +"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"] +"benchmarks/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"] "reflex/.templates/*.py" = ["D100", "D103", "D104"] -"*.pyi" = ["D301", "D415", "D417", "D418", "E742"] +"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N"] +"pyi_generator.py" = ["N802"] +"reflex/constants/*.py" = ["N"] "*/blank.py" = ["I001"] [tool.pytest.ini_options] diff --git a/reflex/app.py b/reflex/app.py index 08cb4314e..b4001003f 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -1164,11 +1164,11 @@ class App(MiddlewareMixin, LifespanMixin): ValueError: If the custom exception handlers are invalid. """ - FRONTEND_ARG_SPEC = { + frontend_arg_spec = { "exception": Exception, } - BACKEND_ARG_SPEC = { + backend_arg_spec = { "exception": Exception, } @@ -1176,8 +1176,8 @@ class App(MiddlewareMixin, LifespanMixin): ["frontend", "backend"], [self.frontend_exception_handler, self.backend_exception_handler], [ - FRONTEND_ARG_SPEC, - BACKEND_ARG_SPEC, + frontend_arg_spec, + backend_arg_spec, ], ): if hasattr(handler_fn, "__name__"): diff --git a/reflex/app_mixins/lifespan.py b/reflex/app_mixins/lifespan.py index 52bf0be1d..9403e0f35 100644 --- a/reflex/app_mixins/lifespan.py +++ b/reflex/app_mixins/lifespan.py @@ -12,7 +12,7 @@ from typing import Callable, Coroutine, Set, Union from fastapi import FastAPI from reflex.utils import console -from reflex.utils.exceptions import InvalidLifespanTaskType +from reflex.utils.exceptions import InvalidLifespanTaskTypeError from .mixin import AppMixin @@ -64,10 +64,10 @@ class LifespanMixin(AppMixin): task_kwargs: The kwargs of the task. Raises: - InvalidLifespanTaskType: If the task is a generator function. + InvalidLifespanTaskTypeError: If the task is a generator function. """ if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task): - raise InvalidLifespanTaskType( + raise InvalidLifespanTaskTypeError( f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager." ) diff --git a/reflex/components/core/html.py b/reflex/components/core/html.py index cfe46e591..2cad4f331 100644 --- a/reflex/components/core/html.py +++ b/reflex/components/core/html.py @@ -14,7 +14,7 @@ class Html(Div): """ # The HTML to render. - dangerouslySetInnerHTML: Var[Dict[str, str]] + dangerouslySetInnerHTML: Var[Dict[str, str]] # noqa: N815 @classmethod def create(cls, *children, **props): diff --git a/reflex/components/dynamic.py b/reflex/components/dynamic.py index 806d610df..d4efcd293 100644 --- a/reflex/components/dynamic.py +++ b/reflex/components/dynamic.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Union from reflex import constants from reflex.utils import imports -from reflex.utils.exceptions import DynamicComponentMissingLibrary +from reflex.utils.exceptions import DynamicComponentMissingLibraryError from reflex.utils.format import format_library_name from reflex.utils.serializers import serializer from reflex.vars import Var, get_unique_variable_name @@ -36,13 +36,15 @@ def bundle_library(component: Union["Component", str]): component: The component to bundle the library with. Raises: - DynamicComponentMissingLibrary: Raised when a dynamic component is missing a library. + DynamicComponentMissingLibraryError: Raised when a dynamic component is missing a library. """ if isinstance(component, str): bundled_libraries.add(component) return if component.library is None: - raise DynamicComponentMissingLibrary("Component must have a library to bundle.") + raise DynamicComponentMissingLibraryError( + "Component must have a library to bundle." + ) bundled_libraries.add(format_library_name(component.library)) diff --git a/reflex/components/next/image.py b/reflex/components/next/image.py index 2011505d8..066565d85 100644 --- a/reflex/components/next/image.py +++ b/reflex/components/next/image.py @@ -8,6 +8,8 @@ from reflex.vars.base import Var from .base import NextComponent +DEFAULT_W_H = "100%" + class Image(NextComponent): """Display an image.""" @@ -53,7 +55,7 @@ class Image(NextComponent): loading: Var[Literal["lazy", "eager"]] # A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur". - blurDataURL: Var[str] + blur_data_url: Var[str] # Fires when the image has loaded. on_load: EventHandler[no_args_event_spec] @@ -81,7 +83,6 @@ class Image(NextComponent): _type_: _description_ """ style = props.get("style", {}) - DEFAULT_W_H = "100%" def check_prop_type(prop_name, prop_value): if types.check_prop_in_allowed_types(prop_value, allowed_types=[int]): diff --git a/reflex/components/next/image.pyi b/reflex/components/next/image.pyi index dd9dd38c3..b8da4973d 100644 --- a/reflex/components/next/image.pyi +++ b/reflex/components/next/image.pyi @@ -11,6 +11,8 @@ from reflex.vars.base import Var from .base import NextComponent +DEFAULT_W_H = "100%" + class Image(NextComponent): @overload @classmethod @@ -30,7 +32,7 @@ class Image(NextComponent): loading: Optional[ Union[Literal["eager", "lazy"], Var[Literal["eager", "lazy"]]] ] = None, - blurDataURL: Optional[Union[Var[str], str]] = None, + blur_data_url: Optional[Union[Var[str], str]] = None, style: Optional[Style] = None, key: Optional[Any] = None, id: Optional[Any] = None, @@ -71,7 +73,7 @@ class Image(NextComponent): priority: When true, the image will be considered high priority and preload. Lazy loading is automatically disabled for images using priority. placeholder: A placeholder to use while the image is loading. Possible values are blur, empty, or data:image/.... Defaults to empty. loading: The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead. - blurDataURL: A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur". + blur_data_url: A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur". on_load: Fires when the image has loaded. on_error: Fires when the image has an error. style: The style of the component. diff --git a/reflex/components/radix/primitives/accordion.py b/reflex/components/radix/primitives/accordion.py index 0ba618e21..170b3ed9c 100644 --- a/reflex/components/radix/primitives/accordion.py +++ b/reflex/components/radix/primitives/accordion.py @@ -485,11 +485,11 @@ to { Returns: The style of the component. """ - slideDown = LiteralVar.create( + slide_down = LiteralVar.create( "${slideDown} var(--animation-duration) var(--animation-easing)", ) - slideUp = LiteralVar.create( + slide_up = LiteralVar.create( "${slideUp} var(--animation-duration) var(--animation-easing)", ) @@ -503,8 +503,8 @@ to { "display": "block", "height": "var(--space-3)", }, - "&[data-state='open']": {"animation": slideDown}, - "&[data-state='closed']": {"animation": slideUp}, + "&[data-state='open']": {"animation": slide_down}, + "&[data-state='closed']": {"animation": slide_up}, _inherited_variant_selector("classic"): { "color": "var(--accent-contrast)", }, diff --git a/reflex/components/radix/primitives/drawer.py b/reflex/components/radix/primitives/drawer.py index ed57dcbd8..534b97ac1 100644 --- a/reflex/components/radix/primitives/drawer.py +++ b/reflex/components/radix/primitives/drawer.py @@ -66,7 +66,7 @@ class DrawerRoot(DrawerComponent): scroll_lock_timeout: Var[int] # When `True`, it prevents scroll restoration. Defaults to `True`. - preventScrollRestoration: Var[bool] + prevent_scroll_restoration: Var[bool] # Enable background scaling, it requires container element with `vaul-drawer-wrapper` attribute to scale its background. should_scale_background: Var[bool] diff --git a/reflex/components/radix/primitives/drawer.pyi b/reflex/components/radix/primitives/drawer.pyi index 1ca1e4325..bb2890fea 100644 --- a/reflex/components/radix/primitives/drawer.pyi +++ b/reflex/components/radix/primitives/drawer.pyi @@ -81,7 +81,7 @@ class DrawerRoot(DrawerComponent): snap_points: Optional[List[Union[float, str]]] = None, fade_from_index: Optional[Union[Var[int], int]] = None, scroll_lock_timeout: Optional[Union[Var[int], int]] = None, - preventScrollRestoration: Optional[Union[Var[bool], bool]] = None, + prevent_scroll_restoration: Optional[Union[Var[bool], bool]] = None, should_scale_background: Optional[Union[Var[bool], bool]] = None, close_threshold: Optional[Union[Var[float], float]] = None, as_child: Optional[Union[Var[bool], bool]] = None, @@ -129,7 +129,7 @@ class DrawerRoot(DrawerComponent): snap_points: Array of numbers from 0 to 100 that corresponds to % of the screen a given snap point should take up. Should go from least visible. Also Accept px values, which doesn't take screen height into account. fade_from_index: Index of a snapPoint from which the overlay fade should be applied. Defaults to the last snap point. scroll_lock_timeout: Duration for which the drawer is not draggable after scrolling content inside of the drawer. Defaults to 500ms - preventScrollRestoration: When `True`, it prevents scroll restoration. Defaults to `True`. + prevent_scroll_restoration: When `True`, it prevents scroll restoration. Defaults to `True`. should_scale_background: Enable background scaling, it requires container element with `vaul-drawer-wrapper` attribute to scale its background. close_threshold: Number between 0 and 1 that determines when the drawer should be closed. as_child: Change the default rendered element for the one passed as a child. @@ -567,7 +567,7 @@ class Drawer(ComponentNamespace): snap_points: Optional[List[Union[float, str]]] = None, fade_from_index: Optional[Union[Var[int], int]] = None, scroll_lock_timeout: Optional[Union[Var[int], int]] = None, - preventScrollRestoration: Optional[Union[Var[bool], bool]] = None, + prevent_scroll_restoration: Optional[Union[Var[bool], bool]] = None, should_scale_background: Optional[Union[Var[bool], bool]] = None, close_threshold: Optional[Union[Var[float], float]] = None, as_child: Optional[Union[Var[bool], bool]] = None, @@ -615,7 +615,7 @@ class Drawer(ComponentNamespace): snap_points: Array of numbers from 0 to 100 that corresponds to % of the screen a given snap point should take up. Should go from least visible. Also Accept px values, which doesn't take screen height into account. fade_from_index: Index of a snapPoint from which the overlay fade should be applied. Defaults to the last snap point. scroll_lock_timeout: Duration for which the drawer is not draggable after scrolling content inside of the drawer. Defaults to 500ms - preventScrollRestoration: When `True`, it prevents scroll restoration. Defaults to `True`. + prevent_scroll_restoration: When `True`, it prevents scroll restoration. Defaults to `True`. should_scale_background: Enable background scaling, it requires container element with `vaul-drawer-wrapper` attribute to scale its background. close_threshold: Number between 0 and 1 that determines when the drawer should be closed. as_child: Change the default rendered element for the one passed as a child. diff --git a/reflex/components/radix/themes/components/icon_button.py b/reflex/components/radix/themes/components/icon_button.py index 68c67485a..aafb9e1eb 100644 --- a/reflex/components/radix/themes/components/icon_button.py +++ b/reflex/components/radix/themes/components/icon_button.py @@ -22,6 +22,8 @@ from ..base import ( LiteralButtonSize = Literal["1", "2", "3", "4"] +RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48} + class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): """A button designed specifically for usage with a single icon.""" @@ -72,8 +74,6 @@ class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): "IconButton requires a child icon. Pass a string as the first child or a rx.icon." ) if "size" in props: - RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48} - if isinstance(props["size"], str): children[0].size = RADIX_TO_LUCIDE_SIZE[props["size"]] else: diff --git a/reflex/components/radix/themes/components/icon_button.pyi b/reflex/components/radix/themes/components/icon_button.pyi index abf77e07b..bdb0fe845 100644 --- a/reflex/components/radix/themes/components/icon_button.pyi +++ b/reflex/components/radix/themes/components/icon_button.pyi @@ -14,6 +14,7 @@ from reflex.vars.base import Var from ..base import RadixLoadingProp, RadixThemesComponent LiteralButtonSize = Literal["1", "2", "3", "4"] +RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48} class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): @overload diff --git a/reflex/components/radix/themes/components/tooltip.py b/reflex/components/radix/themes/components/tooltip.py index 07bab1a4a..53ec35264 100644 --- a/reflex/components/radix/themes/components/tooltip.py +++ b/reflex/components/radix/themes/components/tooltip.py @@ -28,6 +28,9 @@ LiteralStickyType = Literal[ ] +ARIA_LABEL_KEY = "aria_label" + + # The Tooltip inherits props from the Tooltip.Root, Tooltip.Portal, Tooltip.Content class Tooltip(RadixThemesComponent): """Floating element that provides a control with contextual information via pointer or focus.""" @@ -104,7 +107,6 @@ class Tooltip(RadixThemesComponent): Returns: The created component. """ - ARIA_LABEL_KEY = "aria_label" if props.get(ARIA_LABEL_KEY) is not None: props[format.to_kebab_case(ARIA_LABEL_KEY)] = props.pop(ARIA_LABEL_KEY) diff --git a/reflex/components/radix/themes/components/tooltip.pyi b/reflex/components/radix/themes/components/tooltip.pyi index fab1d0c12..a70c33027 100644 --- a/reflex/components/radix/themes/components/tooltip.pyi +++ b/reflex/components/radix/themes/components/tooltip.pyi @@ -14,6 +14,7 @@ from ..base import RadixThemesComponent LiteralSideType = Literal["top", "right", "bottom", "left"] LiteralAlignType = Literal["start", "center", "end"] LiteralStickyType = Literal["partial", "always"] +ARIA_LABEL_KEY = "aria_label" class Tooltip(RadixThemesComponent): @overload @@ -89,36 +90,36 @@ class Tooltip(RadixThemesComponent): Run some additional handling on the props. Args: - *children: The positional arguments - content: The content of the tooltip. - default_open: The open state of the tooltip when it is initially rendered. Use when you do not need to control its open state. - open: The controlled open state of the tooltip. Must be used in conjunction with `on_open_change`. - side: The preferred side of the trigger to render against when open. Will be reversed when collisions occur and `avoid_collisions` is enabled.The position of the tooltip. Defaults to "top". - side_offset: The distance in pixels from the trigger. Defaults to 0. - align: The preferred alignment against the trigger. May change when collisions occur. Defaults to "center". - align_offset: An offset in pixels from the "start" or "end" alignment options. - avoid_collisions: When true, overrides the side and align preferences to prevent collisions with boundary edges. Defaults to True. - collision_padding: The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { "top": 20, "left": 20 }. Defaults to 0. - arrow_padding: The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0. - sticky: The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. Defaults to "partial". - hide_when_detached: Whether to hide the content when the trigger becomes fully occluded. Defaults to False. - delay_duration: Override the duration in milliseconds to customize the open delay for a specific tooltip. Default is 700. - disable_hoverable_content: Prevents Tooltip content from remaining open when hovering. - force_mount: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. - aria_label: By default, screenreaders will announce the content inside the component. If this is not descriptive enough, or you have content that cannot be announced, use aria-label as a more descriptive label. - on_open_change: Fired when the open state changes. - on_escape_key_down: Fired when the escape key is pressed. - on_pointer_down_outside: Fired when the pointer is down outside the tooltip. - 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 keyword arguments + *children: The positional arguments + content: The content of the tooltip. + default_open: The open state of the tooltip when it is initially rendered. Use when you do not need to control its open state. + open: The controlled open state of the tooltip. Must be used in conjunction with `on_open_change`. + side: The preferred side of the trigger to render against when open. Will be reversed when collisions occur and `avoid_collisions` is enabled.The position of the tooltip. Defaults to "top". + side_offset: The distance in pixels from the trigger. Defaults to 0. + align: The preferred alignment against the trigger. May change when collisions occur. Defaults to "center". + align_offset: An offset in pixels from the "start" or "end" alignment options. + avoid_collisions: When true, overrides the side and align preferences to prevent collisions with boundary edges. Defaults to True. + collision_padding: The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { "top": 20, "left": 20 }. Defaults to 0. + arrow_padding: The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0. + sticky: The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. Defaults to "partial". + hide_when_detached: Whether to hide the content when the trigger becomes fully occluded. Defaults to False. + delay_duration: Override the duration in milliseconds to customize the open delay for a specific tooltip. Default is 700. + disable_hoverable_content: Prevents Tooltip content from remaining open when hovering. + force_mount: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. + aria_label: By default, screenreaders will announce the content inside the component. If this is not descriptive enough, or you have content that cannot be announced, use aria-label as a more descriptive label. + on_open_change: Fired when the open state changes. + on_escape_key_down: Fired when the escape key is pressed. + on_pointer_down_outside: Fired when the pointer is down outside the tooltip. + 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 keyword arguments Returns: - The created component. + The created component. """ ... diff --git a/reflex/components/recharts/polar.py b/reflex/components/recharts/polar.py index 1f4974d4c..7bb623d34 100644 --- a/reflex/components/recharts/polar.py +++ b/reflex/components/recharts/polar.py @@ -73,7 +73,7 @@ class Pie(Recharts): data: Var[List[Dict[str, Any]]] # Valid children components - _valid_children: List[str] = ["Cell", "LabelList"] + _valid_children: List[str] = ["Cell", "LabelList", "Bare"] # Stoke color. Default: rx.color("accent", 9) stroke: Var[Union[str, Color]] = LiteralVar.create(Color("accent", 9)) diff --git a/reflex/components/recharts/recharts.py b/reflex/components/recharts/recharts.py index b5a4ed113..ee12bd192 100644 --- a/reflex/components/recharts/recharts.py +++ b/reflex/components/recharts/recharts.py @@ -1,6 +1,6 @@ """A component that wraps a recharts lib.""" -from typing import Dict, Literal +from typing import Literal from reflex.components.component import Component, MemoizationLeaf, NoSSRComponent @@ -10,7 +10,7 @@ class Recharts(Component): library = "recharts@2.13.0" - def _get_style(self) -> Dict: + def _get_style(self) -> dict: return {"wrapperStyle": self.style} diff --git a/reflex/config.py b/reflex/config.py index 7614417d5..68a289c7b 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -389,7 +389,7 @@ class EnvVar(Generic[T]): os.environ[self.name] = str(value) -class env_var: # type: ignore +class env_var: # type: ignore # noqa: N801 """Descriptor for environment variables.""" name: str @@ -807,16 +807,16 @@ class Config(Base): if "api_url" not in self._non_default_attributes: # If running in Github Codespaces, override API_URL codespace_name = os.getenv("CODESPACE_NAME") - GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN = os.getenv( + github_codespaces_port_forwarding_domain = os.getenv( "GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN" ) # If running on Replit.com interactively, override API_URL to ensure we maintain the backend_port replit_dev_domain = os.getenv("REPLIT_DEV_DOMAIN") backend_port = kwargs.get("backend_port", self.backend_port) - if codespace_name and GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN: + if codespace_name and github_codespaces_port_forwarding_domain: self.api_url = ( f"https://{codespace_name}-{kwargs.get('backend_port', self.backend_port)}" - f".{GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}" + f".{github_codespaces_port_forwarding_domain}" ) elif replit_dev_domain and backend_port: self.api_url = f"https://{replit_dev_domain}:{backend_port}" diff --git a/reflex/event.py b/reflex/event.py index 28852fde5..26a1473b7 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -40,7 +40,10 @@ from typing_extensions import ( from reflex import constants from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.utils import console, format -from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgTypeMismatch +from reflex.utils.exceptions import ( + EventFnArgMismatchError, + EventHandlerArgTypeMismatchError, +) from reflex.utils.types import ArgsSpec, GenericType, typehint_issubclass from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var @@ -557,10 +560,10 @@ class JavasciptKeyboardEvent: """Interface for a Javascript KeyboardEvent https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.""" key: str = "" - altKey: bool = False - ctrlKey: bool = False - metaKey: bool = False - shiftKey: bool = False + alt_key: bool = False + ctrl_key: bool = False + meta_key: bool = False + shift_key: bool = False def input_event(e: Var[JavascriptInputEvent]) -> Tuple[Var[str]]: @@ -1364,7 +1367,7 @@ def call_event_handler( if compare_result: continue else: - failure = EventHandlerArgTypeMismatch( + failure = EventHandlerArgTypeMismatchError( f"Event handler {key} expects {args_types_without_vars[i]} for argument {arg} but got {type_hints_of_provided_callback[arg]} as annotated in {event_callback.fn.__qualname__} instead." ) failures.append(failure) @@ -1477,7 +1480,7 @@ def check_fn_match_arg_spec( func_name: str | None = None, ): """Ensures that the function signature matches the passed argument specification - or raises an EventFnArgMismatch if they do not. + or raises an EventFnArgMismatchError if they do not. Args: user_func: The function to be validated. @@ -1487,7 +1490,7 @@ def check_fn_match_arg_spec( func_name: The name of the function to be validated. Raises: - EventFnArgMismatch: Raised if the number of mandatory arguments do not match + EventFnArgMismatchError: Raised if the number of mandatory arguments do not match """ user_args = inspect.getfullargspec(user_func).args # Drop the first argument if it's a bound method @@ -1503,7 +1506,7 @@ def check_fn_match_arg_spec( number_of_event_args = len(parsed_event_args) if number_of_user_args - number_of_user_default_args > number_of_event_args: - raise EventFnArgMismatch( + raise EventFnArgMismatchError( f"Event {key} only provides {number_of_event_args} arguments, but " f"{func_name or user_func} requires at least {number_of_user_args - number_of_user_default_args} " "arguments to be passed to the event handler.\n" diff --git a/reflex/experimental/hooks.py b/reflex/experimental/hooks.py index 7d648225a..e0d3b4a56 100644 --- a/reflex/experimental/hooks.py +++ b/reflex/experimental/hooks.py @@ -26,7 +26,7 @@ def const(name, value) -> Var: return Var(_js_expr=f"const {name} = {value}") -def useCallback(func, deps) -> Var: +def useCallback(func, deps) -> Var: # noqa: N802 """Create a useCallback hook with a function and dependencies. Args: @@ -42,7 +42,7 @@ def useCallback(func, deps) -> Var: ) -def useContext(context) -> Var: +def useContext(context) -> Var: # noqa: N802 """Create a useContext hook with a context. Args: @@ -57,7 +57,7 @@ def useContext(context) -> Var: ) -def useRef(default) -> Var: +def useRef(default) -> Var: # noqa: N802 """Create a useRef hook with a default value. Args: @@ -72,7 +72,7 @@ def useRef(default) -> Var: ) -def useState(var_name, default=None) -> Var: +def useState(var_name, default=None) -> Var: # noqa: N802 """Create a useState hook with a variable name and setter name. Args: diff --git a/reflex/state.py b/reflex/state.py index e15c73978..3034de857 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -93,14 +93,14 @@ from reflex.event import ( ) from reflex.utils import console, format, path_ops, prerequisites, types from reflex.utils.exceptions import ( - ComputedVarShadowsBaseVars, - ComputedVarShadowsStateVar, - DynamicComponentInvalidSignature, - DynamicRouteArgShadowsStateVar, - EventHandlerShadowsBuiltInStateMethod, + ComputedVarShadowsBaseVarsError, + ComputedVarShadowsStateVarError, + DynamicComponentInvalidSignatureError, + DynamicRouteArgShadowsStateVarError, + EventHandlerShadowsBuiltInStateMethodError, ImmutableStateError, InvalidLockWarningThresholdError, - InvalidStateManagerMode, + InvalidStateManagerModeError, LockExpiredError, ReflexRuntimeError, SetUndefinedStateVarError, @@ -815,7 +815,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """Check for shadow methods and raise error if any. Raises: - EventHandlerShadowsBuiltInStateMethod: When an event handler shadows an inbuilt state method. + EventHandlerShadowsBuiltInStateMethodError: When an event handler shadows an inbuilt state method. """ overridden_methods = set() state_base_functions = cls._get_base_functions() @@ -829,7 +829,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): overridden_methods.add(method.__name__) for method_name in overridden_methods: - raise EventHandlerShadowsBuiltInStateMethod( + raise EventHandlerShadowsBuiltInStateMethodError( f"The event handler name `{method_name}` shadows a builtin State method; use a different name instead" ) @@ -838,11 +838,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """Check for shadow base vars and raise error if any. Raises: - ComputedVarShadowsBaseVars: When a computed var shadows a base var. + ComputedVarShadowsBaseVarsError: When a computed var shadows a base var. """ for computed_var_ in cls._get_computed_vars(): if computed_var_._js_expr in cls.__annotations__: - raise ComputedVarShadowsBaseVars( + raise ComputedVarShadowsBaseVarsError( f"The computed var name `{computed_var_._js_expr}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead" ) @@ -851,14 +851,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """Check for shadow computed vars and raise error if any. Raises: - ComputedVarShadowsStateVar: When a computed var shadows another. + ComputedVarShadowsStateVarError: When a computed var shadows another. """ for name, cv in cls.__dict__.items(): if not is_computed_var(cv): continue name = cv._js_expr if name in cls.inherited_vars or name in cls.inherited_backend_vars: - raise ComputedVarShadowsStateVar( + raise ComputedVarShadowsStateVarError( f"The computed var name `{cv._js_expr}` shadows a var in {cls.__module__}.{cls.__name__}; use a different name instead" ) @@ -1218,14 +1218,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): args: a dict of args Raises: - DynamicRouteArgShadowsStateVar: If a dynamic arg is shadowing an existing var. + DynamicRouteArgShadowsStateVarError: If a dynamic arg is shadowing an existing var. """ for arg in args: if ( arg in cls.computed_vars and not isinstance(cls.computed_vars[arg], DynamicRouteVar) ) or arg in cls.base_vars: - raise DynamicRouteArgShadowsStateVar( + raise DynamicRouteArgShadowsStateVarError( f"Dynamic route arg '{arg}' is shadowing an existing var in {cls.__module__}.{cls.__name__}" ) for substate in cls.get_substates(): @@ -2356,8 +2356,7 @@ def dynamic(func: Callable[[T], Component]): The dynamically generated component. Raises: - DynamicComponentInvalidSignature: If the function does not have exactly one parameter. - DynamicComponentInvalidSignature: If the function does not have a type hint for the state class. + DynamicComponentInvalidSignatureError: If the function does not have exactly one parameter or a type hint for the state class. """ number_of_parameters = len(inspect.signature(func).parameters) @@ -2369,12 +2368,12 @@ def dynamic(func: Callable[[T], Component]): values = list(func_signature.values()) if number_of_parameters != 1: - raise DynamicComponentInvalidSignature( + raise DynamicComponentInvalidSignatureError( "The function must have exactly one parameter, which is the state class." ) if len(values) != 1: - raise DynamicComponentInvalidSignature( + raise DynamicComponentInvalidSignatureError( "You must provide a type hint for the state class in the function." ) @@ -2876,7 +2875,7 @@ class StateManager(Base, ABC): state: The state class to use. Raises: - InvalidStateManagerMode: If the state manager mode is invalid. + InvalidStateManagerModeError: If the state manager mode is invalid. Returns: The state manager (either disk, memory or redis). @@ -2899,7 +2898,7 @@ class StateManager(Base, ABC): lock_expiration=config.redis_lock_expiration, lock_warning_threshold=config.redis_lock_warning_threshold, ) - raise InvalidStateManagerMode( + raise InvalidStateManagerModeError( f"Expected one of: DISK, MEMORY, REDIS, got {config.state_manager_mode}" ) @@ -4058,10 +4057,10 @@ def serialize_mutable_proxy(mp: MutableProxy): return mp.__wrapped__ -_orig_json_JSONEncoder_default = json.JSONEncoder.default +_orig_json_encoder_default = json.JSONEncoder.default -def _json_JSONEncoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any: +def _json_encoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any: """Wrap JSONEncoder.default to handle MutableProxy objects. Args: @@ -4075,10 +4074,10 @@ def _json_JSONEncoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any: return o.__wrapped__ except AttributeError: pass - return _orig_json_JSONEncoder_default(self, o) + return _orig_json_encoder_default(self, o) -json.JSONEncoder.default = _json_JSONEncoder_default_wrapper +json.JSONEncoder.default = _json_encoder_default_wrapper class ImmutableMutableProxy(MutableProxy): diff --git a/reflex/testing.py b/reflex/testing.py index b3dedf398..d18003755 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -87,7 +87,7 @@ else: # borrowed from py3.11 -class chdir(contextlib.AbstractContextManager): +class chdir(contextlib.AbstractContextManager): # noqa: N801 """Non thread-safe context manager to change the current working directory.""" def __init__(self, path): diff --git a/reflex/utils/codespaces.py b/reflex/utils/codespaces.py index 7ff686129..bb5286e31 100644 --- a/reflex/utils/codespaces.py +++ b/reflex/utils/codespaces.py @@ -42,10 +42,7 @@ def codespaces_port_forwarding_domain() -> str | None: Returns: The domain for port forwarding in Github Codespaces, or None if not running in Codespaces. """ - GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN = os.getenv( - "GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN" - ) - return GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN + return os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN") def is_running_in_codespaces() -> bool: diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index 339abcda1..91d442951 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -11,7 +11,7 @@ class ConfigError(ReflexError): """Custom exception for config related errors.""" -class InvalidStateManagerMode(ReflexError, ValueError): +class InvalidStateManagerModeError(ReflexError, ValueError): """Raised when an invalid state manager mode is provided.""" @@ -95,43 +95,43 @@ class MatchTypeError(ReflexError, TypeError): """Raised when the return types of match cases are different.""" -class EventHandlerArgTypeMismatch(ReflexError, TypeError): +class EventHandlerArgTypeMismatchError(ReflexError, TypeError): """Raised when the annotations of args accepted by an EventHandler differs from the spec of the event trigger.""" -class EventFnArgMismatch(ReflexError, TypeError): +class EventFnArgMismatchError(ReflexError, TypeError): """Raised when the number of args required by an event handler is more than provided by the event trigger.""" -class DynamicRouteArgShadowsStateVar(ReflexError, NameError): +class DynamicRouteArgShadowsStateVarError(ReflexError, NameError): """Raised when a dynamic route arg shadows a state var.""" -class ComputedVarShadowsStateVar(ReflexError, NameError): +class ComputedVarShadowsStateVarError(ReflexError, NameError): """Raised when a computed var shadows a state var.""" -class ComputedVarShadowsBaseVars(ReflexError, NameError): +class ComputedVarShadowsBaseVarsError(ReflexError, NameError): """Raised when a computed var shadows a base var.""" -class EventHandlerShadowsBuiltInStateMethod(ReflexError, NameError): +class EventHandlerShadowsBuiltInStateMethodError(ReflexError, NameError): """Raised when an event handler shadows a built-in state method.""" -class GeneratedCodeHasNoFunctionDefs(ReflexError): +class GeneratedCodeHasNoFunctionDefsError(ReflexError): """Raised when refactored code generated with flexgen has no functions defined.""" -class PrimitiveUnserializableToJSON(ReflexError, ValueError): +class PrimitiveUnserializableToJSONError(ReflexError, ValueError): """Raised when a primitive type is unserializable to JSON. Usually with NaN and Infinity.""" -class InvalidLifespanTaskType(ReflexError, TypeError): +class InvalidLifespanTaskTypeError(ReflexError, TypeError): """Raised when an invalid task type is registered as a lifespan task.""" -class DynamicComponentMissingLibrary(ReflexError, ValueError): +class DynamicComponentMissingLibraryError(ReflexError, ValueError): """Raised when a dynamic component is missing a library.""" @@ -147,7 +147,7 @@ class EnvironmentVarValueError(ReflexError, ValueError): """Raised when an environment variable is set to an invalid value.""" -class DynamicComponentInvalidSignature(ReflexError, TypeError): +class DynamicComponentInvalidSignatureError(ReflexError, TypeError): """Raised when a dynamic component has an invalid signature.""" diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 621c4a608..a1a802f4f 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -339,11 +339,11 @@ def run_uvicorn_backend_prod(host, port, 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() + 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, + *run_backend_prod_windows, "--host", host, "--port", @@ -352,7 +352,7 @@ def run_uvicorn_backend_prod(host, port, loglevel): ] if constants.IS_WINDOWS else [ - *RUN_BACKEND_PROD, + *run_backend_prod, "--bind", f"{host}:{port}", "--threads", diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index e450393c3..8709bb3d6 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -36,7 +36,7 @@ from reflex.compiler import templates from reflex.config import Config, environment, get_config from reflex.utils import console, net, path_ops, processes, redir from reflex.utils.exceptions import ( - GeneratedCodeHasNoFunctionDefs, + GeneratedCodeHasNoFunctionDefsError, raise_system_package_missing_error, ) from reflex.utils.format import format_library_name @@ -1609,7 +1609,7 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash: generation_hash: The generation hash from reflex.build. Raises: - GeneratedCodeHasNoFunctionDefs: If the fetched code has no function definitions + GeneratedCodeHasNoFunctionDefsError: If the fetched code has no function definitions (the refactored reflex code is expected to have at least one root function defined). """ # Download the reflex code for the generation. @@ -1626,7 +1626,7 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash: # Determine the name of the last function, which renders the generated code. defined_funcs = re.findall(r"def ([a-zA-Z_]+)\(", resp.text) if not defined_funcs: - raise GeneratedCodeHasNoFunctionDefs( + raise GeneratedCodeHasNoFunctionDefsError( f"No function definitions found in generated code from {url!r}." ) render_func_name = defined_funcs[-1] diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 2892d004d..0c2409c99 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1581,7 +1581,7 @@ def figure_out_type(value: Any) -> types.GenericType: return type(value) -class cached_property_no_lock(functools.cached_property): +class cached_property_no_lock(functools.cached_property): # noqa: N801 """A special version of functools.cached_property that does not use a lock.""" def __init__(self, func): diff --git a/reflex/vars/number.py b/reflex/vars/number.py index a2a0293d5..082334450 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -18,7 +18,7 @@ from typing import ( ) from reflex.constants.base import Dirs -from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError +from reflex.utils.exceptions import PrimitiveUnserializableToJSONError, VarTypeError from reflex.utils.imports import ImportDict, ImportVar from .base import ( @@ -987,10 +987,10 @@ class LiteralNumberVar(LiteralVar, NumberVar): The JSON representation of the var. Raises: - PrimitiveUnserializableToJSON: If the var is unserializable to JSON. + PrimitiveUnserializableToJSONError: If the var is unserializable to JSON. """ if math.isinf(self._var_value) or math.isnan(self._var_value): - raise PrimitiveUnserializableToJSON( + raise PrimitiveUnserializableToJSONError( f"No valid JSON representation for {self}" ) return json.dumps(self._var_value) diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index 674873b69..02020fc27 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -27,7 +27,7 @@ from reflex.event import ( from reflex.state import BaseState from reflex.style import Style from reflex.utils import imports -from reflex.utils.exceptions import EventFnArgMismatch +from reflex.utils.exceptions import EventFnArgMismatchError from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var @@ -905,11 +905,11 @@ def test_invalid_event_handler_args(component2, test_state): test_state: A test state. """ # EventHandler args must match - with pytest.raises(EventFnArgMismatch): + with pytest.raises(EventFnArgMismatchError): component2.create(on_click=test_state.do_something_arg) # Multiple EventHandler args: all must match - with pytest.raises(EventFnArgMismatch): + with pytest.raises(EventFnArgMismatchError): component2.create( on_click=[test_state.do_something_arg, test_state.do_something] ) @@ -941,15 +941,15 @@ def test_invalid_event_handler_args(component2, test_state): ) # lambda signature must match event trigger. - with pytest.raises(EventFnArgMismatch): + with pytest.raises(EventFnArgMismatchError): component2.create(on_click=lambda _: test_state.do_something_arg(1)) # lambda returning EventHandler must match spec - with pytest.raises(EventFnArgMismatch): + with pytest.raises(EventFnArgMismatchError): component2.create(on_click=lambda: test_state.do_something_arg) # Mixed EventSpec and EventHandler must match spec. - with pytest.raises(EventFnArgMismatch): + with pytest.raises(EventFnArgMismatchError): component2.create( on_click=lambda: [ test_state.do_something_arg(1), diff --git a/tests/units/conftest.py b/tests/units/conftest.py index fb6229aca..8c1ffe532 100644 --- a/tests/units/conftest.py +++ b/tests/units/conftest.py @@ -1,11 +1,8 @@ """Test fixtures.""" import asyncio -import contextlib -import os import platform import uuid -from pathlib import Path from typing import Dict, Generator, Type from unittest import mock @@ -14,6 +11,7 @@ import pytest from reflex.app import App from reflex.event import EventSpec from reflex.model import ModelRegistry +from reflex.testing import chdir from reflex.utils import prerequisites from .states import ( @@ -191,33 +189,6 @@ def router_data(router_data_headers) -> Dict[str, str]: } -# borrowed from py3.11 -class chdir(contextlib.AbstractContextManager): - """Non thread-safe context manager to change the current working directory.""" - - def __init__(self, path): - """Prepare contextmanager. - - Args: - path: the path to change to - """ - self.path = path - self._old_cwd = [] - - def __enter__(self): - """Save current directory and perform chdir.""" - self._old_cwd.append(Path.cwd()) - os.chdir(self.path) - - def __exit__(self, *excinfo): - """Change back to previous directory on stack. - - Args: - excinfo: sys.exc_info captured in the context block - """ - os.chdir(self._old_cwd.pop()) - - @pytest.fixture def tmp_working_dir(tmp_path): """Create a temporary directory and chdir to it. diff --git a/tests/units/test_var.py b/tests/units/test_var.py index 6ad82a761..39d846ca9 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -11,7 +11,7 @@ import reflex as rx from reflex.base import Base from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG from reflex.state import BaseState -from reflex.utils.exceptions import PrimitiveUnserializableToJSON +from reflex.utils.exceptions import PrimitiveUnserializableToJSONError from reflex.utils.imports import ImportVar from reflex.vars import VarData from reflex.vars.base import ( @@ -1058,7 +1058,7 @@ def test_inf_and_nan(var, expected_js): assert str(var) == expected_js assert isinstance(var, NumberVar) assert isinstance(var, LiteralVar) - with pytest.raises(PrimitiveUnserializableToJSON): + with pytest.raises(PrimitiveUnserializableToJSONError): var.json()