Repository navigation
fix: raise BackendVarFormatError for the remaining backend var UI uses #7908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -241,7 +241,7 @@ def serialize_point(point: Point) -> dict: | |||||
|
|
||||||
| ## Printing a backend var on a state class | ||||||
|
|
||||||
| A backend var read on the state class, such as `State._secret`, is a `Field` since 0.10. In 0.11, `print()`, logging and `str()` of it raise `BackendVarFormatError`, as f-strings already did ([#7651](https://github.com/reflex-dev/reflex/pull/7651)). The same error replaces the `TypeError` or `ValueError` raised when the var is passed where a frontend value is needed, such as a component prop, `rx.toast(State._secret)`, or the `title`, `description` or `image` of `app.add_page(...)`. | ||||||
| A backend var read on the state class, such as `State._secret`, is a `Field` since 0.10. In 0.11, `print()`, logging and `str()` of it raise `BackendVarFormatError`, as f-strings already did ([#7651](https://github.com/reflex-dev/reflex/pull/7651)). The same error replaces the `TypeError` or `ValueError` raised when the var is passed where a frontend value is needed, such as a component child or prop, an event handler argument, `rx.toast(State._secret)`, or the `title`, `description`, `image` or `on_load` of `app.add_page(...)`. Comparing it with a value, as in `rx.cond(State._secret == "x", ...)`, or truth-testing it also raises, where it used to give a plain `False` or `True`. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: Logging does not raise here. With %-style arguments, the stdlib logging handler catches the error and prints a Prompt for AI agents
Suggested change
|
||||||
|
|
||||||
| ```python | ||||||
| class State(rx.State): | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| `app.add_page(...)` now raises `BackendVarFormatError` when `on_load` is a backend var such as `State._handler`, instead of accepting it. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Using a backend var such as `State._secret` as a component child, a typed prop (`rx.el.div(title=State._secret)`, `rx.link(href=State._secret)`) or an event handler argument now raises `BackendVarFormatError`, which names the var and the fix. A child used to raise a `ChildrenTypeError` that named neither, and a typed prop or event argument a generic error that printed the var's default value. Comparing a backend var or a mixin's field with a value (`State._secret == "x"`) or truth-testing it now raises the same error, instead of a plain `False` or `True` that made `rx.cond` always take one branch. Fields still compare equal to themselves. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -789,12 +789,15 @@ def test_component_create_unallowed_types(children, test_component): | |
|
|
||
|
|
||
| def test_component_create_backend_var_child(test_component): | ||
| """A backend var child reports its type rather than formatting the field.""" | ||
| """A backend var child raises the backend var format error.""" | ||
|
|
||
| class BackendChildState(BaseState): | ||
| _secret: int = 42 | ||
|
|
||
| with pytest.raises(ChildrenTypeError, match=r"received child of type Field\."): | ||
| with pytest.raises( | ||
| BackendVarFormatError, | ||
| match=r"Backend var 'BackendChildState\._secret' exists only", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: This prefix-only Prompt for AI agents |
||
| ): | ||
| test_component.create(BackendChildState._secret) | ||
|
|
||
|
|
||
|
|
@@ -844,14 +847,35 @@ def test_component_create_event_child(make_child, type_name, test_component): | |
| ] | ||
|
|
||
|
|
||
| def test_component_create_backend_var_prop(): | ||
| """A backend var passed to a typed prop reports its repr, not a format error.""" | ||
| class BackendPropState(BaseState): | ||
| """A state with a backend var, for typed prop misuse tests.""" | ||
|
|
||
| _size: str = "3" | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "create", | ||
| [ | ||
| lambda f: rx.heading("x", size=f), | ||
| lambda f: rx.el.div(title=f), | ||
| lambda f: rx.link("x", href=f), | ||
| ], | ||
| ids=["heading_size", "div_title", "link_href"], | ||
| ) | ||
| def test_component_create_backend_var_prop(create: Callable[[Any], Component]): | ||
| """A backend var passed to a typed prop raises the backend var format error. | ||
|
|
||
| class BackendPropState(BaseState): | ||
| _size: str = "3" | ||
| The error must not include the field's default value. | ||
|
|
||
| with pytest.raises(TypeError, match=r"got value Field\(default='3'"): | ||
| rx.heading("x", size=BackendPropState._size) # pyright: ignore[reportArgumentType] | ||
| Args: | ||
| create: Creates a component with the backend var as a prop. | ||
| """ | ||
| with pytest.raises( | ||
| BackendVarFormatError, | ||
| match=r"Backend var 'BackendPropState\._size' exists only", | ||
| ) as exc_info: | ||
| create(BackendPropState._size) | ||
| assert "default=" not in str(exc_info.value) | ||
|
Comment on lines
+873
to
+878
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Context Used: CLAUDE.md (source) Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||
|
|
||
|
|
||
| class BackendSrcState(BaseState): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -333,6 +333,46 @@ def test_add_page_backend_var_meta_raises_format_error( | |
| app.add_page(index_page, route="/meta", **{key: BackendMetaState._meta}) # pyright: ignore[reportArgumentType] | ||
|
|
||
|
|
||
| def test_add_page_backend_var_meta_content_raises_format_error( | ||
| app: App, index_page: ComponentCallable | ||
| ): | ||
| """A backend var in a meta tag's content raises when the page is compiled. | ||
|
|
||
| Args: | ||
| app: The app to test. | ||
| index_page: The index page. | ||
| """ | ||
| app.add_page( | ||
| index_page, | ||
| route="/meta", | ||
| meta=[{"name": "x", "content": BackendMetaState._meta}], | ||
| ) | ||
| with pytest.raises( | ||
| exceptions.BackendVarFormatError, | ||
| match=r"Backend var 'BackendMetaState\._meta' exists only", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The new Prompt for AI agents |
||
| ): | ||
| app._compile_page("meta") | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("as_list", [False, True]) | ||
| def test_add_page_backend_var_on_load_raises_format_error( | ||
| app: App, index_page: ComponentCallable, as_list: bool | ||
| ): | ||
| """A backend var passed as on_load raises when the page is added. | ||
|
|
||
| Args: | ||
| app: The app to test. | ||
| index_page: The index page. | ||
| as_list: Whether on_load is given as a list. | ||
| """ | ||
| on_load = [BackendMetaState._meta] if as_list else BackendMetaState._meta | ||
| with pytest.raises( | ||
| exceptions.BackendVarFormatError, | ||
| match=r"Backend var 'BackendMetaState\._meta' exists only", | ||
| ): | ||
| app.add_page(index_page, route="/meta", on_load=on_load) # pyright: ignore[reportArgumentType] | ||
|
|
||
|
|
||
| def test_add_page_set_route(app: App, index_page: ComponentCallable): | ||
| """Test adding a page to an app. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,6 @@ | |
| from reflex_base.utils.exceptions import ( | ||
| BackendVarFormatError, | ||
| EventHandlerArgTypeMismatchError, | ||
| EventHandlerTypeError, | ||
| EventHandlerValueError, | ||
| ) | ||
| from reflex_base.utils.form import FormData | ||
|
|
@@ -266,20 +265,23 @@ def args_spec(value: Var[dict]) -> list[Var[dict]]: | |
| assert handler.prevent_default._type_hints is handler._type_hints | ||
|
|
||
|
|
||
| def test_backend_var_event_arg_reports_repr(): | ||
| """A backend var passed as an event arg reports its repr, not a format error.""" | ||
| def test_backend_var_event_arg_raises_format_error(): | ||
| """A backend var passed as an event arg raises the backend var format error.""" | ||
|
|
||
| class S(BaseState): | ||
| class BackendEventArgState(BaseState): | ||
| _secret: int = 42 | ||
|
|
||
| @event | ||
| def on_event(self, value: int): | ||
| pass | ||
|
|
||
| with pytest.raises(EventHandlerTypeError, match=r"Got Field\(default=42"): | ||
| S.on_event(S._secret) | ||
| with pytest.raises(EventHandlerTypeError, match=r"Got Field\(default=42"): | ||
| cast(EventSpec, S.on_event()).add_args(S._secret) # pyright: ignore[reportArgumentType] | ||
| match = r"Backend var 'BackendEventArgState\._secret' exists only" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: This Prompt for AI agents |
||
| with pytest.raises(BackendVarFormatError, match=match): | ||
| BackendEventArgState.on_event(BackendEventArgState._secret) | ||
| with pytest.raises(BackendVarFormatError, match=match): | ||
| cast(EventSpec, BackendEventArgState.on_event()).add_args( | ||
| BackendEventArgState._secret # pyright: ignore[reportArgumentType] | ||
| ) | ||
|
|
||
|
|
||
| class BackendTriggerState(BaseState): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: This paragraph documents the
str()/f-string raising as 0.10 behavior, but the 0.11 guide and the v0.11.0 changelog put it in 0.11, and v0.10.1 does not mention it. Move thestr()/f-string sentence to the 0.11 guide only, or correct the version it names.Prompt for AI agents