Skip to content

Commit 3f0f8f1

Browse files
Support PEP 696 (#4327)
1 parent 2f88085 commit 3f0f8f1

File tree

7 files changed

+137
-7
lines changed

7 files changed

+137
-7
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030

3131
<!-- Changes to the parser or to version autodetection -->
3232

33+
- Add support for type parameter defaults, a new syntactic feature added to Python 3.13
34+
by PEP 696 (#4327)
35+
3336
### Performance
3437

3538
<!-- Changes that improve Black's performance. -->

src/black/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,12 @@ def get_features_used( # noqa: C901
14361436
elif n.type in (syms.type_stmt, syms.typeparams):
14371437
features.add(Feature.TYPE_PARAMS)
14381438

1439+
elif (
1440+
n.type in (syms.typevartuple, syms.paramspec, syms.typevar)
1441+
and n.children[-2].type == token.EQUAL
1442+
):
1443+
features.add(Feature.TYPE_PARAM_DEFAULTS)
1444+
14391445
return features
14401446

14411447

src/black/mode.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class TargetVersion(Enum):
2424
PY310 = 10
2525
PY311 = 11
2626
PY312 = 12
27+
PY313 = 13
2728

2829

2930
class Feature(Enum):
@@ -47,6 +48,7 @@ class Feature(Enum):
4748
PARENTHESIZED_CONTEXT_MANAGERS = 17
4849
TYPE_PARAMS = 18
4950
FSTRING_PARSING = 19
51+
TYPE_PARAM_DEFAULTS = 20
5052
FORCE_OPTIONAL_PARENTHESES = 50
5153

5254
# __future__ flags
@@ -159,6 +161,27 @@ class Feature(Enum):
159161
Feature.TYPE_PARAMS,
160162
Feature.FSTRING_PARSING,
161163
},
164+
TargetVersion.PY313: {
165+
Feature.F_STRINGS,
166+
Feature.DEBUG_F_STRINGS,
167+
Feature.NUMERIC_UNDERSCORES,
168+
Feature.TRAILING_COMMA_IN_CALL,
169+
Feature.TRAILING_COMMA_IN_DEF,
170+
Feature.ASYNC_KEYWORDS,
171+
Feature.FUTURE_ANNOTATIONS,
172+
Feature.ASSIGNMENT_EXPRESSIONS,
173+
Feature.RELAXED_DECORATORS,
174+
Feature.POS_ONLY_ARGUMENTS,
175+
Feature.UNPACKING_ON_FLOW,
176+
Feature.ANN_ASSIGN_EXTENDED_RHS,
177+
Feature.PARENTHESIZED_CONTEXT_MANAGERS,
178+
Feature.PATTERN_MATCHING,
179+
Feature.EXCEPT_STAR,
180+
Feature.VARIADIC_GENERICS,
181+
Feature.TYPE_PARAMS,
182+
Feature.FSTRING_PARSING,
183+
Feature.TYPE_PARAM_DEFAULTS,
184+
},
162185
}
163186

164187

src/black/resources/black.schema.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"py39",
2828
"py310",
2929
"py311",
30-
"py312"
30+
"py312",
31+
"py313"
3132
]
3233
},
3334
"description": "Python versions that should be supported by Black's output. You should include all versions that your code supports. By default, Black will infer target versions from the project metadata in pyproject.toml. If this does not yield conclusive results, Black will use per-file auto-detection."

src/blib2to3/Grammar.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ file_input: (NEWLINE | stmt)* ENDMARKER
1212
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
1313
eval_input: testlist NEWLINE* ENDMARKER
1414

