-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add validation to function vars #4379
base: main
Are you sure you want to change the base?
Conversation
blocked on microsoft/pyright#9470 |
Are we able to mitigate this with smth like this? from typing import TYPE_CHECKING
from typing_extensions import Self, reveal_type
class Function:
def __call__(self, *args, **kwargs) -> Self:
return self
class ArrayLike:
__getitem__ = Function()
if TYPE_CHECKING:
def __getitem__(self, index) -> Function: ...
x = ArrayLike()[0]
reveal_type(x) # Type of "x" is "Function"
print(type(x)) |
No :( the reason is that We could give up on function vars being like that for dunder methods though, and keep them for normal ones. But I do like the symmetry and I don't want to break it. |
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.
i have to admit this one scares me from a maintainability perspective.
i read through all the code, but i think i'd prefer if we can walk through it together and help me put the pieces together in my head.
not sure if dev documentation is planned for this change, but i think it would be really helpful for future maintainers to understand some of these constructs, like the type_computer.
frozen=True, | ||
**{"slots": True} if sys.version_info >= (3, 10) else {}, | ||
) | ||
class MatchOperation(CachedVarOperation, Var[VAR_TYPE]): |
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.
is this in the number module?
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.
it's there because the bool is there (same goes for ternary), although i admit it's pretty confusing
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.
Generated code is looking much more concise, thanks.
Still not working with form-designer
though:
reflex.utils.exceptions.MatchTypeError: Match cases should have the same return types. Expected return types to be of type Component or Var[Component]. Return type of case 0 is typing.Union[typing.List[reflex.components.radix.themes.layout.box.Box], reflex.components.radix.themes.typography.text.Text]
|
I'm wanting to wait on this one until we can properly turn the components in cond/foreach into StatefulComponents that only bring in the state that they depend on. We tried to convert to A plausible fix to make this work is to identify any non-state vars in the StatefulComponent and replace those with props that get passed into the resulting component. For example, if something in the stateful component references |
Here is an example of how this goes off the rails: Using this patch diff --git a/reflex/components/component.py b/reflex/components/component.py
index 8c3bc518..5fc3d843 100644
--- a/reflex/components/component.py
+++ b/reflex/components/component.py
@@ -2274,6 +2274,10 @@ class StatefulComponent(BaseComponent):
return _compile_component(self)
+ def __getattr__(self, name) -> Any:
+ # if we don't provide the attribute, get it from the wrapped component
+ return getattr(self.component, name)
+
@classmethod
def compile_from(cls, component: BaseComponent) -> BaseComponent:
"""Walk through the component tree and memoize all stateful components.
@@ -2474,6 +2478,8 @@ class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
Returns:
The var.
"""
+ if not isinstance(value, StatefulComponent):
+ value = StatefulComponent.compile_from(value) or value
return LiteralComponentVar(
_js_expr="",
_var_type=type(value), With the following app: import reflex as rx
def index() -> rx.Component:
return rx.vstack(
rx.foreach(
["one", "two", "three"],
lambda item: rx.text(item, on_click=rx.console_log(item)),
)
)
app = rx.App()
app.add_page(index) We currently end up generating code like this export function Text_719e7690cbbecf6b33f0b7a94350b86a() {
const [addEvents, connectErrors] = useContext(EventLoopContext);
const on_click_63778f856f6473ddf372e334cf3dc24c = useCallback(
(...args) =>
addEvents(
[
Event(
"_call_function",
{
["function"]: () => console["log"](sefdkzeh),
["callback"]: null,
},
{}
),
],
args,
{}
),
[addEvents, Event]
);
return (
<RadixThemesText
as={"p"}
onClick={on_click_63778f856f6473ddf372e334cf3dc24c}
>
{sefdkzeh}
</RadixThemesText>
);
}
export function Flex_614876435cb70b6f7eb23c7998c05171() {
return (
<RadixThemesFlex
align={"start"}
className={"rx-Stack"}
direction={"column"}
gap={"3"}
>
{Array.prototype.map.apply(
["one", "two", "three"],
[(sefdkzeh) => jsx(Text_719e7690cbbecf6b33f0b7a94350b86a, {})]
)}
</RadixThemesFlex>
);
} But really we need to be passing the loop variable into the stateful component function as a prop |
No description provided.