Skip to content

Commit fdf93c5

Browse files
authored
Merge pull request #6928 from fanninpm/3.14-test-pep646-syntax
Update `test_pep646_syntax` from v3.14.2
2 parents 380500c + f6d1fe4 commit fdf93c5

File tree

2 files changed

+339
-0
lines changed

2 files changed

+339
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ env:
8686
test_math
8787
test_operator
8888
test_ordered_dict
89+
test_pep646_syntax
8990
test_pow
9091
test_raise
9192
test_richcmp

Lib/test/test_pep646_syntax.py

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
import doctest
2+
import unittest
3+
4+
doctests = """
5+
6+
Setup
7+
8+
>>> class AClass:
9+
... def __init__(self):
10+
... self._setitem_name = None
11+
... self._setitem_val = None
12+
... self._delitem_name = None
13+
... def __setitem__(self, name, val):
14+
... self._delitem_name = None
15+
... self._setitem_name = name
16+
... self._setitem_val = val
17+
... def __repr__(self):
18+
... if self._setitem_name is not None:
19+
... return f"A[{self._setitem_name}]={self._setitem_val}"
20+
... elif self._delitem_name is not None:
21+
... return f"delA[{self._delitem_name}]"
22+
... def __getitem__(self, name):
23+
... return ParameterisedA(name)
24+
... def __delitem__(self, name):
25+
... self._setitem_name = None
26+
... self._delitem_name = name
27+
...
28+
>>> class ParameterisedA:
29+
... def __init__(self, name):
30+
... self._name = name
31+
... def __repr__(self):
32+
... return f"A[{self._name}]"
33+
... def __iter__(self):
34+
... for p in self._name:
35+
... yield p
36+
>>> class B:
37+
... def __iter__(self):
38+
... yield StarredB()
39+
... def __repr__(self):
40+
... return "B"
41+
>>> class StarredB:
42+
... def __repr__(self):
43+
... return "StarredB"
44+
>>> A = AClass()
45+
>>> b = B()
46+
47+
Slices that are supposed to work, starring our custom B class
48+
49+
>>> A[*b]
50+
A[(StarredB,)]
51+
>>> A[*b] = 1; A
52+
A[(StarredB,)]=1
53+
>>> del A[*b]; A
54+
delA[(StarredB,)]
55+
56+
>>> A[*b, *b]
57+
A[(StarredB, StarredB)]
58+
>>> A[*b, *b] = 1; A
59+
A[(StarredB, StarredB)]=1
60+
>>> del A[*b, *b]; A
61+
delA[(StarredB, StarredB)]
62+
63+
>>> A[b, *b]
64+
A[(B, StarredB)]
65+
>>> A[b, *b] = 1; A
66+
A[(B, StarredB)]=1
67+
>>> del A[b, *b]; A
68+
delA[(B, StarredB)]
69+
70+
>>> A[*b, b]
71+
A[(StarredB, B)]
72+
>>> A[*b, b] = 1; A
73+
A[(StarredB, B)]=1
74+
>>> del A[*b, b]; A
75+
delA[(StarredB, B)]
76+
77+
>>> A[b, b, *b]
78+
A[(B, B, StarredB)]
79+
>>> A[b, b, *b] = 1; A
80+
A[(B, B, StarredB)]=1
81+
>>> del A[b, b, *b]; A
82+
delA[(B, B, StarredB)]
83+
84+
>>> A[*b, b, b]
85+
A[(StarredB, B, B)]
86+
>>> A[*b, b, b] = 1; A
87+
A[(StarredB, B, B)]=1
88+
>>> del A[*b, b, b]; A
89+
delA[(StarredB, B, B)]
90+
91+
>>> A[b, *b, b]
92+
A[(B, StarredB, B)]
93+
>>> A[b, *b, b] = 1; A
94+
A[(B, StarredB, B)]=1
95+
>>> del A[b, *b, b]; A
96+
delA[(B, StarredB, B)]
97+
98+
>>> A[b, b, *b, b]
99+
A[(B, B, StarredB, B)]
100+
>>> A[b, b, *b, b] = 1; A
101+
A[(B, B, StarredB, B)]=1
102+
>>> del A[b, b, *b, b]; A
103+
delA[(B, B, StarredB, B)]
104+
105+
>>> A[b, *b, b, b]
106+
A[(B, StarredB, B, B)]
107+
>>> A[b, *b, b, b] = 1; A
108+
A[(B, StarredB, B, B)]=1
109+
>>> del A[b, *b, b, b]; A
110+
delA[(B, StarredB, B, B)]
111+
112+
>>> A[A[b, *b, b]]
113+
A[A[(B, StarredB, B)]]
114+
>>> A[A[b, *b, b]] = 1; A
115+
A[A[(B, StarredB, B)]]=1
116+
>>> del A[A[b, *b, b]]; A
117+
delA[A[(B, StarredB, B)]]
118+
119+
>>> A[*A[b, *b, b]]
120+
A[(B, StarredB, B)]
121+
>>> A[*A[b, *b, b]] = 1; A
122+
A[(B, StarredB, B)]=1
123+
>>> del A[*A[b, *b, b]]; A
124+
delA[(B, StarredB, B)]
125+
126+
>>> A[b, ...]
127+
A[(B, Ellipsis)]
128+
>>> A[b, ...] = 1; A
129+
A[(B, Ellipsis)]=1
130+
>>> del A[b, ...]; A
131+
delA[(B, Ellipsis)]
132+
133+
>>> A[*A[b, ...]]
134+
A[(B, Ellipsis)]
135+
>>> A[*A[b, ...]] = 1; A
136+
A[(B, Ellipsis)]=1
137+
>>> del A[*A[b, ...]]; A
138+
delA[(B, Ellipsis)]
139+
140+
Slices that are supposed to work, starring a list
141+
142+
>>> l = [1, 2, 3]
143+
144+
>>> A[*l]
145+
A[(1, 2, 3)]
146+
>>> A[*l] = 1; A
147+
A[(1, 2, 3)]=1
148+
>>> del A[*l]; A
149+
delA[(1, 2, 3)]
150+
151+
>>> A[*l, 4]
152+
A[(1, 2, 3, 4)]
153+
>>> A[*l, 4] = 1; A
154+
A[(1, 2, 3, 4)]=1
155+
>>> del A[*l, 4]; A
156+
delA[(1, 2, 3, 4)]
157+
158+
>>> A[0, *l]
159+
A[(0, 1, 2, 3)]
160+
>>> A[0, *l] = 1; A
161+
A[(0, 1, 2, 3)]=1
162+
>>> del A[0, *l]; A
163+
delA[(0, 1, 2, 3)]
164+
165+
>>> A[1:2, *l]
166+
A[(slice(1, 2, None), 1, 2, 3)]
167+
>>> A[1:2, *l] = 1; A
168+
A[(slice(1, 2, None), 1, 2, 3)]=1
169+
>>> del A[1:2, *l]; A
170+
delA[(slice(1, 2, None), 1, 2, 3)]
171+
172+
>>> repr(A[1:2, *l]) == repr(A[1:2, 1, 2, 3])
173+
True
174+
175+
Slices that are supposed to work, starring a tuple
176+
177+
>>> t = (1, 2, 3)
178+
179+
>>> A[*t]
180+
A[(1, 2, 3)]
181+
>>> A[*t] = 1; A
182+
A[(1, 2, 3)]=1
183+
>>> del A[*t]; A
184+
delA[(1, 2, 3)]
185+
186+
>>> A[*t, 4]
187+
A[(1, 2, 3, 4)]
188+
>>> A[*t, 4] = 1; A
189+
A[(1, 2, 3, 4)]=1
190+
>>> del A[*t, 4]; A
191+
delA[(1, 2, 3, 4)]
192+
193+
>>> A[0, *t]
194+
A[(0, 1, 2, 3)]
195+
>>> A[0, *t] = 1; A
196+
A[(0, 1, 2, 3)]=1
197+
>>> del A[0, *t]; A
198+
delA[(0, 1, 2, 3)]
199+
200+
>>> A[1:2, *t]
201+
A[(slice(1, 2, None), 1, 2, 3)]
202+
>>> A[1:2, *t] = 1; A
203+
A[(slice(1, 2, None), 1, 2, 3)]=1
204+
>>> del A[1:2, *t]; A
205+
delA[(slice(1, 2, None), 1, 2, 3)]
206+
207+
>>> repr(A[1:2, *t]) == repr(A[1:2, 1, 2, 3])
208+
True
209+
210+
Starring an expression (rather than a name) in a slice
211+
212+
>>> def returns_list():
213+
... return [1, 2, 3]
214+
215+
>>> A[returns_list()]
216+
A[[1, 2, 3]]
217+
>>> A[returns_list()] = 1; A
218+
A[[1, 2, 3]]=1
219+
>>> del A[returns_list()]; A
220+
delA[[1, 2, 3]]
221+
222+
>>> A[returns_list(), 4]
223+
A[([1, 2, 3], 4)]
224+
>>> A[returns_list(), 4] = 1; A
225+
A[([1, 2, 3], 4)]=1
226+
>>> del A[returns_list(), 4]; A
227+
delA[([1, 2, 3], 4)]
228+
229+
>>> A[*returns_list()]
230+
A[(1, 2, 3)]
231+
>>> A[*returns_list()] = 1; A
232+
A[(1, 2, 3)]=1
233+
>>> del A[*returns_list()]; A
234+
delA[(1, 2, 3)]
235+
236+
>>> A[*returns_list(), 4]
237+
A[(1, 2, 3, 4)]
238+
>>> A[*returns_list(), 4] = 1; A
239+
A[(1, 2, 3, 4)]=1
240+
>>> del A[*returns_list(), 4]; A
241+
delA[(1, 2, 3, 4)]
242+
243+
>>> A[0, *returns_list()]
244+
A[(0, 1, 2, 3)]
245+
>>> A[0, *returns_list()] = 1; A
246+
A[(0, 1, 2, 3)]=1
247+
>>> del A[0, *returns_list()]; A
248+
delA[(0, 1, 2, 3)]
249+
250+
>>> A[*returns_list(), *returns_list()]
251+
A[(1, 2, 3, 1, 2, 3)]
252+
>>> A[*returns_list(), *returns_list()] = 1; A
253+
A[(1, 2, 3, 1, 2, 3)]=1
254+
>>> del A[*returns_list(), *returns_list()]; A
255+
delA[(1, 2, 3, 1, 2, 3)]
256+
257+
Using both a starred object and a start:stop in a slice
258+
(See also tests in test_syntax confirming that starring *inside* a start:stop
259+
is *not* valid syntax.)
260+
261+
>>> A[1:2, *b]
262+
A[(slice(1, 2, None), StarredB)]
263+
>>> A[*b, 1:2]
264+
A[(StarredB, slice(1, 2, None))]
265+
>>> A[1:2, *b, 1:2]
266+
A[(slice(1, 2, None), StarredB, slice(1, 2, None))]
267+
>>> A[*b, 1:2, *b]
268+
A[(StarredB, slice(1, 2, None), StarredB)]
269+
270+
>>> A[1:, *b]
271+
A[(slice(1, None, None), StarredB)]
272+
>>> A[*b, 1:]
273+
A[(StarredB, slice(1, None, None))]
274+
>>> A[1:, *b, 1:]
275+
A[(slice(1, None, None), StarredB, slice(1, None, None))]
276+
>>> A[*b, 1:, *b]
277+
A[(StarredB, slice(1, None, None), StarredB)]
278+
279+
>>> A[:1, *b]
280+
A[(slice(None, 1, None), StarredB)]
281+
>>> A[*b, :1]
282+
A[(StarredB, slice(None, 1, None))]
283+
>>> A[:1, *b, :1]
284+
A[(slice(None, 1, None), StarredB, slice(None, 1, None))]
285+
>>> A[*b, :1, *b]
286+
A[(StarredB, slice(None, 1, None), StarredB)]
287+
288+
>>> A[:, *b]
289+
A[(slice(None, None, None), StarredB)]
290+
>>> A[*b, :]
291+
A[(StarredB, slice(None, None, None))]
292+
>>> A[:, *b, :]
293+
A[(slice(None, None, None), StarredB, slice(None, None, None))]
294+
>>> A[*b, :, *b]
295+
A[(StarredB, slice(None, None, None), StarredB)]
296+
297+
*args annotated as starred expression
298+
299+
>>> def f1(*args: *b): pass
300+
>>> f1.__annotations__
301+
{'args': StarredB}
302+
303+
>>> def f2(*args: *b, arg1): pass
304+
>>> f2.__annotations__
305+
{'args': StarredB}
306+
307+
>>> def f3(*args: *b, arg1: int): pass
308+
>>> f3.__annotations__ # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE
309+
{'args': StarredB, 'arg1': <class 'int'>}
310+
311+
>>> def f4(*args: *b, arg1: int = 2): pass
312+
>>> f4.__annotations__ # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE
313+
{'args': StarredB, 'arg1': <class 'int'>}
314+
315+
>>> def f5(*args: *b = (1,)): pass # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE
316+
Traceback (most recent call last):
317+
...
318+
SyntaxError: invalid syntax
319+
"""
320+
321+
__test__ = {'doctests' : doctests}
322+
323+
EXPECTED_FAILURE = doctest.register_optionflag('EXPECTED_FAILURE') # TODO: RUSTPYTHON
324+
class CustomOutputChecker(doctest.OutputChecker): # TODO: RUSTPYTHON
325+
def check_output(self, want, got, optionflags): # TODO: RUSTPYTHON
326+
if optionflags & EXPECTED_FAILURE: # TODO: RUSTPYTHON
327+
if want == got: # TODO: RUSTPYTHON
328+
return False # TODO: RUSTPYTHON
329+
return True # TODO: RUSTPYTHON
330+
return super().check_output(want, got, optionflags) # TODO: RUSTPYTHON
331+
332+
def load_tests(loader, tests, pattern):
333+
tests.addTest(doctest.DocTestSuite(checker=CustomOutputChecker())) # TODO: RUSTPYTHON
334+
return tests
335+
336+
337+
if __name__ == "__main__":
338+
unittest.main()

0 commit comments

Comments
 (0)