Skip to content

erdantic.convenience

create

create(
    *models_or_modules: Union[type, ModuleType],
    terminal_models: Collection[type] = tuple(),
    termini: Collection[type] = tuple(),
    limit_search_models_to: Optional[Collection[str]] = None
) -> EntityRelationshipDiagram

Construct EntityRelationshipDiagram from given data model classes or modules.

Parameters:

Name Type Description Default
*models_or_modules type | ModuleType

Data model classes to add to diagram, or modules to search for data model classes.

()
terminal_models Collection[type]

Data model classes to set as terminal nodes. erdantic will stop searching for component classes when it reaches these models

tuple()
termini Collection[type]

Deprecated. Use terminal_models instead.

tuple()
limit_search_models_to Collection[str] | None

Plugin identifiers to limit to when searching modules for data model classes. Defaults to None which will not impose any limits.

None

Returns:

Type Description
EntityRelationshipDiagram

diagram object for given data model.

Raises:

Type Description
UnknownModelTypeError

if a given model does not match any model types from loaded plugins.

UnresolvableForwardRefError

if a model contains a forward reference that cannot be automatically resolved.

Source code in erdantic/convenience.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
def create(
    *models_or_modules: Union[type, ModuleType],
    terminal_models: Collection[type] = tuple(),
    termini: Collection[type] = tuple(),
    limit_search_models_to: Optional[Collection[str]] = None,
) -> EntityRelationshipDiagram:
    """Construct [`EntityRelationshipDiagram`][erdantic.core.EntityRelationshipDiagram] from given
    data model classes or modules.

    Args:
        *models_or_modules (type | ModuleType): Data model classes to add to diagram, or modules
            to search for data model classes.
        terminal_models (Collection[type]): Data model classes to set as terminal nodes. erdantic
            will stop searching for component classes when it reaches these models
        termini (Collection[type]): Deprecated. Use `terminal_models` instead.
        limit_search_models_to (Collection[str] | None): Plugin identifiers to limit to when
            searching modules for data model classes. Defaults to None which will not impose any
            limits.

    Returns:
        EntityRelationshipDiagram: diagram object for given data model.

    Raises:
        UnknownModelTypeError: if a given model does not match any model types from loaded plugins.
        UnresolvableForwardRefError: if a model contains a forward reference that cannot be
            automatically resolved.
    """
    if termini:
        warnings.warn(
            "The 'termini' argument is deprecated and will be removed in a future release. "
            "Please use 'terminal_models' instead.",
            DeprecationWarning,
        )
        if terminal_models:
            raise ValueError(
                "Cannot specify both 'terminal_models' and 'termini' at the same time."
            )
        terminal_models = termini

    diagram = EntityRelationshipDiagram()

    # Add terminal models and don't recurse
    for model in terminal_models:
        diagram.add_model(model, recurse=False)

    for mm in models_or_modules:
        if isinstance(mm, ModuleType):
            logger.debug("Searching input module '%s' for data model classes...", mm.__name__)
            for member in find_models(mm, limit_search_models_to=limit_search_models_to):
                diagram.add_model(member)
        else:
            diagram.add_model(mm)
    return diagram

draw

draw(
    *models_or_modules: Union[type, ModuleType],
    out: Union[str, PathLike],
    terminal_models: Collection[type] = tuple(),
    termini: Collection[type] = tuple(),
    limit_search_models_to: Optional[
        Collection[str]
    ] = None,
    graph_attr: Optional[Mapping[str, Any]] = None,
    node_attr: Optional[Mapping[str, Any]] = None,
    edge_attr: Optional[Mapping[str, Any]] = None,
    **kwargs
)

Render entity relationship diagram for given data model classes to file.

Parameters:

Name Type Description Default
*models_or_modules type | ModuleType

Data model classes to add to diagram, or modules to search for data model classes.

()
terminal_models Collection[type]

Data model classes to set as terminal nodes. erdantic will stop searching for component classes when it reaches these models

tuple()
termini Collection[type]

Deprecated. Use terminal_models instead.

tuple()
limit_search_models_to Optional[Collection[str]]

Plugin identifiers to limit to when searching modules for data model classes. Defaults to None which will not impose any limits.

