1
0
forked from VimPlug/jedi

Replacing the types list with a types set. Some tests are failing, though.

This commit is contained in:
Dave Halter
2015-10-13 18:03:36 +02:00
parent bf3fa11f6f
commit 844a011193
13 changed files with 166 additions and 163 deletions

View File

@@ -331,12 +331,13 @@ class Script(object):
:rtype: list of :class:`classes.Definition` :rtype: list of :class:`classes.Definition`
""" """
def resolve_import_paths(scopes): def resolve_import_paths(definitions):
for s in set(scopes): new_defs = list(definitions)
for s in definitions:
if isinstance(s, imports.ImportWrapper): if isinstance(s, imports.ImportWrapper):
scopes.remove(s) new_defs.remove(s)
scopes.update(resolve_import_paths(set(s.follow()))) new_defs += resolve_import_paths(set(s.follow()))
return scopes return new_defs
goto_path = self._user_context.get_path_under_cursor() goto_path = self._user_context.get_path_under_cursor()
context = self._user_context.get_context() context = self._user_context.get_context()

View File

@@ -152,7 +152,7 @@ class Evaluator(object):
# only in for loops without clutter, because they are # only in for loops without clutter, because they are
# predictable. # predictable.
for r in types: for r in types:
left = precedence.calculate(self, left, operator, [r]) left = precedence.calculate(self, left, operator, set([r]))
types = left types = left
else: else:
types = precedence.calculate(self, left, operator, types) types = precedence.calculate(self, left, operator, types)
@@ -161,9 +161,9 @@ class Evaluator(object):
def eval_element(self, element): def eval_element(self, element):
if isinstance(element, iterable.AlreadyEvaluated): if isinstance(element, iterable.AlreadyEvaluated):
return list(element) return set(element)
elif isinstance(element, iterable.MergedNodes): elif isinstance(element, iterable.MergedNodes):
return iterable.unite(self.eval_element(e) for e in element) return set(iterable.unite(self.eval_element(e) for e in element))
parent = element.get_parent_until((tree.IfStmt, tree.IsScope)) parent = element.get_parent_until((tree.IfStmt, tree.IsScope))
predefined_if_name_dict = self.predefined_if_name_dict_dict.get(parent) predefined_if_name_dict = self.predefined_if_name_dict_dict.get(parent)
@@ -208,11 +208,11 @@ class Evaluator(object):
for name_dict in name_dicts: for name_dict in name_dicts:
name_dict[str(if_name)] = definitions name_dict[str(if_name)] = definitions
if len(name_dicts) > 1: if len(name_dicts) > 1:
result = [] result = set()
for name_dict in name_dicts: for name_dict in name_dicts:
self.predefined_if_name_dict_dict[parent] = name_dict self.predefined_if_name_dict_dict[parent] = name_dict
try: try:
result += self._eval_element_not_cached(element) result |= self._eval_element_not_cached(element)
finally: finally:
del self.predefined_if_name_dict_dict[parent] del self.predefined_if_name_dict_dict[parent]
return result return result
@@ -235,13 +235,13 @@ class Evaluator(object):
elif isinstance(element, tree.Keyword): elif isinstance(element, tree.Keyword):
# For False/True/None # For False/True/None
if element.value in ('False', 'True', 'None'): if element.value in ('False', 'True', 'None'):
return [compiled.builtin.get_by_name(element.value)] return set([compiled.builtin.get_by_name(element.value)])
else: else:
return [] return []
elif element.isinstance(tree.Lambda): elif element.isinstance(tree.Lambda):
return [er.LambdaWrapper(self, element)] return set([er.LambdaWrapper(self, element)])
elif element.isinstance(er.LambdaWrapper): elif element.isinstance(er.LambdaWrapper):
return [element] # TODO this is no real evaluation. return set([element]) # TODO this is no real evaluation.
elif element.type == 'expr_stmt': elif element.type == 'expr_stmt':
return self.eval_statement(element) return self.eval_statement(element)
elif element.type == 'power': elif element.type == 'power':
@@ -254,24 +254,24 @@ class Evaluator(object):
return types return types
elif element.type in ('testlist_star_expr', 'testlist',): elif element.type in ('testlist_star_expr', 'testlist',):
# The implicit tuple in statements. # The implicit tuple in statements.
return [iterable.ImplicitTuple(self, element)] return set([iterable.ImplicitTuple(self, element)])
elif element.type in ('not_test', 'factor'): elif element.type in ('not_test', 'factor'):
types = self.eval_element(element.children[-1]) types = self.eval_element(element.children[-1])
for operator in element.children[:-1]: for operator in element.children[:-1]:
types = list(precedence.factor_calculate(self, types, operator)) types = precedence.factor_calculate(self, types, operator)
return types return types
elif element.type == 'test': elif element.type == 'test':
# `x if foo else y` case. # `x if foo else y` case.
return (self.eval_element(element.children[0]) + return (self.eval_element(element.children[0]) |
self.eval_element(element.children[-1])) self.eval_element(element.children[-1]))
elif element.type == 'operator': elif element.type == 'operator':
# Must be an ellipsis, other operators are not evaluated. # Must be an ellipsis, other operators are not evaluated.
return [] # Ignore for now. return set() # Ignore for now.
elif element.type == 'dotted_name': elif element.type == 'dotted_name':
types = self._eval_atom(element.children[0]) types = self._eval_atom(element.children[0])
for next_name in element.children[2::2]: for next_name in element.children[2::2]:
types = list(chain.from_iterable(self.find_types(typ, next_name) types = set(chain.from_iterable(self.find_types(typ, next_name)
for typ in types)) for typ in types))
return types return types
else: else:
return precedence.calculate_children(self, element.children) return precedence.calculate_children(self, element.children)
@@ -294,7 +294,7 @@ class Evaluator(object):
stmt = atom stmt = atom
return self.find_types(scope, atom, stmt.start_pos, search_global=True) return self.find_types(scope, atom, stmt.start_pos, search_global=True)
elif isinstance(atom, tree.Literal): elif isinstance(atom, tree.Literal):
return [compiled.create(self, atom.eval())] return set([compiled.create(self, atom.eval())])
else: else:
c = atom.children c = atom.children
# Parentheses without commas are not tuples. # Parentheses without commas are not tuples.
@@ -308,20 +308,20 @@ class Evaluator(object):
pass pass
else: else:
if isinstance(comp_for, tree.CompFor): if isinstance(comp_for, tree.CompFor):
return [iterable.Comprehension.from_atom(self, atom)] return set([iterable.Comprehension.from_atom(self, atom)])
return [iterable.Array(self, atom)] return set([iterable.Array(self, atom)])
def eval_trailer(self, types, trailer): def eval_trailer(self, types, trailer):
trailer_op, node = trailer.children[:2] trailer_op, node = trailer.children[:2]
if node == ')': # `arglist` is optional. if node == ')': # `arglist` is optional.
node = () node = ()
new_types = [] new_types = set()
for typ in types: for typ in types:
debug.dbg('eval_trailer: %s in scope %s', trailer, typ) debug.dbg('eval_trailer: %s in scope %s', trailer, typ)
if trailer_op == '.': if trailer_op == '.':
new_types += self.find_types(typ, node) new_types |= self.find_types(typ, node)
elif trailer_op == '(': elif trailer_op == '(':
new_types += self.execute(typ, node, trailer) new_types |= self.execute(typ, node, trailer)
elif trailer_op == '[': elif trailer_op == '[':
try: try:
get = typ.get_index_types get = typ.get_index_types
@@ -329,7 +329,7 @@ class Evaluator(object):
debug.warning("TypeError: '%s' object is not subscriptable" debug.warning("TypeError: '%s' object is not subscriptable"
% typ) % typ)
else: else:
new_types += get(self, node) new_types |= get(self, node)
return new_types return new_types
def execute_evaluated(self, obj, *args): def execute_evaluated(self, obj, *args):
@@ -362,7 +362,7 @@ class Evaluator(object):
func = obj.py__call__ func = obj.py__call__
except AttributeError: except AttributeError:
debug.warning("no execution possible %s", obj) debug.warning("no execution possible %s", obj)
return [] return set()
else: else:
types = func(self, arguments) types = func(self, arguments)
debug.dbg('execute result: %s in %s', types, obj) debug.dbg('execute result: %s in %s', types, obj)

