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.
Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
Jupyter Notebooks (#2744)
- Deprecate `--experimental-string-processing` and move the functionality under
`--preview` (#2789)
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)
-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."
PY2_HINT: Final = "Python 2 support was removed in version 22.0."
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,
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,
- 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
# If we have to parse both, try to parse async as a keyword first
if not supports_feature(
target_versions, Feature.ASYNC_IDENTIFIERS
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 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
# 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
src_txt += "\n"
grammars = get_grammars(set(target_versions))
src_txt += "\n"
grammars = get_grammars(set(target_versions))
for grammar in grammars:
drv = driver.Driver(grammar)
try:
for grammar in grammars:
drv = driver.Driver(grammar)
try:
faulty_line = lines[lineno - 1]
except IndexError:
faulty_line = "<line number missing in source>"
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]
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]}"
+ )
- 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
if matches_grammar(src_txt, pygram.python_grammar) or matches_grammar(
src_txt, pygram.python_grammar_no_print_statement
self.soft_keywords: Dict[str, int] = {}
self.tokens: Dict[int, int] = {}
self.symbol2label: Dict[str, int] = {}
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
self.start = 256
# Python 3.7+ parses async as a keyword, not an identifier
self.async_keywords = False
new.labels = self.labels[:]
new.states = self.states[:]
new.start = self.start
new.labels = self.labels[:]
new.states = self.states[:]
new.start = self.start
+ new.version = self.version
new.async_keywords = self.async_keywords
return new
new.async_keywords = self.async_keywords
return new
# Python 2
python_grammar = driver.load_packaged_grammar("blib2to3", _GRAMMAR_FILE, cache_dir)
# 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()
soft_keywords = python_grammar.soft_keywords.copy()
python_grammar.soft_keywords.clear()
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 = 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 = (
# Python 3.7+
python_grammar_no_print_statement_no_exec_statement_async_keywords = (
python_grammar_no_print_statement_no_exec_statement_async_keywords.async_keywords = (
True
)
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 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
pattern_grammar = driver.load_packaged_grammar(
"blib2to3", _PATTERN_GRAMMAR_FILE, cache_dir
assert_format(source, expected, mode, minimum_version=(3, 10))
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})
def test_patma_invalid() -> None:
source, expected = read_data("pattern_matching_invalid")
mode = black.Mode(target_versions={black.TargetVersion.PY310})
exc_info.match("Cannot parse: 10:11")
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'")
def test_python_2_hint() -> None:
with pytest.raises(black.parsing.InvalidInput) as exc_info:
assert_format("print 'daylily'", "print 'daylily'")