Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/rich/repr.py: 39%

85 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1import inspect 

2from functools import partial 

3from typing import ( 

4 Any, 

5 Callable, 

6 Iterable, 

7 List, 

8 Optional, 

9 Tuple, 

10 Type, 

11 TypeVar, 

12 Union, 

13 overload, 

14) 

15 

16T = TypeVar("T") 

17 

18 

19Result = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]] 

20RichReprResult = Result 

21 

22 

23class ReprError(Exception): 

24 """An error occurred when attempting to build a repr.""" 

25 

26 

27@overload 

28def auto(cls: Optional[Type[T]]) -> Type[T]: 

29 ... 

30 

31 

32@overload 

33def auto(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]: 

34 ... 

35 

36 

37def auto( 

38 cls: Optional[Type[T]] = None, *, angular: Optional[bool] = None 

39) -> Union[Type[T], Callable[[Type[T]], Type[T]]]: 

40 """Class decorator to create __repr__ from __rich_repr__""" 

41 

42 def do_replace(cls: Type[T], angular: Optional[bool] = None) -> Type[T]: 

43 def auto_repr(self: T) -> str: 

44 """Create repr string from __rich_repr__""" 

45 repr_str: List[str] = [] 

46 append = repr_str.append 

47 

48 angular: bool = getattr(self.__rich_repr__, "angular", False) # type: ignore[attr-defined] 

49 for arg in self.__rich_repr__(): # type: ignore[attr-defined] 

50 if isinstance(arg, tuple): 

51 if len(arg) == 1: 

52 append(repr(arg[0])) 

53 else: 

54 key, value, *default = arg 

55 if key is None: 

56 append(repr(value)) 

57 else: 

58 if len(default) and default[0] == value: 

59 continue 

60 append(f"{key}={value!r}") 

61 else: 

62 append(repr(arg)) 

63 if angular: 

64 return f"<{self.__class__.__name__} {' '.join(repr_str)}>" 

65 else: 

66 return f"{self.__class__.__name__}({', '.join(repr_str)})" 

67 

68 def auto_rich_repr(self: Type[T]) -> Result: 

69 """Auto generate __rich_rep__ from signature of __init__""" 

70 try: 

71 signature = inspect.signature(self.__init__) 

72 for name, param in signature.parameters.items(): 

73 if param.kind == param.POSITIONAL_ONLY: 

74 yield getattr(self, name) 

75 elif param.kind in ( 

76 param.POSITIONAL_OR_KEYWORD, 

77 param.KEYWORD_ONLY, 

78 ): 

79 if param.default == param.empty: 

80 yield getattr(self, param.name) 

81 else: 

82 yield param.name, getattr(self, param.name), param.default 

83 except Exception as error: 

84 raise ReprError( 

85 f"Failed to auto generate __rich_repr__; {error}" 

86 ) from None 

87 

88 if not hasattr(cls, "__rich_repr__"): 

89 auto_rich_repr.__doc__ = "Build a rich repr" 

90 cls.__rich_repr__ = auto_rich_repr # type: ignore[attr-defined] 

91 

92 auto_repr.__doc__ = "Return repr(self)" 

93 cls.__repr__ = auto_repr # type: ignore[assignment] 

94 if angular is not None: 

95 cls.__rich_repr__.angular = angular # type: ignore[attr-defined] 

96 return cls 

97 

98 if cls is None: 

99 return partial(do_replace, angular=angular) 

100 else: 

101 return do_replace(cls, angular=angular) 

102 

103 

104@overload 

105def rich_repr(cls: Optional[Type[T]]) -> Type[T]: 

106 ... 

107 

108 

109@overload 

110def rich_repr(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]: 

111 ... 

112 

113 

114def rich_repr( 

115 cls: Optional[Type[T]] = None, *, angular: bool = False 

116) -> Union[Type[T], Callable[[Type[T]], Type[T]]]: 

117 if cls is None: 

118 return auto(angular=angular) 

119 else: 

120 return auto(cls) 

121 

122 

123if __name__ == "__main__": 

124 

125 @auto 

126 class Foo: 

127 def __rich_repr__(self) -> Result: 

128 yield "foo" 

129 yield "bar", {"shopping": ["eggs", "ham", "pineapple"]} 

130 yield "buy", "hand sanitizer" 

131 

132 foo = Foo() 

133 from rich.console import Console 

134 

135 console = Console() 

136 

137 console.rule("Standard repr") 

138 console.print(foo) 

139 

140 console.print(foo, width=60) 

141 console.print(foo, width=30) 

142 

143 console.rule("Angular repr") 

144 Foo.__rich_repr__.angular = True # type: ignore[attr-defined] 

145 

146 console.print(foo) 

147 

148 console.print(foo, width=60) 

149 console.print(foo, width=30)