View File

@@ -51,9 +51,9 @@ class CompiledObject(Base):
def actual(evaluator, params): def actual(evaluator, params):
if inspect.isclass(self.obj): if inspect.isclass(self.obj):
from jedi.evaluate.representation import Instance from jedi.evaluate.representation import Instance
return [Instance(evaluator, self, params)] return set([Instance(evaluator, self, params)])
else: else:
return list(self._execute_function(evaluator, params)) return set(self._execute_function(evaluator, params))
# Might raise an AttributeError, which is intentional. # Might raise an AttributeError, which is intentional.
self.obj.__call__ self.obj.__call__
@@ -173,12 +173,12 @@ class CompiledObject(Base):
# AttributeError. # AttributeError.
if not hasattr(self.obj, '__getitem__'): if not hasattr(self.obj, '__getitem__'):
debug.warning('Tried to call __getitem__ on non-iterable.') debug.warning('Tried to call __getitem__ on non-iterable.')
return [] return set()
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict): if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
# 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 set()
result = [] result = set()
from jedi.evaluate.iterable import create_indexes_or_slices from jedi.evaluate.iterable import create_indexes_or_slices
for typ in create_indexes_or_slices(evaluator, index_array): for typ in create_indexes_or_slices(evaluator, index_array):
index = None index = None
@@ -188,9 +188,9 @@ class CompiledObject(Base):
except (KeyError, IndexError, TypeError, AttributeError): except (KeyError, IndexError, TypeError, AttributeError):
# Just try, we don't care if it fails, except for slices. # Just try, we don't care if it fails, except for slices.
if isinstance(index, slice): if isinstance(index, slice):
result.append(self) result.add(self)
else: else:
result.append(CompiledObject(new)) result.add(CompiledObject(new))
if not result: if not result:
try: try:
for obj in self.obj: for obj in self.obj:

View File

@@ -176,11 +176,11 @@ def _execute_array_values(evaluator, array):
def follow_param(evaluator, param): def follow_param(evaluator, param):
func = param.parent_function func = param.parent_function
return [p return set(
for param_str in _search_param_in_docstr(func.raw_doc, [p for param_str in _search_param_in_docstr(func.raw_doc,
str(param.name)) str(param.name))
for p in _evaluate_for_statement_string(evaluator, param_str, for p in _evaluate_for_statement_string(evaluator, param_str,
param.get_parent_until())] param.get_parent_until())])
@memoize_default(None, evaluator_is_first_arg=True) @memoize_default(None, evaluator_is_first_arg=True)

View File

@@ -60,7 +60,7 @@ def search_params(evaluator, param):
names = [n for n in search_function_call(evaluator, func) names = [n for n in search_function_call(evaluator, func)
if n.value == param.name.value] if n.value == param.name.value]
# Evaluate the ExecutedParams to types. # Evaluate the ExecutedParams to types.
result = list(chain.from_iterable(n.parent.eval(evaluator) for n in names)) result = set(chain.from_iterable(n.parent.eval(evaluator) for n in names))
debug.dbg('Dynamic param result %s', result) debug.dbg('Dynamic param result %s', result)
return result return result

View File

