Content Parse

Generate Pydantic Schema

The GeneratePydanticSchema class was developed to make it easier to dynamically create Pydantic models from nested Python dictionaries.

On this page

    #Overview

    The GeneratePydanticSchema class was developed to make it easier to dynamically create Pydantic models from nested Python dictionaries. In scenarios where complex, structured data is received, such as in APIs or systems that deal with various JSON structures, this class automates the generation of Pydantic schemas, used for validating, converting and documenting those structures.

    The problem the class solves is the manual, repetitive need to create Pydantic models for each complex data structure, which often varies in depth and format. By using this class, the developer passes in a data dictionary and gets a Pydantic model that exactly reflects the structure and types of that data, including nested schemas for inner objects and lists.

    In practice, it can be used to validate input data, generate examples for automatic documentation or build adaptive interfaces in systems that consume dynamic data.

    #Execution Flow

    1. The user instantiates the GeneratePydanticSchema class, and may optionally provide a FieldMetadataParser object to customize the extraction of field metadata.
    2. The convert() method is called with a Python dictionary representing the data to be modeled and a root name for the model (default "RootModel").
    3. The class recursively analyzes each key and value of the dictionary:
      • For scalar fields, it determines the basic type.
      • For nested dictionaries, it generates a new Pydantic model with a unique automatic name.
      • For lists, it analyzes the type of the first element to define the type of the items in the list, generating models for objects if necessary.
    4. Fields receive metadata (description) generated automatically or through the analysis by the metadata_parser.
    5. All generated models are stored internally and can be retrieved with the get_models() method.
    6. If an error occurs during conversion, a RuntimeError exception is raised with the error details.

    #Class Methods Table

    MethodDescription
    __init__Initializes the class with an optional metadata parser.
    convertConverts a dictionary into a root Pydantic model.
    get_modelsReturns all the Pydantic models generated so far.
    _generate_nameGenerates unique names for nested models.
    _create_modelCreates a Pydantic model from defined fields.
    _resolve_typeDeduces the base type of the received value.
    _parse_objectRecursively builds Pydantic models for objects.
    _parse_fieldAnalyzes the type and metadata of an individual field.

    #Key Architecture Points and Insights

    • Dynamic generation takes advantage of Pydantic's create_model method to create classes at runtime, making it easier to create models that are not known at coding time.
    • Recursive use allows the creation of nested models that reflect the complex structure of the input data.
    • The incremental counter ensures unique names for the auxiliary models, avoiding collisions.
    • The class depends on FieldMetadataParser to enrich the fields with metadata, creating a separation that favors customization and extensibility of field analysis.
    • The specific handling of lists, with the attempt to singularize names (presumably using inflector.singular_noun), shows attention to the naming of the models.
    • Careful handling of exceptions during parsing and conversion, recording the error message and keeping usability by exposing clear errors to the user.
    • Internally, storing the models in a dictionary allows later lookup and reuse.

    #Class and Methods Description

    #GeneratePydanticSchema Class

    #Description

    This class has the role of converting complex, nested dictionaries into Pydantic models programmatically. It automates the generation of validation schemas that faithfully reflect the structure of the input data, with support for nested fields, lists and integration with a metadata parser to enrich the description of the fields.

    Its use is recommended for dynamic validation scenarios and for building APIs or systems that receive diverse JSON data and need strong, explicit validation.

    #Constructor Arguments

    ArgumentTypeDescriptionDefault Value
    metadata_parserFieldMetadataParserObject for analyzing and extracting field metadata.New instance of FieldMetadataParser

    #Methods

    #1. __init__

    Description

    Initializes the class instance, setting the metadata parser and preparing the internal storage for the generated models.

    Arguments

    • metadata_parser (FieldMetadataParser): Optional parser for metadata extraction.

    Returns

    • Returns no value.

    Raises

    • None.

    Examples

    schema_generator = GeneratePydanticSchema()

    #2. convert

    Description

    Receives a Python dictionary and converts it into a root Pydantic model, automatically generating all the nested models needed for full validation of the structure.

    Arguments

    • data (Dict[str, Any]): Data dictionary to be converted into a model.
    • root_name (str): Name of the root model to be created. Default is "RootModel".

    Returns

    • Type[BaseModel]: Pydantic model generated for the given dictionary.

    Raises

    • RuntimeError: If an error occurs during data conversion.

    Examples

    data = {
        "nome": "João",
        "idade": 30,
        "endereco": {
            "rua": "Av. Brasil",
            "numero": 100
        }
    }
    
    model = schema_generator.convert(data, root_name="Pessoa")
    # model agora é uma classe Pydantic com campos nome, idade e endereco (que é outro modelo)

    #3. get_models

    Description

    Returns all the Pydantic models created so far, including nested models generated during data conversion.

    Arguments

    None.

    Returns

    • Dict[str, Type[BaseModel]]: Dictionary with the model names as keys and Pydantic classes as values.

    Raises

    None.

    Examples

    all_models = schema_generator.get_models()
    # Pode acessar, por exemplo, all_models["Pessoa1"] para um modelo aninhado

    #4. _generate_name

    Description

    Generates a unique name for nested Pydantic models, combining a name base with an incremental counter.

    Arguments

    • base (str): Base name for the model.

    Returns

    • str: Unique generated name, e.g. "Endereco1".

    Raises

    None.

    Examples

    nome = schema_generator._generate_name("endereco")
    # "Endereco1"

    #5. _create_model

    Description

    Dynamically creates a Pydantic model from a given name and fields, storing it in the internal dictionary.

    Arguments

    • name (str): Name of the model.
    • fields (Dict[str, Tuple[Any, Any]]): Mapping of fields to tuples (type, metadata).

    Returns

    • Type[BaseModel]: Pydantic model created.

    Raises

    None.

    Examples

    fields = {
        "nome": (str, ...),
        "idade": (int, ...)
    }
    
    model = schema_generator._create_model("Pessoa", fields)

    #6. _resolve_type

    Description

    Determines the basic Pydantic type of a simple Python value.

    Arguments

    • value (Any): Value whose type must be deduced.

    Returns

    • Any: Corresponding Python type (str, bool, int, float, list, dict or Any as a fallback).

    Raises

    None.

    Examples

    t = schema_generator._resolve_type(10)   # int
    t2 = schema_generator._resolve_type("hi") # str

    #7. _parse_object

    Description

    Analyzes a dictionary and creates a Pydantic model for it, recursively processing all the fields of the object.

    Arguments

    • obj (Dict[str, Any]): Dictionary to be parsed.
    • name (str): Name of the model to be created.

    Returns

    • Type[BaseModel]: Pydantic model created for the analyzed object.

    Raises

    None.

    Examples

    model = schema_generator._parse_object({"a": 1, "b": "x"}, "SimpleModel")

    #8. _parse_field

    Description

    Determines the type and metadata for an individual field, handling the cases of dictionaries, lists and scalar values and applying custom analysis via metadata_parser.

    Arguments

    • key (str): Name of the field.
    • value (Any): Value of the field for type deduction.

    Returns

    • Tuple[Any, Any]: Tuple with the field type and the Field instance containing metadata for Pydantic.

    Raises

    • RuntimeError: If there is an error during parsing, it wraps the original error.

    Examples

    if __name__ == "__main__":
        json_data = {
            "script": {
                "setting": {
                    "type": "str",
                    "description": "Onde o filme acontece",
                    "example": "Tokyo"
                },
                "genre": {
                    "type": "str",
                    "description": "Gênero do filme",
                    "example": "Heist"
                },
                "storyline": "A big robbery"
            },
            "context": {
                "year": {
                    "type": "int",
                    "description": "Ano da história",
                    "example": 2025
                }
            },
            "people": {
                "characters": [
                    {
                        "name": {
                            "type": "str",
                            "description": "Nome do personagem"
                        },
                        "role": "protagonist"
                    }
                ]
            }
        }
    
        converter = JsonToPydantic()
        Movie = converter.convert(json_data, "Movie")
    
        print(Movie.schema_json(indent=2))
    
    # python -m src.content_parse.pydantic_shema

    This documentation offers a detailed guide for programmers to understand and use the GeneratePydanticSchema class in a practical and efficient way, ensuring fast and correct generation of Pydantic models for validating and manipulating complex data.

    Source: src/content_parse/pydantic_schema.py

    Esc
    ↑↓navigate Enteropen