15-
typevar: NAME [':' expr]
16-
paramspec: '**' NAME
17-
typevartuple: '*' NAME
15+
typevar: NAME [':' expr] ['=' expr]
16+
paramspec: '**' NAME ['=' expr]
17+
typevartuple: '*' NAME ['=' (expr|star_expr)]
1818
typeparam: typevar | paramspec | typevartuple
1919
typeparams: '[' typeparam (',' typeparam)* [','] ']'
2020

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# flags: --minimum-version=3.13
2+
3+
type A[T=int] = float
4+
type B[*P=int] = float
5+
type C[*Ts=int] = float
6+
type D[*Ts=*int] = float
7+
type D[something_that_is_very_very_very_long=something_that_is_very_very_very_long] = float
8+
type D[*something_that_is_very_very_very_long=*something_that_is_very_very_very_long] = float
9+
type something_that_is_long[something_that_is_long=something_that_is_long] = something_that_is_long
10+
11+
def simple[T=something_that_is_long](short1: int, short2: str, short3: bytes) -> float:
12+
pass
13+
14+
def longer[something_that_is_long=something_that_is_long](something_that_is_long: something_that_is_long) -> something_that_is_long:
15+
pass
16+
17+
def trailing_comma1[T=int,](a: str):
18+
pass
19+
20+
def trailing_comma2[T=int](a: str,):
21+
pass
22+
23+
# output
24+
25+
type A[T = int] = float
26+
type B[*P = int] = float
27+
type C[*Ts = int] = float
28+
type D[*Ts = *int] = float
29+
type D[
30+
something_that_is_very_very_very_long = something_that_is_very_very_very_long
31+
] = float
32+
type D[
33+
*something_that_is_very_very_very_long = *something_that_is_very_very_very_long
34+
] = float
35+
type something_that_is_long[
36+
something_that_is_long = something_that_is_long
37+
] = something_that_is_long
38+
39+
40+
def simple[
41+
T = something_that_is_long
42+
](short1: int, short2: str, short3: bytes) -> float:
43+
pass
44+
45+
46+
def longer[
47+
something_that_is_long = something_that_is_long
48+
](something_that_is_long: something_that_is_long) -> something_that_is_long:
49+
pass
50+
51+
52+
def trailing_comma1[
53+
T = int,
54+
](a: str):
55+
pass
56+
57+
58+
def trailing_comma2[
59+
T = int
60+
](a: str,):
61+
pass

tests/test_black.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,21 @@ def test_pep_695_version_detection(self) -> None:
263263
versions = black.detect_target_versions(root)
264264
self.assertIn(black.TargetVersion.PY312, versions)
265265

266+
def test_pep_696_version_detection(self) -> None:
267+
source, _ = read_data("cases", "type_param_defaults")
268+
samples = [
269+
source,
270+
"type X[T=int] = float",
271+
"type X[T:int=int]=int",
272+
"type X[*Ts=int]=int",
273+
"type X[*Ts=*int]=int",
274+
"type X[**P=int]=int",
275+
]
276+
for sample in samples:
277+
root = black.lib2to3_parse(sample)
278+
features = black.get_features_used(root)
279+
self.assertIn(black.Feature.TYPE_PARAM_DEFAULTS, features)
280+
266281
def test_expression_ff(self) -> None:
267282
source, expected = read_data("cases", "expression.py")
268283
tmp_file = Path(black.dump_to_file(source))
@@ -1531,16 +1546,34 @@ def test_infer_target_version(self) -> None:
15311546
for version, expected in [
15321547
("3.6", [TargetVersion.PY36]),
15331548
("3.11.0rc1", [TargetVersion.PY311]),
1534-
(">=3.10", [TargetVersion.PY310, TargetVersion.PY311, TargetVersion.PY312]),
1549+
(
1550+
">=3.10",
1551+
[
1552+
TargetVersion.PY310,
1553+
TargetVersion.PY311,
1554+
TargetVersion.PY312,
1555+
TargetVersion.PY313,
1556+
],
1557+
),
15351558
(
15361559
">=3.10.6",
1537-
[TargetVersion.PY310, TargetVersion.PY311, TargetVersion.PY312],
1560+
[
1561+
TargetVersion.PY310,
1562+
TargetVersion.PY311,
1563+
TargetVersion.PY312,
1564+
TargetVersion.PY313,
1565+
],
15381566
),
15391567
("<3.6", [TargetVersion.PY33, TargetVersion.PY34, TargetVersion.PY35]),
15401568
(">3.7,<3.10", [TargetVersion.PY38, TargetVersion.PY39]),
15411569
(
15421570
">3.7,!=3.8,!=3.9",
1543-
[TargetVersion.PY310, TargetVersion.PY311, TargetVersion.PY312],
1571+
[
1572+
TargetVersion.PY310,
1573+
TargetVersion.PY311,
1574+
TargetVersion.PY312,
1575+
TargetVersion.PY313,
1576+
],
15441577
),
15451578
(
15461579
"> 3.9.4, != 3.10.3",
@@ -1549,6 +1582,7 @@ def test_infer_target_version(self) -> None:
15491582
TargetVersion.PY310,
15501583
TargetVersion.PY311,
15511584
TargetVersion.PY312,
1585+
TargetVersion.PY313,
15521586
],
15531587
),
15541588
(
@@ -1562,6 +1596,7 @@ def test_infer_target_version(self) -> None:
15621596
TargetVersion.PY310,
15631597
TargetVersion.PY311,
15641598
TargetVersion.PY312,
1599+
TargetVersion.PY313,
15651600
],
15661601
),
15671602
(
@@ -1577,6 +1612,7 @@ def test_infer_target_version(self) -> None:
15771612
TargetVersion.PY310,
15781613
TargetVersion.PY311,
15791614
TargetVersion.PY312,
1615+
TargetVersion.PY313,
15801616
],
15811617
),
15821618
("==3.8.*", [TargetVersion.PY38]),

0 commit comments

Comments
 (0)