From 3350fa038849f07d9ae7d7d5ceda115e96b53e2a Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 15 Feb 2024 20:46:06 -0800 Subject: [PATCH] Component: translate underscore suffix for props supported by chakra (#2636) * Component: translate underscore suffix for props supported by chakra type_ becomes type min_ becomes min max_ becomes max id_ becomes id The deprecation warning is only displayed when the underscore suffix prop is passed and the non-underscore suffix prop is defined on the given component. * Rename type_ to type in accordion and scroll_area All of the new radix components avoid the underscore suffix names where possible. * Update deprecation warning wording * Refactor for readability * Do not raise deprecation warning for `id_` id is kind of a special prop because it exists on all components * Add test case for deprecating underscore suffix props --- reflex/components/component.py | 15 +++++ .../components/radix/primitives/accordion.py | 2 +- .../components/radix/primitives/accordion.pyi | 4 +- .../radix/themes/components/scroll_area.py | 2 +- .../radix/themes/components/scroll_area.pyi | 4 +- tests/components/test_component.py | 56 +++++++++++++++++++ 6 files changed, 77 insertions(+), 6 deletions(-) diff --git a/reflex/components/component.py b/reflex/components/component.py index 5c71216f1..ffee162fa 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -598,6 +598,21 @@ class Component(BaseComponent, ABC): # Import here to avoid circular imports. from reflex.components.base.bare import Bare + # Translate deprecated props to new names. + new_prop_names = [ + prop for prop in cls.get_props() if prop in ["type", "min", "max"] + ] + for prop in new_prop_names: + under_prop = f"{prop}_" + if under_prop in props: + console.deprecate( + f"Underscore suffix for prop `{under_prop}`", + reason=f"for consistency. Use `{prop}` instead.", + deprecation_version="0.4.0", + removal_version="0.5.0", + ) + props[prop] = props.pop(under_prop) + # Validate all the children. for child in children: # Make sure the child is a valid type. diff --git a/reflex/components/radix/primitives/accordion.py b/reflex/components/radix/primitives/accordion.py index da790b0b2..cf5e630ab 100644 --- a/reflex/components/radix/primitives/accordion.py +++ b/reflex/components/radix/primitives/accordion.py @@ -311,7 +311,7 @@ class AccordionRoot(AccordionComponent): alias = "RadixAccordionRoot" # The type of accordion (single or multiple). - type_: Var[LiteralAccordionType] + type: Var[LiteralAccordionType] # The value of the item to expand. value: Var[Optional[Union[str, List[str]]]] diff --git a/reflex/components/radix/primitives/accordion.pyi b/reflex/components/radix/primitives/accordion.pyi index e5b94bf7b..457e53ee0 100644 --- a/reflex/components/radix/primitives/accordion.pyi +++ b/reflex/components/radix/primitives/accordion.pyi @@ -125,7 +125,7 @@ class AccordionRoot(AccordionComponent): def create( # type: ignore cls, *children, - type_: Optional[ + type: Optional[ Union[Var[Literal["single", "multiple"]], Literal["single", "multiple"]] ] = None, value: Optional[ @@ -274,7 +274,7 @@ class AccordionRoot(AccordionComponent): Args: *children: The children of the component. - type_: The type of accordion (single or multiple). + type: The type of accordion (single or multiple). value: The value of the item to expand. default_value: The default value of the item to expand. collapsible: Whether or not the accordion is collapsible. diff --git a/reflex/components/radix/themes/components/scroll_area.py b/reflex/components/radix/themes/components/scroll_area.py index f829b5b8d..b7b79286b 100644 --- a/reflex/components/radix/themes/components/scroll_area.py +++ b/reflex/components/radix/themes/components/scroll_area.py @@ -17,7 +17,7 @@ class ScrollArea(RadixThemesComponent): scrollbars: Var[Literal["vertical", "horizontal", "both"]] # Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars. "auto" | "always" | "scroll" | "hover" - type_: Var[Literal["auto", "always", "scroll", "hover"]] + type: Var[Literal["auto", "always", "scroll", "hover"]] # If type is set to either "scroll" or "hover", this prop determines the length of time, in milliseconds, before the scrollbars are hidden after the user stops interacting with scrollbars. scroll_hide_delay: Var[int] diff --git a/reflex/components/radix/themes/components/scroll_area.pyi b/reflex/components/radix/themes/components/scroll_area.pyi index 2202990df..676cc41ae 100644 --- a/reflex/components/radix/themes/components/scroll_area.pyi +++ b/reflex/components/radix/themes/components/scroll_area.pyi @@ -23,7 +23,7 @@ class ScrollArea(RadixThemesComponent): Literal["vertical", "horizontal", "both"], ] ] = None, - type_: Optional[ + type: Optional[ Union[ Var[Literal["auto", "always", "scroll", "hover"]], Literal["auto", "always", "scroll", "hover"], @@ -91,7 +91,7 @@ class ScrollArea(RadixThemesComponent): Args: *children: Child components. scrollbars: The alignment of the scroll area - type_: Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars. "auto" | "always" | "scroll" | "hover" + type: Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars. "auto" | "always" | "scroll" | "hover" scroll_hide_delay: If type is set to either "scroll" or "hover", this prop determines the length of time, in milliseconds, before the scrollbars are hidden after the user stops interacting with scrollbars. style: The style of the component. key: A unique key for the component. diff --git a/tests/components/test_component.py b/tests/components/test_component.py index 74656c5c1..04468b2ba 100644 --- a/tests/components/test_component.py +++ b/tests/components/test_component.py @@ -1213,3 +1213,59 @@ def test_rename_props(): assert "renamed_prop1={`prop1_2`}" in rendered_c2["props"] assert "subclass_prop2={`prop2_2`}" in rendered_c2["props"] assert "renamed_prop3={`prop3_2`}" in rendered_c2["props"] + + +def test_deprecated_props(capsys): + """Assert that deprecated underscore suffix props are translated. + + Args: + capsys: Pytest fixture for capturing stdout and stderr. + """ + + class C1(Component): + tag = "C1" + + type: Var[str] + min: Var[str] + max: Var[str] + + # No warnings are emitted when using the new prop names. + c1_1 = C1.create(type="type1", min="min1", max="max1") + out_err = capsys.readouterr() + assert not out_err.err + assert not out_err.out + + c1_1_render = c1_1.render() + assert "type={`type1`}" in c1_1_render["props"] + assert "min={`min1`}" in c1_1_render["props"] + assert "max={`max1`}" in c1_1_render["props"] + + # Deprecation warning is emitted with underscore suffix, + # but the component still works. + c1_2 = C1.create(type_="type2", min_="min2", max_="max2") + out_err = capsys.readouterr() + assert out_err.out.count("DeprecationWarning:") == 3 + assert not out_err.err + + c1_2_render = c1_2.render() + assert "type={`type2`}" in c1_2_render["props"] + assert "min={`min2`}" in c1_2_render["props"] + assert "max={`max2`}" in c1_2_render["props"] + + class C2(Component): + tag = "C2" + + type_: Var[str] + min_: Var[str] + max_: Var[str] + + # No warnings are emitted if the actual prop has an underscore suffix + c2_1 = C2.create(type_="type1", min_="min1", max_="max1") + out_err = capsys.readouterr() + assert not out_err.err + assert not out_err.out + + c2_1_render = c2_1.render() + assert "type={`type1`}" in c2_1_render["props"] + assert "min={`min1`}" in c2_1_render["props"] + assert "max={`max1`}" in c2_1_render["props"]