Skip to content

Instantly share code, notes, and snippets.

@jimkring
Last active August 14, 2024 02:45
Show Gist options
  • Save jimkring/32885d8fad3991dbc7069202cdb0b217 to your computer and use it in GitHub Desktop.
Save jimkring/32885d8fad3991dbc7069202cdb0b217 to your computer and use it in GitHub Desktop.
Create a Pydantic model from JSON Schema dynamically at runtime
import tempfile
import json
from pathlib import Path
from typing import Any, Dict, Type
import datamodel_code_generator
from pydantic import BaseModel
def json_schema_to_pydantic_model(json_schema: Dict[str, Any]) -> Type[BaseModel]:
"""Generate a Pydantic model from a JSON schema in memory."""
# Create temporary files for input and output
with tempfile.NamedTemporaryFile(
mode="w+", suffix=".json", delete=False
) as input_file, tempfile.NamedTemporaryFile(mode="w+", suffix=".py", delete=False) as output_file:
# Write the JSON schema to the input file
input_file.write(json.dumps(json_schema))
input_file.flush()
# Generate the model code
datamodel_code_generator.generate(
input_=Path(input_file.name),
input_file_type=datamodel_code_generator.InputFileType.JsonSchema,
output=Path(output_file.name),
target_python_version=datamodel_code_generator.PythonVersion.PY_312,
allow_population_by_field_name=True, # causes json title's to be used as field aliases
)
# Read the generated code
output_file.seek(0)
generated_code = output_file.read()
print(f"Generated code:\n\n{generated_code}")
# Clean up temporary files
Path(input_file.name).unlink()
Path(output_file.name).unlink()
# Create a namespace to execute the code in
namespace = {}
# Execute the generated code in the namespace
exec(generated_code, namespace)
# Convert the model name to a valid Python class name
schema_root_item_name = json_schema["title"]
model_name = datamodel_code_generator.parser.base.title_to_class_name(schema_root_item_name)
model = namespace[model_name]
assert issubclass(model, BaseModel)
return model
if __name__ == "__main__":
# todo: add a test case
# Example usage
json_schema = """
{
"title": "person",
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"pets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"species": {"type": "string"}
},
"required": ["name", "species"],
"additionalProperties": true
}
}
},
"required": ["name", "age"],
"additionalProperties": false
}
"""
PersonModel = json_schema_to_pydantic_model(
json_schema=json.loads(json_schema),
)
print(f"Generated model: {PersonModel}")
print(f"Model schema:\n\n{json.dumps(PersonModel.model_json_schema(), indent=2)}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment