Added isinstance type checks in the linter.

This commit is contained in:
Dave Halter
2015-12-03 16:14:26 +01:00
parent 8daa0b8784
commit 21faf2431a
4 changed files with 21 additions and 9 deletions

View File

@@ -19,6 +19,7 @@ CODES = {
'type-error-star': (10, TypeError, None), 'type-error-star': (10, TypeError, None),
'type-error-operation': (11, TypeError, None), 'type-error-operation': (11, TypeError, None),
'type-error-not-iterable': (12, TypeError, None), 'type-error-not-iterable': (12, TypeError, None),
'type-error-isinstance': (13, TypeError, None),
} }

View File

@@ -208,8 +208,8 @@ class CompiledObject(Base):
# Get rid of side effects, we won't call custom `__getitem__`s. # Get rid of side effects, we won't call custom `__getitem__`s.
return return
for obj in self.obj: for part in self.obj:
yield set([CompiledObject(obj)]) yield set([CompiledObject(part)])
return actual return actual
@property @property

View File

@@ -12,8 +12,13 @@ from jedi.evaluate.helpers import FakeName
from jedi.cache import underscore_memoization from jedi.cache import underscore_memoization
def try_iter_content(types): def try_iter_content(types, depth=0):
"""Helper method for static analysis.""" """Helper method for static analysis."""
if depth > 10:
# It's possible that a loop has references on itself (especially with
# CompiledObject). Therefore don't loop infinitely.
return
for typ in types: for typ in types:
try: try:
f = typ.py__iter__ f = typ.py__iter__
@@ -21,7 +26,7 @@ def try_iter_content(types):
pass pass
else: else:
for iter_types in f(): for iter_types in f():
try_iter_content(iter_types) try_iter_content(iter_types, depth + 1)
class Arguments(tree.Base): class Arguments(tree.Base):

View File

@@ -19,6 +19,7 @@ from jedi.parser import tree
from jedi import debug from jedi import debug
from jedi.evaluate import precedence from jedi.evaluate import precedence
from jedi.evaluate import param from jedi.evaluate import param
from jedi.evaluate import analysis
class NotInStdLib(LookupError): class NotInStdLib(LookupError):
@@ -40,9 +41,11 @@ def execute(evaluator, obj, arguments):
# for now we just support builtin functions. # for now we just support builtin functions.
try: try:
return _implemented[module_name][obj_name](evaluator, obj, arguments) func = _implemented[module_name][obj_name]
except KeyError: except KeyError:
pass pass
else:
return func(evaluator, obj, arguments)
raise NotInStdLib() raise NotInStdLib()
@@ -186,12 +189,15 @@ def builtins_isinstance(evaluator, objects, types, arguments):
for cls_or_tup in types: for cls_or_tup in types:
if cls_or_tup.is_class(): if cls_or_tup.is_class():
bool_results.add(cls_or_tup in mro) bool_results.add(cls_or_tup in mro)
else: elif str(cls_or_tup.name) == 'tuple' \
# TODO Actually we should check for non iterables here (the and cls_or_tup.get_parent_scope() == compiled.builtin:
# type should be object or tuple of object)
# Check for tuples. # Check for tuples.
classes = iterable.py__iter__types(evaluator, set([cls_or_tup])) classes = unite(cls_or_tup.py__iter__())
bool_results.add(any(cls in mro for cls in classes)) bool_results.add(any(cls in mro for cls in classes))
else:
_, nodes = list(arguments.unpack())[1]
for node in nodes:
analysis.add(evaluator, 'type-error-isinstance', node)
return set(compiled.keyword_from_value(x) for x in bool_results) return set(compiled.keyword_from_value(x) for x in bool_results)