None
graph_attr Mapping[str, Any] | None

Override any graph attributes on the pygraphviz.AGraph instance. Defaults to None.

None
node_attr Mapping[str, Any] | None

Override any node attributes for all nodes on the pygraphviz.AGraph instance. Defaults to None.

None
edge_attr Mapping[str, Any] | None

Override any edge attributes for all edges on the pygraphviz.AGraph instance. Defaults to None.

None
**kwargs

Additional keyword arguments to pygraphviz.AGraph.draw.

{}

Raises:

Type Description
UnknownModelTypeError

if a given model does not match any model types from loaded plugins.

UnresolvableForwardRefError

if a model contains a forward reference that cannot be automatically resolved.

Source code in erdantic/convenience.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def draw(
    *models_or_modules: Union[type, ModuleType],
    out: Union[str, os.PathLike],
    terminal_models: Collection[type] = tuple(),
    termini: Collection[type] = tuple(),
    limit_search_models_to: Optional[Collection[str]] = None,
    graph_attr: Optional[Mapping[str, Any]] = None,
    node_attr: Optional[Mapping[str, Any]] = None,
    edge_attr: Optional[Mapping[str, Any]] = None,
    **kwargs,
):
    """Render entity relationship diagram for given data model classes to file.

    Args:
        *models_or_modules (type | ModuleType): Data model classes to add to diagram, or modules
            to search for data model classes.
        terminal_models (Collection[type]): Data model classes to set as terminal nodes. erdantic
            will stop searching for component classes when it reaches these models
        termini (Collection[type]): Deprecated. Use `terminal_models` instead.
        limit_search_models_to (Optional[Collection[str]]): Plugin identifiers to limit to when
            searching modules for data model classes. Defaults to None which will not impose any
            limits.
        graph_attr (Mapping[str, Any] | None, optional): Override any graph attributes on
            the `pygraphviz.AGraph` instance. Defaults to None.
        node_attr (Mapping[str, Any] | None, optional): Override any node attributes for all
            nodes on the `pygraphviz.AGraph` instance. Defaults to None.
        edge_attr (Mapping[str, Any] | None, optional): Override any edge attributes for all
            edges on the `pygraphviz.AGraph` instance. Defaults to None.
        **kwargs: Additional keyword arguments to
            [`pygraphviz.AGraph.draw`][pygraphviz.AGraph.draw].

    Raises:
        UnknownModelTypeError: if a given model does not match any model types from loaded plugins.
        UnresolvableForwardRefError: if a model contains a forward reference that cannot be
            automatically resolved.
    """
    diagram = create(
        *models_or_modules,
        terminal_models=terminal_models,
        limit_search_models_to=limit_search_models_to,
    )
    diagram.draw(
        out=out, graph_attr=graph_attr, node_attr=node_attr, edge_attr=edge_attr, **kwargs
    )

find_models

find_models(
    module: ModuleType,
    limit_search_models_to: Optional[
        Collection[str]
    ] = None,
) -> Iterator[type]

Searches a module and yields all data model classes found.

Parameters:

Name Type Description Default
module ModuleType

Module to search for data model classes.

required
limit_search_models_to Collection[str] | None

Plugin identifiers to limit to when searching modules for data model classes. Defaults to None which will not impose any limits.

None

Yields:

Type Description
type

Iterator[type]: Members of module that are data model classes.

Raises:

Type Description
UnknownModelTypeError

if a given model does not match any model types from loaded plugins.

UnresolvableForwardRefError

if a model contains a forward reference that cannot be automatically resolved.

