diff --git a/src/ipyautoui/autoform.py b/src/ipyautoui/autoform.py index 84ab745b..12e46e90 100644 --- a/src/ipyautoui/autoform.py +++ b/src/ipyautoui/autoform.py @@ -1,5 +1,3 @@ -# + - """layout attributes of a form box """ # %run _dev_maplocal_params.py @@ -9,34 +7,19 @@ import typing as ty from IPython.display import display, clear_output -from ipyautoui.constants import BUTTON_WIDTH_MIN +from ipyautoui.nullable import Nullable +from ipyautoui.constants import KWARGS_SHOWNULL, KWARGS_SHOWRAW, SHOWNULL_ICON_SHOW, SHOWNULL_ICON_HIDE from ipyautoui.custom.buttonbars import SaveButtonBar from ipyautoui.custom.title_description import TitleDescription from ipyautoui._utils import display_python_string, show_hide_widget -from ipyautoui.nullable import Nullable def make_bold(s: str) -> str: return f"{s}" # - - -SHOWNULL_ICON_SHOW = "plus" -SHOWNULL_ICON_HIDE = "minus" -KWARGS_SHOWNULL = dict( - icon=SHOWNULL_ICON_SHOW, - layout=w.Layout(width=BUTTON_WIDTH_MIN, display=""), - tooltip="show null form fields", - style={"font_weight": "bold"}) -KWARGS_SHOWRAW = dict(icon="code", - layout=w.Layout(width=BUTTON_WIDTH_MIN, display="None"), - tooltip="show raw data", - style={"font_weight": "bold"}, - ) - - class ShowNull(tr.HasTraits): - display_bn_shownull = tr.Bool(default_value=True) + display_bn_shownull = tr.Bool(default_value=True) @tr.observe("display_bn_shownull") def _observe_display_bn_shownull(self, change): @@ -63,20 +46,13 @@ def bn_shownull(self): def bn_shownull(self, value): self._bn_shownull = value - def show_hide_bn_nullable(self): # work with AutoObject only - is_nullable = [True for v in self.di_widgets.values() if isinstance(v, Nullable)] - if len(is_nullable) > 0: - if self.display_bn_shownull: - show_hide_widget(self.bn_shownull, self.display_bn_shownull) - # NOTE: don't think should be required but it appeared to be saving the - # state of the button.layout.display between objects otherwise ... - # ... not sure... but this seems to fix it - else: - self.display_bn_shownull = True + def show_hide_bn_nullable(self): + """Set display of show null button based on if any nullable widgets are found.""" + if self.check_for_nullables(): # check_for_nullables is defined in AutoObject + self.display_bn_shownull = True else: self.display_bn_shownull = False - - + if __name__ == "__main__": sn = ShowNull() @@ -247,11 +223,6 @@ class AutoObjectFormLayout(ShowRaw, ShowNull, WrapSaveButtonBar): # + - - - - - def demo_autoobject_form(title="test", description="a description of the title"): """for docs and testing only...""" from ipyautoui.custom.buttonbars import SaveButtonBar diff --git a/src/ipyautoui/autoobject.py b/src/ipyautoui/autoobject.py index c95b6ef9..bdda2a73 100644 --- a/src/ipyautoui/autoobject.py +++ b/src/ipyautoui/autoobject.py @@ -21,23 +21,18 @@ import logging import pathlib -import functools import ipywidgets as w -from IPython.display import display +import pandas as pd # TODO: pandas is a heavy dep. if only used for pd.isnull... ? import traitlets as tr -import typing as ty -import json +from IPython.display import display +from jsonref import replace_refs import ipyautoui.automapschema as aumap from ipyautoui._utils import obj_from_importstr from ipyautoui.nullable import Nullable from ipyautoui.autobox import AutoBox from ipyautoui.autoform import AutoObjectFormLayout -from jsonref import replace_refs -from pydantic import BaseModel from ipyautoui.watch_validate import WatchValidate from ipyautoui.custom.title_description import TitleDescription -import contextlib -import pandas as pd # TODO: pandas is a heavy dep. if only used for pd.isnull... ? logger = logging.getLogger(__name__) @@ -438,6 +433,14 @@ def di_widgets_value(self): # used to set _value get_value = lambda v: v._value if "_value" in v.traits() else v.value return {k: get_value(v) for k, v in self.di_widgets.items()} + def check_for_nullables(self) -> bool: + """Search through widgets and as soon as a Nullable widget is found, return True. + Else, return False.""" + for v in self.di_widgets.values(): + if isinstance(v, Nullable): + return True + return False + class AutoObjectForm(AutoObject, AutoObjectFormLayout): def __init__(self, **kwargs): @@ -452,7 +455,7 @@ def __init__(self, **kwargs): self.vbx_showraw, ] self.show_hide_bn_nullable() - + def display_ui(self): # NOTE: this overwritten this in AutoObjectForm self.vbx_widget.layout.display = "" diff --git a/src/ipyautoui/autoui.py b/src/ipyautoui/autoui.py index 1b3ce0b7..3dd231aa 100644 --- a/src/ipyautoui/autoui.py +++ b/src/ipyautoui/autoui.py @@ -31,37 +31,25 @@ # %load_ext lab_black import pathlib -from IPython.display import display -from pydantic import BaseModel, ValidationError import json +import logging +import functools import traitlets as tr import typing as ty -from ipyautoui.autoform import AutoObjectFormLayout, ShowRaw -from ipyautoui.custom import SaveButtonBar # removing makes circular import error -import json -import logging -from ipyautoui.automapschema import map_widget, widgetcaller, _init_model_schema import ipywidgets as w -from pydantic import BaseModel -from ipyautoui.automapschema import pydantic_validate -from IPython.display import clear_output -from ipyautoui.automapschema import ( - map_widget, - widgetcaller, - _init_model_schema, - get_widgets_map, - get_containers_map, -) +from pydantic import BaseModel, ValidationError +from IPython.display import display + +from ipyautoui.custom import SaveButtonBar # removing makes circular import error from ipyautoui.autobox import AutoBox -from ipyautoui.autoform import TitleDescription, WrapSaveButtonBar, ShowRaw, ShowNull +from ipyautoui.autoform import AutoObjectFormLayout, TitleDescription, WrapSaveButtonBar, ShowRaw, ShowNull from ipyautoui.custom.editgrid import EditGrid +from ipyautoui.automapschema import get_widgets_map, get_containers_map, map_widget, widgetcaller, _init_model_schema, pydantic_validate + logger = logging.getLogger(__name__) # + -import functools - - def wrapped_partial(func, *args, **kwargs): # http://louistiao.me/posts/adding-__name__-and-__doc__-attributes-to-functoolspartial-objects/ partial_func = functools.partial(func, *args, **kwargs) @@ -217,9 +205,6 @@ def create_autodisplay_map( return {ext: AutoRenderer} - - - def get_autoui(schema: ty.Union[ty.Type[BaseModel], dict], **kwargs): model, schema = _init_model_schema(schema) schema = {**schema, **kwargs} @@ -258,6 +243,7 @@ def _set_children(self): self.vbx_widget, self.vbx_showraw, ] + self.show_hide_bn_nullable() if model is not None: return wrapped_partial( diff --git a/src/ipyautoui/constants.py b/src/ipyautoui/constants.py index 4651b63f..5c5d914f 100644 --- a/src/ipyautoui/constants.py +++ b/src/ipyautoui/constants.py @@ -138,6 +138,19 @@ layout={"width": BUTTON_WIDTH_MIN}, ) +SHOWNULL_ICON_SHOW = "plus" +SHOWNULL_ICON_HIDE = "minus" +KWARGS_SHOWNULL = frozenmap( + icon=SHOWNULL_ICON_SHOW, + layout=dict(width=BUTTON_WIDTH_MIN, display=""), + tooltip="show null form fields", + style={"font_weight": "bold"}) +KWARGS_SHOWRAW = frozenmap(icon="code", + layout=dict(width=BUTTON_WIDTH_MIN, display="None"), + tooltip="show raw data", + style={"font_weight": "bold"}, + ) + KWARGS_DATAGRID_DEFAULT = frozenmap( header_renderer=TextRenderer( diff --git a/tests/test_autoobject.py b/tests/test_autoobject.py index 5c801e68..480504aa 100644 --- a/tests/test_autoobject.py +++ b/tests/test_autoobject.py @@ -106,7 +106,7 @@ class NoNullables(BaseModel): a: str = Field(default="Test", description="This test is important") b: str = Field(default="Test1", description="This test is important too") - ui = AutoObjectForm.from_pydantic_model(NoNullables) + ui = AutoObjectForm.from_pydantic_model(NoNullables) assert ui.display_bn_shownull == False assert ui.bn_shownull.layout.display == "None"