Support PEP 696 (#4327)
This commit is contained in:
parent
2f88085da5
commit
3f0f8f1956
@ -30,6 +30,9 @@
|
||||
|
||||
<!-- Changes to the parser or to version autodetection -->
|
||||
|
||||
- Add support for type parameter defaults, a new syntactic feature added to Python 3.13
|
||||
by PEP 696 (#4327)
|
||||
|
||||
### Performance
|
||||
|
||||
<!-- Changes that improve Black's performance. -->
|
||||
|
@ -1436,6 +1436,12 @@ def get_features_used( # noqa: C901
|
||||
elif n.type in (syms.type_stmt, syms.typeparams):
|
||||
features.add(Feature.TYPE_PARAMS)
|
||||
|
||||
elif (
|
||||
n.type in (syms.typevartuple, syms.paramspec, syms.typevar)
|
||||
and n.children[-2].type == token.EQUAL
|
||||
):
|
||||
features.add(Feature.TYPE_PARAM_DEFAULTS)
|
||||
|
||||
return features
|
||||
|
||||
|
||||
|
@ -24,6 +24,7 @@ class TargetVersion(Enum):
|
||||
PY310 = 10
|
||||
PY311 = 11
|
||||
PY312 = 12
|
||||
PY313 = 13
|
||||
|
||||
|
||||
class Feature(Enum):
|
||||
@ -47,6 +48,7 @@ class Feature(Enum):
|
||||
PARENTHESIZED_CONTEXT_MANAGERS = 17
|
||||
TYPE_PARAMS = 18
|
||||
FSTRING_PARSING = 19
|
||||
TYPE_PARAM_DEFAULTS = 20
|
||||
FORCE_OPTIONAL_PARENTHESES = 50
|
||||
|
||||
# __future__ flags
|
||||
@ -159,6 +161,27 @@ class Feature(Enum):
|
||||
Feature.TYPE_PARAMS,
|
||||
Feature.FSTRING_PARSING,
|
||||
},
|
||||
TargetVersion.PY313: {
|
||||
Feature.F_STRINGS,
|
||||
Feature.DEBUG_F_STRINGS,
|
||||
Feature.NUMERIC_UNDERSCORES,
|
||||
Feature.TRAILING_COMMA_IN_CALL,
|
||||
Feature.TRAILING_COMMA_IN_DEF,
|
||||
Feature.ASYNC_KEYWORDS,
|
||||
Feature.FUTURE_ANNOTATIONS,
|
||||
Feature.ASSIGNMENT_EXPRESSIONS,
|
||||
Feature.RELAXED_DECORATORS,
|
||||
Feature.POS_ONLY_ARGUMENTS,
|
||||
Feature.UNPACKING_ON_FLOW,
|
||||
Feature.ANN_ASSIGN_EXTENDED_RHS,
|
||||
Feature.PARENTHESIZED_CONTEXT_MANAGERS,
|
||||
Feature.PATTERN_MATCHING,
|
||||
Feature.EXCEPT_STAR,
|
||||
Feature.VARIADIC_GENERICS,
|
||||
Feature.TYPE_PARAMS,
|
||||
Feature.FSTRING_PARSING,
|
||||
Feature.TYPE_PARAM_DEFAULTS,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,7 +27,8 @@
|
||||
"py39",
|
||||
"py310",
|
||||
"py311",
|
||||
"py312"
|
||||
"py312",
|
||||
"py313"
|
||||
]
|
||||
},
|
||||
"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."
|
||||
|
@ -12,9 +12,9 @@ file_input: (NEWLINE | stmt)* ENDMARKER
|
||||
single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
|
||||
eval_input: testlist NEWLINE* ENDMARKER
|
||||
|
||||
typevar: NAME [':' expr]
|
||||
paramspec: '**' NAME
|
||||
typevartuple: '*' NAME
|
||||
typevar: NAME [':' expr] ['=' expr]
|
||||
paramspec: '**' NAME ['=' expr]
|
||||
typevartuple: '*' NAME ['=' (expr|star_expr)]
|
||||
typeparam: typevar | paramspec | typevartuple
|
||||
typeparams: '[' typeparam (',' typeparam)* [','] ']'
|
||||
|
||||
|
61
tests/data/cases/type_param_defaults.py
Normal file
61
tests/data/cases/type_param_defaults.py
Normal file
@ -0,0 +1,61 @@
|
||||
# flags: --minimum-version=3.13
|
||||
|
||||
type A[T=int] = float
|
||||
type B[*P=int] = float
|
||||
type C[*Ts=int] = float
|
||||
type D[*Ts=*int] = float
|
||||
type D[something_that_is_very_very_very_long=something_that_is_very_very_very_long] = float
|
||||
type D[*something_that_is_very_very_very_long=*something_that_is_very_very_very_long] = float
|
||||
type something_that_is_long[something_that_is_long=something_that_is_long] = something_that_is_long
|
||||
|
||||
def simple[T=something_that_is_long](short1: int, short2: str, short3: bytes) -> float:
|
||||
pass
|
||||
|
||||
def longer[something_that_is_long=something_that_is_long](something_that_is_long: something_that_is_long) -> something_that_is_long:
|
||||
pass
|
||||
|
||||
def trailing_comma1[T=int,](a: str):
|
||||
pass
|
||||
|
||||
def trailing_comma2[T=int](a: str,):
|
||||
pass
|
||||
|
||||
# output
|
||||
|
||||
type A[T = int] = float
|
||||
type B[*P = int] = float
|
||||
type C[*Ts = int] = float
|
||||
type D[*Ts = *int] = float
|
||||
type D[
|
||||
something_that_is_very_very_very_long = something_that_is_very_very_very_long
|
||||
] = float
|
||||
type D[
|
||||
*something_that_is_very_very_very_long = *something_that_is_very_very_very_long
|
||||
] = float
|
||||
type something_that_is_long[
|
||||
something_that_is_long = something_that_is_long
|
||||
] = something_that_is_long
|
||||
|
||||
|
||||
def simple[
|
||||
T = something_that_is_long
|
||||
](short1: int, short2: str, short3: bytes) -> float:
|
||||
pass
|
||||
|
||||
|
||||
def longer[
|
||||
something_that_is_long = something_that_is_long
|
||||
](something_that_is_long: something_that_is_long) -> something_that_is_long:
|
||||
pass
|
||||
|
||||
|
||||
def trailing_comma1[
|
||||
T = int,
|
||||
](a: str):
|
||||
pass
|
||||
|
||||
|
||||
def trailing_comma2[
|
||||
T = int
|
||||
](a: str,):
|
||||
pass
|
@ -263,6 +263,21 @@ def test_pep_695_version_detection(self) -> None:
|
||||
versions = black.detect_target_versions(root)
|
||||
self.assertIn(black.TargetVersion.PY312, versions)
|
||||
|
||||
def test_pep_696_version_detection(self) -> None:
|
||||
source, _ = read_data("cases", "type_param_defaults")
|
||||
samples = [
|
||||
source,
|
||||
"type X[T=int] = float",
|
||||
"type X[T:int=int]=int",
|
||||
"type X[*Ts=int]=int",
|
||||
"type X[*Ts=*int]=int",
|
||||
"type X[**P=int]=int",
|
||||
]
|
||||
for sample in samples:
|
||||
root = black.lib2to3_parse(sample)
|
||||
features = black.get_features_used(root)
|
||||
self.assertIn(black.Feature.TYPE_PARAM_DEFAULTS, features)
|
||||
|
||||
def test_expression_ff(self) -> None:
|
||||
source, expected = read_data("cases", "expression.py")
|
||||
tmp_file = Path(black.dump_to_file(source))
|
||||
@ -1531,16 +1546,34 @@ def test_infer_target_version(self) -> None:
|
||||
for version, expected in [
|
||||
("3.6", [TargetVersion.PY36]),
|
||||
("3.11.0rc1", [TargetVersion.PY311]),
|
||||
(">=3.10", [TargetVersion.PY310, TargetVersion.PY311, TargetVersion.PY312]),
|
||||
(
|
||||
">=3.10",
|
||||
[
|
||||
TargetVersion.PY310,
|
||||
TargetVersion.PY311,
|
||||
TargetVersion.PY312,
|
||||
TargetVersion.PY313,
|
||||
],
|
||||
),
|
||||
(
|
||||
">=3.10.6",
|
||||
[TargetVersion.PY310, TargetVersion.PY311, TargetVersion.PY312],
|
||||
[
|
||||
TargetVersion.PY310,
|
||||
TargetVersion.PY311,
|
||||
TargetVersion.PY312,
|
||||
TargetVersion.PY313,
|
||||
],
|
||||
),
|
||||
("<3.6", [TargetVersion.PY33, TargetVersion.PY34, TargetVersion.PY35]),
|
||||
(">3.7,<3.10", [TargetVersion.PY38, TargetVersion.PY39]),
|
||||
(
|
||||
">3.7,!=3.8,!=3.9",
|
||||
[TargetVersion.PY310, TargetVersion.PY311, TargetVersion.PY312],
|
||||
[
|
||||
TargetVersion.PY310,
|
||||
TargetVersion.PY311,
|
||||
TargetVersion.PY312,
|
||||
TargetVersion.PY313,
|
||||
],
|
||||
),
|
||||
(
|
||||
"> 3.9.4, != 3.10.3",
|
||||
@ -1549,6 +1582,7 @@ def test_infer_target_version(self) -> None:
|
||||
TargetVersion.PY310,
|
||||
TargetVersion.PY311,
|
||||
TargetVersion.PY312,
|
||||
TargetVersion.PY313,
|
||||
],
|
||||
),
|
||||
(
|
||||
@ -1562,6 +1596,7 @@ def test_infer_target_version(self) -> None:
|
||||
TargetVersion.PY310,
|
||||
TargetVersion.PY311,
|
||||
TargetVersion.PY312,
|
||||
TargetVersion.PY313,
|
||||
],
|
||||
),
|
||||
(
|
||||
@ -1577,6 +1612,7 @@ def test_infer_target_version(self) -> None:
|
||||
TargetVersion.PY310,
|
||||
TargetVersion.PY311,
|
||||
TargetVersion.PY312,
|
||||
TargetVersion.PY313,
|
||||
],
|
||||
),
|
||||
("==3.8.*", [TargetVersion.PY38]),
|
||||
|
Loading…
Reference in New Issue
Block a user