Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/rich/repr.py: 38%
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
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
1from functools import partial
2from typing import (
3 Any,
4 Callable,
5 Iterable,
6 List,
7 Optional,
8 Tuple,
9 Type,
10 TypeVar,
11 Union,
12 overload,
13)
15T = TypeVar("T")
18Result = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]]
19RichReprResult = Result
22class ReprError(Exception):
23 """An error occurred when attempting to build a repr."""
26@overload
27def auto(cls: Optional[Type[T]]) -> Type[T]:
28 ...
31@overload
32def auto(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]:
33 ...
36def auto(
37 cls: Optional[Type[T]] = None, *, angular: Optional[bool] = None
38) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
39 """Class decorator to create __repr__ from __rich_repr__"""
41 def do_replace(cls: Type[T], angular: Optional[bool] = None) -> Type[T]:
42 def auto_repr(self: T) -> str:
43 """Create repr string from __rich_repr__"""
44 repr_str: List[str] = []
45 append = repr_str.append
47 angular: bool = getattr(self.__rich_repr__, "angular", False) # type: ignore[attr-defined]
48 for arg in self.__rich_repr__(): # type: ignore[attr-defined]
49 if isinstance(arg, tuple):
50 if len(arg) == 1:
51 append(repr(arg[0]))
52 else:
53 key, value, *default = arg
54 if key is None:
55 append(repr(value))
56 else:
57 if default and default[0] == value:
58 continue
59 append(f"{key}={value!r}")
60 else:
61 append(repr(arg))
62 if angular:
63 return f"<{self.__class__.__name__} {' '.join(repr_str)}>"
64 else:
65 return f"{self.__class__.__name__}({', '.join(repr_str)})"
67 def auto_rich_repr(self: Type[T]) -> Result:
68 """Auto generate __rich_rep__ from signature of __init__"""
69 try:
70 import inspect
72 signature = inspect.signature(self.__init__)
73 for name, param in signature.parameters.items():
74 if param.kind == param.POSITIONAL_ONLY:
75 yield getattr(self, name)
76 elif param.kind in (
77 param.POSITIONAL_OR_KEYWORD,
78 param.KEYWORD_ONLY,
79 ):
80 if param.default is param.empty:
81 yield getattr(self, param.name)
82 else:
83 yield param.name, getattr(self, param.name), param.default
84 except Exception as error:
85 raise ReprError(
86 f"Failed to auto generate __rich_repr__; {error}"
87 ) from None
89 if not hasattr(cls, "__rich_repr__"):
90 auto_rich_repr.__doc__ = "Build a rich repr"
91 cls.__rich_repr__ = auto_rich_repr # type: ignore[attr-defined]
93 auto_repr.__doc__ = "Return repr(self)"
94 cls.__repr__ = auto_repr # type: ignore[assignment]
95 if angular is not None:
96 cls.__rich_repr__.angular = angular # type: ignore[attr-defined]
97 return cls
99 if cls is None:
100 return partial(do_replace, angular=angular)
101 else:
102 return do_replace(cls, angular=angular)
105@overload
106def rich_repr(cls: Optional[Type[T]]) -> Type[T]:
107 ...
110@overload
111def rich_repr(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]:
112 ...
115def rich_repr(
116 cls: Optional[Type[T]] = None, *, angular: bool = False
117) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
118 if cls is None:
119 return auto(angular=angular)
120 else:
121 return auto(cls)
124if __name__ == "__main__":
126 @auto
127 class Foo:
128 def __rich_repr__(self) -> Result:
129 yield "foo"
130 yield "bar", {"shopping": ["eggs", "ham", "pineapple"]}
131 yield "buy", "hand sanitizer"
133 foo = Foo()
134 from rich.console import Console
136 console = Console()
138 console.rule("Standard repr")
139 console.print(foo)
141 console.print(foo, width=60)
142 console.print(foo, width=30)
144 console.rule("Angular repr")
145 Foo.__rich_repr__.angular = True # type: ignore[attr-defined]
147 console.print(foo)
149 console.print(foo, width=60)
150 console.print(foo, width=30)