Skip to content

Commit 2777568

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 2777568

File tree

1 file changed

+35
-24
lines changed

1 file changed

+35
-24
lines changed

rich/repr.py

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,65 @@
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,
1210
Tuple,
1311
Type,
1412
TypeVar,
13+
Union,
14+
cast,
15+
overload,
1516
)
1617

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

1824
T = TypeVar("T")
1925

2026

21-
Result = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]]
27+
Result = Iterable[Union[object, Tuple[object], Tuple[str, object], Tuple[str, object, object]]]
2228
RichReprResult = Result
2329

2430

2531
class ReprError(Exception):
2632
"""An error occurred when attempting to build a repr."""
2733

2834

35+
class SupportsRichRepr(Protocol):
36+
def __rich_repr__(self) -> Result: # pragma: no cover
37+
...
38+
39+
2940
@overload
30-
def auto(cls: Optional[T]) -> T:
41+
def auto(cls: Optional[Type[T]]) -> Type[T]:
3142
...
3243

3344

3445
@overload
35-
def auto(*, angular: bool = False) -> Callable[[T], T]:
46+
def auto(*, angular: bool) -> Callable[[Type[T]], Type[T]]:
3647
...
3748

3849

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

4455
def do_replace(cls: Type[T], angular: Optional[bool] = None) -> Type[T]:
45-
def auto_repr(self: Type[T]) -> str:
56+
def auto_repr(self: SupportsRichRepr) -> str:
4657
"""Create repr string from __rich_repr__"""
4758
repr_str: List[str] = []
4859
append = repr_str.append
4960

50-
angular = getattr(self.__rich_repr__, "angular", False) # type: ignore
51-
for arg in self.__rich_repr__(): # type: ignore
61+
angular = getattr(self.__rich_repr__, "angular", False)
62+
for arg in self.__rich_repr__():
5263
if isinstance(arg, tuple):
5364
if len(arg) == 1:
5465
append(repr(arg[0]))
@@ -67,10 +78,10 @@ def auto_repr(self: Type[T]) -> str:
6778
else:
6879
return f"{self.__class__.__name__}({', '.join(repr_str)})"
6980

70-
def auto_rich_repr(self: Type[T]) -> Result:
71-
"""Auto generate __rich_rep__ from signature of __init__"""
81+
def auto_rich_repr(self: T) -> Result:
82+
"""Auto generate __rich_repr__ from signature of __init__"""
7283
try:
73-
signature = inspect.signature(self.__init__) ## type: ignore
84+
signature = inspect.signature(self.__init__) # type: ignore[misc]
7485
for name, param in signature.parameters.items():
7586
if param.kind == param.POSITIONAL_ONLY:
7687
yield getattr(self, name)
@@ -89,33 +100,33 @@ def auto_rich_repr(self: Type[T]) -> Result:
89100

90101
if not hasattr(cls, "__rich_repr__"):
91102
auto_rich_repr.__doc__ = "Build a rich repr"
92-
cls.__rich_repr__ = auto_rich_repr # type: ignore
103+
setattr(cls, "__rich_repr__", auto_rich_repr)
93104

94105
auto_repr.__doc__ = "Return repr(self)"
95-
cls.__repr__ = auto_repr # type: ignore
106+
setattr(cls, "__repr__", auto_repr)
96107
if angular is not None:
97-
cls.__rich_repr__.angular = angular # type: ignore
108+
setattr(cast(SupportsRichRepr, cls).__rich_repr__, "angular", angular)
98109
return cls
99110

100111
if cls is None:
101-
return partial(do_replace, angular=angular) # type: ignore
112+
return partial(do_replace, angular=angular)
102113
else:
103-
return do_replace(cls, angular=angular) # type: ignore
114+
return do_replace(cls, angular=angular)
104115

105116

106117
@overload
107-
def rich_repr(cls: Optional[T]) -> T:
118+
def rich_repr(cls: Optional[Type[T]]) -> Type[T]:
108119
...
109120

110121

111122
@overload
112-
def rich_repr(*, angular: bool = False) -> Callable[[T], T]:
123+
def rich_repr(*, angular: bool = False) -> Callable[[Type[T]], Type[T]]:
113124
...
114125

115126

116127
def rich_repr(
117-
cls: Optional[T] = None, *, angular: bool = False
118-
) -> Union[T, Callable[[T], T]]:
128+
cls: Optional[Type[T]] = None, *, angular: bool = False
129+
) -> Union[Type[T], Callable[[Type[T]], Type[T]]]:
119130
if cls is None:
120131
return auto(angular=angular)
121132
else:
@@ -143,7 +154,7 @@ def __rich_repr__(self) -> Result:
143154
console.print(foo, width=30)
144155

145156
console.rule("Angular repr")
146-
Foo.__rich_repr__.angular = True # type: ignore
157+
setattr(Foo.__rich_repr__, "angular", True)
147158

148159
console.print(foo)
149160

0 commit comments

Comments
 (0)