Source code in erdantic/convenience.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def find_models(
    module: ModuleType, limit_search_models_to: Optional[Collection[str]] = None
) -> Iterator[type]:
    """Searches a module and yields all data model classes found.

    Args:
        module (ModuleType): Module to search for data model classes.
        limit_search_models_to (Collection[str] | None): Plugin identifiers to limit to when
            searching modules for data model classes. Defaults to None which will not impose any
            limits.

    Yields:
        Iterator[type]: Members of module that are data model classes.

    Raises:
        UnknownModelTypeError: if a given model does not match any model types from loaded plugins.
        UnresolvableForwardRefError: if a model contains a forward reference that cannot be
            automatically resolved.
    """
    all_plugins = list_plugins()
    if limit_search_models_to is not None:
        predicate_fns = [get_predicate_fn(key) for key in limit_search_models_to]
    else:
        predicate_fns = [get_predicate_fn(key) for key in all_plugins]
    for _, member in inspect.getmembers(module, inspect.isclass):
        if member.__module__ == module.__name__:
            for predicate_fn in predicate_fns:
                if predicate_fn(member):
                    logger.debug(
                        "Found data model class '%s' in module '%s'",
                        typenames(member, remove_modules=REMOVE_ALL_MODULES),
                        module.__name__,
                    )
                    yield member

to_dot

to_dot(
    *models_or_modules: Union[type, ModuleType],
    terminal_models: Collection[type] = [],
    termini: Collection[type] = tuple(),
    limit_search_models_to: Optional[
        Collection[str]
    ] = None,
    graph_attr: Optional[Mapping[str, Any]] = None,
    node_attr: Optional[Mapping[str, Any]] = None,
    edge_attr: Optional[Mapping[str, Any]] = None
) -> str

Generate Graphviz DOT language representation of entity relationship diagram for given data model classes.

Parameters:

Name Type Description Default
*models_or_modules type | ModuleType

Data model classes to add to diagram, or modules to search for data model classes.

()
terminal_models Collection[type]

Data model classes to set as terminal nodes. erdantic will stop searching for component classes when it reaches these models

[]
termini Collection[type]

Deprecated. Use terminal_models instead.

tuple()
limit_search_models_to Optional[Collection[str]]

Plugin identifiers to limit to when searching modules for data model classes. Defaults to None which will not impose any limits.

None
graph_attr Mapping[str, Any] | None

Override any graph attributes on the pygraphviz.AGraph instance. Defaults to None.

None
node_attr Mapping[str, Any] | None

Override any node attributes for all nodes on the pygraphviz.AGraph instance. Defaults to None.

None
edge_attr Mapping[str, Any] | None

Override any edge attributes for all edges on the pygraphviz.AGraph instance. Defaults to None.

None

Returns:

Type Description
str

DOT language representation of diagram

Source code in erdantic/convenience.py
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
def to_dot(
    *models_or_modules: Union[type, ModuleType],
    terminal_models: Collection[type] = [],
    termini: Collection[type] = tuple(),
    limit_search_models_to: Optional[Collection[str]] = None,
    graph_attr: Optional[Mapping[str, Any]] = None,
    node_attr: Optional[Mapping[str, Any]] = None,
    edge_attr: Optional[Mapping[str, Any]] = None,
) -> str:
    """Generate Graphviz [DOT language](https://graphviz.org/doc/info/lang.html) representation of
    entity relationship diagram for given data model classes.

    Args:
        *models_or_modules (type | ModuleType): Data model classes to add to diagram, or modules
            to search for data model classes.
        terminal_models (Collection[type]): Data model classes to set as terminal nodes. erdantic
            will stop searching for component classes when it reaches these models
        termini (Collection[type]): Deprecated. Use `terminal_models` instead.
        limit_search_models_to (Optional[Collection[str]]): Plugin identifiers to limit to when
            searching modules for data model classes. Defaults to None which will not impose any
            limits.
        graph_attr (Mapping[str, Any] | None, optional): Override any graph attributes on
            the `pygraphviz.AGraph` instance. Defaults to None.
        node_attr (Mapping[str, Any] | None, optional): Override any node attributes for all
            nodes on the `pygraphviz.AGraph` instance. Defaults to None.
        edge_attr (Mapping[str, Any] | None, optional): Override any edge attributes for all
            edges on the `pygraphviz.AGraph` instance. Defaults to None.

    Returns:
        str: DOT language representation of diagram
    """
    diagram = create(
        *models_or_modules,
        terminal_models=terminal_models,
        termini=termini,
        limit_search_models_to=limit_search_models_to,
    )
    return diagram.to_dot(graph_attr=graph_attr, node_attr=node_attr, edge_attr=edge_attr)