-
-
Notifications
You must be signed in to change notification settings - Fork 630
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
Introduce bindable dataclass fields #3987
base: main
Are you sure you want to change the base?
Conversation
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.
Thank you for the pull request, @balex89!
@rodja and I thought about the API quite a bit. Requiring the @bindable_dataclass
decorator and the field wrapper feels a bit verbose. In #3957 you wrote "One might want to be able to pick specific attributes only". But let's question this requirement. Do we really need to handle this use case? I know, the bindable_field
function was kind of my idea. But if 99% of our users want to mark all fields as bindable anyway, your initial approach of converting all fields would be much simpler and nicer to use. What do you think?
Apart from that we think we should merge @dataclass
and @bindable_dataclass
so that the user doesn't have to write both decorators and remember the right order. The new decorator would simply forward all keyword arguments to the dataclass
decorator.
@falkoschindler, I do agree on making that a default behavior. And yet, shouldn't we leave an option to specify fields explicitly for those 1%? For instance: @bindable_dataclass
class A:
x: int # bindable
y: int # bindable
z: int # bindable
@bindable_dataclass(bindable_fields=['x', 'y'])
class B:
x: int # bindable
y: int # bindable
z: int # not bindable That doesn't seem to complicate implementation or interface much while providing full control on attribute picking, if ever needed. As was said above, we forward additional |
@balex89 You're right. Even though we could add such an additional attribute later on demand, we can as well add it right now. 👍 |
2b22bd9
to
d7c3418
Compare
API is simplified according to comments above. |
Thanks for the update, @balex89! I just tested with the following code: @binding.bindable_dataclass # version 1
# @binding.bindable_dataclass(bindable_fields=['x']) # version 2
# @binding.bindable_dataclass(slots=True) # version 3
class A:
x: float
y: float
a = A(x=1, y=2) # a should be of type A
x = a.x # x should be of type float
with ui.row():
ui.number('X').bind_value(a, 'x')
ui.slider(min=0, max=10).bind_value(a, 'x')
with ui.row():
ui.number('Y').bind_value(a, 'y')
ui.slider(min=0, max=10).bind_value(a, 'y') It mostly works as expected, but there are still some subtle issues:
|
@falkoschindler, I pushed some improvements. Futher down your list:
|
This PR follows up an idea #3957 to introduce bindable
dataclasses.dataclass
fields.The main challenge is to marry
bindableProperty
withdataclasses.field
, and by that preserve native dataclass features.The proposed idea is to use a wrapper around dataclasses.field that updates passed
metadata
, adding nicegui-specific options (for now just a "bindable" flag). Then use it to addbindableProperties
retroactively on dataclass type postprocessing (much like it is done in dataclasses_json.config)Usage example
Known tradeoffs
MyClass.x
) is lost.