Generating json schema using the JSON Schema Draft-7 dialect #12153
Replies: 3 comments
-
|
Changing So an override like this only labels the schema: from pydantic.json_schema import GenerateJsonSchema
class Draft7Label(GenerateJsonSchema):
schema_dialect = "http://json-schema.org/draft-07/schema#"
def generate(self, schema, mode="validation"):
json_schema = super().generate(schema, mode=mode)
json_schema["$schema"] = self.schema_dialect
return json_schemaIt does not rewrite 2020-12 keywords or semantics into Draft 7. For a real Draft 7 output, you would need a custom generator or a post-processing conversion step that handles the incompatible pieces explicitly. |
Beta Was this translation helpful? Give feedback.
-
|
@cookesan is right that 1. The 2020-12 to Draft-7 keyword shifts.
2. Drop-in converter. import re
from copy import deepcopy
from typing import Any
from pydantic.json_schema import GenerateJsonSchema
DRAFT7 = "http://json-schema.org/draft-07/schema#"
def to_draft7(schema: Any) -> Any:
if isinstance(schema, dict):
out = {}
for k, v in schema.items():
if k == "$defs":
out["definitions"] = to_draft7(v)
continue
if k == "$dynamicRef" or k == "$dynamicAnchor":
continue # drop, not representable
if k == "unevaluatedProperties":
# Conservative fall-back: treat like additionalProperties
out["additionalProperties"] = to_draft7(v)
continue
if k == "$ref" and isinstance(v, str):
out["$ref"] = v.replace("#/$defs/", "#/definitions/")
continue
if k == "exclusiveMaximum" and isinstance(v, (int, float)):
out["maximum"] = v
out["exclusiveMaximum"] = True
continue
if k == "exclusiveMinimum" and isinstance(v, (int, float)):
out["minimum"] = v
out["exclusiveMinimum"] = True
continue
if k == "prefixItems":
# Need to also look at sibling 'items'
continue # handled in second pass
out[k] = to_draft7(v)
# Second pass: prefixItems + items folded together
if "prefixItems" in schema:
out["items"] = to_draft7(schema["prefixItems"])
sibling = schema.get("items", True)
if sibling is False:
out["additionalItems"] = False
elif sibling is True or sibling == {}:
pass # default open
else:
out["additionalItems"] = to_draft7(sibling)
return out
if isinstance(schema, list):
return [to_draft7(x) for x in schema]
return schema
class Draft7Generator(GenerateJsonSchema):
schema_dialect = DRAFT7
def generate(self, schema, mode="validation"):
s = super().generate(schema, mode=mode)
s = to_draft7(s)
s["$schema"] = DRAFT7
return s3. Use it. from pydantic import BaseModel, Field
class Item(BaseModel):
name: str
age: int = Field(gt=0, lt=120)
print(Item.model_json_schema(schema_generator=Draft7Generator))Output is a syntactically valid Draft-7 schema with 4. Edge cases worth knowing about.
5. Validate the output to be sure. from jsonschema import Draft7Validator
schema = Item.model_json_schema(schema_generator=Draft7Generator)
Draft7Validator.check_schema(schema) # raises if any keyword is invalid for Draft-7
Draft7Validator(schema).validate({"name": "Alice", "age": 30})
If you have many models and need to do this in production, cache the converted schema per model class - the rewrite is non-trivial but deterministic, so it's a clean memoise target. Recipe: subclass |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
I'm using Pydantic V2.11.
I'm trying to subclass
GenerateJsonSchemato override theschema_dialectattribute, but it doesn't seem to have any effect on the output schema. I'd like to generate a schema according to the Draft-7 dialect, not the 2020-12 default. I've looked at the source code, and it appears thatschema_dialecthas no impact on the generation.Could someone please provide a working example?
Beta Was this translation helpful? Give feedback.
All reactions