Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pydantic/_internal/_repr.py: 53%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

75 statements  

1"""Tools to provide pretty/human-readable display of objects.""" 

2 

3from __future__ import annotations as _annotations 

4 

5import types 

6from collections.abc import Callable, Collection, Generator, Iterable 

7from typing import TYPE_CHECKING, Any, ForwardRef, cast 

8 

9import typing_extensions 

10from typing_extensions import TypeAlias 

11from typing_inspection import typing_objects 

12from typing_inspection.introspection import is_union_origin 

13 

14from . import _typing_extra 

15 

16if TYPE_CHECKING: 

17 # TODO remove type error comments when we drop support for Python 3.9 

18 ReprArgs: TypeAlias = Iterable[tuple[str | None, Any]] # pyright: ignore[reportGeneralTypeIssues] 

19 RichReprResult: TypeAlias = Iterable[Any | tuple[Any] | tuple[str, Any] | tuple[str, Any, Any]] # pyright: ignore[reportGeneralTypeIssues] 

20 

21 

22class PlainRepr(str): 

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 """ 

26 

27 def __repr__(self) -> str: 

28 return str(self) 

29 

30 

31class Representation: 

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) 

36 

37 __slots__ = () 

38 

39 def __repr_args__(self) -> ReprArgs: 

40 """Returns the attributes to show in __str__, __repr__, and __pretty__ this is generally overridden. 

41 

42 Can either return: 

43 * name - value pairs, e.g.: `[('foo_name', 'foo'), ('bar_name', ['b', 'a', 'r'])]` 

44 * or, just values, e.g.: `[(None, 'foo'), (None, ['b', 'a', 'r'])]` 

45 """ 

46 attrs_names = cast(Collection[str], self.__slots__) 

47 if not attrs_names and hasattr(self, '__dict__'): 

48 attrs_names = self.__dict__.keys() 

49 attrs = ((s, getattr(self, s)) for s in attrs_names) 

50 return [(a, v if v is not self else self.__repr_recursion__(v)) for a, v in attrs if v is not None] 

51 

52 def __repr_name__(self) -> str: 

53 """Name of the instance's class, used in __repr__.""" 

54 return self.__class__.__name__ 

55 

56 def __repr_recursion__(self, object: Any) -> str: 

57 """Returns the string representation of a recursive object.""" 

58 # This is copied over from the stdlib `pprint` module: 

59 return f'<Recursion on {type(object).__name__} with id={id(object)}>' 

60 

61 def __repr_str__(self, join_str: str) -> str: 

62 return join_str.join(repr(v) if a is None else f'{a}={v!r}' for a, v in self.__repr_args__()) 

63 

64 def __pretty__(self, fmt: Callable[[Any], Any], **kwargs: Any) -> Generator[Any]: 

65 """Used by devtools (https://python-devtools.helpmanual.io/) to pretty print objects.""" 

66 yield self.__repr_name__() + '(' 

67 yield 1 

68 for name, value in self.__repr_args__(): 

69 if name is not None: 

70 yield name + '=' 

71 yield fmt(value) 

72 yield ',' 

73 yield 0 

74 yield -1 

75 yield ')' 

76 

77 def __rich_repr__(self) -> RichReprResult: 

78 """Used by Rich (https://rich.readthedocs.io/en/stable/pretty.html) to pretty print objects.""" 

79 for name, field_repr in self.__repr_args__(): 

80 if name is None: 

81 yield field_repr 

82 else: 

83 yield name, field_repr 

84 

85 def __str__(self) -> str: 

86 return self.__repr_str__(' ') 

87 

88 def __repr__(self) -> str: 

89 return f'{self.__repr_name__()}({self.__repr_str__(", ")})' 

90 

91 

92def display_as_type(obj: Any) -> str: 

93 """Pretty representation of a type, should be as close as possible to the original type definition string. 

94 

95 Takes some logic from `typing._type_repr`. 

96 """ 

97 if isinstance(obj, (types.FunctionType, types.BuiltinFunctionType)): 

98 return obj.__name__ 

99 elif obj is ...: 

100 return '...' 

101 elif isinstance(obj, Representation): 

102 return repr(obj) 

103 elif isinstance(obj, ForwardRef) or typing_objects.is_typealiastype(obj): 

104 return str(obj) 

105 

106 if not isinstance(obj, (_typing_extra.typing_base, _typing_extra.WithArgsTypes, type)): 

107 obj = obj.__class__ 

108 

109 if is_union_origin(typing_extensions.get_origin(obj)): 

110 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 

111 return f'Union[{args}]' 

112 elif isinstance(obj, _typing_extra.WithArgsTypes): 

113 if typing_objects.is_literal(typing_extensions.get_origin(obj)): 

114 args = ', '.join(map(repr, typing_extensions.get_args(obj))) 

115 else: 

116 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 

117 try: 

118 return f'{obj.__qualname__}[{args}]' 

119 except AttributeError: 

120 return str(obj).replace('typing.', '').replace('typing_extensions.', '') # handles TypeAliasType in 3.12 

121 elif isinstance(obj, type): 

122 return obj.__qualname__ 

123 else: 

124 return repr(obj).replace('typing.', '').replace('typing_extensions.', '')