Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Update test_pep646_syntax from v3.14.2-288-g06f9c8ca1c
  • Loading branch information
CPython Developers authored and fanninpm committed Feb 1, 2026
commit 553be2af334f317f4ac73c057d5e746ecfb47ec4
329 changes: 329 additions & 0 deletions Lib/test/test_pep646_syntax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
import doctest
import unittest

doctests = """

Setup

>>> class AClass:
... def __init__(self):
... self._setitem_name = None
... self._setitem_val = None
... self._delitem_name = None
... def __setitem__(self, name, val):
... self._delitem_name = None
... self._setitem_name = name
... self._setitem_val = val
... def __repr__(self):
... if self._setitem_name is not None:
... return f"A[{self._setitem_name}]={self._setitem_val}"
... elif self._delitem_name is not None:
... return f"delA[{self._delitem_name}]"
... def __getitem__(self, name):
... return ParameterisedA(name)
... def __delitem__(self, name):
... self._setitem_name = None
... self._delitem_name = name
...
>>> class ParameterisedA:
... def __init__(self, name):
... self._name = name
... def __repr__(self):
... return f"A[{self._name}]"
... def __iter__(self):
... for p in self._name:
... yield p
>>> class B:
... def __iter__(self):
... yield StarredB()
... def __repr__(self):
... return "B"
>>> class StarredB:
... def __repr__(self):
... return "StarredB"
>>> A = AClass()
>>> b = B()

Slices that are supposed to work, starring our custom B class

>>> A[*b]
A[(StarredB,)]
>>> A[*b] = 1; A
A[(StarredB,)]=1
>>> del A[*b]; A
delA[(StarredB,)]

>>> A[*b, *b]
A[(StarredB, StarredB)]
>>> A[*b, *b] = 1; A
A[(StarredB, StarredB)]=1
>>> del A[*b, *b]; A
delA[(StarredB, StarredB)]

>>> A[b, *b]
A[(B, StarredB)]
>>> A[b, *b] = 1; A
A[(B, StarredB)]=1
>>> del A[b, *b]; A
delA[(B, StarredB)]

>>> A[*b, b]
A[(StarredB, B)]
>>> A[*b, b] = 1; A
A[(StarredB, B)]=1
>>> del A[*b, b]; A
delA[(StarredB, B)]

>>> A[b, b, *b]
A[(B, B, StarredB)]
>>> A[b, b, *b] = 1; A
A[(B, B, StarredB)]=1
>>> del A[b, b, *b]; A
delA[(B, B, StarredB)]

>>> A[*b, b, b]
A[(StarredB, B, B)]
>>> A[*b, b, b] = 1; A
A[(StarredB, B, B)]=1
>>> del A[*b, b, b]; A
delA[(StarredB, B, B)]

>>> A[b, *b, b]
A[(B, StarredB, B)]
>>> A[b, *b, b] = 1; A
A[(B, StarredB, B)]=1
>>> del A[b, *b, b]; A
delA[(B, StarredB, B)]

>>> A[b, b, *b, b]
A[(B, B, StarredB, B)]
>>> A[b, b, *b, b] = 1; A
A[(B, B, StarredB, B)]=1
>>> del A[b, b, *b, b]; A
delA[(B, B, StarredB, B)]

>>> A[b, *b, b, b]
A[(B, StarredB, B, B)]
>>> A[b, *b, b, b] = 1; A
A[(B, StarredB, B, B)]=1
>>> del A[b, *b, b, b]; A
delA[(B, StarredB, B, B)]

>>> A[A[b, *b, b]]
A[A[(B, StarredB, B)]]
>>> A[A[b, *b, b]] = 1; A
A[A[(B, StarredB, B)]]=1
>>> del A[A[b, *b, b]]; A
delA[A[(B, StarredB, B)]]

>>> A[*A[b, *b, b]]
A[(B, StarredB, B)]
>>> A[*A[b, *b, b]] = 1; A
A[(B, StarredB, B)]=1
>>> del A[*A[b, *b, b]]; A
delA[(B, StarredB, B)]

>>> A[b, ...]
A[(B, Ellipsis)]
>>> A[b, ...] = 1; A
A[(B, Ellipsis)]=1
>>> del A[b, ...]; A
delA[(B, Ellipsis)]

>>> A[*A[b, ...]]
A[(B, Ellipsis)]
>>> A[*A[b, ...]] = 1; A
A[(B, Ellipsis)]=1
>>> del A[*A[b, ...]]; A
delA[(B, Ellipsis)]

Slices that are supposed to work, starring a list

>>> l = [1, 2, 3]

>>> A[*l]
A[(1, 2, 3)]
>>> A[*l] = 1; A
A[(1, 2, 3)]=1
>>> del A[*l]; A
delA[(1, 2, 3)]

>>> A[*l, 4]
A[(1, 2, 3, 4)]
>>> A[*l, 4] = 1; A
A[(1, 2, 3, 4)]=1
>>> del A[*l, 4]; A
delA[(1, 2, 3, 4)]

>>> A[0, *l]
A[(0, 1, 2, 3)]
>>> A[0, *l] = 1; A
A[(0, 1, 2, 3)]=1
>>> del A[0, *l]; A
delA[(0, 1, 2, 3)]

>>> A[1:2, *l]
A[(slice(1, 2, None), 1, 2, 3)]
>>> A[1:2, *l] = 1; A
A[(slice(1, 2, None), 1, 2, 3)]=1
>>> del A[1:2, *l]; A
delA[(slice(1, 2, None), 1, 2, 3)]

>>> repr(A[1:2, *l]) == repr(A[1:2, 1, 2, 3])
True

Slices that are supposed to work, starring a tuple

>>> t = (1, 2, 3)

>>> A[*t]
A[(1, 2, 3)]
>>> A[*t] = 1; A
A[(1, 2, 3)]=1
>>> del A[*t]; A
delA[(1, 2, 3)]

>>> A[*t, 4]
A[(1, 2, 3, 4)]
>>> A[*t, 4] = 1; A
A[(1, 2, 3, 4)]=1
>>> del A[*t, 4]; A
delA[(1, 2, 3, 4)]

>>> A[0, *t]
A[(0, 1, 2, 3)]
>>> A[0, *t] = 1; A
A[(0, 1, 2, 3)]=1
>>> del A[0, *t]; A
delA[(0, 1, 2, 3)]

>>> A[1:2, *t]
A[(slice(1, 2, None), 1, 2, 3)]
>>> A[1:2, *t] = 1; A
A[(slice(1, 2, None), 1, 2, 3)]=1
>>> del A[1:2, *t]; A
delA[(slice(1, 2, None), 1, 2, 3)]

>>> repr(A[1:2, *t]) == repr(A[1:2, 1, 2, 3])
True

Starring an expression (rather than a name) in a slice

>>> def returns_list():
... return [1, 2, 3]

>>> A[returns_list()]
A[[1, 2, 3]]
>>> A[returns_list()] = 1; A
A[[1, 2, 3]]=1
>>> del A[returns_list()]; A
delA[[1, 2, 3]]

>>> A[returns_list(), 4]
A[([1, 2, 3], 4)]
>>> A[returns_list(), 4] = 1; A
A[([1, 2, 3], 4)]=1
>>> del A[returns_list(), 4]; A
delA[([1, 2, 3], 4)]

>>> A[*returns_list()]
A[(1, 2, 3)]
>>> A[*returns_list()] = 1; A
A[(1, 2, 3)]=1
>>> del A[*returns_list()]; A
delA[(1, 2, 3)]

>>> A[*returns_list(), 4]
A[(1, 2, 3, 4)]
>>> A[*returns_list(), 4] = 1; A
A[(1, 2, 3, 4)]=1
>>> del A[*returns_list(), 4]; A
delA[(1, 2, 3, 4)]

>>> A[0, *returns_list()]
A[(0, 1, 2, 3)]
>>> A[0, *returns_list()] = 1; A
A[(0, 1, 2, 3)]=1
>>> del A[0, *returns_list()]; A
delA[(0, 1, 2, 3)]

>>> A[*returns_list(), *returns_list()]
A[(1, 2, 3, 1, 2, 3)]
>>> A[*returns_list(), *returns_list()] = 1; A
A[(1, 2, 3, 1, 2, 3)]=1
>>> del A[*returns_list(), *returns_list()]; A
delA[(1, 2, 3, 1, 2, 3)]

Using both a starred object and a start:stop in a slice
(See also tests in test_syntax confirming that starring *inside* a start:stop
is *not* valid syntax.)

>>> A[1:2, *b]
A[(slice(1, 2, None), StarredB)]
>>> A[*b, 1:2]
A[(StarredB, slice(1, 2, None))]
>>> A[1:2, *b, 1:2]
A[(slice(1, 2, None), StarredB, slice(1, 2, None))]
>>> A[*b, 1:2, *b]
A[(StarredB, slice(1, 2, None), StarredB)]

>>> A[1:, *b]
A[(slice(1, None, None), StarredB)]
>>> A[*b, 1:]
A[(StarredB, slice(1, None, None))]
>>> A[1:, *b, 1:]
A[(slice(1, None, None), StarredB, slice(1, None, None))]
>>> A[*b, 1:, *b]
A[(StarredB, slice(1, None, None), StarredB)]

>>> A[:1, *b]
A[(slice(None, 1, None), StarredB)]
>>> A[*b, :1]
A[(StarredB, slice(None, 1, None))]
>>> A[:1, *b, :1]
A[(slice(None, 1, None), StarredB, slice(None, 1, None))]
>>> A[*b, :1, *b]
A[(StarredB, slice(None, 1, None), StarredB)]

>>> A[:, *b]
A[(slice(None, None, None), StarredB)]
>>> A[*b, :]
A[(StarredB, slice(None, None, None))]
>>> A[:, *b, :]
A[(slice(None, None, None), StarredB, slice(None, None, None))]
>>> A[*b, :, *b]
A[(StarredB, slice(None, None, None), StarredB)]

*args annotated as starred expression

>>> def f1(*args: *b): pass
>>> f1.__annotations__
{'args': StarredB}

>>> def f2(*args: *b, arg1): pass
>>> f2.__annotations__
{'args': StarredB}

>>> def f3(*args: *b, arg1: int): pass
>>> f3.__annotations__
{'args': StarredB, 'arg1': <class 'int'>}

>>> def f4(*args: *b, arg1: int = 2): pass
>>> f4.__annotations__
{'args': StarredB, 'arg1': <class 'int'>}

>>> def f5(*args: *b = (1,)): pass
Traceback (most recent call last):
...
SyntaxError: invalid syntax
"""

__test__ = {'doctests' : doctests}

def load_tests(loader, tests, pattern):
tests.addTest(doctest.DocTestSuite())
return tests


if __name__ == "__main__":
unittest.main()