-
Notifications
You must be signed in to change notification settings - Fork 50
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
UIFields and dataclasses: near-term roadmap for magicgui #474
Comments
Love this! It came up before several times, and I'm one of the many who use magicgui in the way you described. Couldn't be more on board! |
It looks like something that will allow replacing part of the old PartSeg code. I like it. |
I totally agree with these updates! One thing I concern is that users still have to rely on class Person:
button = SomeField(widget_type=PushButton) but,
I think the direct widget API still needs more emphasis. |
Yeah, this feels odd... My intuition would want something like this: class Person:
@button
def callback(self): ... |
Yeah, I recognize that buttons are still problematic. They are, of course, fundamentally a bit different than all of the other ValueWidgets in that they don't (really) contain a value. So, keeping with that, I don't see them as part of the dataclass & UiField abstraction per se... but rather something that would come on top of it / in addition to it. I do like something along the lines of the @dataclass
class Person:
name: str
age: int = 0
@button(label='Say Hi', order=0)
def _say_hi(self):
print(f"hi {self.name}!") then: model = build_model(Person)
# [
# UiField(name='_say_hi', label='Say Hi', widget='PushButton', on_click=Person._say_hi)
# UiField(name='name', type=str),
# UiField(name='age', type=int, default=0),
# ]
# ... or something like that
I agree with this, and that would be part of the docs update mentioned in the original post |
Just wanted to lay out in writing some of the near-term plans that I have for magicgui:
Widget "fields" not "parameters"
I regret that function signatures were chosen as the most common way to instantiate and present a group of widgets in magicgui. I think it is one or two levels "too high". A think a better parallel would have been dataclasses. So many things fall into the general pattern of
name: annotation = default value
beyond just functions, such astyping.NamedTuple
,typing.TypedDict
,dataclasses.dataclass
,pydantic.BaseModel
,attrs.define
... and, yes, function signatures.Rather than framing a widget as having a relation to an
inspect.Parameter
(see magicgui/signature.py), i think a better analogue would have beendataclasses.Field
. Currently, if one wants to make a compound widget in magicgui, you either manually construct it using the direct widget API withContainer
andcreate_widget
, or you create a function and use@magicgui
(which then usesinspect.signature
and widgets are created for eachParameter
withMagicParameter.to_widget()
).I've seen people do this:
...just to create a widget. Which is a good indicator that the abstraction was too specific. There are plenty of use cases where one just wants to collect some data without necessarily passing them all to a specific function.
a collection of
UiField
sIn upcoming PRs, I'll be creating a "parallel API" (probably under a
v2
ordatagui
namespace) that instead adds amagicgui.UiField
object, (akin todataclasses.Field
, orpydantic.fields.ModelField
orattrs.Attribute
) that stores the metadata associated with a widget. This will still applicable to function signatures, but will make it much easier to construct a widget using a dataclass, or pydantic model, or attrs class, etc...:under the hood, each of these is reduced to a gui model that consists of a sequence of
UIFields
:and then to make a widget:
what about
@magicgui
for functionsFunctions are still easy: you can always connect a callback to be called with the current values of the widgets... but it should be much easier to create a widget representing a set of fields without having to associate them with some callback. So none of this needs to affect the use case for functions... it's more about how we conceive of the underlying model here.
JSON schema connection
I'd like
UiField
to have a direct parallel with other schema languages, with JSON schema being the reference. So, all of the keywords in the validation vocabulary (things likemaximum
,maxLength
,multipleOf
, etc...) would have direct parallels in theUiField
object (similar to a pydantic FieldInfo object). This would provide an easier connection with non-python representations of data schema, and would make it easier to do things in browsers (e.g. jupyter) with one of many javascript libraries that create UIs from schemas.TODO:
UiField
as the new intermediate object representing widget parameters #475UiModel
representationtype_map.py
(it has become messy)__init__
signatures, possibly deprecate/rename things (mostly done in docs: attempting to simplify/clarify widget init docstrings #519)@magicgui
to use theUiField
stuff instead ofMagicSignature
, etcSpinBox
,Slider
, etc..))int
->SpinBox
)Container
widget... which has parallels to a dataclass APIThe text was updated successfully, but these errors were encountered: