-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpytest_checkipdb.py
72 lines (54 loc) · 2.09 KB
/
pytest_checkipdb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import pytest
import ast
def pytest_addoption(parser):
group = parser.getgroup('general')
group.addoption(
'--cipdb',
action='store_true',
dest='check_ipdb',
help='perform ipdb sanity check on .py files'
)
def pytest_collect_file(parent, path):
config = parent.config
if path.ext != '.py' or not config.option.check_ipdb:
return
if hasattr(CheckIpdbItem, "from_parent"):
return CheckIpdbItem.from_parent(parent, fspath=path)
else:
return CheckIpdbItem(path, parent)
class CheckIpdbItem(pytest.Item, pytest.File):
def __init__(self, fspath, parent):
"""fixing the raw content when instantiating the item
:param fspath:
:param parent:
"""
self.raw_content = fspath.open().read()
super(CheckIpdbItem, self).__init__(fspath, parent=parent)
def runtest(self):
t = ast.parse(self.raw_content)
Visitor().visit(t)
def repr_failure(self, excinfo):
if excinfo.errisinstance(CheckIpdbError):
return '{} in file {}'.format(excinfo.value.args[0], self.fspath)
return super(CheckIpdbItem, self).repr_failure(excinfo)
def reportinfo(self):
return self.fspath, -1, "cipdb-check"
class CheckIpdbError(Exception):
""" indicates an error during cipdb checks. """
class Visitor(ast.NodeVisitor):
check_functions = ['ipdb', 'pdb', 'set_trace', 'breakpoint']
def visit_Call(self, node):
try:
object_to_evaluate = node.func
try:
attribute_to_evaluate = node.func.id
except AttributeError:
attribute_to_evaluate = node.func.attr
for item in self.check_functions:
if attribute_to_evaluate == item:
line_number = object_to_evaluate.lineno
col_number = object_to_evaluate.col_offset
raise CheckIpdbError('Detected {} call at line {} col {}'.format(item, line_number, col_number))
except AttributeError:
pass
ast.NodeVisitor.generic_visit(self, node)