@@ -164,7 +164,7 @@ class NameFinder(object):
elif isinstance(scope, tree.IfStmt): elif isinstance(scope, tree.IfStmt):
try: try:
name_dict = self._evaluator.predefined_if_name_dict_dict[scope] name_dict = self._evaluator.predefined_if_name_dict_dict[scope]
types = name_dict[str(self.name_str)] types = set(name_dict[str(self.name_str)])
except KeyError: except KeyError:
continue continue
else: else:
@@ -177,7 +177,7 @@ class NameFinder(object):
check = flow_analysis.break_check(self._evaluator, self.scope, check = flow_analysis.break_check(self._evaluator, self.scope,
origin_scope) origin_scope)
if check is flow_analysis.UNREACHABLE: if check is flow_analysis.UNREACHABLE:
self._found_predefined_if_name = [] self._found_predefined_if_name = set()
else: else:
self._found_predefined_if_name = types self._found_predefined_if_name = types
break break
@@ -230,7 +230,7 @@ class NameFinder(object):
def _check_getattr(self, inst): def _check_getattr(self, inst):
"""Checks for both __getattr__ and __getattribute__ methods""" """Checks for both __getattr__ and __getattribute__ methods"""
result = [] result = set()
# str is important, because it shouldn't be `Name`! # str is important, because it shouldn't be `Name`!
name = compiled.create(self._evaluator, str(self.name_str)) name = compiled.create(self._evaluator, str(self.name_str))
with common.ignored(KeyError): with common.ignored(KeyError):
@@ -285,51 +285,50 @@ class NameFinder(object):
if not isinstance(name_scope, (er.Instance, tree.Class)): if not isinstance(name_scope, (er.Instance, tree.Class)):
return types return types
result = [] result = set()
for r in types: for r in types:
try: try:
desc_return = r.get_descriptor_returns desc_return = r.get_descriptor_returns
except AttributeError: except AttributeError:
result.append(r) result.add(r)
else: else:
result += desc_return(self.scope) result |= desc_return(self.scope)
return result return result
@memoize_default([], evaluator_is_first_arg=True) @memoize_default(set(), evaluator_is_first_arg=True)
def _name_to_types(evaluator, name, scope): def _name_to_types(evaluator, name, scope):
types = [] types = set()
typ = name.get_definition() typ = name.get_definition()
if typ.isinstance(tree.ForStmt, tree.CompFor): if typ.isinstance(tree.ForStmt, tree.CompFor):
for_types = iterable.get_iterator_types(evaluator, typ.children[3]) for_types = iterable.get_iterator_types(evaluator, typ.children[3])
types += check_tuple_assignments(for_types, name) types |= check_tuple_assignments(for_types, name)
elif isinstance(typ, tree.Param): elif isinstance(typ, tree.Param):
types += _eval_param(evaluator, typ, scope) types |= _eval_param(evaluator, typ, scope)
elif typ.isinstance(tree.ExprStmt): elif typ.isinstance(tree.ExprStmt):
types += _remove_statements(evaluator, typ, name) types |= _remove_statements(evaluator, typ, name)
elif typ.isinstance(tree.WithStmt): elif typ.isinstance(tree.WithStmt):
types += evaluator.eval_element(typ.node_from_name(name)) types |= evaluator.eval_element(typ.node_from_name(name))
elif isinstance(typ, tree.Import): elif isinstance(typ, tree.Import):
types += imports.ImportWrapper(evaluator, name).follow() types |= imports.ImportWrapper(evaluator, name).follow()
elif isinstance(typ, tree.GlobalStmt): elif isinstance(typ, tree.GlobalStmt):
# TODO theoretically we shouldn't be using search_global here, it # TODO theoretically we shouldn't be using search_global here, it
# doesn't make sense, because it's a local search (for that name)! # doesn't make sense, because it's a local search (for that name)!
# However, globals are not that important and resolving them doesn't # However, globals are not that important and resolving them doesn't
# guarantee correctness in any way, because we don't check for when # guarantee correctness in any way, because we don't check for when
# something is executed. # something is executed.
types += evaluator.find_types(typ.get_parent_scope(), str(name), types |= evaluator.find_types(typ.get_parent_scope(), str(name),
search_global=True) search_global=True)
elif isinstance(typ, tree.TryStmt): elif isinstance(typ, tree.TryStmt):
# TODO an exception can also be a tuple. Check for those. # TODO an exception can also be a tuple. Check for those.
# TODO check for types that are not classes and add it to # TODO check for types that are not classes and add it to
# the static analysis report. # the static analysis report.
exceptions = evaluator.eval_element(name.prev_sibling().prev_sibling()) exceptions = evaluator.eval_element(name.prev_sibling().prev_sibling())
types = list(chain.from_iterable( types = set(chain.from_iterable(evaluator.execute(t) for t in exceptions))
evaluator.execute(t) for t in exceptions))
else: else:
if typ.isinstance(er.Function): if typ.isinstance(er.Function):
typ = typ.get_decorated_func() typ = typ.get_decorated_func()
types.append(typ) types.add(typ)
return types return types
@@ -340,7 +339,7 @@ def _remove_statements(evaluator, stmt, name):
Due to lazy evaluation, statements like a = func; b = a; b() have to be Due to lazy evaluation, statements like a = func; b = a; b() have to be
evaluated. evaluated.
""" """
types = [] types = set()
# Remove the statement docstr stuff for now, that has to be # Remove the statement docstr stuff for now, that has to be
# implemented with the evaluator class. # implemented with the evaluator class.
#if stmt.docstr: #if stmt.docstr:
@@ -351,18 +350,18 @@ def _remove_statements(evaluator, stmt, name):
check_instance = stmt.instance check_instance = stmt.instance
stmt = stmt.var stmt = stmt.var
types += evaluator.eval_statement(stmt, seek_name=name) types |= evaluator.eval_statement(stmt, seek_name=name)
if check_instance is not None: if check_instance is not None:
# class renames # class renames
types = [er.get_instance_el(evaluator, check_instance, a, True) types = set([er.get_instance_el(evaluator, check_instance, a, True)
if isinstance(a, (er.Function, tree.Function)) if isinstance(a, (er.Function, tree.Function))
else a for a in types] else a for a in types])
return types return types
def _eval_param(evaluator, param, scope): def _eval_param(evaluator, param, scope):
res_new = [] res_new = set()
func = param.get_parent_scope() func = param.get_parent_scope()
cls = func.parent.get_parent_until((tree.Class, tree.Function)) cls = func.parent.get_parent_until((tree.Class, tree.Function))
@@ -373,11 +372,11 @@ def _eval_param(evaluator, param, scope):
# This is where we add self - if it has never been # This is where we add self - if it has never been
# instantiated. # instantiated.
if isinstance(scope, er.InstanceElement): if isinstance(scope, er.InstanceElement):
res_new.append(scope.instance) res_new.add(scope.instance)
else: else:
inst = er.Instance(evaluator, evaluator.wrap(cls), inst = er.Instance(evaluator, evaluator.wrap(cls),
Arguments(evaluator, ()), is_generated=True) Arguments(evaluator, ()), is_generated=True)
res_new.append(inst) res_new.add(inst)
return res_new return res_new
# Instances are typically faked, if the instance is not called from # Instances are typically faked, if the instance is not called from
@@ -392,17 +391,17 @@ def _eval_param(evaluator, param, scope):
return doc_params return doc_params
if isinstance(param, ExecutedParam): if isinstance(param, ExecutedParam):
return res_new + param.eval(evaluator) return res_new | param.eval(evaluator)
else: else:
# Param owns no information itself. # Param owns no information itself.
res_new += dynamic.search_params(evaluator, param) res_new |= dynamic.search_params(evaluator, param)
if not res_new: if not res_new:
if param.stars: if param.stars:
t = 'tuple' if param.stars == 1 else 'dict' t = 'tuple' if param.stars == 1 else 'dict'
typ = evaluator.find_types(compiled.builtin, t)[0] typ = list(evaluator.find_types(compiled.builtin, t))[0]
res_new = evaluator.execute(typ) res_new = evaluator.execute(typ)
if param.default: if param.default:
res_new += evaluator.eval_element(param.default) res_new |= evaluator.eval_element(param.default)
return res_new return res_new
@@ -418,7 +417,7 @@ def check_flow_information(evaluator, flow, search_name, pos):
if not settings.dynamic_flow_information: if not settings.dynamic_flow_information:
return None return None
result = [] result = set()
if flow.is_scope(): if flow.is_scope():
# Check for asserts. # Check for asserts.
try: try:
@@ -462,12 +461,12 @@ def _check_isinstance_type(evaluator, element, search_name):
call = helpers.call_of_name(search_name) call = helpers.call_of_name(search_name)
assert name.get_code() == call.get_code() assert name.get_code() == call.get_code()
except AssertionError: except AssertionError:
return [] return set()
result = [] result = set()
for typ in evaluator.eval_element(classes): for typ in evaluator.eval_element(classes):
for typ in (typ.values() if isinstance(typ, iterable.Array) else [typ]): for typ in (typ.values() if isinstance(typ, iterable.Array) else [typ]):
result += evaluator.execute(typ) result |= evaluator.execute(typ)
return result return result
@@ -546,7 +545,7 @@ def check_tuple_assignments(types, name):
Checks if tuples are assigned. Checks if tuples are assigned.
""" """
for index in name.assignment_indexes(): for index in name.assignment_indexes():
new_types = [] new_types = set()
for r in types: for r in types:
try: try:
func = r.get_exact_index_types func = r.get_exact_index_types
@@ -555,7 +554,7 @@ def check_tuple_assignments(types, name):
index, types, name) index, types, name)
else: else:
try: try:
new_types += func(index) new_types |= func(index)
except IndexError: except IndexError:
pass pass
types = new_types types = new_types

View File

@@ -70,7 +70,7 @@ class ImportWrapper(tree.Base):
def follow(self, is_goto=False): def follow(self, is_goto=False):
if self._evaluator.recursion_detector.push_stmt(self._import): if self._evaluator.recursion_detector.push_stmt(self._import):
# check recursion # check recursion
return [] return set()
try: try:
module = self._evaluator.wrap(self._import.get_parent_until()) module = self._evaluator.wrap(self._import.get_parent_until())
@@ -97,7 +97,7 @@ class ImportWrapper(tree.Base):
# scopes = [NestedImportModule(module, self._import)] # scopes = [NestedImportModule(module, self._import)]
if from_import_name is not None: if from_import_name is not None:
types = list(chain.from_iterable( types = set(chain.from_iterable(
self._evaluator.find_types(t, unicode(from_import_name), self._evaluator.find_types(t, unicode(from_import_name),
is_goto=is_goto) is_goto=is_goto)
for t in types)) for t in types))
@@ -109,11 +109,11 @@ class ImportWrapper(tree.Base):
types = importer.follow() types = importer.follow()
# goto only accepts `Name` # goto only accepts `Name`
if is_goto: if is_goto:
types = [s.name for s in types] types = set(s.name for s in types)
else: else:
# goto only accepts `Name` # goto only accepts `Name`
if is_goto: if is_goto:
types = [s.name for s in types] types = set(s.name for s in types)
debug.dbg('after import: %s', types) debug.dbg('after import: %s', types)
finally: finally:
@@ -248,7 +248,7 @@ class Importer(object):
@memoize_default(NO_DEFAULT) @memoize_default(NO_DEFAULT)
def follow(self): def follow(self):
if not self.import_path: if not self.import_path:
return [] return set()
return self._do_import(self.import_path, self.sys_path_with_modifications()) return self._do_import(self.import_path, self.sys_path_with_modifications())
def _do_import(self, import_path, sys_path): def _do_import(self, import_path, sys_path):
@@ -271,7 +271,7 @@ class Importer(object):
module_name = '.'.join(import_parts) module_name = '.'.join(import_parts)
try: try:
return [self._evaluator.modules[module_name]] return set([self._evaluator.modules[module_name]])
except KeyError: except KeyError:
pass pass
@@ -280,11 +280,11 @@ class Importer(object):
# the module cache. # the module cache.
bases = self._do_import(import_path[:-1], sys_path) bases = self._do_import(import_path[:-1], sys_path)
if not bases: if not bases:
return [] return set()
# We can take the first element, because only the os special # We can take the first element, because only the os special
# case yields multiple modules, which is not important for # case yields multiple modules, which is not important for
# further imports. # further imports.
base = bases[0] base = list(bases)[0]
# This is a huge exception, we follow a nested import # This is a huge exception, we follow a nested import
# ``os.path``, because it's a very important one in Python # ``os.path``, because it's a very important one in Python
@@ -301,7 +301,7 @@ class Importer(object):
except AttributeError: except AttributeError:
# The module is not a package. # The module is not a package.
_add_error(self._evaluator, import_path[-1]) _add_error(self._evaluator, import_path[-1])
return [] return set()
else: else:
debug.dbg('search_module %s in paths %s', module_name, paths) debug.dbg('search_module %s in paths %s', module_name, paths)
for path in paths: for path in paths:
@@ -315,7 +315,7 @@ class Importer(object):
module_path = None module_path = None
if module_path is None: if module_path is None:
_add_error(self._evaluator, import_path[-1]) _add_error(self._evaluator, import_path[-1])
return [] return set()
else: else:
try: try:
debug.dbg('search_module %s in %s', import_parts[-1], self.file_path) debug.dbg('search_module %s in %s', import_parts[-1], self.file_path)
@@ -330,7 +330,7 @@ class Importer(object):
except ImportError: except ImportError:
# The module is not a package. # The module is not a package.
_add_error(self._evaluator, import_path[-1]) _add_error(self._evaluator, import_path[-1])
return [] return set()
source = None source = None
if is_pkg: if is_pkg:
@@ -347,7 +347,7 @@ class Importer(object):
module = _load_module(self._evaluator, module_path, source, sys_path) module = _load_module(self._evaluator, module_path, source, sys_path)
self._evaluator.modules[module_name] = module self._evaluator.modules[module_name] = module
return [module] return set([module])
def _generate_name(self, name): def _generate_name(self, name):
return helpers.FakeName(name, parent=self.module) return helpers.FakeName(name, parent=self.module)

View File

@@ -53,14 +53,14 @@ class GeneratorMixin(object):
def get_index_types(self, evaluator, index_array): def get_index_types(self, evaluator, index_array):
#debug.warning('Tried to get array access on a generator: %s', self) #debug.warning('Tried to get array access on a generator: %s', self)
analysis.add(self._evaluator, 'type-error-generator', index_array) analysis.add(self._evaluator, 'type-error-generator', index_array)
return [] return set()
def get_exact_index_types(self, index): def get_exact_index_types(self, index):
""" """
Exact lookups are used for tuple lookups, which are perfectly fine if Exact lookups are used for tuple lookups, which are perfectly fine if
used with generators. used with generators.
""" """
return [self.iter_content()[index]] return set([list(self.iter_content())[index]])
def py__bool__(self): def py__bool__(self):
return True return True
@@ -145,7 +145,9 @@ class Comprehension(IterableWrapper):
return helpers.deep_ast_copy(comprehension.children[0], parent=last_comp) return helpers.deep_ast_copy(comprehension.children[0], parent=last_comp)
def get_exact_index_types(self, index): def get_exact_index_types(self, index):
return [self._evaluator.eval_element(self.eval_node())[index]] # TODO this will return a random type (depending on the current set
# hash function).
return set([list(self._evaluator.eval_element(self.eval_node()))[index]])
def __repr__(self): def __repr__(self):
return "<%s of %s>" % (type(self).__name__, self._atom) return "<%s of %s>" % (type(self).__name__, self._atom)
@@ -155,9 +157,9 @@ class ArrayMixin(object):
@memoize_default() @memoize_default()
def names_dicts(self, search_global=False): # Always False. def names_dicts(self, search_global=False): # Always False.
# `array.type` is a string with the type, e.g. 'list'. # `array.type` is a string with the type, e.g. 'list'.
scope = self._evaluator.find_types(compiled.builtin, self.type)[0] scope = list(self._evaluator.find_types(compiled.builtin, self.type))[0]
# builtins only have one class -> [0] # builtins only have one class -> [0]
scope = self._evaluator.execute(scope, (AlreadyEvaluated((self,)),))[0] scope = list(self._evaluator.execute(scope, (AlreadyEvaluated((self,)),)))[0]
return scope.names_dicts(search_global) return scope.names_dicts(search_global)
def py__bool__(self): def py__bool__(self):
@@ -217,23 +219,23 @@ class Array(IterableWrapper, ArrayMixin):
""" """
indexes = create_indexes_or_slices(evaluator, index) indexes = create_indexes_or_slices(evaluator, index)
lookup_done = False lookup_done = False
types = [] types = set()
for index in indexes: for index in indexes:
if isinstance(index, Slice): if isinstance(index, Slice):
types += [self] types.add(self)
lookup_done = True lookup_done = True
elif isinstance(index, compiled.CompiledObject) \ elif isinstance(index, compiled.CompiledObject) \
and isinstance(index.obj, (int, str, unicode)): and isinstance(index.obj, (int, str, unicode)):
with ignored(KeyError, IndexError, TypeError): with ignored(KeyError, IndexError, TypeError):
types += self.get_exact_index_types(index.obj) types |= self.get_exact_index_types(index.obj)
lookup_done = True lookup_done = True
return types if lookup_done else self.values() return types if lookup_done else self.values()
@memoize_default() @memoize_default()
def values(self): def values(self):
result = unite(self._evaluator.eval_element(v) for v in self._values()) result = set(unite(self._evaluator.eval_element(v) for v in self._values()))
result += check_array_additions(self._evaluator, self) result |= check_array_additions(self._evaluator, self)
return result return result
def get_exact_index_types(self, mixed_index): def get_exact_index_types(self, mixed_index):
@@ -353,7 +355,7 @@ class FakeDict(_FakeArray):
self._dct = dct self._dct = dct
def get_exact_index_types(self, index): def get_exact_index_types(self, index):
return unite(self._evaluator.eval_element(v) for v in self._dct[index]) return set(unite(self._evaluator.eval_element(v) for v in self._dct[index]))
def _items(self): def _items(self):
return self._dct.items() return self._dct.items()
@@ -368,7 +370,7 @@ class MergedArray(_FakeArray):
raise IndexError raise IndexError
def values(self): def values(self):
return unite((a.values() for a in self._arrays)) return set(unite((a.values() for a in self._arrays)))
def __iter__(self): def __iter__(self):
for array in self._arrays: for array in self._arrays:
@@ -397,24 +399,24 @@ def get_iterator_types(evaluator, element):
except KeyError: except KeyError:
debug.warning('iterators: No __iter__ method found.') debug.warning('iterators: No __iter__ method found.')
result = [] result = set()
from jedi.evaluate.representation import Instance from jedi.evaluate.representation import Instance
for it in iterators: for it in iterators:
if isinstance(it, Array): if isinstance(it, Array):
# Array is a little bit special, since this is an internal array, # Array is a little bit special, since this is an internal array,
# but there's also the list builtin, which is another thing. # but there's also the list builtin, which is another thing.
result += it.values() result |= it.values()
elif isinstance(it, Instance): elif isinstance(it, Instance):
# __iter__ returned an instance. # __iter__ returned an instance.
name = '__next__' if is_py3 else 'next' name = '__next__' if is_py3 else 'next'
try: try:
result += it.execute_subscope_by_name(name) result |= it.execute_subscope_by_name(name)
except KeyError: except KeyError:
debug.warning('Instance has no __next__ function in %s.', it) debug.warning('Instance has no __next__ function in %s.', it)
else: else:
# TODO this is not correct, __iter__ can return arbitrary input! # TODO this is not correct, __iter__ can return arbitrary input!
# Is a generator. # Is a generator.
result += it.iter_content() result |= it.iter_content()
return result return result
@@ -422,7 +424,7 @@ def check_array_additions(evaluator, array):
""" Just a mapper function for the internal _check_array_additions """ """ Just a mapper function for the internal _check_array_additions """
if array.type not in ('list', 'set'): if array.type not in ('list', 'set'):
# TODO also check for dict updates # TODO also check for dict updates
return [] return set()
is_list = array.type == 'list' is_list = array.type == 'list'
try: try:
@@ -431,7 +433,7 @@ def check_array_additions(evaluator, array):
# If there's no get_parent_until, it's a FakeSequence or another Fake # If there's no get_parent_until, it's a FakeSequence or another Fake
# type. Those fake types are used inside Jedi's engine. No values may # type. Those fake types are used inside Jedi's engine. No values may
# be added to those after their creation. # be added to those after their creation.
return [] return set()
return _check_array_additions(evaluator, array, current_module, is_list) return _check_array_additions(evaluator, array, current_module, is_list)
@@ -444,19 +446,19 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
>>> a.append(1) >>> a.append(1)
""" """
if not settings.dynamic_array_additions or isinstance(module, compiled.CompiledObject): if not settings.dynamic_array_additions or isinstance(module, compiled.CompiledObject):
return [] return set()
def check_additions(arglist, add_name): def check_additions(arglist, add_name):
params = list(param.Arguments(evaluator, arglist).unpack()) params = list(param.Arguments(evaluator, arglist).unpack())
result = [] result = set()
if add_name in ['insert']: if add_name in ['insert']:
params = params[1:] params = params[1:]
if add_name in ['append', 'add', 'insert']: if add_name in ['append', 'add', 'insert']:
for key, nodes in params: for key, nodes in params:
result += unite(evaluator.eval_element(node) for node in nodes) result |= set(unite(evaluator.eval_element(node) for node in nodes))
elif add_name in ['extend', 'update']: elif add_name in ['extend', 'update']:
for key, nodes in params: for key, nodes in params:
result += unite(get_iterator_types(evaluator, node) for node in nodes) result |= set(unite(get_iterator_types(evaluator, node) for node in nodes))
return result return result
from jedi.evaluate import representation as er, param from jedi.evaluate import representation as er, param
@@ -480,7 +482,7 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
search_names = ['append', 'extend', 'insert'] if is_list else ['add', 'update'] search_names = ['append', 'extend', 'insert'] if is_list else ['add', 'update']
comp_arr_parent = get_execution_parent(compare_array) comp_arr_parent = get_execution_parent(compare_array)
added_types = [] added_types = set()
for add_name in search_names: for add_name in search_names:
try: try:
possible_names = module.used_names[add_name] possible_names = module.used_names[add_name]
@@ -525,7 +527,7 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
continue continue
if compare_array in evaluator.eval_element(power): if compare_array in evaluator.eval_element(power):
# The arrays match. Now add the results # The arrays match. Now add the results
added_types += check_additions(execution_trailer.children[1], add_name) added_types |= check_additions(execution_trailer.children[1], add_name)
evaluator.recursion_detector.pop_stmt() evaluator.recursion_detector.pop_stmt()
# reset settings # reset settings
@@ -564,14 +566,14 @@ class ArrayInstance(IterableWrapper):
The index is here just ignored, because of all the appends, etc. The index is here just ignored, because of all the appends, etc.
lists/sets are too complicated too handle that. lists/sets are too complicated too handle that.
""" """
items = [] items = set()
for key, nodes in self.var_args.unpack(): for key, nodes in self.var_args.unpack():
for node in nodes: for node in nodes:
items += get_iterator_types(self._evaluator, node) items |= get_iterator_types(self._evaluator, node)
module = self.var_args.get_parent_until() module = self.var_args.get_parent_until()
is_list = str(self.instance.name) == 'list' is_list = str(self.instance.name) == 'list'
items += _check_array_additions(self._evaluator, self.instance, module, is_list) items |= _check_array_additions(self._evaluator, self.instance, module, is_list)
return items return items
@@ -624,5 +626,5 @@ def create_indexes_or_slices(evaluator, index):
result.append(el) result.append(el)
result += [None] * (3 - len(result)) result += [None] * (3 - len(result))
return (Slice(evaluator, *result),) return set([Slice(evaluator, *result)])
return evaluator.eval_element(index) return evaluator.eval_element(index)

