[pypy-commit] pypy py3.5: "print x" now raises a nice SyntaxError("Missing parentheses in call to 'print'")
amauryfa
pypy.commits at gmail.com
Sun Oct 9 10:50:20 EDT 2016
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.5
Changeset: r87663:eacce032f81c
Date: 2016-10-01 22:29 +0200
http://bitbucket.org/pypy/pypy/changeset/eacce032f81c/
Log: "print x" now raises a nice SyntaxError("Missing parentheses in call
to 'print'")
diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -728,6 +728,8 @@
args_w = args_w[:]
args_w[1] = space.newtuple(values_w[:4])
W_BaseException.descr_init(self, space, args_w)
+ if self.w_text and space.isinstance_w(self.w_text, space.w_unicode):
+ self._report_missing_parentheses(space)
def descr_str(self, space):
return space.appexec([self], """(self):
@@ -770,6 +772,42 @@
else:
return W_Exception.descr_repr(self, space)
+ # CPython Issue #21669: Custom error for 'print' & 'exec' as statements
+ def _report_missing_parentheses(self, space):
+ text = space.unicode_w(self.w_text)
+ if u'(' in text:
+ # Use default error message for any line with an opening paren
+ return
+ # handle the simple statement case
+ if self._check_for_legacy_statements(space, text, 0):
+ return
+ # Handle the one-line complex statement case
+ pos = text.find(u':')
+ if pos < 0:
+ return
+ # Check again, starting from just after the colon
+ self._check_for_legacy_statements(space, text, pos+1)
+
+ def _check_for_legacy_statements(self, space, text, start):
+ # Ignore leading whitespace
+ while start < len(text) and text[start] == u' ':
+ start += 1
+ # Checking against an empty or whitespace-only part of the string
+ if start == len(text):
+ return False
+ if start > 0:
+ text = text[start:]
+ # Check for legacy print statements
+ if text.startswith(u"print "):
+ self.w_msg = space.wrap("Missing parentheses in call to 'print'")
+ return True
+ # Check for legacy exec statements
+ if text.startswith(u"exec "):
+ self.w_msg = space.wrap("Missing parentheses in call to 'exec'")
+ return True
+ return False
+
+
W_SyntaxError.typedef = TypeDef(
'SyntaxError',
W_Exception.typedef,
diff --git a/pypy/module/exceptions/test/test_exc.py b/pypy/module/exceptions/test/test_exc.py
--- a/pypy/module/exceptions/test/test_exc.py
+++ b/pypy/module/exceptions/test/test_exc.py
@@ -375,3 +375,27 @@
assert e.baz == "baz"
assert e.args == ("some message",)
+ # Check the heuristic for print & exec covers significant cases
+ # As well as placing some limits on false positives
+ def test_former_statements_refer_to_builtins(self):
+ keywords = "print", "exec"
+ def exec_(s): exec(s)
+ # Cases where we want the custom error
+ cases = [
+ "{} foo",
+ "{} {{1:foo}}",
+ "if 1: {} foo",
+ "if 1: {} {{1:foo}}",
+ "if 1:\n {} foo",
+ "if 1:\n {} {{1:foo}}",
+ ]
+ for keyword in keywords:
+ custom_msg = "call to '{}'".format(keyword)
+ for case in cases:
+ source = case.format(keyword)
+ exc = raises(SyntaxError, exec_, source)
+ assert custom_msg in exc.value.msg
+ assert exc.value.args[0] == 'invalid syntax'
+ source = source.replace("foo", "(foo.)")
+ exc = raises(SyntaxError, exec_, source)
+ assert custom_msg not in exc.value.msg
More information about the pypy-commit
mailing list