]> git.madduck.net Git - etc/vim.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Enable pattern matching by default (#2758)
authorBatuhan Taskaya <isidentical@gmail.com>
Sat, 22 Jan 2022 20:05:26 +0000 (23:05 +0300)
committerGitHub <noreply@github.com>
Sat, 22 Jan 2022 20:05:26 +0000 (12:05 -0800)
Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
CHANGES.md
src/black/parsing.py
src/blib2to3/pgen2/grammar.py
src/blib2to3/pygram.py
tests/test_format.py

index dc52ca34cbbb06675d101e27f2e1039b0b785c67..634db79bf730ffe1f51de26e859f64ff6f5e0a3b 100644 (file)
@@ -36,6 +36,8 @@
   Jupyter Notebooks (#2744)
 - Deprecate `--experimental-string-processing` and move the functionality under
   `--preview` (#2789)
+- Enable Python 3.10+ by default, without any extra need to specify
+  `--target-version=py310`. (#2758)
 
 ### Packaging
 
index 6b63368871c80c29a4e353d4c126d141235d0f61..db48ae4baf5cf181b7647609603c6f75d6b2d523 100644 (file)
@@ -42,7 +42,6 @@ except ImportError:
         ast3 = ast
 
 
-PY310_HINT: Final = "Consider using --target-version py310 to parse Python 3.10 code."
 PY2_HINT: Final = "Python 2 support was removed in version 22.0."
 
 
@@ -58,12 +57,11 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
             pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords,
             # Python 3.0-3.6
             pygram.python_grammar_no_print_statement_no_exec_statement,
+            # Python 3.10+
+            pygram.python_grammar_soft_keywords,
         ]
 
     grammars = []
-    if supports_feature(target_versions, Feature.PATTERN_MATCHING):
-        # Python 3.10+
-        grammars.append(pygram.python_grammar_soft_keywords)
     # If we have to parse both, try to parse async as a keyword first
     if not supports_feature(
         target_versions, Feature.ASYNC_IDENTIFIERS
@@ -75,6 +73,10 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]:
     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)
+    if supports_feature(target_versions, Feature.PATTERN_MATCHING):
+        # Python 3.10+
+        grammars.append(pygram.python_grammar_soft_keywords)
+
     # At least one of the above branches must have been taken, because every Python
     # version has exactly one of the two 'ASYNC_*' flags
     return grammars
@@ -86,6 +88,7 @@ def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -
         src_txt += "\n"
 
     grammars = get_grammars(set(target_versions))
+    errors = {}
     for grammar in grammars:
         drv = driver.Driver(grammar)
         try:
@@ -99,20 +102,21 @@ def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -
                 faulty_line = lines[lineno - 1]
             except IndexError:
                 faulty_line = "<line number missing in source>"
-            exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {faulty_line}")
+            errors[grammar.version] = InvalidInput(
+                f"Cannot parse: {lineno}:{column}: {faulty_line}"
+            )
 
         except TokenError as te:
             # In edge cases these are raised; and typically don't have a "faulty_line".
             lineno, column = te.args[1]
-            exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {te.args[0]}")
+            errors[grammar.version] = InvalidInput(
+                f"Cannot parse: {lineno}:{column}: {te.args[0]}"
+            )
 
     else:
-        if pygram.python_grammar_soft_keywords not in grammars and matches_grammar(
-            src_txt, pygram.python_grammar_soft_keywords
-        ):
-            original_msg = exc.args[0]
-            msg = f"{original_msg}\n{PY310_HINT}"
-            raise InvalidInput(msg) from None
+        # 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
index 56851070933a708d7a0fadce36bdb6c6ffd6e4c5..337a64f17269c80005c295e757949dc086dc7c19 100644 (file)
@@ -92,6 +92,7 @@ class Grammar(object):
         self.soft_keywords: Dict[str, int] = {}
         self.tokens: Dict[int, int] = {}
         self.symbol2label: Dict[str, int] = {}
+        self.version: Tuple[int, int] = (0, 0)
         self.start = 256
         # Python 3.7+ parses async as a keyword, not an identifier
         self.async_keywords = False
@@ -145,6 +146,7 @@ class Grammar(object):
         new.labels = self.labels[:]
         new.states = self.states[:]
         new.start = self.start
+        new.version = self.version
         new.async_keywords = self.async_keywords
         return new
 
index aa20b8104aea914d4751c6ed40a93a18cb57f76b..a3df9be1265655a413cdfae0163ab14512f85df1 100644 (file)
@@ -178,6 +178,8 @@ def initialize(cache_dir: Union[str, "os.PathLike[str]", None] = None) -> None:
 
     # Python 2
     python_grammar = driver.load_packaged_grammar("blib2to3", _GRAMMAR_FILE, cache_dir)
+    python_grammar.version = (2, 0)
+
     soft_keywords = python_grammar.soft_keywords.copy()
     python_grammar.soft_keywords.clear()
 
@@ -191,6 +193,7 @@ def initialize(cache_dir: Union[str, "os.PathLike[str]", None] = None) -> None:
     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 3.7+
     python_grammar_no_print_statement_no_exec_statement_async_keywords = (
@@ -199,12 +202,14 @@ def initialize(cache_dir: Union[str, "os.PathLike[str]", None] = None) -> None:
     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 3.10+
     python_grammar_soft_keywords = (
         python_grammar_no_print_statement_no_exec_statement_async_keywords.copy()
     )
     python_grammar_soft_keywords.soft_keywords = soft_keywords
+    python_grammar_soft_keywords.version = (3, 10)
 
     pattern_grammar = driver.load_packaged_grammar(
         "blib2to3", _PATTERN_GRAMMAR_FILE, cache_dir
index 40f225c95547786d78bb85434164a17d1944f3b8..3895a095e863c2ec503fa43e272add8062da9f8e 100644 (file)
@@ -191,6 +191,12 @@ def test_python_310(filename: str) -> None:
     assert_format(source, expected, mode, minimum_version=(3, 10))
 
 
+def test_python_310_without_target_version() -> None:
+    source, expected = read_data("pattern_matching_simple")
+    mode = black.Mode()
+    assert_format(source, expected, mode, minimum_version=(3, 10))
+
+
 def test_patma_invalid() -> None:
     source, expected = read_data("pattern_matching_invalid")
     mode = black.Mode(target_versions={black.TargetVersion.PY310})
@@ -200,15 +206,6 @@ def test_patma_invalid() -> None:
     exc_info.match("Cannot parse: 10:11")
 
 
-def test_patma_hint() -> None:
-    source, expected = read_data("pattern_matching_simple")
-    mode = black.Mode(target_versions={black.TargetVersion.PY39})
-    with pytest.raises(black.parsing.InvalidInput) as exc_info:
-        assert_format(source, expected, mode, minimum_version=(3, 10))
-
-    exc_info.match(black.parsing.PY310_HINT)
-
-
 def test_python_2_hint() -> None:
     with pytest.raises(black.parsing.InvalidInput) as exc_info:
         assert_format("print 'daylily'", "print 'daylily'")