View File

@@ -142,8 +142,8 @@ class Arguments(tree.Base):
debug.warning('TypeError: %s expected at least %s arguments, got %s', debug.warning('TypeError: %s expected at least %s arguments, got %s',
name, len(arguments), i) name, len(arguments), i)
raise ValueError raise ValueError
values = list(chain.from_iterable(self._evaluator.eval_element(el) values = set(chain.from_iterable(self._evaluator.eval_element(el)
for el in va_values)) for el in va_values))
if not values and not optional: if not values and not optional:
# For the stdlib we always want values. If we don't get them, # For the stdlib we always want values. If we don't get them,
# that's ok, maybe something is too hard to resolve, however, # that's ok, maybe something is too hard to resolve, however,
@@ -190,9 +190,9 @@ class ExecutedParam(tree.Param):
self._values = values self._values = values
def eval(self, evaluator): def eval(self, evaluator):
types = [] types = set()
for v in self._values: for v in self._values:
types += evaluator.eval_element(v) types |= evaluator.eval_element(v)
return types return types
@property @property

View File

@@ -26,13 +26,14 @@ COMPARISON_OPERATORS = {
def _literals_to_types(evaluator, result): def _literals_to_types(evaluator, result):
# Changes literals ('a', 1, 1.0, etc) to its type instances (str(), # Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
# int(), float(), etc). # int(), float(), etc).
result = list(result)
for i, r in enumerate(result): for i, r in enumerate(result):
if is_literal(r): if is_literal(r):
# Literals are only valid as long as the operations are # Literals are only valid as long as the operations are
# correct. Otherwise add a value-free instance. # correct. Otherwise add a value-free instance.
cls = builtin.get_by_name(r.name.get_code()) cls = builtin.get_by_name(r.name.get_code())
result[i] = evaluator.execute(cls)[0] result[i] = list(evaluator.execute(cls))[0]
return list(set(result)) return set(result)
def calculate_children(evaluator, children): def calculate_children(evaluator, children):
@@ -64,21 +65,21 @@ def calculate_children(evaluator, children):
def calculate(evaluator, left_result, operator, right_result): def calculate(evaluator, left_result, operator, right_result):
result = [] result = set()
if not left_result or not right_result: if not left_result or not right_result:
# illegal slices e.g. cause left/right_result to be None # illegal slices e.g. cause left/right_result to be None
result = (left_result or []) + (right_result or []) result = (left_result or set()) | (right_result or set())
result = _literals_to_types(evaluator, result) result = _literals_to_types(evaluator, result)
else: else:
# I don't think there's a reasonable chance that a string # I don't think there's a reasonable chance that a string
# operation is still correct, once we pass something like six # operation is still correct, once we pass something like six
# objects. # objects.
if len(left_result) * len(right_result) > 6: if len(left_result) * len(right_result) > 6:
result = _literals_to_types(evaluator, left_result + right_result) result = _literals_to_types(evaluator, left_result | right_result)
else: else:
for left in left_result: for left in left_result:
for right in right_result: for right in right_result:
result += _element_calculate(evaluator, left, operator, right) result |= _element_calculate(evaluator, left, operator, right)
return result return result
@@ -130,21 +131,21 @@ def _element_calculate(evaluator, left, operator, right):
if operator == '*': if operator == '*':
# for iterables, ignore * operations # for iterables, ignore * operations
if isinstance(left, iterable.Array) or is_string(left): if isinstance(left, iterable.Array) or is_string(left):
return [left] return set([left])
elif isinstance(right, iterable.Array) or is_string(right): elif isinstance(right, iterable.Array) or is_string(right):
return [right] return set([right])
elif operator == '+': elif operator == '+':
if l_is_num and r_is_num or is_string(left) and is_string(right): if l_is_num and r_is_num or is_string(left) and is_string(right):
return [create(evaluator, left.obj + right.obj)] return set([create(evaluator, left.obj + right.obj)])
elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right):
return [iterable.MergedArray(evaluator, (left, right))] return set([iterable.MergedArray(evaluator, (left, right))])
elif operator == '-': elif operator == '-':
if l_is_num and r_is_num: if l_is_num and r_is_num:
return [create(evaluator, left.obj - right.obj)] return set([create(evaluator, left.obj - right.obj)])
elif operator == '%': elif operator == '%':
# With strings and numbers the left type typically remains. Except for # With strings and numbers the left type typically remains. Except for
# `int() % float()`. # `int() % float()`.
return [left] return set([left])
elif operator in COMPARISON_OPERATORS: elif operator in COMPARISON_OPERATORS:
operation = COMPARISON_OPERATORS[operator] operation = COMPARISON_OPERATORS[operator]
if isinstance(left, CompiledObject) and isinstance(right, CompiledObject): if isinstance(left, CompiledObject) and isinstance(right, CompiledObject):
@@ -153,12 +154,12 @@ def _element_calculate(evaluator, left, operator, right):
right = right.obj right = right.obj
try: try:
return [keyword_from_value(operation(left, right))] return set([keyword_from_value(operation(left, right))])
except TypeError: except TypeError:
# Could be True or False. # Could be True or False.
return [true_obj, false_obj] return set([true_obj, false_obj])
elif operator == 'in': elif operator == 'in':
return [] return set()
def check(obj): def check(obj):
"""Checks if a Jedi object is either a float or an int.""" """Checks if a Jedi object is either a float or an int."""
@@ -171,4 +172,4 @@ def _element_calculate(evaluator, left, operator, right):
analysis.add(evaluator, 'type-error-operation', operator, analysis.add(evaluator, 'type-error-operation', operator,
message % (left, right)) message % (left, right))
return [left, right] return set([left, right])

