check-code: disallow use of hasattr()
The hasattr() builtin from Python < 3.2 [1] has slightly surprising
behavior: it catches all exceptions, even KeyboardInterrupt. This
causes it to have several surprising side effects, such as hiding
warnings that occur during attribute load and causing mysterious
failure modes when ^Cing an application. In later versions of Python
2.x [0], exception classes which do not inherit from Exception (such
as SystemExit and KeyboardInterrupt) are not caught, but other types
of exceptions may still silently cause returning False instead of
getting a reasonable exception.
[0] http://bugs.python.org/
issue2196
[1] http://docs.python.org/dev/whatsnew/3.2.html
--- a/contrib/check-code.py Mon Jul 25 21:15:48 2011 -0500
+++ b/contrib/check-code.py Mon Jul 25 14:59:31 2011 -0500
@@ -148,7 +148,7 @@
(r'(?<!def)\s+(any|all|format)\(',
"any/all/format not available in Python 2.4"),
(r'(?<!def)\s+(callable)\(',
- "callable not available in Python 3, use hasattr(f, '__call__')"),
+ "callable not available in Python 3, use getattr(f, '__call__', None)"),
(r'if\s.*\selse', "if ... else form not available in Python 2.4"),
(r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
"gratuitous whitespace after Python keyword"),
@@ -168,6 +168,8 @@
"comparison with singleton, use 'is' or 'is not' instead"),
(r'^\s*(while|if) [01]:',
"use True/False for constant Boolean expression"),
+ (r'(?<!def)\s+hasattr',
+ 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
(r'opener\([^)]*\).read\(',
"use opener.read() instead"),
(r'opener\([^)]*\).write\(',