From 715f60c11bc12d8d6ffedded90c2b9a6a1b6a287 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Mon, 9 Oct 2023 07:02:49 -0700 Subject: [PATCH] Drop support for parsing Python 2 (#3933) --- CHANGES.md | 3 +++ src/black/parsing.py | 22 +++++---------------- src/blib2to3/Grammar.txt | 7 ++----- src/blib2to3/pygram.py | 41 ++++++++++------------------------------ tests/test_format.py | 6 ------ 5 files changed, 20 insertions(+), 59 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 062a195..ffc63b3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -40,6 +40,9 @@ +- Black no longer attempts to provide special errors for attempting to format Python 2 + code (#3933) + ### _Blackd_ diff --git a/src/black/parsing.py b/src/black/parsing.py index e98e019..03e767a 100644 --- a/src/black/parsing.py +++ b/src/black/parsing.py @@ -3,7 +3,7 @@ Parse Python code and perform AST validation. """ import ast import sys -from typing import Final, Iterable, Iterator, List, Set, Tuple +from typing import Iterable, Iterator, List, Set, Tuple from black.mode import VERSION_TO_FEATURES, Feature, TargetVersion, supports_feature from black.nodes import syms @@ -14,8 +14,6 @@ from blib2to3.pgen2.parse import ParseError from blib2to3.pgen2.tokenize import TokenError from blib2to3.pytree import Leaf, Node -PY2_HINT: Final = "Python 2 support was removed in version 22.0." - class InvalidInput(ValueError): """Raised when input source code fails all parse attempts.""" @@ -26,9 +24,9 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: # No target_version specified, so try all grammars. return [ # Python 3.7-3.9 - pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords, + pygram.python_grammar_async_keywords, # Python 3.0-3.6 - pygram.python_grammar_no_print_statement_no_exec_statement, + pygram.python_grammar, # Python 3.10+ pygram.python_grammar_soft_keywords, ] @@ -39,12 +37,10 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: target_versions, Feature.ASYNC_IDENTIFIERS ) and not supports_feature(target_versions, Feature.PATTERN_MATCHING): # Python 3.7-3.9 - grammars.append( - pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords - ) + grammars.append(pygram.python_grammar_async_keywords) if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS): # Python 3.0-3.6 - grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement) + grammars.append(pygram.python_grammar) if any(Feature.PATTERN_MATCHING in VERSION_TO_FEATURES[v] for v in target_versions): # Python 3.10+ grammars.append(pygram.python_grammar_soft_keywords) @@ -89,14 +85,6 @@ def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) - # Choose the latest version when raising the actual parsing error. assert len(errors) >= 1 exc = errors[max(errors)] - - if matches_grammar(src_txt, pygram.python_grammar) or matches_grammar( - src_txt, pygram.python_grammar_no_print_statement - ): - original_msg = exc.args[0] - msg = f"{original_msg}\n{PY2_HINT}" - raise InvalidInput(msg) from None - raise exc from None if isinstance(result, Leaf): diff --git a/src/blib2to3/Grammar.txt b/src/blib2to3/Grammar.txt index e48e663..be91df7 100644 --- a/src/blib2to3/Grammar.txt +++ b/src/blib2to3/Grammar.txt @@ -80,8 +80,8 @@ vfplist: vfpdef (',' vfpdef)* [','] stmt: simple_stmt | compound_stmt simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE -small_stmt: (type_stmt | expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | - import_stmt | global_stmt | exec_stmt | assert_stmt) +small_stmt: (type_stmt | expr_stmt | del_stmt | pass_stmt | flow_stmt | + import_stmt | global_stmt | assert_stmt) expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*) annassign: ':' test ['=' (yield_expr|testlist_star_expr)] @@ -89,8 +89,6 @@ testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=') # For normal and annotated assignments, additional restrictions enforced by the interpreter -print_stmt: 'print' ( [ test (',' test)* [','] ] | - '>>' test [ (',' test)+ [','] ] ) del_stmt: 'del' exprlist pass_stmt: 'pass' flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt @@ -109,7 +107,6 @@ import_as_names: import_as_name (',' import_as_name)* [','] dotted_as_names: dotted_as_name (',' dotted_as_name)* dotted_name: NAME ('.' NAME)* global_stmt: ('global' | 'nonlocal') NAME (',' NAME)* -exec_stmt: 'exec' expr ['in' test [',' test]] assert_stmt: 'assert' test [',' test] type_stmt: "type" NAME [typeparams] '=' expr diff --git a/src/blib2to3/pygram.py b/src/blib2to3/pygram.py index c30c630..2b43b4c 100644 --- a/src/blib2to3/pygram.py +++ b/src/blib2to3/pygram.py @@ -63,7 +63,6 @@ class _python_symbols(Symbols): encoding_decl: int eval_input: int except_clause: int - exec_stmt: int expr: int expr_stmt: int exprlist: int @@ -97,7 +96,6 @@ class _python_symbols(Symbols): pattern: int patterns: int power: int - print_stmt: int raise_stmt: int return_stmt: int shift_expr: int @@ -153,22 +151,16 @@ class _pattern_symbols(Symbols): python_grammar: Grammar -python_grammar_no_print_statement: Grammar -python_grammar_no_print_statement_no_exec_statement: Grammar -python_grammar_no_print_statement_no_exec_statement_async_keywords: Grammar -python_grammar_no_exec_statement: Grammar -pattern_grammar: Grammar +python_grammar_async_keywords: Grammar python_grammar_soft_keywords: Grammar - +pattern_grammar: Grammar python_symbols: _python_symbols pattern_symbols: _pattern_symbols def initialize(cache_dir: Union[str, "os.PathLike[str]", None] = None) -> None: global python_grammar - global python_grammar_no_print_statement - global python_grammar_no_print_statement_no_exec_statement - global python_grammar_no_print_statement_no_exec_statement_async_keywords + global python_grammar_async_keywords global python_grammar_soft_keywords global python_symbols global pattern_grammar @@ -180,38 +172,25 @@ def initialize(cache_dir: Union[str, "os.PathLike[str]", None] = None) -> None: os.path.dirname(__file__), "PatternGrammar.txt" ) - # Python 2 python_grammar = driver.load_packaged_grammar("blib2to3", _GRAMMAR_FILE, cache_dir) - python_grammar.version = (2, 0) + assert "print" not in python_grammar.keywords + assert "exec" not in python_grammar.keywords soft_keywords = python_grammar.soft_keywords.copy() python_grammar.soft_keywords.clear() python_symbols = _python_symbols(python_grammar) - # Python 2 + from __future__ import print_function - python_grammar_no_print_statement = python_grammar.copy() - del python_grammar_no_print_statement.keywords["print"] - # Python 3.0-3.6 - python_grammar_no_print_statement_no_exec_statement = python_grammar.copy() - del python_grammar_no_print_statement_no_exec_statement.keywords["print"] - del python_grammar_no_print_statement_no_exec_statement.keywords["exec"] - python_grammar_no_print_statement_no_exec_statement.version = (3, 0) + python_grammar.version = (3, 0) # Python 3.7+ - python_grammar_no_print_statement_no_exec_statement_async_keywords = ( - python_grammar_no_print_statement_no_exec_statement.copy() - ) - python_grammar_no_print_statement_no_exec_statement_async_keywords.async_keywords = ( - True - ) - python_grammar_no_print_statement_no_exec_statement_async_keywords.version = (3, 7) + python_grammar_async_keywords = python_grammar.copy() + python_grammar_async_keywords.async_keywords = True + python_grammar_async_keywords.version = (3, 7) # Python 3.10+ - python_grammar_soft_keywords = ( - python_grammar_no_print_statement_no_exec_statement_async_keywords.copy() - ) + python_grammar_soft_keywords = python_grammar_async_keywords.copy() python_grammar_soft_keywords.soft_keywords = soft_keywords python_grammar_soft_keywords.version = (3, 10) diff --git a/tests/test_format.py b/tests/test_format.py index f3db423..ff358d5 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -155,12 +155,6 @@ def test_fast_cases(filename: str) -> None: assert_format(source, expected, fast=True) -def test_python_2_hint() -> None: - with pytest.raises(black.parsing.InvalidInput) as exc_info: - assert_format("print 'daylily'", "print 'daylily'") - exc_info.match(black.parsing.PY2_HINT) - - @pytest.mark.filterwarnings("ignore:invalid escape sequence.*:DeprecationWarning") def test_docstring_no_string_normalization() -> None: """Like test_docstring but with string normalization off.""" -- 2.39.2