Skip to content

erdantic.pydantic

Classes

PydanticField (Field)

Concrete field adapter class for Pydantic fields.

Attributes:

Name Type Description
field pydantic.fields.ModelField

The Pydantic field object that is associated with this adapter instance.

Source code in erdantic/pydantic.py
class PydanticField(Field[pydantic.fields.ModelField]):
    """Concrete field adapter class for Pydantic fields.

    Attributes:
        field (pydantic.fields.ModelField): The Pydantic field object that is associated with this
            adapter instance.
    """

    def __init__(self, field: pydantic.fields.ModelField):
        if not isinstance(field, pydantic.fields.ModelField):
            raise InvalidFieldError(
                f"field must be of type pydantic.fields.ModelField. Got: {type(field)}"
            )
        super().__init__(field=field)

    @property
    def name(self) -> str:
        return self.field.name

    @property
    def type_obj(self) -> Union[type, GenericAlias]:
        tp = self.field.outer_type_
        if self.field.allow_none:
            return Optional[tp]
        return tp

    def is_many(self) -> bool:
        return self.field.shape > 1

    def is_nullable(self) -> bool:
        return self.field.allow_none

Attributes

name: str property readonly

Name of this field on the parent data model.

type_name: str inherited property readonly

String representation of the Python type annotation for this field.

type_obj: Union[type, _GenericAlias] property readonly

Python type object for this field.

Methods

__init__(self, field: ModelField) special
Source code in erdantic/pydantic.py
def __init__(self, field: pydantic.fields.ModelField):
    if not isinstance(field, pydantic.fields.ModelField):
        raise InvalidFieldError(
            f"field must be of type pydantic.fields.ModelField. Got: {type(field)}"
        )
    super().__init__(field=field)
dot_row(self) -> str inherited

Returns the DOT language "HTML-like" syntax specification of a row detailing this field that is part of a table describing the field's parent data model. It is used as part the label attribute of data model's node in the graph's DOT representation.

Returns:

Type Description
str

DOT language for table row

Source code in erdantic/pydantic.py
def dot_row(self) -> str:
    """Returns the DOT language "HTML-like" syntax specification of a row detailing this field
    that is part of a table describing the field's parent data model. It is used as part the
    `label` attribute of data model's node in the graph's DOT representation.

    Returns:
        str: DOT language for table row
    """
    return _row_template.format(name=self.name, type_name=self.type_name)
is_many(self) -> bool

Check whether this field represents a one-to-one or one-to-many relationship.

Returns:

Type Description
bool

True if one-to-many relationship, else False.

Source code in erdantic/pydantic.py
def is_many(self) -> bool:
    return self.field.shape > 1
is_nullable(self) -> bool

Check whether this field is nullable, i.e., can be None.

Returns:

Type Description
bool

True if nullable, else False.

Source code in erdantic/pydantic.py
def is_nullable(self) -> bool:
    return self.field.allow_none

PydanticModel (Model)

Concrete model adapter class for a Pydantic BaseModel.

Attributes:

Name Type Description
model Type[pydantic.BaseModel]

The Pydantic model class that is associated with this adapter instance.

forward_ref_help Optional[str]

Instructions for how to resolve an unevaluated forward reference in a field's type declaration.

Source code in erdantic/pydantic.py
class PydanticModel(Model[Type[pydantic.BaseModel]]):
    """Concrete model adapter class for a Pydantic
    [`BaseModel`](https://pydantic-docs.helpmanual.io/usage/models/).

    Attributes:
        model (Type[pydantic.BaseModel]): The Pydantic model class that is associated with this
            adapter instance.
        forward_ref_help (Optional[str]): Instructions for how to resolve an unevaluated forward
            reference in a field's type declaration.
    """

    forward_ref_help = (
        "Call 'update_forward_refs' after model is created to resolve. "
        "See: https://pydantic-docs.helpmanual.io/usage/postponed_annotations/"
    )

    def __init__(self, model: Type[pydantic.BaseModel]):
        if not self.is_model_type(model):
            raise InvalidModelError(
                "Argument model must be a subclass of pydantic.BaseModel. "
                f"Got {repr_type_with_mro(model)}"
            )
        super().__init__(model=model)

    @staticmethod
    def is_model_type(obj: Any) -> bool:
        return isinstance(obj, type) and issubclass(obj, pydantic.BaseModel)

    @property
    def fields(self) -> List[Field]:
        return [PydanticField(field=f) for f in self.model.__fields__.values()]

    @property
    def docstring(self) -> str:
        out = super().docstring
        field_descriptions = [
            getattr(field.field.field_info, "description", None) for field in self.fields
        ]
        if any(descr is not None for descr in field_descriptions):
            # Sometimes Pydantic models have field documentation as descriptions as metadata on the
            # field instead of in the docstring. If detected, construct docstring and add.
            out += "\nAttributes:\n"
            field_defaults = [field.field.field_info.default for field in self.fields]
            for field, descr, default in zip(self.fields, field_descriptions, field_defaults):
                if descr is not None:
                    line = f"{field.name} ({field.type_name}): {descr}"
                    if (
                        not isinstance(default, pydantic.fields.UndefinedType)
                        and default is not ...
                    ):
                        if not line.strip().endswith("."):
                            line = line.rstrip() + ". "
                        else:
                            line = line.rstrip() + " "
                        if isinstance(default, str):
                            line += f"Default is '{default}'."
                        else:
                            line += f"Default is {default}."
                    out += "    " + line.strip() + "\n"

        return out

Attributes

docstring: str property readonly

Docstring for this data model.

fields: List[erdantic.base.Field] property readonly

List of fields defined on this data model.

forward_ref_help: Optional[str]
key: str inherited property readonly

Human-readable unique identifier for this data model. Should be stable across sessions.

name: str inherited property readonly

Name of this data model.

Methods

__init__(self, model: Type[pydantic.main.BaseModel]) special
Source code in erdantic/pydantic.py
def __init__(self, model: Type[pydantic.BaseModel]):
    if not self.is_model_type(model):
        raise InvalidModelError(
            "Argument model must be a subclass of pydantic.BaseModel. "
            f"Got {repr_type_with_mro(model)}"
        )
    super().__init__(model=model)
dot_label(self) -> str inherited

Returns the DOT language "HTML-like" syntax specification of a table for this data model. It is used as the label attribute of data model's node in the graph's DOT representation.

Returns:

Type Description
str

DOT language for table

Source code in erdantic/pydantic.py
def dot_label(self) -> str:
    """Returns the DOT language "HTML-like" syntax specification of a table for this data
    model. It is used as the `label` attribute of data model's node in the graph's DOT
    representation.

    Returns:
        str: DOT language for table
    """
    rows = "\n".join(field.dot_row() for field in self.fields)
    return _table_template.format(name=self.name, rows=rows).replace("\n", "")
is_model_type(obj: Any) -> bool staticmethod

Check if object is the type of data model class that this model adapter works with.

Source code in erdantic/pydantic.py
@staticmethod
def is_model_type(obj: Any) -> bool:
    return isinstance(obj, type) and issubclass(obj, pydantic.BaseModel)
Back to top