Skip to content

erdantic.plugins.dataclasses

get_fields_from_dataclass

get_fields_from_dataclass(
    model: DataclassType,
) -> List[FieldInfo]

Given a dataclass, return a list of FieldInfo instances for each field in the class.

Parameters:

Name Type Description Default
model DataclassType

The dataclass to get fields from.

required

Returns:

Type Description
List[FieldInfo]

List of FieldInfo instances for each field in the class

Source code in erdantic/plugins/dataclasses.py
40
41
42
43
44
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
def get_fields_from_dataclass(model: DataclassType) -> List[FieldInfo]:
    """Given a dataclass, return a list of FieldInfo instances for each field in the class.

    Args:
        model (DataclassType): The dataclass to get fields from.

    Returns:
        List[FieldInfo]: List of FieldInfo instances for each field in the class
    """
    try:
        # Try to automatically resolve forward references
        resolve_types_on_dataclass(model)
    except NameError as e:
        model_full_name = FullyQualifiedName.from_object(model)
        forward_ref = getattr(
            e,
            "name",
            re.search(r"(?<=')(?:[^'])*(?=')", str(e)).group(0),  # type: ignore [union-attr]
        )
        msg = (
            f"Failed to resolve forward reference '{forward_ref}' in the type annotations for "
            f"dataclass {model_full_name}. "
            "You should use erdantic.plugins.dataclasses.resolve_types_on_dataclass with locals() "
            "where you define the class."
        )
        raise UnresolvableForwardRefError(
            msg, name=forward_ref, model_full_name=model_full_name
        ) from e
    return [
        FieldInfo.from_raw_type(
            model_full_name=FullyQualifiedName.from_object(model),
            name=f.name,
            raw_type=f.type,
        )
        for f in dataclasses.fields(model)
    ]

is_dataclass_class

is_dataclass_class(obj: Any) -> TypeGuard[DataclassType]

Predicate function to determine if an object is a dataclass (not an instance).

Parameters:

Name Type Description Default
obj Any

The object to check.

required

Returns:

Type Description
bool

True if the object is a dataclass, False otherwise.

Source code in erdantic/plugins/dataclasses.py
28
29
30
31
32
33
34
35
36
37
def is_dataclass_class(obj: Any) -> TypeGuard[DataclassType]:
    """Predicate function to determine if an object is a dataclass (not an instance).

    Args:
        obj (Any): The object to check.

    Returns:
        bool: True if the object is a dataclass, False otherwise.
    """
    return isinstance(obj, type) and dataclasses.is_dataclass(obj)

resolve_types_on_dataclass

resolve_types_on_dataclass(
    cls: DataclassType,
    globalns=None,
    localns=None,
    include_extras=True,
) -> DataclassType

Resolve forward references in type annotations on a dataclass. This will modify the fields metadata on the class to replace forward references with the actual types.

Parameters:

Name Type Description Default
cls DataclassType

The dataclass to resolve forward references on.

required
globalns Dict[str, Any] | None

A global namespace to evaluate forward references against. Defaults to None.

None
localns Dict[str, Any] | None

A local namespace to evaluate forward references against. Defaults to None.

None
include_extras bool

Whether to keep extra metadata from typing.Annotated. Defaults to True.

True
Source code in erdantic/plugins/dataclasses.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def resolve_types_on_dataclass(
    cls: DataclassType, globalns=None, localns=None, include_extras=True
) -> DataclassType:
    """Resolve forward references in type annotations on a dataclass. This will modify the fields
    metadata on the class to replace forward references with the actual types.

    Args:
        cls (DataclassType): The dataclass to resolve forward references on.
        globalns (Dict[str, Any] | None, optional): A global namespace to evaluate forward
            references against. Defaults to None.
        localns (Dict[str, Any] | None, optional): A local namespace to evaluate forward
            references against. Defaults to None.
        include_extras (bool, optional): Whether to keep extra metadata from `typing.Annotated`.
            Defaults to True.
    """
    # Cache whether we have already run this on a cls
    # Inspired by attrs.resolve_types
    if getattr(cls, "__erdantic_dataclass_types_resolved__", None) != cls:
        hints = get_type_hints(
            cls, globalns=globalns, localns=localns, include_extras=include_extras
        )
        for field in dataclasses.fields(cls):
            field.type = hints[field.name]
        # Use reference to cls as indicator in case of subclasses
        setattr(cls, "__erdantic_dataclass_types_resolved__", cls)
    return cls