Coverage for pydantic/_internal/_repr.py: 100.00%

68 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-13 19:35 +0000

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

2 

3from __future__ import annotations as _annotations 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

4 

5import types 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

6import typing 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

7from typing import Any 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

8 

9import typing_extensions 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

10 

11from . import _typing_extra 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

12 

13if typing.TYPE_CHECKING: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

14 ReprArgs: typing_extensions.TypeAlias = 'typing.Iterable[tuple[str | None, Any]]' 

15 RichReprResult: typing_extensions.TypeAlias = ( 

16 'typing.Iterable[Any | tuple[Any] | tuple[str, Any] | tuple[str, Any, Any]]' 

17 ) 

18 

19 

20class PlainRepr(str): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

21 """String class where repr doesn't include quotes. Useful with Representation when you want to return a string 

22 representation of something that is valid (or pseudo-valid) python. 

23 """ 

24 

25 def __repr__(self) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

26 return str(self) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

27 

28 

29class Representation: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

30 # Mixin to provide `__str__`, `__repr__`, and `__pretty__` and `__rich_repr__` methods. 

31 # `__pretty__` is used by [devtools](https://python-devtools.helpmanual.io/). 

32 # `__rich_repr__` is used by [rich](https://rich.readthedocs.io/en/stable/pretty.html). 

33 # (this is not a docstring to avoid adding a docstring to classes which inherit from Representation) 

34 

35 # we don't want to use a type annotation here as it can break get_type_hints 

36 __slots__ = () # type: typing.Collection[str] 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

37 

38 def __repr_args__(self) -> ReprArgs: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

40 

41 Can either return: 

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

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

44 """ 

45 attrs_names = self.__slots__ 1abhijklmnocpdeqrstuvwxfgyzABCDEF

46 if not attrs_names and hasattr(self, '__dict__'): 1abhijklmnocpdeqrstuvwxfgyzABCDEF

47 attrs_names = self.__dict__.keys() 1abhijklmnocpdeqrstuvwxfgyzABCDEF

48 attrs = ((s, getattr(self, s)) for s in attrs_names) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

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

50 

51 def __repr_name__(self) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

53 return self.__class__.__name__ 1abhijklmnocpdeqrstuvwxfgyzABCDEF

54 

55 def __repr_recursion__(self, object: Any) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

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

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

59 

60 def __repr_str__(self, join_str: str) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

62 

63 def __pretty__(self, fmt: typing.Callable[[Any], Any], **kwargs: Any) -> typing.Generator[Any, None, None]: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

65 yield self.__repr_name__() + '(' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

66 yield 1 1abhijklmnocpdeqrstuvwxfgyzABCDEF

67 for name, value in self.__repr_args__(): 1abhijklmnocpdeqrstuvwxfgyzABCDEF

68 if name is not None: 1abhijklmnocpdeqrstuvwxfgyzABCDEF

69 yield name + '=' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

70 yield fmt(value) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

71 yield ',' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

72 yield 0 1abhijklmnocpdeqrstuvwxfgyzABCDEF

73 yield -1 1abhijklmnocpdeqrstuvwxfgyzABCDEF

74 yield ')' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

75 

76 def __rich_repr__(self) -> RichReprResult: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

78 for name, field_repr in self.__repr_args__(): 1abhijklmnocpdeqrstuvwxfgyzABCDEF

79 if name is None: 1abhijklmnocpdeqrstuvwxfgyzABCDEF

80 yield field_repr 1abhijklmnocpdeqrstuvwxfgyzABCDEF

81 else: 

82 yield name, field_repr 1abhijklmnocpdeqrstuvwxfgyzABCDEF

83 

84 def __str__(self) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

85 return self.__repr_str__(' ') 1abhijklmnocpdeqrstuvwxfgyzABCDEF

86 

87 def __repr__(self) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

88 return f'{self.__repr_name__()}({self.__repr_str__(", ")})' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

89 

90 

91def display_as_type(obj: Any) -> str: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

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

93 

94 Takes some logic from `typing._type_repr`. 

95 """ 

96 if isinstance(obj, (types.FunctionType, types.BuiltinFunctionType)): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

97 return obj.__name__ 1abhijklmnocpdeqrstuvwxfgyzABCDEF

98 elif obj is ...: 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

99 return '...' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

100 elif isinstance(obj, Representation): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

101 return repr(obj) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

102 elif isinstance(obj, typing.ForwardRef) or _typing_extra.is_type_alias_type(obj): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

103 return str(obj) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

104 

105 if not isinstance(obj, (_typing_extra.typing_base, _typing_extra.WithArgsTypes, type)): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

106 obj = obj.__class__ 1abhijklmnocpdeqrstuvwxfgyzABCDEF

107 

108 if _typing_extra.origin_is_union(typing_extensions.get_origin(obj)): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

109 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

110 return f'Union[{args}]' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

111 elif isinstance(obj, _typing_extra.WithArgsTypes): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

112 if _typing_extra.is_literal(obj): 1abhijklmnocpdeqrstuvwxfgyzABCDEF

113 args = ', '.join(map(repr, typing_extensions.get_args(obj))) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

114 else: 

115 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 1abhijklmnocpdeqrstuvwxfgyzABCDEF

116 try: 1abhijklmnocpdeqrstuvwxfgyzABCDEF

117 return f'{obj.__qualname__}[{args}]' 1abhijklmnocpdeqrstuvwxfgyzABCDEF

118 except AttributeError: 1abcdefg

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

120 elif isinstance(obj, type): 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

121 return obj.__qualname__ 1abhijklmnocpdeqrstuvwxGHIJKLMfgyzABCDEF

122 else: 

123 return repr(obj).replace('typing.', '').replace('typing_extensions.', '') 1abhijklmnocpdeqrstuvwxfgyzABCDEF