Coverage for /pythoncovmergedfiles/medio/medio/src/pydantic/pydantic/_internal/_repr.py: 31%

62 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-27 07:38 +0000

1""" 

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

3""" 

4from __future__ import annotations as _annotations 

5 

6import types 

7import typing 

8from typing import Any 

9 

10import typing_extensions 

11 

12from . import _typing_extra 

13 

14if typing.TYPE_CHECKING: 

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

16 RichReprResult: typing_extensions.TypeAlias = ( 

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

18 ) 

19 

20 

21class PlainRepr(str): 

22 """ 

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 # we don't want to use a type annotation here as it can break get_type_hints 

38 __slots__ = tuple() # type: typing.Collection[str] 

39 

40 def __repr_args__(self) -> ReprArgs: 

41 """ 

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

43 

44 Can either return: 

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

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

47 """ 

48 attrs_names = self.__slots__ 

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

50 attrs_names = self.__dict__.keys() 

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

52 return [(a, v) for a, v in attrs if v is not None] 

53 

54 def __repr_name__(self) -> str: 

55 """ 

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

57 """ 

58 return self.__class__.__name__ 

59 

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

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

62 

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

64 """ 

65 Used by devtools (https://python-devtools.helpmanual.io/) to provide a human-readable representations of objects 

66 """ 

67 yield self.__repr_name__() + '(' 

68 yield 1 

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

70 if name is not None: 

71 yield name + '=' 

72 yield fmt(value) 

73 yield ',' 

74 yield 0 

75 yield -1 

76 yield ')' 

77 

78 def __str__(self) -> str: 

79 return self.__repr_str__(' ') 

80 

81 def __repr__(self) -> str: 

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

83 

84 def __rich_repr__(self) -> RichReprResult: 

85 """Get fields for Rich library""" 

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

87 if name is None: 

88 yield field_repr 

89 else: 

90 yield name, field_repr 

91 

92 

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

94 """ 

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

96 

97 Takes some logic from `typing._type_repr`. 

98 """ 

99 if isinstance(obj, types.FunctionType): 

100 return obj.__name__ 

101 elif obj is ...: 

102 return '...' 

103 elif isinstance(obj, Representation): 

104 return repr(obj) 

105 

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

107 obj = obj.__class__ 

108 

109 if _typing_extra.origin_is_union(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 args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) 

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

115 elif isinstance(obj, type): 

116 return obj.__qualname__ 

117 else: 

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