Author: Amaury Forgeot d'Arc <amaur...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit