Skip to content

Commit fe0f803

Browse files
authored
Merge branch 'ssciwr:main' into string-format
2 parents c1b88cb + 1588566 commit fe0f803

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

ipywidgets_jsonschema/form.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import re
1414
import traitlets
1515
import collections.abc
16+
from pydantic import BaseModel
1617

1718
# We are providing some compatibility for ipywidgets v7 and v8
1819
IS_VERSION_8 = version.parse(ipywidgets.__version__).major == 8
@@ -48,6 +49,15 @@ def as_tuple(obj):
4849
return (obj,)
4950

5051

52+
def convert_pydantic_to_schema(model) -> dict:
53+
"""
54+
Converts a Pydantic model class to its corresponding JSON schema.
55+
"""
56+
if isinstance(model, type) and issubclass(model, BaseModel):
57+
return model.model_json_schema()
58+
return model
59+
60+
5161
def minmax_schema_rule(widget, schema):
5262
"""This implements the minimum/maximum rules
5363
@@ -122,6 +132,7 @@ def __init__(
122132
A function that is used to sort the keys in a dictionary. Defaults to
123133
the built-in sorted, but is no-op if sorted raises a TypeError.
124134
"""
135+
schema = convert_pydantic_to_schema(schema)
125136
# Make sure that the given schema is valid
126137
Draft7Validator.check_schema(schema)
127138

@@ -449,6 +460,25 @@ def pattern_checker(val):
449460
def _register_observer(h, n, t):
450461
widget.observe(h, names=n, type=t)
451462

463+
warning_label = ipywidgets.Label(
464+
"", layout=ipywidgets.Layout(color="red", display="none")
465+
)
466+
467+
def _observer(change):
468+
if not pattern_checker(widget.value):
469+
pattern = schema.get("pattern", ".*")
470+
warning_label.value = (
471+
f"Warning: Input does not match the specified pattern"
472+
)
473+
warning_label.layout.display = "block"
474+
change.owner.layout.border = "2px solid red"
475+
else:
476+
change.owner.layout.border = "none"
477+
warning_label.value = ""
478+
warning_label.layout.display = "none"
479+
480+
widget.observe(_observer, names="value", type="change")
481+
452482
def _setter(_d):
453483
if pattern_checker(_d):
454484
widget.value = _d
@@ -519,7 +549,7 @@ def _getter():
519549
getter=_getter,
520550
setter=_setter,
521551
resetter=_resetter,
522-
widgets=[box],
552+
widgets=[box, warning_label],
523553
register_observer=_register_observer,
524554
)
525555

@@ -967,12 +997,18 @@ def _resetter():
967997
# Initially call the resetter
968998
_resetter()
969999

1000+
def _getter():
1001+
result = [h.getter() for h in elements[:element_size]]
1002+
if schema.get("uniqueItems", False):
1003+
result = list(set(result))
1004+
return result
1005+
9701006
wrapped_vbox[0] = self._wrap_description(
9711007
wrapped_vbox[0], schema.get("description", None)
9721008
)
9731009

9741010
return self.construct_element(
975-
getter=lambda: [h.getter() for h in elements[:element_size]],
1011+
getter=_getter,
9761012
setter=_setter,
9771013
resetter=_resetter,
9781014
widgets=wrapped_vbox,

tests/schemas/array-set.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"default": [],
3+
"invalid": [
4+
[
5+
"1",
6+
"1",
7+
"3"
8+
]
9+
],
10+
"schema": {
11+
"description": "Bla bla",
12+
"items": {
13+
"default": "foo",
14+
"type": "string"
15+
},
16+
"type": "array",
17+
"uniqueItems": true
18+
},
19+
"valid": [
20+
[
21+
"foo"
22+
],
23+
[
24+
"1",
25+
"2",
26+
"3"
27+
]
28+
]
29+
}

0 commit comments

Comments
 (0)