-
Notifications
You must be signed in to change notification settings - Fork 53
feat: add guiclass decorator #498
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
Conversation
|
I love this, and will be an avid user :) I assume it's intended to also allow keywords for extra customizability the same as with functions? |
|
All widget specific customizations should come either in Annotated type annotations, or in a data classes.field() metadata entry. (I dislike the "kwargs with the same name as the parameter" pattern in magicgui... and want to move towards type annotations only) I'm still thinking about where the container level config (like layout, etc) should go |
|
I see; I like the move to annotations only, I often found it counterintuitive (especially to explain) whether something was supposed to be in the annotation or in the kwarg. I mean, there's still a bit the problem, but at least they're on the same line :P So you mean something like: from magicgui._guiclass import button, guiclass
from dataclasses import field
@guiclass
class Foo:
a: int = field(widget_type='Slider', ...)
b: str = "bar"
@button
def func(self):
print(self)
foo = Foo()
foo.gui.show() |
|
yeah, something like that (though note that since you're using More generally though, the goal here is to support any sort of dataclass (pydantic, attrs, dataclasses) etc... have a look through this test to see all the patterns that we can build widgets from. So really here, the key bit about class GuiBuilder:
def __get__(self, instance, owner):
wdg = build_widget(instance or owner)
if instance:
# this part assumes we have an evented instance
bind_gui_to_instance(wdg, instance)
return wdg
@evented
@dataclass
class MyClass:
x: int
gui = GuiBuilder()
# or, with guiclass, just:
@guiclass
class MyClass:
x: intand so, the widget-level control can come in so many different ways: dataclasses @dataclass
class Foo:
c: float = field(default=0.0, metadata={"widget": "FloatSlider", "maximum": 100})attrs import attrs
@attrs.define
class Foo:
c: float = attrs.field(default=0.0, metadata={"widget": "FloatSlider", "maximum": 100})pydantic class Foo(pydantic.BaseModel):
c: float = pydantic.Field(0, widget="FloatSlider", le=100)from magicgui.schema import UiField
@dataclass
class Foo:
c: Annotated[float, UiField(widget='Slider', maximum=100)] = 0
# or
from annotated_types import Le
@dataclass
class Foo:
c: Annotated[float, Le(100)] = 0so the magicgui-specific part is really quite "light" here. just accepting any form of dataclass and building a widget. and then, optionally offering a |
Codecov ReportBase: 89.61% // Head: 89.75% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## main #498 +/- ##
==========================================
+ Coverage 89.61% 89.75% +0.13%
==========================================
Files 36 37 +1
Lines 4353 4441 +88
==========================================
+ Hits 3901 3986 +85
- Misses 452 455 +3
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
|
This will go through more iterations before it becomes public, but I'm going to merge it as is to play with it some more. Will probably release a long-lived rc soon |
this adds a
guiclassdecorator that combinespsygnal.eventedanddataclasses.dataclassas well as a descriptor method for building a widget, as a one-stop-shop for easily creating a dataclass that can create a gui with two-way communication with the underlying object. It also implements @brisvag's suggestion for the@buttondecoratoras with #475 ... this is all still private and internally experimental
see test for example ... which looks like this: