magicgui icon indicating copy to clipboard operation
magicgui copied to clipboard

Initial support for pydantic models

Open tlambert03 opened this issue 4 years ago • 3 comments

A start on #98: support for pydantic models.

I say a "start" because I'm certain there are going to be types that are rather easy to declare in pydantic, for which generating a widget is not straightforward.

@aeisenbarth, I'd be curious to hear your experience if you pull this and try it with your models. See examples/pydantic_model ... (basic idea is that magicui() now also takes a BaseModel as an argument

tlambert03 avatar Nov 14 '21 17:11 tlambert03

Codecov Report

Merging #318 (4eafd75) into main (b30588d) will decrease coverage by 1.69%. The diff coverage is 21.42%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #318      +/-   ##
==========================================
- Coverage   90.33%   88.64%   -1.70%     
==========================================
  Files          29       30       +1     
  Lines        3364     3442      +78     
==========================================
+ Hits         3039     3051      +12     
- Misses        325      391      +66     
Impacted Files Coverage Δ
magicgui/_pydantic.py 0.00% <0.00%> (ø)
magicgui/type_map.py 90.42% <38.88%> (-5.49%) :arrow_down:
magicgui/_magicgui.py 91.37% <40.00%> (-4.92%) :arrow_down:
magicgui/types.py 97.61% <75.00%> (-2.39%) :arrow_down:
magicgui/__init__.py 62.50% <100.00%> (+2.50%) :arrow_up:
magicgui/backends/_qtpy/widgets.py 86.26% <100.00%> (+0.03%) :arrow_up:
magicgui/widgets/_bases/container_widget.py 92.34% <100.00%> (ø)
magicgui/widgets/_bases/create_widget.py 97.22% <100.00%> (ø)
magicgui/widgets/_concrete.py 84.63% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update b30588d...4eafd75. Read the comment docs.

codecov[bot] avatar Nov 14 '21 17:11 codecov[bot]

Thanks, this looks good! In my GUI, I wasn't annotating a function signature but I subclassed Container and added widgets using the direct widget API. This GUI class is then registered as a dock, and it has a model attribute which is the Pydantic model (the GUI class itself was not a Pydantic class). So it took me a while to see how I best integrate this.

I tried two approaches:

  1. Keep my Pydantic model under the model attribute, convert it to a widget and add it to the container

    class MyDock(Container):
        …
        inputs = model_widget(self.model.__class__) # Important: I used to instantiate my model, but here the class is needed.
        self.append(inputs)
    
    • Pro: It is easy to add more widgets (buttons, layer selector) and you are not required to have them in the model.
    • Issues: I tried the Tuple[int, int] annotation and it can only have a label/tooltip on container of the tuple, not different texts individually on the inputs for each int. Alternatively I used a nested pydantic model (class Shape(BaseModel) … grid_shape: Shape = Field(title="Shape", ui_layout="horizontal")) with two int attributes, but the container created from this submodel would not take up the submodel's properties ("grid_shape" instead of "Shape", and vertical layout instead of horizontal)
  2. Turn the dock into a Pydantic model (class MyDock(BaseModel)

    • In my UI init function added to this model class, it is not clear how to access the input widgets to connect them to further functions because accessing an attribute gives its value, not the created widget.
    • Also I could not append extra widgets that are not represented in the model. Underscored attributes (_my_private_attribute) would cause errors in Pydantic.

aeisenbarth avatar Nov 22 '21 12:11 aeisenbarth

pydantic -> widgets? If so I think that would make a great example/ call out because I see that as a major usecase of this too. Maybe once this is merged we could then drop our vendored qtjsonschema and use this instead (cc @ppwadhwa @goanpeca).

Thanks for the ping @sofroniewn. We could do pydantic -> widgets directly, but need to make sure to add the ability to provide custom widgets that follow an interface, we could actually reuse some of the qtjsonschema code.

goanpeca avatar Nov 22 '21 15:11 goanpeca

closing this in favor of #446

tlambert03 avatar Aug 24 '22 13:08 tlambert03