Skip to content

Commit 8198668

Browse files
authored
[red-knot] MDTest: Use custom class names instead of builtins (#16269)
## Summary Follow up on the discussion [here](#16121 (comment)). Replace builtin classes with custom placeholder names, which should hopefully make the tests a bit easier to understand. I carefully renamed things one after the other, to make sure that there is no functional change in the tests.
1 parent fc6b03c commit 8198668

File tree

4 files changed

+359
-282
lines changed

4 files changed

+359
-282
lines changed

crates/red_knot_python_semantic/resources/mdtest/comparison/instances/rich_comparison.md

+109-79
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,38 @@ most common case involves implementing these methods for the same type:
1616
```py
1717
from __future__ import annotations
1818

19+
class EqReturnType: ...
20+
class NeReturnType: ...
21+
class LtReturnType: ...
22+
class LeReturnType: ...
23+
class GtReturnType: ...
24+
class GeReturnType: ...
25+
1926
class A:
20-
def __eq__(self, other: A) -> int:
21-
return 42
27+
def __eq__(self, other: A) -> EqReturnType:
28+
return EqReturnType()
2229

23-
def __ne__(self, other: A) -> bytearray:
24-
return bytearray()
30+
def __ne__(self, other: A) -> NeReturnType:
31+
return NeReturnType()
2532

26-
def __lt__(self, other: A) -> str:
27-
return "42"
33+
def __lt__(self, other: A) -> LtReturnType:
34+
return LtReturnType()
2835

29-
def __le__(self, other: A) -> bytes:
30-
return b"42"
36+
def __le__(self, other: A) -> LeReturnType:
37+
return LeReturnType()
3138

32-
def __gt__(self, other: A) -> list:
33-
return [42]
39+
def __gt__(self, other: A) -> GtReturnType:
40+
return GtReturnType()
3441

35-
def __ge__(self, other: A) -> set:
36-
return {42}
42+
def __ge__(self, other: A) -> GeReturnType:
43+
return GeReturnType()
3744

38-
reveal_type(A() == A()) # revealed: int
39-
reveal_type(A() != A()) # revealed: bytearray
40-
reveal_type(A() < A()) # revealed: str
41-
reveal_type(A() <= A()) # revealed: bytes
42-
reveal_type(A() > A()) # revealed: list
43-
reveal_type(A() >= A()) # revealed: set
45+
reveal_type(A() == A()) # revealed: EqReturnType
46+
reveal_type(A() != A()) # revealed: NeReturnType
47+
reveal_type(A() < A()) # revealed: LtReturnType
48+
reveal_type(A() <= A()) # revealed: LeReturnType
49+
reveal_type(A() > A()) # revealed: GtReturnType
50+
reveal_type(A() >= A()) # revealed: GeReturnType
4451
```
4552

4653
## Rich Comparison Dunder Implementations for Other Class
@@ -51,33 +58,40 @@ type:
5158
```py
5259
from __future__ import annotations
5360

61+
class EqReturnType: ...
62+
class NeReturnType: ...
63+
class LtReturnType: ...
64+
class LeReturnType: ...
65+
class GtReturnType: ...
66+
class GeReturnType: ...
67+
5468
class A:
55-
def __eq__(self, other: B) -> int:
56-
return 42
69+
def __eq__(self, other: B) -> EqReturnType:
70+
return EqReturnType()
5771

58-
def __ne__(self, other: B) -> bytearray:
59-
return bytearray()
72+
def __ne__(self, other: B) -> NeReturnType:
73+
return NeReturnType()
6074

61-
def __lt__(self, other: B) -> str:
62-
return "42"
75+
def __lt__(self, other: B) -> LtReturnType:
76+
return LtReturnType()
6377

64-
def __le__(self, other: B) -> bytes:
65-
return b"42"
78+
def __le__(self, other: B) -> LeReturnType:
79+
return LeReturnType()
6680

67-
def __gt__(self, other: B) -> list:
68-
return [42]
81+
def __gt__(self, other: B) -> GtReturnType:
82+
return GtReturnType()
6983

70-
def __ge__(self, other: B) -> set:
71-
return {42}
84+
def __ge__(self, other: B) -> GeReturnType:
85+
return GeReturnType()
7286

7387
class B: ...
7488

75-
reveal_type(A() == B()) # revealed: int
76-
reveal_type(A() != B()) # revealed: bytearray
77-
reveal_type(A() < B()) # revealed: str
78-
reveal_type(A() <= B()) # revealed: bytes
79-
reveal_type(A() > B()) # revealed: list
80-
reveal_type(A() >= B()) # revealed: set
89+
reveal_type(A() == B()) # revealed: EqReturnType
90+
reveal_type(A() != B()) # revealed: NeReturnType
91+
reveal_type(A() < B()) # revealed: LtReturnType
92+
reveal_type(A() <= B()) # revealed: LeReturnType
93+
reveal_type(A() > B()) # revealed: GtReturnType
94+
reveal_type(A() >= B()) # revealed: GeReturnType
8195
```
8296

8397
## Reflected Comparisons
@@ -89,55 +103,64 @@ these methods will be ignored here because they require a mismatched operand typ
89103
```py
90104
from __future__ import annotations
91105

106+
class EqReturnType: ...
107+
class NeReturnType: ...
108+
class LtReturnType: ...
109+
class LeReturnType: ...
110+
class GtReturnType: ...
111+
class GeReturnType: ...
112+
92113
class A:
93-
def __eq__(self, other: B) -> int:
94-
return 42
114+
def __eq__(self, other: B) -> EqReturnType:
115+
return EqReturnType()
116+
117+
def __ne__(self, other: B) -> NeReturnType:
118+
return NeReturnType()
95119

96-
def __ne__(self, other: B) -> bytearray:
97-
return bytearray()
120+
def __lt__(self, other: B) -> LtReturnType:
121+
return LtReturnType()
98122

99-
def __lt__(self, other: B) -> str:
100-
return "42"
123+
def __le__(self, other: B) -> LeReturnType:
124+
return LeReturnType()
101125

102-
def __le__(self, other: B) -> bytes:
103-
return b"42"
126+
def __gt__(self, other: B) -> GtReturnType:
127+
return GtReturnType()
104128

105-
def __gt__(self, other: B) -> list:
106-
return [42]
129+
def __ge__(self, other: B) -> GeReturnType:
130+
return GeReturnType()
107131

108-
def __ge__(self, other: B) -> set:
109-
return {42}
132+
class Unrelated: ...
110133

111134
class B:
112135
# To override builtins.object.__eq__ and builtins.object.__ne__
113136
# TODO these should emit an invalid override diagnostic
114-
def __eq__(self, other: str) -> B:
137+
def __eq__(self, other: Unrelated) -> B:
115138
return B()
116139

117-
def __ne__(self, other: str) -> B:
140+
def __ne__(self, other: Unrelated) -> B:
118141
return B()
119142

120143
# Because `object.__eq__` and `object.__ne__` accept `object` in typeshed,
121144
# this can only happen with an invalid override of these methods,
122145
# but we still support it.
123-
reveal_type(B() == A()) # revealed: int
124-
reveal_type(B() != A()) # revealed: bytearray
146+
reveal_type(B() == A()) # revealed: EqReturnType
147+
reveal_type(B() != A()) # revealed: NeReturnType
125148

126-
reveal_type(B() < A()) # revealed: list
127-
reveal_type(B() <= A()) # revealed: set
149+
reveal_type(B() < A()) # revealed: GtReturnType
150+
reveal_type(B() <= A()) # revealed: GeReturnType
128151

129-
reveal_type(B() > A()) # revealed: str
130-
reveal_type(B() >= A()) # revealed: bytes
152+
reveal_type(B() > A()) # revealed: LtReturnType
153+
reveal_type(B() >= A()) # revealed: LeReturnType
131154

132155
class C:
133-
def __gt__(self, other: C) -> int:
156+
def __gt__(self, other: C) -> EqReturnType:
134157
return 42
135158

136-
def __ge__(self, other: C) -> bytearray:
137-
return bytearray()
159+
def __ge__(self, other: C) -> NeReturnType:
160+
return NeReturnType()
138161

139-
reveal_type(C() < C()) # revealed: int
140-
reveal_type(C() <= C()) # revealed: bytearray
162+
reveal_type(C() < C()) # revealed: EqReturnType
163+
reveal_type(C() <= C()) # revealed: NeReturnType
141164
```
142165

143166
## Reflected Comparisons with Subclasses
@@ -149,6 +172,13 @@ than `A`.
149172
```py
150173
from __future__ import annotations
151174

175+
class EqReturnType: ...
176+
class NeReturnType: ...
177+
class LtReturnType: ...
178+
class LeReturnType: ...
179+
class GtReturnType: ...
180+
class GeReturnType: ...
181+
152182
class A:
153183
def __eq__(self, other: A) -> A:
154184
return A()
@@ -169,32 +199,32 @@ class A:
169199
return A()
170200

171201
class B(A):
172-
def __eq__(self, other: A) -> int:
173-
return 42
202+
def __eq__(self, other: A) -> EqReturnType:
203+
return EqReturnType()
174204

175-
def __ne__(self, other: A) -> bytearray:
176-
return bytearray()
205+
def __ne__(self, other: A) -> NeReturnType:
206+
return NeReturnType()
177207

178-
def __lt__(self, other: A) -> str:
179-
return "42"
208+
def __lt__(self, other: A) -> LtReturnType:
209+
return LtReturnType()
180210

181-
def __le__(self, other: A) -> bytes:
182-
return b"42"
211+
def __le__(self, other: A) -> LeReturnType:
212+
return LeReturnType()
183213

184-
def __gt__(self, other: A) -> list:
185-
return [42]
214+
def __gt__(self, other: A) -> GtReturnType:
215+
return GtReturnType()
186216

187-
def __ge__(self, other: A) -> set:
188-
return {42}
217+
def __ge__(self, other: A) -> GeReturnType:
218+
return GeReturnType()
189219

190-
reveal_type(A() == B()) # revealed: int
191-
reveal_type(A() != B()) # revealed: bytearray
220+
reveal_type(A() == B()) # revealed: EqReturnType
221+
reveal_type(A() != B()) # revealed: NeReturnType
192222

193-
reveal_type(A() < B()) # revealed: list
194-
reveal_type(A() <= B()) # revealed: set
223+
reveal_type(A() < B()) # revealed: GtReturnType
224+
reveal_type(A() <= B()) # revealed: GeReturnType
195225

196-
reveal_type(A() > B()) # revealed: str
197-
reveal_type(A() >= B()) # revealed: bytes
226+
reveal_type(A() > B()) # revealed: LtReturnType
227+
reveal_type(A() >= B()) # revealed: LeReturnType
198228
```
199229

200230
## Reflected Comparisons with Subclass But Falls Back to LHS

crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.md

+27-18
Original file line numberDiff line numberDiff line change
@@ -147,33 +147,40 @@ of the dunder methods.)
147147
```py
148148
from __future__ import annotations
149149

150+
class EqReturnType: ...
151+
class NeReturnType: ...
152+
class LtReturnType: ...
153+
class LeReturnType: ...
154+
class GtReturnType: ...
155+
class GeReturnType: ...
156+
150157
class A:
151-
def __eq__(self, o: object) -> str:
152-
return "hello"
158+
def __eq__(self, o: object) -> EqReturnType:
159+
return EqReturnType()
153160

154-
def __ne__(self, o: object) -> bytes:
155-
return b"world"
161+
def __ne__(self, o: object) -> NeReturnType:
162+
return NeReturnType()
156163

157-
def __lt__(self, o: A) -> bytearray:
158-
return bytearray()
164+
def __lt__(self, o: A) -> LtReturnType:
165+
return LtReturnType()
159166

160-
def __le__(self, o: A) -> memoryview:
161-
return memoryview(b"")
167+
def __le__(self, o: A) -> LeReturnType:
168+
return LeReturnType()
162169

163-
def __gt__(self, o: A) -> tuple:
164-
return (1, 2, 3)
170+
def __gt__(self, o: A) -> GtReturnType:
171+
return GtReturnType()
165172

166-
def __ge__(self, o: A) -> list:
167-
return [1, 2, 3]
173+
def __ge__(self, o: A) -> GeReturnType:
174+
return GeReturnType()
168175

169176
a = (A(), A())
170177

171178
reveal_type(a == a) # revealed: bool
172179
reveal_type(a != a) # revealed: bool
173-
reveal_type(a < a) # revealed: bytearray | Literal[False]
174-
reveal_type(a <= a) # revealed: memoryview | Literal[True]
175-
reveal_type(a > a) # revealed: tuple | Literal[False]
176-
reveal_type(a >= a) # revealed: list | Literal[True]
180+
reveal_type(a < a) # revealed: LtReturnType | Literal[False]
181+
reveal_type(a <= a) # revealed: LeReturnType | Literal[True]
182+
reveal_type(a > a) # revealed: GtReturnType | Literal[False]
183+
reveal_type(a >= a) # revealed: GeReturnType | Literal[True]
177184

178185
# If lexicographic comparison is finished before comparing A()
179186
b = ("1_foo", A())
@@ -186,11 +193,13 @@ reveal_type(b <= c) # revealed: Literal[True]
186193
reveal_type(b > c) # revealed: Literal[False]
187194
reveal_type(b >= c) # revealed: Literal[False]
188195

196+
class LtReturnTypeOnB: ...
197+
189198
class B:
190-
def __lt__(self, o: B) -> set:
199+
def __lt__(self, o: B) -> LtReturnTypeOnB:
191200
return set()
192201

193-
reveal_type((A(), B()) < (A(), B())) # revealed: bytearray | set | Literal[False]
202+
reveal_type((A(), B()) < (A(), B())) # revealed: LtReturnType | LtReturnTypeOnB | Literal[False]
194203
```
195204

196205
#### Special Handling of Eq and NotEq in Lexicographic Comparisons

0 commit comments

Comments
 (0)