View File

@@ -95,7 +95,7 @@ def execution_recursion_decorator(func):
def run(execution, **kwargs): def run(execution, **kwargs):
detector = execution._evaluator.execution_recursion_detector detector = execution._evaluator.execution_recursion_detector
if detector.push_execution(execution): if detector.push_execution(execution):
result = [] result = set()
else: else:
result = func(execution, **kwargs) result = func(execution, **kwargs)
detector.pop_execution() detector.pop_execution()

View File

@@ -180,7 +180,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
try: try:
return self.execute_subscope_by_name('__get__', *args) return self.execute_subscope_by_name('__get__', *args)
except KeyError: except KeyError:
return [self] return set([self])
@memoize_default() @memoize_default()
def names_dicts(self, search_global): def names_dicts(self, search_global):
@@ -207,7 +207,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
method = self.get_subscope_by_name('__getitem__') method = self.get_subscope_by_name('__getitem__')
except KeyError: except KeyError:
debug.warning('No __getitem__, cannot access the array.') debug.warning('No __getitem__, cannot access the array.')
return [] return set()
else: else:
return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)]) return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)])
@@ -440,7 +440,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
return [compiled.object_obj] return [compiled.object_obj]
def py__call__(self, evaluator, params): def py__call__(self, evaluator, params):
return [Instance(evaluator, self, params)] return set([Instance(evaluator, self, params)])
def py__getattribute__(self, name): def py__getattribute__(self, name):
return self._evaluator.find_types(self, name) return self._evaluator.find_types(self, name)
@@ -541,7 +541,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
# TODO resolve issue with multiple wrappers -> multiple types # TODO resolve issue with multiple wrappers -> multiple types
debug.warning('multiple wrappers found %s %s', debug.warning('multiple wrappers found %s %s',
self.base_func, wrappers) self.base_func, wrappers)
f = wrappers[0] f = list(wrappers)[0]
if isinstance(f, (Instance, Function)): if isinstance(f, (Instance, Function)):
f.decorates = self f.decorates = self
@@ -558,7 +558,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
@Python3Method @Python3Method
def py__call__(self, evaluator, params): def py__call__(self, evaluator, params):
if self.base.is_generator(): if self.base.is_generator():
return [iterable.Generator(evaluator, self, params)] return set([iterable.Generator(evaluator, self, params)])
else: else:
return FunctionExecution(evaluator, self, params).get_return_types() return FunctionExecution(evaluator, self, params).get_return_types()
@@ -613,21 +613,21 @@ class FunctionExecution(Executed):
# If we do have listeners, that means that there's not a regular # If we do have listeners, that means that there's not a regular
# execution ongoing. In this case Jedi is interested in the # execution ongoing. In this case Jedi is interested in the
# inserted params, not in the actual execution of the function. # inserted params, not in the actual execution of the function.
return [] return set()
if check_yields: if check_yields:
types = [] types = set()
returns = self.yields returns = self.yields
else: else:
returns = self.returns returns = self.returns
types = list(docstrings.find_return_types(self._evaluator, func)) types = set(docstrings.find_return_types(self._evaluator, func))
for r in returns: for r in returns:
check = flow_analysis.break_check(self._evaluator, self, r) check = flow_analysis.break_check(self._evaluator, self, r)
if check is flow_analysis.UNREACHABLE: if check is flow_analysis.UNREACHABLE:
debug.dbg('Return unreachable: %s', r) debug.dbg('Return unreachable: %s', r)
else: else:
types += self._evaluator.eval_element(r.children[1]) types |= self._evaluator.eval_element(r.children[1])
if check is flow_analysis.REACHABLE: if check is flow_analysis.REACHABLE:
debug.dbg('Return reachable: %s', r) debug.dbg('Return reachable: %s', r)
break break
@@ -748,7 +748,8 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
@memoize_default() @memoize_default()
def _module_attributes_dict(self): def _module_attributes_dict(self):
def parent_callback(): def parent_callback():
return self._evaluator.execute(compiled.create(self._evaluator, str))[0] # Create a string type object (without a defined string in it):
return list(self._evaluator.execute(compiled.create(self._evaluator, str)))[0]
names = ['__file__', '__package__', '__doc__', '__name__'] names = ['__file__', '__package__', '__doc__', '__name__']
# All the additional module attributes are strings. # All the additional module attributes are strings.

