Skip to content

Commit e2a4bbe

Browse files
committed
Fix and narrow repr.py typing
First of many stabs at eliminating Any and # type: ignore from the codebase. Here we eliminated several different type ignores; the remaining # type: ignore is just a mypy limitation. I also narrowed the typing of RichReprResult from Iterable[Any|...]] to Iterable[object] since after inspection of the code this is what's really required. In order to correctly type the auto_repr function, I introduced a SupportsRichRepr protocol; we could also have made this runtimecheckable and replaced a hasattr check in the code with it, but it seemed unnecessary so I opted not to.
1 parent eb673d1 commit e2a4bbe

File tree

1 file changed

+35
-25
lines changed

1 file changed

+35
-25
lines changed

rich/repr.py

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,64 @@
11
from functools import partial
22
import inspect
3+
import sys
34

45
from typing import (
5-
Any,
66
Callable,
77
Iterable,
88
List,
99
Optional,
10-
overload,
11-
Union,
12-
Tuple,
1310
Type,
1411
TypeVar,
12+
Union,
13+
cast,
14+
overload,
1515
)
1616

17+
if sys.version_info >= (3, 8):
18+
from typing import Protocol
19+
else:
20+
from typing_extensions import Protocol # pragma: no cover
21+
1722

1823
T = TypeVar("T")
1924

2025

21-
Result = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]]
26+
Result = Iterable[object]
2227
RichReprResult = Result
2328

2429

2530
class ReprError(Exception):
2631
"""An error occurred when attempting to build a repr."""
2732

2833

34+
class SupportsRichRepr(Protocol):
35+
def __rich_repr__(self) -> Result: # pragma: no cover
36+
...
37+
38+
2939
@overload
30-
def auto(cls: Optional[T]) -> T:
40+
def auto(cls: Optional[Type[T]]) -> Type[T]:
3141
...
3242

3343

3444
@overload
35-
def auto(*, angular: bool = False) -> Callable[[T], T]:
45+
def auto(*, angular: bool) -> Callable[[Type[T]], Type[T]]:
3646
...
3747

3848

3949
def auto(
40-
cls: Optional[T] = None, *, angular: Optional[bool] = None
41-
) -> Union[T, Callable[[T], T]]:
50+
cls: Optional[Type[T]] = None, *, angular: Optional[bool] = None
51+
) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
4252
"""Class decorator to create __repr__ from __rich_repr__"""
4353

4454
def do_replace(cls: Type[T], angular: Optional[bool] = None) -> Type[T]:
45-
def auto_repr(self: Type[T]) -> str:
55+
def auto_repr(self: SupportsRichRepr) -> str:
4656
"""Create repr string from __rich_repr__"""
4757
repr_str: List[str] = []
4858
append = repr_str.append
4959

50-
angular = getattr(self.__rich_repr__, "angular", False) # type: ignore
51-
for arg in self.__rich_repr__(): # type: ignore
60+
angular = getattr(self.__rich_repr__, "angular", False)
61+
for arg in self.__rich_repr__():
5262
if isinstance(arg, tuple):
5363
if len(arg) == 1:
5464
append(repr(arg[0]))
@@ -67,10 +77,10 @@ def auto_repr(self: Type[T]) -> str:
6777
else:
6878
return f"{self.__class__.__name__}({', '.join(repr_str)})"
6979

70-
def auto_rich_repr(self: Type[T]) -> Result:
71-
"""Auto generate __rich_rep__ from signature of __init__"""
80+
def auto_rich_repr(self: T) -> Result:
81+
"""Auto generate __rich_repr__ from signature of __init__"""
7282
try:
73-
signature = inspect.signature(self.__init__) ## type: ignore
83+
signature = inspect.signature(self.__init__) # type: ignore[misc]
7484
for name, param in signature.parameters.items():
7585
if param.kind == param.POSITIONAL_ONLY:
7686
yield getattr(self, name)
@@ -89,33 +99,33 @@ def auto_rich_repr(self: Type[T]) -> Result:
8999

90100
if not hasattr(cls, "__rich_repr__"):
91101
auto_rich_repr.__doc__ = "Build a rich repr"
92-
cls.__rich_repr__ = auto_rich_repr # type: ignore
102+
setattr(cls, "__rich_repr__", auto_rich_repr)
93103

94104
auto_repr.__doc__ = "Return repr(self)"
95-
cls.__repr__ = auto_repr # type: ignore
105+
setattr(cls, "__repr__", auto_repr)
96106
if angular is not None:
97-
cls.__rich_repr__.angular = angular # type: ignore
107+
setattr(cast(SupportsRichRepr, cls).__rich_repr__, "angular", angular)
98108
return cls
99109

100110
if cls is None:
101-
return partial(do_replace, angular=angular) # type: ignore
111+
return partial(do_replace, angular=angular)
102112
else:
103-
return do_replace(cls, angular=angular) # type: ignore
113+
return do_replace(cls, angular=angular)
104114

105115

106116
@overload
107-
def rich_repr(cls: Optional[T]) -> T:
117+
def rich_repr(cls: Optional[Type[T]]) -> Type[T]:
108118
...
109119

110120

111121
@overload
112-
def rich_repr(*, angular: bool = False) -> Callable[[T], T]:
122+
def rich_repr(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]:
113123
...
114124

115125

116126
def rich_repr(
117-
cls: Optional[T] = None, *, angular: bool = False
118-
) -> Union[T, Callable[[T], T]]:
127+
cls: Optional[Type[T]] = None, *, angular: bool = False
128+
) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
119129
if cls is None:
120130
return auto(angular=angular)
121131
else:
@@ -143,7 +153,7 @@ def __rich_repr__(self) -> Result:
143153
console.print(foo, width=30)
144154

145155
console.rule("Angular repr")
146-
Foo.__rich_repr__.angular = True # type: ignore
156+
setattr(Foo.__rich_repr__, "angular", True)
147157

148158
console.print(foo)
149159

0 commit comments

Comments
 (0)