Skip to content

auto_rest.interfaces

Pydantic models are used to facilitate data validation and to define interfaces for FastAPI endpoint handlers. The interfaces module provides utility functions for converting SQLAlchemy models into Pydantic interfaces. Interfaces can be created using different modes which force interface fields to be optional or read only.

Example: Creating an Interface

The create_interface_default method creates an interface class based on a SQLAlchemy table.

default_interface = create_interface(database_model)
required_interface = create_interface(database_model, mode="required")
optional_interface = create_interface(database_model, mode="optional")

create_field_definition(col, mode='default')

Return a tuple with the type and default value for a database table column.

The returned tuple is compatible for use with Pydantic as a field definition during dynamic model generation. The mode argument modifies returned values to enforce different behavior in the generated Pydantic interface.

Modes

default: Values are marked as (not)required based on the column schema. required: Values are always marked required. required: Values are always marked optional.

Parameters:

Name Type Description Default
col Column

The column to return values for.

required
mode MODE_TYPE

The mode to use when determining the default value.

'default'

Returns:

Type Description
tuple[type[any], any]

The default value for the column.

Source code in auto_rest/interfaces.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
def create_field_definition(col: Column, mode: MODE_TYPE = "default") -> tuple[type[any], any]:
    """Return a tuple with the type and default value for a database table column.

    The returned tuple is compatible for use with Pydantic as a field definition
    during dynamic model generation. The `mode` argument modifies returned
    values to enforce different behavior in the generated Pydantic interface.

    Modes:
        default: Values are marked as (not)required based on the column schema.
        required: Values are always marked required.
        required: Values are always marked optional.

    Args:
        col: The column to return values for.
        mode: The mode to use when determining the default value.

    Returns:
        The default value for the column.
    """

    try:
        col_type = col.type.python_type

    except NotImplementedError:
        col_type = Any

    col_default = getattr(col.default, "arg", col.default)

    if mode == "required":
        return col_type, ...

    elif mode == "optional":
        return col_type | None, col_default

    elif mode == "default" and (col.nullable or col.default):
        return col_type | None, col_default

    elif mode == "default":
        return col_type, ...

    raise RuntimeError(f"Unknown mode: {mode}")

create_interface(table, pk_only=False, mode='default')

Create a Pydantic interface for a SQLAlchemy model where all fields are required.

Modes

default: Values are marked as (not)required based on the column schema. required: Values are always marked required. required: Values are always marked optional.

Parameters:

Name Type Description Default
table Table

The SQLAlchemy table to create an interface for.

required
pk_only bool

If True, only include primary key columns.

False
mode MODE_TYPE

Whether to force fields to all be optional or required.

'default'

Returns:

Type Description
type[BaseModel]

A dynamically generated Pydantic model with all fields required.

Source code in auto_rest/interfaces.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def create_interface(table: Table, pk_only: bool = False, mode: MODE_TYPE = "default") -> type[PydanticModel]:
    """Create a Pydantic interface for a SQLAlchemy model where all fields are required.

    Modes:
        default: Values are marked as (not)required based on the column schema.
        required: Values are always marked required.
        required: Values are always marked optional.

    Args:
        table: The SQLAlchemy table to create an interface for.
        pk_only: If True, only include primary key columns.
        mode: Whether to force fields to all be optional or required.

    Returns:
        A dynamically generated Pydantic model with all fields required.
    """

    # Map field names to the column type and default value.
    fields = {
        col.name: create_field_definition(col, mode) for col in iter_columns(table, pk_only)
    }

    # Create a unique name for the interface
    name = f"{table.name}-{mode.title()}"
    if pk_only:
        name += '-PK'

    return create_model(name, __config__={'arbitrary_types_allowed': True}, **fields)

iter_columns(table, pk_only=False)

Iterate over the columns of a SQLAlchemy model.

Parameters:

Name Type Description Default
table Table

The table to iterate columns over.

required
pk_only bool

If True, only iterate over primary key columns.

False

Yields:

Type Description
Column

A column of the SQLAlchemy model.

Source code in auto_rest/interfaces.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def iter_columns(table: Table, pk_only: bool = False) -> Iterator[Column]:
    """Iterate over the columns of a SQLAlchemy model.

    Args:
        table: The table to iterate columns over.
        pk_only: If True, only iterate over primary key columns.

    Yields:
        A column of the SQLAlchemy model.
    """

    for column in table.columns.values():
        if column.primary_key or not pk_only:
            yield column