maxfordham / ipyautoui

create ipywidgets user input form pydantic model or jsonschema
https://maxfordham.github.io/ipyautoui/
40 stars 4 forks source link

Implement bounded widgets #187

Open Will-Curwen opened 1 year ago

Will-Curwen commented 1 year ago

Feature request Implement BoundedFloatText and BoundedIntText into autowidgets.

Solution Add to autowidgets:

class BoundedFloatText(w.BoundedFloatText):
    def __init__(self, schema):
        self.schema = schema
        self.caller = create_widget_caller(schema)
        super().__init__(**self.caller)

NOTE The below works but defaults upper limit to 100. If ge just specified, should we make the upper limit sys.float_info.max?

from pydantic import BaseModel
class Test(BaseModel):
    working_plane_height: float = Field(default = 0.8, ge=0, le=sys.float_info.max, autoui="BoundedFloatText")
jgunstone commented 1 year ago

good idea -

if there is a "minimum" and "maximum" in the jsonschema it will automatically resolve to a slider... we should probably make it easier than shown above to revert to another valid option...

pydantic offers more specific numeric types:

https://docs.pydantic.dev/latest/usage/types/number_types/#constrained-integers

from pydantic import (
    BaseModel,
    NegativeInt,
    NonNegativeInt,
    NonPositiveInt,
    PositiveInt,
)

class Model(BaseModel):
    positive: PositiveInt
    negative: NegativeInt
    non_positive: NonPositiveInt
    non_negative: NonNegativeInt

m = Model(positive=1, negative=-1, non_positive=0, non_negative=0)
print(m)
#> positive=1 negative=-1 non_positive=0 non_negative=0

m.model_json_schema()
#> {'properties': {'positive': {'exclusiveMinimum': 0, 'title': 'Positive', 'type': 'integer'}, 'negative': {'exclusiveMaximum': 0, 'title': 'Negative', 'type': 'integer'}, 'non_positive': {'maximum': 0, 'title': 'Non Positive', 'type': 'integer'}, 'non_negative': {'minimum': 0, 'title': 'Non Negative', 'type': 'integer'}}, 'required': ['positive', 'negative', 'non_positive', 'non_negative'], 'title': 'Model', 'type': 'object'}

which convert to these json schema vals https://json-schema.org/understanding-json-schema/reference/numeric.html#range a PositiveInt will have an minimum but won't have a maximum in this scenario we could automatically resolve to a BoundedIntText. it automatically assigns max as 100 if nothing given:

import ipywidgets as w_
>>> w_ = widgets.BoundedIntText(
...     value=71,
...     min=0,
...     step=1,
...     description='Text:',
...     disabled=False
... )
>>> w_.max
100

so maybe this is when sys.float_info.max is used...