Skip to content

Commit

Permalink
pythongh-96052: codeop: fix handling compiler warnings in incomplete …
Browse files Browse the repository at this point in the history
…input (pythonGH-96132)

Previously codeop.compile_command() emitted compiler warnings (SyntaxWarning or
DeprecationWarning) and raised a SyntaxError for incomplete input containing
a potentially incorrect code. Now it always returns None for incomplete input
without emitting any warnings.
  • Loading branch information
serhiy-storchaka authored Sep 16, 2022
1 parent e47b96c commit 426d72e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
26 changes: 13 additions & 13 deletions Lib/codeop.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,22 @@ def _maybe_compile(compiler, source, filename, symbol):
if symbol != "eval":
source = "pass" # Replace it with a 'pass' statement

try:
return compiler(source, filename, symbol)
except SyntaxError: # Let other compile() errors propagate.
pass

# Catch syntax warnings after the first compile
# to emit warnings (SyntaxWarning, DeprecationWarning) at most once.
# Disable compiler warnings when checking for incomplete input.
with warnings.catch_warnings():
warnings.simplefilter("error")

warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning))
try:
compiler(source + "\n", filename, symbol)
except SyntaxError as e:
if "incomplete input" in str(e):
compiler(source, filename, symbol)
except SyntaxError: # Let other compile() errors propagate.
try:
compiler(source + "\n", filename, symbol)
return None
raise
except SyntaxError as e:
if "incomplete input" in str(e):
return None
# fallthrough

return compiler(source, filename, symbol)


def _is_syntax_error(err1, err2):
rep1 = repr(err1)
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_codeop.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,26 @@ def test_warning(self):
warnings.simplefilter('error', SyntaxWarning)
compile_command('1 is 1', symbol='exec')

# Check DeprecationWarning treated as an SyntaxError
with warnings.catch_warnings(), self.assertRaises(SyntaxError):
warnings.simplefilter('error', DeprecationWarning)
compile_command(r"'\e'", symbol='exec')

def test_incomplete_warning(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
self.assertIncomplete("'\\e' + (")
self.assertEqual(w, [])

def test_invalid_warning(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
self.assertInvalid("'\\e' 1")
self.assertEqual(len(w), 1)
self.assertEqual(w[0].category, DeprecationWarning)
self.assertRegex(str(w[0].message), 'invalid escape sequence')
self.assertEqual(w[0].filename, '<input>')


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix handling compiler warnings (SyntaxWarning and DeprecationWarning) in
:func:`codeop.compile_command` when checking for incomplete input.
Previously it emitted warnings and raised a SyntaxError. Now it always
returns ``None`` for incomplete input without emitting any warnings.

0 comments on commit 426d72e

Please sign in to comment.