Skip to content

Commit

Permalink
Pass key constraints as propertyNames in JSON Schema
Browse files Browse the repository at this point in the history
This adds support for publicizing constraints on dict keys using the
`propertyNames` field when generating a JSON Schema. For now this is
only done for dicts with string keys; constraints on other key types are
trickier to specify.
  • Loading branch information
jcrist committed Dec 7, 2023
1 parent 330c00d commit ad5801d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 0 deletions.
11 changes: 11 additions & 0 deletions msgspec/_json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,17 @@ def _to_schema(
schema["items"] = False
elif isinstance(t, mi.DictType):
schema["type"] = "object"
# If there are restrictions on the keys, specify them as propertyNames
if isinstance(key_type := t.key_type, mi.StrType):
property_names = {}
if key_type.min_length is not None:
property_names["minLength"] = key_type.min_length
if key_type.max_length is not None:
property_names["maxLength"] = key_type.max_length
if key_type.pattern is not None:
property_names["pattern"] = key_type.pattern
if property_names:
schema["propertyNames"] = property_names
if not isinstance(t.value_type, mi.AnyType):
schema["additionalProperties"] = _to_schema(
t.value_type, name_map, ref_template
Expand Down
17 changes: 17 additions & 0 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,23 @@ def test_string_metadata(field, val, constraint):
assert msgspec.json.schema(typ) == {"type": "string", constraint: val}


@pytest.mark.parametrize(
"field, val, constraint",
[
("pattern", "[a-z]*", "pattern"),
("min_length", 0, "minLength"),
("max_length", 3, "maxLength"),
],
)
def test_dict_key_metadata(field, val, constraint):
typ = Annotated[str, Meta(**{field: val})]
assert msgspec.json.schema(Dict[typ, int]) == {
"type": "object",
"additionalProperties": {"type": "integer"},
"propertyNames": {constraint: val},
}


@pytest.mark.parametrize("typ", [bytes, bytearray])
@pytest.mark.parametrize(
"field, n, constraint",
Expand Down

0 comments on commit ad5801d

Please sign in to comment.