Implement support for PEP 646 (#3071)
This commit is contained in:
parent
9fe788d870
commit
1e557184b0
@ -56,6 +56,8 @@
|
|||||||
|
|
||||||
- [PEP 654](https://peps.python.org/pep-0654/#except) syntax (for example,
|
- [PEP 654](https://peps.python.org/pep-0654/#except) syntax (for example,
|
||||||
`except *ExceptionGroup:`) is now supported (#3016)
|
`except *ExceptionGroup:`) is now supported (#3016)
|
||||||
|
- [PEP 646](https://peps.python.org/pep-0646) syntax (for example,
|
||||||
|
`Array[Batch, *Shape]` or `def fn(*args: *T) -> None`) is now supported (#3071)
|
||||||
|
|
||||||
<!-- Changes to the parser or to version autodetection -->
|
<!-- Changes to the parser or to version autodetection -->
|
||||||
|
|
||||||
|
@ -1308,6 +1308,18 @@ def get_features_used( # noqa: C901
|
|||||||
):
|
):
|
||||||
features.add(Feature.EXCEPT_STAR)
|
features.add(Feature.EXCEPT_STAR)
|
||||||
|
|
||||||
|
elif n.type in {syms.subscriptlist, syms.trailer} and any(
|
||||||
|
child.type == syms.star_expr for child in n.children
|
||||||
|
):
|
||||||
|
features.add(Feature.VARIADIC_GENERICS)
|
||||||
|
|
||||||
|
elif (
|
||||||
|
n.type == syms.tname_star
|
||||||
|
and len(n.children) == 3
|
||||||
|
and n.children[2].type == syms.star_expr
|
||||||
|
):
|
||||||
|
features.add(Feature.VARIADIC_GENERICS)
|
||||||
|
|
||||||
return features
|
return features
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ class Feature(Enum):
|
|||||||
UNPACKING_ON_FLOW = 12
|
UNPACKING_ON_FLOW = 12
|
||||||
ANN_ASSIGN_EXTENDED_RHS = 13
|
ANN_ASSIGN_EXTENDED_RHS = 13
|
||||||
EXCEPT_STAR = 14
|
EXCEPT_STAR = 14
|
||||||
|
VARIADIC_GENERICS = 15
|
||||||
FORCE_OPTIONAL_PARENTHESES = 50
|
FORCE_OPTIONAL_PARENTHESES = 50
|
||||||
|
|
||||||
# __future__ flags
|
# __future__ flags
|
||||||
@ -132,6 +133,7 @@ class Feature(Enum):
|
|||||||
Feature.ANN_ASSIGN_EXTENDED_RHS,
|
Feature.ANN_ASSIGN_EXTENDED_RHS,
|
||||||
Feature.PATTERN_MATCHING,
|
Feature.PATTERN_MATCHING,
|
||||||
Feature.EXCEPT_STAR,
|
Feature.EXCEPT_STAR,
|
||||||
|
Feature.VARIADIC_GENERICS,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +120,7 @@
|
|||||||
syms.term,
|
syms.term,
|
||||||
syms.power,
|
syms.power,
|
||||||
}
|
}
|
||||||
|
TYPED_NAMES: Final = {syms.tname, syms.tname_star}
|
||||||
ASSIGNMENTS: Final = {
|
ASSIGNMENTS: Final = {
|
||||||
"=",
|
"=",
|
||||||
"+=",
|
"+=",
|
||||||
@ -243,6 +244,14 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa: C901
|
|||||||
# that, too.
|
# that, too.
|
||||||
return prevp.prefix
|
return prevp.prefix
|
||||||
|
|
||||||
|
elif (
|
||||||
|
prevp.type == token.STAR
|
||||||
|
and parent_type(prevp) == syms.star_expr
|
||||||
|
and parent_type(prevp.parent) == syms.subscriptlist
|
||||||
|
):
|
||||||
|
# No space between typevar tuples.
|
||||||
|
return NO
|
||||||
|
|
||||||
elif prevp.type in VARARGS_SPECIALS:
|
elif prevp.type in VARARGS_SPECIALS:
|
||||||
if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS):
|
if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS):
|
||||||
return NO
|
return NO
|
||||||
@ -281,7 +290,7 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa: C901
|
|||||||
return NO
|
return NO
|
||||||
|
|
||||||
if t == token.EQUAL:
|
if t == token.EQUAL:
|
||||||
if prev.type != syms.tname:
|
if prev.type not in TYPED_NAMES:
|
||||||
return NO
|
return NO
|
||||||
|
|
||||||
elif prev.type == token.EQUAL:
|
elif prev.type == token.EQUAL:
|
||||||
@ -292,7 +301,7 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa: C901
|
|||||||
elif prev.type != token.COMMA:
|
elif prev.type != token.COMMA:
|
||||||
return NO
|
return NO
|
||||||
|
|
||||||
elif p.type == syms.tname:
|
elif p.type in TYPED_NAMES:
|
||||||
# type names
|
# type names
|
||||||
if not prev:
|
if not prev:
|
||||||
prevp = preceding_leaf(p)
|
prevp = preceding_leaf(p)
|
||||||
|
@ -24,7 +24,7 @@ parameters: '(' [typedargslist] ')'
|
|||||||
# arguments = argument (',' argument)*
|
# arguments = argument (',' argument)*
|
||||||
# argument = tfpdef ['=' test]
|
# argument = tfpdef ['=' test]
|
||||||
# kwargs = '**' tname [',']
|
# kwargs = '**' tname [',']
|
||||||
# args = '*' [tname]
|
# args = '*' [tname_star]
|
||||||
# kwonly_kwargs = (',' argument)* [',' [kwargs]]
|
# kwonly_kwargs = (',' argument)* [',' [kwargs]]
|
||||||
# args_kwonly_kwargs = args kwonly_kwargs | kwargs
|
# args_kwonly_kwargs = args kwonly_kwargs | kwargs
|
||||||
# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
|
# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
|
||||||
@ -34,14 +34,15 @@ parameters: '(' [typedargslist] ')'
|
|||||||
# It needs to be fully expanded to allow our LL(1) parser to work on it.
|
# It needs to be fully expanded to allow our LL(1) parser to work on it.
|
||||||
|
|
||||||
typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [
|
typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [
|
||||||
',' [((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])*
|
',' [((tfpdef ['=' test] ',')* ('*' [tname_star] (',' tname ['=' test])*
|
||||||
[',' ['**' tname [',']]] | '**' tname [','])
|
[',' ['**' tname [',']]] | '**' tname [','])
|
||||||
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])]
|
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])]
|
||||||
] | ((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])*
|
] | ((tfpdef ['=' test] ',')* ('*' [tname_star] (',' tname ['=' test])*
|
||||||
[',' ['**' tname [',']]] | '**' tname [','])
|
[',' ['**' tname [',']]] | '**' tname [','])
|
||||||
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
|
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
|
||||||
|
|
||||||
tname: NAME [':' test]
|
tname: NAME [':' test]
|
||||||
|
tname_star: NAME [':' (test|star_expr)]
|
||||||
tfpdef: tname | '(' tfplist ')'
|
tfpdef: tname | '(' tfplist ')'
|
||||||
tfplist: tfpdef (',' tfpdef)* [',']
|
tfplist: tfpdef (',' tfpdef)* [',']
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ listmaker: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star
|
|||||||
testlist_gexp: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star_expr))* [','] )
|
testlist_gexp: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star_expr))* [','] )
|
||||||
lambdef: 'lambda' [varargslist] ':' test
|
lambdef: 'lambda' [varargslist] ':' test
|
||||||
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
|
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
|
||||||
subscriptlist: subscript (',' subscript)* [',']
|
subscriptlist: (subscript|star_expr) (',' (subscript|star_expr))* [',']
|
||||||
subscript: test [':=' test] | [test] ':' [test] [sliceop]
|
subscript: test [':=' test] | [test] ':' [test] [sliceop]
|
||||||
sliceop: ':' [test]
|
sliceop: ':' [test]
|
||||||
exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']
|
exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']
|
||||||
|
@ -123,6 +123,7 @@ class _python_symbols(Symbols):
|
|||||||
tfpdef: int
|
tfpdef: int
|
||||||
tfplist: int
|
tfplist: int
|
||||||
tname: int
|
tname: int
|
||||||
|
tname_star: int
|
||||||
trailer: int
|
trailer: int
|
||||||
try_stmt: int
|
try_stmt: int
|
||||||
typedargslist: int
|
typedargslist: int
|
||||||
|
194
tests/data/py_311/pep_646.py
Normal file
194
tests/data/py_311/pep_646.py
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
A[*b]
|
||||||
|
A[*b] = 1
|
||||||
|
A
|
||||||
|
del A[*b]
|
||||||
|
A
|
||||||
|
A[*b, *b]
|
||||||
|
A[*b, *b] = 1
|
||||||
|
A
|
||||||
|
del A[*b, *b]
|
||||||
|
A
|
||||||
|
A[b, *b]
|
||||||
|
A[b, *b] = 1
|
||||||
|
A
|
||||||
|
del A[b, *b]
|
||||||
|
A
|
||||||
|
A[*b, b]
|
||||||
|
A[*b, b] = 1
|
||||||
|
A
|
||||||
|
del A[*b, b]
|
||||||
|
A
|
||||||
|
A[b, b, *b]
|
||||||
|
A[b, b, *b] = 1
|
||||||
|
A
|
||||||
|
del A[b, b, *b]
|
||||||
|
A
|
||||||
|
A[*b, b, b]
|
||||||
|
A[*b, b, b] = 1
|
||||||
|
A
|
||||||
|
del A[*b, b, b]
|
||||||
|
A
|
||||||
|
A[b, *b, b]
|
||||||
|
A[b, *b, b] = 1
|
||||||
|
A
|
||||||
|
del A[b, *b, b]
|
||||||
|
A
|
||||||
|
A[b, b, *b, b]
|
||||||
|
A[b, b, *b, b] = 1
|
||||||
|
A
|
||||||
|
del A[b, b, *b, b]
|
||||||
|
A
|
||||||
|
A[b, *b, b, b]
|
||||||
|
A[b, *b, b, b] = 1
|
||||||
|
A
|
||||||
|
del A[b, *b, b, b]
|
||||||
|
A
|
||||||
|
A[A[b, *b, b]]
|
||||||
|
A[A[b, *b, b]] = 1
|
||||||
|
A
|
||||||
|
del A[A[b, *b, b]]
|
||||||
|
A
|
||||||
|
A[*A[b, *b, b]]
|
||||||
|
A[*A[b, *b, b]] = 1
|
||||||
|
A
|
||||||
|
del A[*A[b, *b, b]]
|
||||||
|
A
|
||||||
|
A[b, ...]
|
||||||
|
A[b, ...] = 1
|
||||||
|
A
|
||||||
|
del A[b, ...]
|
||||||
|
A
|
||||||
|
A[*A[b, ...]]
|
||||||
|
A[*A[b, ...]] = 1
|
||||||
|
A
|
||||||
|
del A[*A[b, ...]]
|
||||||
|
A
|
||||||
|
l = [1, 2, 3]
|
||||||
|
A[*l]
|
||||||
|
A[*l] = 1
|
||||||
|
A
|
||||||
|
del A[*l]
|
||||||
|
A
|
||||||
|
A[*l, 4]
|
||||||
|
A[*l, 4] = 1
|
||||||
|
A
|
||||||
|
del A[*l, 4]
|
||||||
|
A
|
||||||
|
A[0, *l]
|
||||||
|
A[0, *l] = 1
|
||||||
|
A
|
||||||
|
del A[0, *l]
|
||||||
|
A
|
||||||
|
A[1:2, *l]
|
||||||
|
A[1:2, *l] = 1
|
||||||
|
A
|
||||||
|
del A[1:2, *l]
|
||||||
|
A
|
||||||
|
repr(A[1:2, *l]) == repr(A[1:2, 1, 2, 3])
|
||||||
|
t = (1, 2, 3)
|
||||||
|
A[*t]
|
||||||
|
A[*t] = 1
|
||||||
|
A
|
||||||
|
del A[*t]
|
||||||
|
A
|
||||||
|
A[*t, 4]
|
||||||
|
A[*t, 4] = 1
|
||||||
|
A
|
||||||
|
del A[*t, 4]
|
||||||
|
A
|
||||||
|
A[0, *t]
|
||||||
|
A[0, *t] = 1
|
||||||
|
A
|
||||||
|
del A[0, *t]
|
||||||
|
A
|
||||||
|
A[1:2, *t]
|
||||||
|
A[1:2, *t] = 1
|
||||||
|
A
|
||||||
|
del A[1:2, *t]
|
||||||
|
A
|
||||||
|
repr(A[1:2, *t]) == repr(A[1:2, 1, 2, 3])
|
||||||
|
|
||||||
|
|
||||||
|
def returns_list():
|
||||||
|
return [1, 2, 3]
|
||||||
|
|
||||||
|
|
||||||
|
A[returns_list()]
|
||||||
|
A[returns_list()] = 1
|
||||||
|
A
|
||||||
|
del A[returns_list()]
|
||||||
|
A
|
||||||
|
A[returns_list(), 4]
|
||||||
|
A[returns_list(), 4] = 1
|
||||||
|
A
|
||||||
|
del A[returns_list(), 4]
|
||||||
|
A
|
||||||
|
A[*returns_list()]
|
||||||
|
A[*returns_list()] = 1
|
||||||
|
A
|
||||||
|
del A[*returns_list()]
|
||||||
|
A
|
||||||
|
A[*returns_list(), 4]
|
||||||
|
A[*returns_list(), 4] = 1
|
||||||
|
A
|
||||||
|
del A[*returns_list(), 4]
|
||||||
|
A
|
||||||
|
A[0, *returns_list()]
|
||||||
|
A[0, *returns_list()] = 1
|
||||||
|
A
|
||||||
|
del A[0, *returns_list()]
|
||||||
|
A
|
||||||
|
A[*returns_list(), *returns_list()]
|
||||||
|
A[*returns_list(), *returns_list()] = 1
|
||||||
|
A
|
||||||
|
del A[*returns_list(), *returns_list()]
|
||||||
|
A
|
||||||
|
A[1:2, *b]
|
||||||
|
A[*b, 1:2]
|
||||||
|
A[1:2, *b, 1:2]
|
||||||
|
A[*b, 1:2, *b]
|
||||||
|
A[1:, *b]
|
||||||
|
A[*b, 1:]
|
||||||
|
A[1:, *b, 1:]
|
||||||
|
A[*b, 1:, *b]
|
||||||
|
A[:1, *b]
|
||||||
|
A[*b, :1]
|
||||||
|
A[:1, *b, :1]
|
||||||
|
A[*b, :1, *b]
|
||||||
|
A[:, *b]
|
||||||
|
A[*b, :]
|
||||||
|
A[:, *b, :]
|
||||||
|
A[*b, :, *b]
|
||||||
|
A[a * b()]
|
||||||
|
A[a * b(), *c, *d(), e * f(g * h)]
|
||||||
|
A[a * b(), :]
|
||||||
|
A[a * b(), *c, *d(), e * f(g * h) :]
|
||||||
|
A[[b] * len(c), :]
|
||||||
|
|
||||||
|
|
||||||
|
def f1(*args: *b):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
f1.__annotations__
|
||||||
|
|
||||||
|
|
||||||
|
def f2(*args: *b, arg1):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
f2.__annotations__
|
||||||
|
|
||||||
|
|
||||||
|
def f3(*args: *b, arg1: int):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
f3.__annotations__
|
||||||
|
|
||||||
|
|
||||||
|
def f4(*args: *b, arg1: int = 2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
f4.__annotations__
|
@ -804,6 +804,12 @@ def test_get_features_used(self) -> None:
|
|||||||
self.assertEqual(black.get_features_used(node), set())
|
self.assertEqual(black.get_features_used(node), set())
|
||||||
node = black.lib2to3_parse("try: pass\nexcept *Group: pass")
|
node = black.lib2to3_parse("try: pass\nexcept *Group: pass")
|
||||||
self.assertEqual(black.get_features_used(node), {Feature.EXCEPT_STAR})
|
self.assertEqual(black.get_features_used(node), {Feature.EXCEPT_STAR})
|
||||||
|
node = black.lib2to3_parse("a[*b]")
|
||||||
|
self.assertEqual(black.get_features_used(node), {Feature.VARIADIC_GENERICS})
|
||||||
|
node = black.lib2to3_parse("a[x, *y(), z] = t")
|
||||||
|
self.assertEqual(black.get_features_used(node), {Feature.VARIADIC_GENERICS})
|
||||||
|
node = black.lib2to3_parse("def fn(*args: *T): pass")
|
||||||
|
self.assertEqual(black.get_features_used(node), {Feature.VARIADIC_GENERICS})
|
||||||
|
|
||||||
def test_get_features_used_for_future_flags(self) -> None:
|
def test_get_features_used_for_future_flags(self) -> None:
|
||||||
for src, features in [
|
for src, features in [
|
||||||
|
Loading…
Reference in New Issue
Block a user