Path: blob/master/elisp/emacs-for-python/rope-dist/rope/contrib/finderrors.py
1441 views
"""Finding bad name and attribute accesses12`find_errors` function can be used to find possible bad name and3attribute accesses. As an example::45errors = find_errors(project, project.get_resource('mod.py'))6for error in errors:7print '%s: %s' % (error.lineno, error.error)89prints possible errors for ``mod.py`` file.1011TODO:1213* use task handles14* reporting names at most once15* attributes of extension modules that don't appear in16extension_modules project config can be ignored17* not calling `PyScope.get_inner_scope_for_line()` if it is a18bottleneck; needs profiling19* not reporting occurrences where rope cannot infer the object20* rope saves multiple objects for some of the names in its objectdb21use all of them not to give false positives22* ... ;-)2324"""25from rope.base import ast, evaluate, pyobjects262728def find_errors(project, resource):29"""Find possible bad name and attribute accesses3031It returns a list of `Error`\s.32"""33pymodule = project.pycore.resource_to_pyobject(resource)34finder = _BadAccessFinder(pymodule)35ast.walk(pymodule.get_ast(), finder)36return finder.errors373839class _BadAccessFinder(object):4041def __init__(self, pymodule):42self.pymodule = pymodule43self.scope = pymodule.get_scope()44self.errors = []4546def _Name(self, node):47if isinstance(node.ctx, (ast.Store, ast.Param)):48return49scope = self.scope.get_inner_scope_for_line(node.lineno)50pyname = scope.lookup(node.id)51if pyname is None:52self._add_error(node, 'Unresolved variable')53elif self._is_defined_after(scope, pyname, node.lineno):54self._add_error(node, 'Defined later')5556def _Attribute(self, node):57if not isinstance(node.ctx, ast.Store):58scope = self.scope.get_inner_scope_for_line(node.lineno)59pyname = evaluate.eval_node(scope, node.value)60if pyname is not None and \61pyname.get_object() != pyobjects.get_unknown():62if node.attr not in pyname.get_object():63self._add_error(node, 'Unresolved attribute')64ast.walk(node.value, self)6566def _add_error(self, node, msg):67if isinstance(node, ast.Attribute):68name = node.attr69else:70name = node.id71if name != 'None':72error = Error(node.lineno, msg + ' ' + name)73self.errors.append(error)7475def _is_defined_after(self, scope, pyname, lineno):76location = pyname.get_definition_location()77if location is not None and location[1] is not None:78if location[0] == self.pymodule and \79lineno <= location[1] <= scope.get_end():80return True818283class Error(object):8485def __init__(self, lineno, error):86self.lineno = lineno87self.error = error8889def __str__(self):90return '%s: %s' % (self.lineno, self.error)919293