Consider the following sample code:
data = []
try:
print data[0]
except IndexError as error:
print error.message
There is nothing syntactically wrong (using Python2.7) with the code except that if you run python with warnings turned on, you would see a DeprecationWarning
:
$ python -W always test.py
test.py:5: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
print error.message
list index out of range
FYI, this is because .message
was deprecated since python2.6 and removed in python3.
Now, I'd like to find all places in the project where .message
is called on any exception instance by using static code analysis tools. As an end goal, I'm planning to have this check running as a part of a daily build&test&code quality check task and raise an error if the syntax is still used.
Is it possible? Is it something that pylint
, pyflakes
or other code analysis tools are capable of?
I found that pep8
tool has several similar checks implemented, for instance, has_key()
usage check:
$ cat test.py
my_dict = {}
print my_dict.has_key('test')
$ pep8 test.py
test.py:2:14: W601 .has_key() is deprecated, use 'in'
As an alternative solution, I can treat all warnings as errors (like suggested here) and make my tests fail but this has its disadvantages:
Since you want to do this statically, you can use the ast
module to parse the code and then scan it for any occurrence of the deprecated code with a subclass of the NodeVisitor
class. Like so:
import ast, sys
class UsingMessageAttr(ast.NodeVisitor):
error_object_names = []
def visit_Attribute(self, node):
if (node.attr == 'message' and
hasattr(node.value, 'id') and
node.value.id in self.error_object_names):
print("Danger Will Robinson!!")
sys.exit(1)
self.generic_visit(node)
def visit_ExceptHandler(self, node):
if node.name is not None:
self.error_object_names.append(node.name)
self.generic_visit(node)
self.error_object_names.pop()
else:
self.generic_visit(node)
with open('sourcefile.py', 'r') as f:
UsingMessageAttr().visit(ast.parse(f.read()))
This works by using python parse the source file into an AST and then uses the visitor pattern to walk through the entire file and find any instances of the deprecated attribute. For more information on how this works, see the python documentation on the ast module.
Note that this won't work if you use something clever to refer to the exception object. It simply takes the variable name that the exception object was bound to and checks if a message
attribute is ever accessed from a variable of the same name inside the body of the exception handler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With