[Python-ideas] Should a single/double quote followed by a left parenthesis raise SyntaxError?
Jacob Niehus
jacob.niehus at gmail.com
Wed Jul 15 17:40:59 CEST 2015
I recently forgot the '%' between a format string and its tuple of
values and got "TypeError: 'str' object is not callable." The error
makes sense, of course, because function calling has higher precedence
than anything else in the expression, so while:
>>> '%s' 'abc'
yields '%sabc',
>>> '%s' ('abc')
yields a TypeError.
My question is whether this should be caught as a syntax error instead
of a runtime error. I can't think of any possible case where a
single/double quote followed by '(' (optionally separated by whitespace)
would not raise an exception when the '(' is not in a string or comment.
I even wrote a script (below) to check every Python file on my computer
for occurrences of the regular expression r'[''"]\s*\(' occurring
outside of a string or comment. The sole result of my search, a file in
a wx library, is a definite runtime error by inspection:
raise IndexError, "Index out of range: %d > %d" (idx, len(self._items))
Can anyone think of a counter-example?
-Jake
--------------------------------------------------------------------------------
#!/usr/bin/env python2
import re
import sys
import tokenize
from py_compile import PyCompileError, compile
ttypes = {v: k for k, v in tokenize.__dict__.items()
if isinstance(v, int) and k == k.upper()}
for filename in sys.argv[1:]:
lines = file(filename, 'r').readlines()
matches = []
for lnum, line in enumerate(lines, 1):
for match in re.finditer(r'[''"]\s*\(', line):
matches.append((lnum, match.span(), match.group(0)))
try:
assert(matches)
compile(filename, doraise=True)
except (AssertionError, PyCompileError, IOError):
continue
matchdict = {k: [] for k in [m[0] for m in matches]}
for match in matches:
matchdict[match[0]].append(match)
with open(filename, 'r') as f:
gen = tokenize.generate_tokens(f.readline)
for ttype, tstr, (srow, scol), (erow, ecol), line in gen:
if srow == erow:
for mrow, (mscol, mecol), mstr in matchdict.get(srow, []):
pcols = [mscol + i for i, x in enumerate(mstr) if x == '(']
for p in pcols:
if (p in range(scol, ecol) and
ttypes[ttype] not in ['COMMENT', 'STRING']):
print filename
print srow
print ttypes[ttype]
More information about the Python-ideas
mailing list