Also issue warnings if setattr is used in a class instead of an error

This commit is contained in:
Dave Halter
2014-06-26 13:40:15 +02:00
parent 4238538df4
commit 1c9058ce6b
3 changed files with 38 additions and 2 deletions

View File

@@ -82,6 +82,20 @@ def add(evaluator, name, jedi_obj, message=None, typ=Error, payload=None):
evaluator.analysis.append(instance)
def _check_for_setattr(instance):
"""
Check if there's any setattr method inside an instance. If so, return True.
"""
module = instance.get_parent_until()
try:
stmts = module.used_names['setattr']
except KeyError:
return False
return any(instance.start_pos < stmt.start_pos < instance.end_pos
for stmt in stmts)
def add_attribute_error(evaluator, scope, name_part):
message = ('AttributeError: %s has no attribute %s.' % (scope, name_part))
from jedi.evaluate.representation import Instance
@@ -95,6 +109,7 @@ def add_attribute_error(evaluator, scope, name_part):
try:
scope.get_subscope_by_name('__getattribute__')
except KeyError:
if not _check_for_setattr(scope):
typ = Error
else:
typ = Error

View File

@@ -115,7 +115,6 @@ class NameFinder(object):
if result:
break
self._last_filter_name_scope = name_list_scope
scope_txt = (self.scope if self.scope == name_list_scope
else '%s-%s' % (self.scope, name_list_scope))
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str,

View File

@@ -3,6 +3,10 @@ Jedi issues warnings for possible errors if ``__getattr__``,
``__getattribute__`` or ``setattr`` are used.
"""
# -----------------
# __getattr*__
# -----------------
class Cls():
def __getattr__(self, name):
@@ -22,3 +26,21 @@ Inherited().upper
#! 12 warning attribute-error
Inherited().undefined
# -----------------
# setattr
# -----------------
class SetattrCls():
def __init__(self, dct):
# Jedi doesn't even try to understand such code
for k, v in dct:
setattr(self, k, v)
self.defined = 3
c = SetattrCls({'a': 'b'})
c.defined
#! 2 warning attribute-error
c.undefined