Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/emacs-for-python/rope-dist/rope/contrib/finderrors.py
1441 views
1
"""Finding bad name and attribute accesses
2
3
`find_errors` function can be used to find possible bad name and
4
attribute accesses. As an example::
5
6
errors = find_errors(project, project.get_resource('mod.py'))
7
for error in errors:
8
print '%s: %s' % (error.lineno, error.error)
9
10
prints possible errors for ``mod.py`` file.
11
12
TODO:
13
14
* use task handles
15
* reporting names at most once
16
* attributes of extension modules that don't appear in
17
extension_modules project config can be ignored
18
* not calling `PyScope.get_inner_scope_for_line()` if it is a
19
bottleneck; needs profiling
20
* not reporting occurrences where rope cannot infer the object
21
* rope saves multiple objects for some of the names in its objectdb
22
use all of them not to give false positives
23
* ... ;-)
24
25
"""
26
from rope.base import ast, evaluate, pyobjects
27
28
29
def find_errors(project, resource):
30
"""Find possible bad name and attribute accesses
31
32
It returns a list of `Error`\s.
33
"""
34
pymodule = project.pycore.resource_to_pyobject(resource)
35
finder = _BadAccessFinder(pymodule)
36
ast.walk(pymodule.get_ast(), finder)
37
return finder.errors
38
39
40
class _BadAccessFinder(object):
41
42
def __init__(self, pymodule):
43
self.pymodule = pymodule
44
self.scope = pymodule.get_scope()
45
self.errors = []
46
47
def _Name(self, node):
48
if isinstance(node.ctx, (ast.Store, ast.Param)):
49
return
50
scope = self.scope.get_inner_scope_for_line(node.lineno)
51
pyname = scope.lookup(node.id)
52
if pyname is None:
53
self._add_error(node, 'Unresolved variable')
54
elif self._is_defined_after(scope, pyname, node.lineno):
55
self._add_error(node, 'Defined later')
56
57
def _Attribute(self, node):
58
if not isinstance(node.ctx, ast.Store):
59
scope = self.scope.get_inner_scope_for_line(node.lineno)
60
pyname = evaluate.eval_node(scope, node.value)
61
if pyname is not None and \
62
pyname.get_object() != pyobjects.get_unknown():
63
if node.attr not in pyname.get_object():
64
self._add_error(node, 'Unresolved attribute')
65
ast.walk(node.value, self)
66
67
def _add_error(self, node, msg):
68
if isinstance(node, ast.Attribute):
69
name = node.attr
70
else:
71
name = node.id
72
if name != 'None':
73
error = Error(node.lineno, msg + ' ' + name)
74
self.errors.append(error)
75
76
def _is_defined_after(self, scope, pyname, lineno):
77
location = pyname.get_definition_location()
78
if location is not None and location[1] is not None:
79
if location[0] == self.pymodule and \
80
lineno <= location[1] <= scope.get_end():
81
return True
82
83
84
class Error(object):
85
86
def __init__(self, lineno, error):
87
self.lineno = lineno
88
self.error = error
89
90
def __str__(self):
91
return '%s: %s' % (self.lineno, self.error)
92
93