- Bumped typed-ast version minimum to 1.4.3 for 3.10 compatiblity (#2519)
- Fixed a Python 3.10 compatibility issue where the loop argument was still being passed
even though it has been removed (#2580)
+- Deprecate Python 2 formatting support (#2523)
### _Blackd_
## Does Black support Python 2?
+```{warning}
+Python 2 support has been deprecated since 21.10b0.
+
+This support will be dropped in the first stable release, expected for January 2022.
+See [The Black Code Style](the_black_code_style/index.rst) for details.
+```
+
For formatting, yes! [Install](getting_started.md#installation) with the `python2` extra
to format Python 2 files too! In terms of running _Black_ though, Python 3.6 or newer is
required.
-Note that this support will be dropped in the first stable release, expected for
-January 2022. See [The Black Code Style](the_black_code_style/index.rst) for details.
-
## Why does my linter or typechecker complain after I format my code?
Some linters and other tools use magical comments (e.g., `# noqa`, `# type: ignore`) to
versions = mode.target_versions
else:
versions = detect_target_versions(src_node)
+
+ # TODO: fully drop support and this code hopefully in January 2022 :D
+ if TargetVersion.PY27 in mode.target_versions or versions == {TargetVersion.PY27}:
+ msg = (
+ "DEPRECATION: Python 2 support will be removed in the first stable release"
+ "expected in January 2022."
+ )
+ err(msg, fg="yellow", bold=True)
+
normalize_fmt_off(src_node)
lines = LineGenerator(
mode=mode,
return tiow.read(), encoding, newline
-def get_features_used(node: Node) -> Set[Feature]:
+def get_features_used(node: Node) -> Set[Feature]: # noqa: C901
"""Return a set of (relatively) new Python features used in this file.
Currently looking for:
- positional only arguments in function signatures and lambdas;
- assignment expression;
- relaxed decorator syntax;
+ - print / exec statements;
"""
features: Set[Feature] = set()
for n in node.pre_order():
if argch.type in STARS:
features.add(feature)
+ elif n.type == token.PRINT_STMT:
+ features.add(Feature.PRINT_STMT)
+ elif n.type == token.EXEC_STMT:
+ features.add(Feature.EXEC_STMT)
+
return features
RELAXED_DECORATORS = 10
FORCE_OPTIONAL_PARENTHESES = 50
+ # temporary for Python 2 deprecation
+ PRINT_STMT = 200
+ EXEC_STMT = 201
+
VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
- TargetVersion.PY27: {Feature.ASYNC_IDENTIFIERS},
+ TargetVersion.PY27: {
+ Feature.ASYNC_IDENTIFIERS,
+ Feature.PRINT_STMT,
+ Feature.EXEC_STMT,
+ },
TargetVersion.PY33: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY34: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS},
TargetVersion.PY35: {
COLONEQUAL: Final = 59
N_TOKENS: Final = 60
NT_OFFSET: Final = 256
+# temporary for Python 2 deprecation
+PRINT_STMT: Final = 316
+EXEC_STMT: Final = 288
# --end constants--
tok_name: Final[Dict[int, str]] = {}
)
expected = 'def foo():\n """Testing\n Testing"""\n print "Foo"\n'
- result = CliRunner().invoke(
+ result = BlackRunner().invoke(
black.main,
["-", "-q", "--target-version=py27"],
input=BytesIO(source),
)
self.assertEqual(result.exit_code, 0)
- actual = result.output
+ actual = result.stdout
self.assertFormatEqual(actual, expected)
@staticmethod
)
+@pytest.mark.parametrize("explicit", [True, False], ids=["explicit", "autodetection"])
+def test_python_2_deprecation_with_target_version(explicit: bool) -> None:
+ args = [
+ "--config",
+ str(THIS_DIR / "empty.toml"),
+ str(DATA_DIR / "python2.py"),
+ "--check",
+ ]
+ if explicit:
+ args.append("--target-version=py27")
+ with cache_dir():
+ result = BlackRunner().invoke(black.main, args)
+ assert "DEPRECATION: Python 2 support will be removed" in result.stderr
+
+
with open(black.__file__, "r", encoding="utf-8") as _bf:
black_source_lines = _bf.readlines()