Skip to content

Commit

Permalink
Migrate type name rendering to typenames (#103)
Browse files Browse the repository at this point in the history
* Migrate to typenames for rendering names of types

* Fix lint

* Fix lint

---------

Co-authored-by: Jay Qi <[email protected]>
  • Loading branch information
jayqi and jayqi authored Feb 11, 2024
1 parent 207601a commit 7036d0c
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 277 deletions.
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## v0.8.0 (Unreleased)

- Removed support for Python 3.7. ([PR #102](https://github.com/drivendataorg/erdantic/pull/102))
- Changed rendering of type names to use the [typenames](https://github.com/jayqi/typenames) library. This should generally produce with same rendered outputs, with the following exception:
- Removed the special case behavior for rendering enum classes. Enums now just show the class name without inheritance information.

## v0.7.0 (2024-02-11)

Expand Down
6 changes: 4 additions & 2 deletions erdantic/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
Union,
)

from typenames import REMOVE_ALL_MODULES, typenames

from erdantic.exceptions import InvalidModelAdapterError, ModelAdapterNotFoundError
from erdantic.typing import GenericAlias, repr_type
from erdantic.typing import GenericAlias

_row_template = """<tr><td>{name}</td><td port="{name}">{type_name}</td></tr>"""

Expand Down Expand Up @@ -73,7 +75,7 @@ def is_nullable(self) -> bool: # pragma: no cover
@property
def type_name(self) -> str: # pragma: no cover
"""String representation of the Python type annotation for this field."""
return repr_type(self.type_obj)
return typenames(self.type_obj, remove_modules=REMOVE_ALL_MODULES)

def dot_row(self) -> str:
"""Returns the DOT language "HTML-like" syntax specification of a row detailing this field
Expand Down
38 changes: 0 additions & 38 deletions erdantic/typing.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import collections.abc
from enum import Enum
from typing import (
Any,
ForwardRef,
List,
Literal,
Type,
Union,
get_args,
get_origin,
Expand Down Expand Up @@ -79,42 +77,6 @@ def recurse(t):
return list(recurse(tp))


def repr_type(tp: Union[type, GenericAlias]) -> str:
"""Return pretty, compact string representation of a type. Principles of behavior:
- Names without module path
- Generic capitalization matches which was used (`typing` module's aliases vs. builtin types)
- Union[..., None] -> Optional[...]
- Enums show base classes, e.g., `MyEnum(str, Enum)`
"""
origin = get_origin(tp)
if origin:
origin_name = getattr(origin, "__name__", str(origin))
args = get_args(tp)
# Union[..., None] -> Optional[...]
if origin is Union and args[-1] is type(None): # noqa: E721
origin_name = "Optional"
args = args[:-1]
# If generic alias from typing module, back out its name
elif isinstance(tp, GenericAlias) and tp.__module__ == "typing":
origin_name = str(tp).split("[")[0].replace("typing.", "")
return f"{origin_name}[{', '.join(repr_type(a) for a in args)}]"
if tp is Ellipsis:
return "..."
if isinstance(tp, type) and issubclass(tp, Enum):
return repr_enum(tp)
if isinstance(tp, ForwardRef):
return tp.__forward_arg__
return getattr(tp, "__name__", repr(tp).replace("typing.", ""))


def repr_enum(tp: Type[Enum]) -> str:
"""Return pretty, compact string representation of an Enum type with its depth-1 base
classes, e.g., `MyEnum(str, Enum)`."""
depth1_bases = get_depth1_bases(tp)
return f"{tp.__name__}({', '.join(b.__name__ for b in depth1_bases)})"


def repr_type_with_mro(obj: Any) -> str:
"""Return MRO of object if it has one. Otherwise return its repr."""

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies = [
"pydantic >= 2",
"pydantic-core",
"pygraphviz",
"typenames",
"typer",
]

Expand Down
2 changes: 1 addition & 1 deletion tests/assets/dataclasses/diagram.dot
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ digraph "Entity Relationship Diagram" {
label="\N",
shape=plain
];
"erdantic.examples.dataclasses.Adventurer" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Adventurer</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>profession</td><td port="profession">str</td></tr><tr><td>level</td><td port="level">int</td></tr><tr><td>alignment</td><td port="alignment">Alignment(str, Enum)</td></tr></table>>,
"erdantic.examples.dataclasses.Adventurer" [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="_root" colspan="2"><b>Adventurer</b></td></tr><tr><td>name</td><td port="name">str</td></tr><tr><td>profession</td><td port="profession">str</td></tr><tr><td>level</td><td port="level">int</td></tr><tr><td>alignment</td><td port="alignment">Alignment</td></tr></table>>,
tooltip="erdantic.examples.dataclasses.Adventurer&#xA;&#xA;A person often late for dinner but with a tale or two to tell.&#xA;&#xA;Attributes:&#\
xA; name (str): Name of this adventurer&#xA; profession (str): Profession of this adventurer&#xA; level (int): Level of \
this adventurer&#xA; alignment (Alignment): Alignment of this adventurer&#xA;"];
Expand Down
Binary file modified tests/assets/dataclasses/diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 7036d0c

Please sign in to comment.