diff --git a/CHANGES.md b/CHANGES.md index 7214405c429..c0cf60af98a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ times, like `match re.match()` (#2661) - Fix assignment to environment variables in Jupyter Notebooks (#2642) - Add `flake8-simplify` and `flake8-comprehensions` plugins (#2653) +- Fix parser error location on invalid syntax in a `match` statement (#2649) ## 21.11b1 diff --git a/src/black/parsing.py b/src/black/parsing.py index 32cfa5239f1..e38405637cd 100644 --- a/src/black/parsing.py +++ b/src/black/parsing.py @@ -75,8 +75,10 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: # 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): - # Python 3.7+ + if not supports_feature( + 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 ) diff --git a/tests/data/pattern_matching_invalid.py b/tests/data/pattern_matching_invalid.py new file mode 100644 index 00000000000..22b5b94c0a4 --- /dev/null +++ b/tests/data/pattern_matching_invalid.py @@ -0,0 +1,18 @@ +# First match, no errors +match something: + case bla(): + pass + +# Problem on line 10 +match invalid_case: + case valid_case: + pass + case a := b: + pass + case valid_case: + pass + +# No problems either +match something: + case bla(): + pass diff --git a/tests/test_format.py b/tests/test_format.py index 8f8ffb3610e..f97d7165b1a 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -200,6 +200,15 @@ def test_python_310(filename: str) -> None: 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}) + with pytest.raises(black.parsing.InvalidInput) as exc_info: + assert_format(source, expected, mode, minimum_version=(3, 10)) + + exc_info.match("Cannot parse: 10:11") + + def test_docstring_no_string_normalization() -> None: """Like test_docstring but with string normalization off.""" source, expected = read_data("docstring_no_string_normalization")