View File

@@ -80,7 +80,7 @@ def argument_clinic(string, want_obj=False, want_scope=False, want_arguments=Fal
try: try:
lst = list(arguments.eval_argument_clinic(clinic_args)) lst = list(arguments.eval_argument_clinic(clinic_args))
except ValueError: except ValueError:
return [] return set()
else: else:
kwargs = {} kwargs = {}
if want_scope: if want_scope:
@@ -97,7 +97,6 @@ def argument_clinic(string, want_obj=False, want_scope=False, want_arguments=Fal
@argument_clinic('object, name[, default], /') @argument_clinic('object, name[, default], /')
def builtins_getattr(evaluator, objects, names, defaults=None): def builtins_getattr(evaluator, objects, names, defaults=None):
types = []
# follow the first param # follow the first param
for obj in objects: for obj in objects:
if not isinstance(obj, (er.Instance, er.Class, tree.Module, compiled.CompiledObject)): if not isinstance(obj, (er.Instance, er.Class, tree.Module, compiled.CompiledObject)):
@@ -110,16 +109,16 @@ def builtins_getattr(evaluator, objects, names, defaults=None):
else: else:
debug.warning('getattr called without str') debug.warning('getattr called without str')
continue continue
return types return set()
@argument_clinic('object[, bases, dict], /') @argument_clinic('object[, bases, dict], /')
def builtins_type(evaluator, objects, bases, dicts): def builtins_type(evaluator, objects, bases, dicts):
if bases or dicts: if bases or dicts:
# It's a type creation... maybe someday... # It's a type creation... maybe someday...
return [] return set()
else: else:
return [o.py__class__(evaluator) for o in objects] return set([o.py__class__(evaluator) for o in objects])
class SuperInstance(er.Instance): class SuperInstance(er.Instance):
@@ -145,20 +144,20 @@ def builtins_super(evaluator, types, objects, scope):
su = cls.py__bases__(evaluator) su = cls.py__bases__(evaluator)
if su: if su:
return evaluator.execute(su[0]) return evaluator.execute(su[0])
return [] return set()
def get_iterable_content(evaluator, arguments, argument_index): def get_iterable_content(evaluator, arguments, argument_index):
nodes = list(arguments.unpack())[argument_index][1] nodes = list(arguments.unpack())[argument_index][1]
return tuple(iterable.unite(iterable.get_iterator_types(evaluator, node) return set(iterable.unite(iterable.get_iterator_types(evaluator, node)
for node in nodes)) for node in nodes))
@argument_clinic('sequence, /', want_obj=True, want_arguments=True) @argument_clinic('sequence, /', want_obj=True, want_arguments=True)
def builtins_reversed(evaluator, sequences, obj, arguments): def builtins_reversed(evaluator, sequences, obj, arguments):
# Unpack the iterator values # Unpack the iterator values
objects = get_iterable_content(evaluator, arguments, 0) objects = get_iterable_content(evaluator, arguments, 0)
rev = [iterable.AlreadyEvaluated([o]) for o in reversed(objects)] rev = [iterable.AlreadyEvaluated([o]) for o in reversed(list(objects))]
# Repack iterator values and then run it the normal way. This is # Repack iterator values and then run it the normal way. This is
# necessary, because `reversed` is a function and autocompletion # necessary, because `reversed` is a function and autocompletion
# would fail in certain cases like `reversed(x).__iter__` if we # would fail in certain cases like `reversed(x).__iter__` if we
@@ -166,7 +165,7 @@ def builtins_reversed(evaluator, sequences, obj, arguments):
rev = iterable.AlreadyEvaluated( rev = iterable.AlreadyEvaluated(
[iterable.FakeSequence(evaluator, rev, 'list')] [iterable.FakeSequence(evaluator, rev, 'list')]
) )
return [er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))] return set([er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))])
@argument_clinic('obj, type, /', want_arguments=True) @argument_clinic('obj, type, /', want_arguments=True)
@@ -179,7 +178,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
# This is temporary. Everything should have a class attribute in # This is temporary. Everything should have a class attribute in
# Python?! Maybe we'll leave it here, because some numpy objects or # Python?! Maybe we'll leave it here, because some numpy objects or
# whatever might not. # whatever might not.
return [compiled.true_obj, compiled.false_obj] return set([compiled.true_obj, compiled.false_obj])
mro = mro_func(evaluator) mro = mro_func(evaluator)
@@ -191,7 +190,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
classes = get_iterable_content(evaluator, arguments, 1) classes = get_iterable_content(evaluator, arguments, 1)
bool_results.add(any(cls in mro for cls in classes)) bool_results.add(any(cls in mro for cls in classes))
return [compiled.keyword_from_value(x) for x in bool_results] return set(compiled.keyword_from_value(x) for x in bool_results)
def collections_namedtuple(evaluator, obj, arguments): def collections_namedtuple(evaluator, obj, arguments):
@@ -206,7 +205,7 @@ def collections_namedtuple(evaluator, obj, arguments):
""" """
# Namedtuples are not supported on Python 2.6 # Namedtuples are not supported on Python 2.6
if not hasattr(collections, '_class_template'): if not hasattr(collections, '_class_template'):
return [] return set()
# Process arguments # Process arguments
name = _follow_param(evaluator, arguments, 0)[0].obj name = _follow_param(evaluator, arguments, 0)[0].obj
@@ -217,9 +216,9 @@ def collections_namedtuple(evaluator, obj, arguments):
try: try:
fields = [v.obj for v in _fields.values()] fields = [v.obj for v in _fields.values()]
except AttributeError: except AttributeError:
return [] return set()
else: else:
return [] return set()
# Build source # Build source
source = collections._class_template.format( source = collections._class_template.format(
@@ -234,7 +233,7 @@ def collections_namedtuple(evaluator, obj, arguments):
# Parse source # Parse source
generated_class = Parser(evaluator.grammar, unicode(source)).module.subscopes[0] generated_class = Parser(evaluator.grammar, unicode(source)).module.subscopes[0]
return [er.Class(evaluator, generated_class)] return set(er.Class(evaluator, generated_class))
@argument_clinic('first, /') @argument_clinic('first, /')
@@ -255,8 +254,8 @@ _implemented = {
'deepcopy': _return_first_param, 'deepcopy': _return_first_param,
}, },
'json': { 'json': {
'load': lambda *args: [], 'load': lambda *args: set(),
'loads': lambda *args: [], 'loads': lambda *args: set(),
}, },
'collections': { 'collections': {
'namedtuple': collections_namedtuple, 'namedtuple': collections_namedtuple,