Coverage for pydantic/_internal/_repr.py: 100.00%
70 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-20 16:49 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-20 16:49 +0000
1"""Tools to provide pretty/human-readable display of objects."""
3from __future__ import annotations as _annotations 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
5import types 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
6import typing 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
7from typing import Any 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
9import typing_extensions 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
10from typing_inspection import typing_objects 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
11from typing_inspection.introspection import is_union_origin 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
13from . import _typing_extra 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
15if typing.TYPE_CHECKING: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
16 ReprArgs: typing_extensions.TypeAlias = 'typing.Iterable[tuple[str | None, Any]]'
17 RichReprResult: typing_extensions.TypeAlias = (
18 'typing.Iterable[Any | tuple[Any] | tuple[str, Any] | tuple[str, Any, Any]]'
19 )
22class PlainRepr(str): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
23 """String class where repr doesn't include quotes. Useful with Representation when you want to return a string
24 representation of something that is valid (or pseudo-valid) python.
25 """
27 def __repr__(self) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
28 return str(self) 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
31class Representation: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
32 # Mixin to provide `__str__`, `__repr__`, and `__pretty__` and `__rich_repr__` methods.
33 # `__pretty__` is used by [devtools](https://python-devtools.helpmanual.io/).
34 # `__rich_repr__` is used by [rich](https://rich.readthedocs.io/en/stable/pretty.html).
35 # (this is not a docstring to avoid adding a docstring to classes which inherit from Representation)
37 # we don't want to use a type annotation here as it can break get_type_hints
38 __slots__ = () # type: typing.Collection[str] 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
40 def __repr_args__(self) -> ReprArgs: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
41 """Returns the attributes to show in __str__, __repr__, and __pretty__ this is generally overridden.
43 Can either return:
44 * name - value pairs, e.g.: `[('foo_name', 'foo'), ('bar_name', ['b', 'a', 'r'])]`
45 * or, just values, e.g.: `[(None, 'foo'), (None, ['b', 'a', 'r'])]`
46 """
47 attrs_names = self.__slots__ 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
48 if not attrs_names and hasattr(self, '__dict__'): 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
49 attrs_names = self.__dict__.keys() 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
50 attrs = ((s, getattr(self, s)) for s in attrs_names) 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
51 return [(a, v if v is not self else self.__repr_recursion__(v)) for a, v in attrs if v is not None] 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
53 def __repr_name__(self) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
54 """Name of the instance's class, used in __repr__."""
55 return self.__class__.__name__ 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
57 def __repr_recursion__(self, object: Any) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
58 """Returns the string representation of a recursive object."""
59 # This is copied over from the stdlib `pprint` module:
60 return f'<Recursion on {type(object).__name__} with id={id(object)}>' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
62 def __repr_str__(self, join_str: str) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
63 return join_str.join(repr(v) if a is None else f'{a}={v!r}' for a, v in self.__repr_args__()) 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
65 def __pretty__(self, fmt: typing.Callable[[Any], Any], **kwargs: Any) -> typing.Generator[Any, None, None]: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
66 """Used by devtools (https://python-devtools.helpmanual.io/) to pretty print objects."""
67 yield self.__repr_name__() + '(' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
68 yield 1 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
69 for name, value in self.__repr_args__(): 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
70 if name is not None: 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
71 yield name + '=' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
72 yield fmt(value) 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
73 yield ',' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
74 yield 0 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
75 yield -1 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
76 yield ')' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
78 def __rich_repr__(self) -> RichReprResult: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
79 """Used by Rich (https://rich.readthedocs.io/en/stable/pretty.html) to pretty print objects."""
80 for name, field_repr in self.__repr_args__(): 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
81 if name is None: 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
82 yield field_repr 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
83 else:
84 yield name, field_repr 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
86 def __str__(self) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
87 return self.__repr_str__(' ') 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
89 def __repr__(self) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
90 return f'{self.__repr_name__()}({self.__repr_str__(", ")})' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
93def display_as_type(obj: Any) -> str: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
94 """Pretty representation of a type, should be as close as possible to the original type definition string.
96 Takes some logic from `typing._type_repr`.
97 """
98 if isinstance(obj, (types.FunctionType, types.BuiltinFunctionType)): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
99 return obj.__name__ 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
100 elif obj is ...: 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
101 return '...' 1abhijklmnopqcrdestuvwxyzABfgCDEFGHIJKL
102 elif isinstance(obj, Representation): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
103 return repr(obj) 1abhijklmnopqcrdestuvwxyzABfgCDEFGHIJKL
104 elif isinstance(obj, typing.ForwardRef) or typing_objects.is_typealiastype(obj): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
105 return str(obj) 1abhijklmnopqcrdestuvwxyzABfgCDEFGHIJKL
107 if not isinstance(obj, (_typing_extra.typing_base, _typing_extra.WithArgsTypes, type)): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
108 obj = obj.__class__ 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
110 if is_union_origin(typing_extensions.get_origin(obj)): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
111 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
112 return f'Union[{args}]' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
113 elif isinstance(obj, _typing_extra.WithArgsTypes): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
114 if typing_objects.is_literal(typing_extensions.get_origin(obj)): 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
115 args = ', '.join(map(repr, typing_extensions.get_args(obj))) 1abhijklmnopqcrdestuvwxyzABfgCDEFGHIJKL
116 else:
117 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
118 try: 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
119 return f'{obj.__qualname__}[{args}]' 1abhijklmnopqMcrdestuvwxyzABNfgCDEFGHIJKLO
120 except AttributeError: 1abcdefg
121 return str(obj).replace('typing.', '').replace('typing_extensions.', '') # handles TypeAliasType in 3.12 1abcdefg
122 elif isinstance(obj, type): 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
123 return obj.__qualname__ 1abhijklmnopqMcrdestuvwxyzABNPfgCDEFGHIJKLO
124 else:
125 return repr(obj).replace('typing.', '').replace('typing_extensions.', '') 1abhijklmnopqcrdestuvwxyzABfgCDEFGHIJKL