From 174eff58758a6ee57add114ce6fc5f735afbc19a Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Mon, 25 Sep 2017 23:08:59 +0200 Subject: [PATCH] Replace a lot more of empty sets and unite calls. --- jedi/common/context.py | 3 +++ jedi/evaluate/__init__.py | 2 +- jedi/evaluate/docstrings.py | 10 ++++++-- jedi/evaluate/dynamic.py | 7 +++--- jedi/evaluate/filters.py | 6 ++--- jedi/evaluate/finder.py | 8 ++----- jedi/evaluate/imports.py | 13 ++++------- jedi/evaluate/instance.py | 11 ++++----- jedi/evaluate/iterable.py | 17 +++++++------- jedi/evaluate/param.py | 3 ++- jedi/evaluate/pep0484.py | 5 ++-- jedi/evaluate/precedence.py | 4 ++-- jedi/evaluate/recursion.py | 3 ++- jedi/evaluate/stdlib.py | 46 +++++++++++++++++++------------------ 14 files changed, 72 insertions(+), 66 deletions(-) diff --git a/jedi/common/context.py b/jedi/common/context.py index b29b7c2f..95c4671b 100644 --- a/jedi/common/context.py +++ b/jedi/common/context.py @@ -35,6 +35,9 @@ class ContextSet(object): def __bool__(self): return bool(self._set) + def __len__(self): + return len(self._set) + def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join(str(s) for s in self._set)) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 7cff98d4..35c4256e 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -433,7 +433,7 @@ class Evaluator(object): node = () if trailer_op == '[': - return ContextSet(iterable.py__getitem__(self, context, types, trailer)) + return iterable.py__getitem__(self, context, types, trailer) else: context_set = ContextSet() for typ in types: diff --git a/jedi/evaluate/docstrings.py b/jedi/evaluate/docstrings.py index 43c950ed..ea471811 100644 --- a/jedi/evaluate/docstrings.py +++ b/jedi/evaluate/docstrings.py @@ -223,7 +223,10 @@ def _execute_types_in_stmt(module_context, stmt): contain is executed. (Used as type information). """ definitions = module_context.eval_node(stmt) - return unite(_execute_array_values(module_context.evaluator, d) for d in definitions) + return ContextSet.from_sets( + _execute_array_values(module_context.evaluator, d) + for d in definitions + ) def _execute_array_values(evaluator, array): @@ -234,7 +237,10 @@ def _execute_array_values(evaluator, array): if isinstance(array, SequenceLiteralContext): values = [] for lazy_context in array.py__iter__(): - objects = unite(_execute_array_values(evaluator, typ) for typ in lazy_context.infer()) + objects = ContextSet.from_sets( + _execute_array_values(evaluator, typ) + for typ in lazy_context.infer() + ) values.append(context.LazyKnownContexts(objects)) return set([FakeSequence(evaluator, array.array_type, values)]) else: diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index fb179b58..946d81e2 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -24,7 +24,8 @@ from jedi.evaluate.cache import evaluator_function_cache from jedi.evaluate import imports from jedi.evaluate.param import TreeArguments, create_default_params from jedi.evaluate.helpers import is_stdlib_path -from jedi.evaluate.utils import to_list, unite +from jedi.evaluate.utils import to_list +from jedi.common import ContextSet from jedi.parser_utils import get_parent_scope @@ -50,7 +51,7 @@ class MergedExecutedParams(object): self._executed_params = executed_params def infer(self): - return unite(p.infer() for p in self._executed_params) + return ContextSet.from_sets(p.infer() for p in self._executed_params) @debug.increase_indent @@ -103,7 +104,7 @@ def search_params(evaluator, execution_context, funcdef): evaluator.dynamic_params_depth -= 1 -@evaluator_function_cache(default=[]) +@evaluator_function_cache(default=None) @to_list def _search_function_executions(evaluator, module_context, funcdef): """ diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index c94f9758..e3edb1eb 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -6,9 +6,9 @@ from abc import abstractmethod from parso.tree import search_ancestor from jedi.evaluate import flow_analysis -from jedi.evaluate.utils import to_list, unite from jedi.common import ContextSet from jedi.parser_utils import get_parent_scope +from jedi.evaluate.utils import to_list class AbstractNameDefinition(object): @@ -36,10 +36,10 @@ class AbstractNameDefinition(object): return '<%s: %s@%s>' % (self.__class__.__name__, self.string_name, self.start_pos) def execute(self, arguments): - return unite(context.execute(arguments) for context in self.infer()) + return self.infer().execute(arguments) def execute_evaluated(self, *args, **kwargs): - return unite(context.execute_evaluated(*args, **kwargs) for context in self.infer()) + return self.infer().execute_evaluated(*args, **kwargs) @property def api_type(self): diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 3e5e2ef5..15d45108 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -233,10 +233,7 @@ def _name_to_types(evaluator, context, tree_name): # TODO check for types that are not classes and add it to # the static analysis report. exceptions = context.eval_node(tree_name.get_previous_sibling().get_previous_sibling()) - types = unite( - evaluator.execute(t, param.ValuesArguments([])) - for t in exceptions - ) + types = exceptions.execute_evaluated() else: raise ValueError("Should not happen.") return types @@ -274,8 +271,7 @@ def _apply_decorators(evaluator, context, node): debug.warning('decorator not found: %s on %s', dec, node) return initial - values = unite(dec_value.execute(param.ValuesArguments([values])) - for dec_value in dec_values) + values = dec_values.execute(param.ValuesArguments([values])) if not len(values): debug.warning('not possible to resolve wrappers found %s', node) return initial diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 75139d15..5d69e931 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -24,7 +24,6 @@ from parso import python_bytes_to_unicode from jedi._compatibility import find_module, unicode, ImplicitNSInfo from jedi import debug from jedi import settings -from jedi.evaluate.utils import unite from jedi.evaluate import sys_path from jedi.evaluate import helpers from jedi.evaluate import compiled @@ -67,13 +66,11 @@ def infer_import(context, tree_name, is_goto=False): return NO_CONTEXTS if from_import_name is not None: - types = unite( - t.py__getattribute__( - from_import_name, - name_context=context, - is_goto=is_goto, - analysis_errors=False - ) for t in types + types = types.py__getattribute__( + from_import_name, + name_context=context, + is_goto=is_goto, + analysis_errors=False ) if not types: diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index f8df7a1b..f1116707 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -1,7 +1,6 @@ from abc import abstractproperty from jedi._compatibility import is_py3 -from jedi.evaluate.utils import unite from jedi import debug from jedi.evaluate import compiled from jedi.evaluate import filters @@ -11,7 +10,7 @@ from jedi.evaluate.param import AbstractArguments, AnonymousArguments from jedi.cache import memoize_method from jedi.evaluate import representation as er from jedi.evaluate import iterable -from jedi.common import ContextSet, iterator_to_context_set +from jedi.common import ContextSet, iterator_to_context_set, NO_CONTEXTS from jedi.parser_utils import get_parent_scope @@ -59,7 +58,7 @@ class AbstractInstanceContext(Context): raise AttributeError def execute(arguments): - return unite(name.execute(arguments) for name in names) + return ContextSet.from_sets(name.execute(arguments) for name in names) return execute @@ -81,7 +80,7 @@ class AbstractInstanceContext(Context): return [] def execute_function_slots(self, names, *evaluated_args): - return unite( + return ContextSet.from_sets( name.execute_evaluated(*evaluated_args) for name in names ) @@ -97,7 +96,7 @@ class AbstractInstanceContext(Context): none_obj = compiled.create(self.evaluator, None) return self.execute_function_slots(names, none_obj, obj) else: - return set([self]) + return ContextSet(self) def get_filters(self, search_global=None, until_position=None, origin_scope=None, include_self_names=True): @@ -123,7 +122,7 @@ class AbstractInstanceContext(Context): names = self.get_function_slot_names('__getitem__') except KeyError: debug.warning('No __getitem__, cannot access the array.') - return set() + return NO_CONTEXTS else: index_obj = compiled.create(self.evaluator, index) return self.execute_function_slots(names, index_obj) diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index cee0879b..dcc2b939 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -144,7 +144,7 @@ class GeneratorMixin(object): @register_builtin_method('__next__', python_version_match=3) def py__next__(self): # TODO add TypeError if params are given. - return unite(lazy_context.infer() for lazy_context in self.py__iter__()) + return ContextSet.from_sets(lazy_context.infer() for lazy_context in self.py__iter__()) def get_filters(self, search_global, until_position=None, origin_scope=None): gen_obj = compiled.get_special_object(self.evaluator, 'GENERATOR_OBJECT') @@ -297,7 +297,8 @@ class ArrayMixin(object): return self.evaluator.BUILTINS def dict_values(self): - return unite(self._defining_context.eval_node(v) for k, v in self._items()) + return ContextSet.from_sets(self._defining_context.eval_node(v) + for k, v in self._items()) class ListComprehension(ArrayMixin, Comprehension): @@ -335,7 +336,7 @@ class DictComprehension(ArrayMixin, Comprehension): return self.dict_values() def dict_values(self): - return unite(values for keys, values in self._iterate()) + return ContextSet.from_sets(values for keys, values in self._iterate()) @register_builtin_method('values') def _imitate_values(self): @@ -414,7 +415,7 @@ class SequenceLiteralContext(ArrayMixin, AbstractSequence): def _values(self): """Returns a list of a list of node.""" if self.array_type == 'dict': - return unite(v for k, v in self._items()) + return ContextSet.from_sets(v for k, v in self._items()) else: return self._items() @@ -532,7 +533,7 @@ class FakeDict(_FakeArray): return self._dct[index].infer() def dict_values(self): - return unite(lazy_context.infer() for lazy_context in self._dct.values()) + return ContextSet.from_sets(lazy_context.infer() for lazy_context in self._dct.values()) def _items(self): raise DeprecationWarning @@ -555,7 +556,7 @@ class MergedArray(_FakeArray): yield lazy_context def py__getitem__(self, index): - return unite(lazy_context.infer() for lazy_context in self.py__iter__()) + return ContextSet.from_sets(lazy_context.infer() for lazy_context in self.py__iter__()) def _items(self): for array in self._arrays: @@ -633,7 +634,7 @@ def py__iter__types(evaluator, types, contextualized_node=None): Calls `py__iter__`, but ignores the ordering in the end and just returns all types that it contains. """ - return unite( + return ContextSet.from_sets( lazy_context.infer() for lazy_context in py__iter__(evaluator, types, contextualized_node) ) @@ -740,7 +741,7 @@ def _check_array_additions(context, sequence): is_list = sequence.name.string_name == 'list' search_names = (['append', 'extend', 'insert'] if is_list else ['add', 'update']) - added_types = NO_CONTEXTS() + added_types = NO_CONTEXTS for add_name in search_names: try: possible_names = module_context.tree_node.get_used_names()[add_name] diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 04d93d42..a914d81a 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -10,6 +10,7 @@ from jedi.evaluate import context from jedi.evaluate import docstrings from jedi.evaluate import pep0484 from jedi.evaluate.filters import ParamName +from jedi.common import NO_CONTEXTS def add_argument_issue(parent_context, error_name, lazy_context, message): @@ -51,7 +52,7 @@ class AbstractArguments(): debug.warning('TypeError: %s expected at least %s arguments, got %s', name, len(parameters), i) raise ValueError - values = set() if argument is None else argument.infer() + values = NO_CONTEXTS if argument is None else argument.infer() if not values and not optional: # For the stdlib we always want values. If we don't get them, diff --git a/jedi/evaluate/pep0484.py b/jedi/evaluate/pep0484.py index 8e741fb0..0fa7ca41 100644 --- a/jedi/evaluate/pep0484.py +++ b/jedi/evaluate/pep0484.py @@ -25,11 +25,10 @@ import re from parso import ParserSyntaxError from parso.python import tree -from jedi.evaluate.utils import unite from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate import compiled from jedi.evaluate.context import LazyTreeContext -from jedi.common import NO_CONTEXTS +from jedi.common import NO_CONTEXTS, ContextSet from jedi import debug from jedi import _compatibility from jedi import parser_utils @@ -146,7 +145,7 @@ def py__getitem__(context, typ, node): if type_name in ("Union", '_Union'): # In Python 3.6 it's still called typing.Union but it's an instance # called _Union. - return unite(context.eval_node(node) for node in nodes) + return ContextSet.from_sets(context.eval_node(node) for node in nodes) if type_name in ("Optional", '_Optional'): # Here we have the same issue like in Union. Therefore we also need to # check for the instance typing._Optional (Python 3.6). diff --git a/jedi/evaluate/precedence.py b/jedi/evaluate/precedence.py index 5d6aef13..72b7a432 100644 --- a/jedi/evaluate/precedence.py +++ b/jedi/evaluate/precedence.py @@ -7,7 +7,7 @@ from jedi._compatibility import unicode from jedi import debug from jedi.evaluate.compiled import CompiledObject, create, builtin_from_name from jedi.evaluate import analysis -from jedi.common import ContextSet +from jedi.common import ContextSet, NO_CONTEXTS # Maps Python syntax to the operator module. COMPARISON_OPERATORS = { @@ -162,7 +162,7 @@ def _element_calculate(evaluator, context, left, operator, right): else: return ContextSet(create(evaluator, result)) elif operator == 'in': - return set() + return NO_CONTEXTS def check(obj): """Checks if a Jedi object is either a float or an int.""" diff --git a/jedi/evaluate/recursion.py b/jedi/evaluate/recursion.py index 85499496..ebc71f09 100644 --- a/jedi/evaluate/recursion.py +++ b/jedi/evaluate/recursion.py @@ -29,6 +29,7 @@ therefore the quality might not always be maximal. from contextlib import contextmanager from jedi import debug +from jedi.common import NO_CONTEXTS recursion_limit = 15 @@ -71,7 +72,7 @@ def execution_allowed(evaluator, node): pushed_nodes.pop() -def execution_recursion_decorator(default=set()): +def execution_recursion_decorator(default=NO_CONTEXTS): def decorator(func): def wrapper(execution, **kwargs): detector = execution.evaluator.execution_recursion_detector diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index f2878e71..053f2b9c 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -24,6 +24,7 @@ from jedi.evaluate import precedence from jedi.evaluate import param from jedi.evaluate import analysis from jedi.evaluate.context import LazyTreeContext, ContextualizedNode +from jedi.common import NO_CONTEXTS, ContextSet # Now this is all part of fake tuples in Jedi. However super doesn't work on # __init__ and __new__ doesn't work at all. So adding this to nametuples is @@ -77,7 +78,7 @@ def _follow_param(evaluator, arguments, index): try: key, lazy_context = list(arguments.unpack())[index] except IndexError: - return set() + return NO_CONTEXTS else: return lazy_context.infer() @@ -109,7 +110,7 @@ def argument_clinic(string, want_obj=False, want_context=False, want_arguments=F try: lst = list(arguments.eval_argument_clinic(clinic_args)) except ValueError: - return set() + return NO_CONTEXTS else: kwargs = {} if want_context: @@ -137,15 +138,16 @@ def builtins_next(evaluator, iterators, defaults): else: name = '__next__' - types = set() + context_set = NO_CONTEXTS for iterator in iterators: if isinstance(iterator, AbstractInstanceContext): - for filter in iterator.get_filters(include_self_names=True): - for n in filter.get(name): - for context in n.infer(): - types |= context.execute_evaluated() - if types: - return types + context_set = ContextSet.from_sets( + n.infer() + for filter in iterator.get_filters(include_self_names=True) + for n in filter.get(name) + ).execute_evaluated() + if context_set: + return context_set return defaults @@ -159,16 +161,16 @@ def builtins_getattr(evaluator, objects, names, defaults=None): else: debug.warning('getattr called without str') continue - return set() + return NO_CONTEXTS @argument_clinic('object[, bases, dict], /') def builtins_type(evaluator, objects, bases, dicts): if bases or dicts: # It's a type creation... maybe someday... - return set() + return NO_CONTEXTS else: - return set([o.py__class__() for o in objects]) + return ContextSet.from_iterable(o.py__class__() for o in objects) class SuperInstance(AbstractInstanceContext): @@ -185,7 +187,7 @@ def builtins_super(evaluator, types, objects, context): AnonymousInstanceFunctionExecution)): su = context.instance.py__class__().py__bases__() return unite(context.execute_evaluated() for context in su[0].infer()) - return set() + return NO_CONTEXTS @argument_clinic('sequence, /', want_obj=True, want_arguments=True) @@ -207,12 +209,12 @@ def builtins_reversed(evaluator, sequences, obj, arguments): # just returned the result directly. seq = iterable.FakeSequence(evaluator, 'list', rev) arguments = param.ValuesArguments([[seq]]) - return set([CompiledInstance(evaluator, evaluator.BUILTINS, obj, arguments)]) + return ContextSet(CompiledInstance(evaluator, evaluator.BUILTINS, obj, arguments)) @argument_clinic('obj, type, /', want_arguments=True) def builtins_isinstance(evaluator, objects, types, arguments): - bool_results = set([]) + bool_results = set() for o in objects: try: mro_func = o.py__class__().py__mro__ @@ -220,7 +222,7 @@ def builtins_isinstance(evaluator, objects, types, arguments): # This is temporary. Everything should have a class attribute in # Python?! Maybe we'll leave it here, because some numpy objects or # whatever might not. - return set([compiled.create(True), compiled.create(False)]) + return ContextSet(compiled.create(True), compiled.create(False)) mro = mro_func() @@ -244,7 +246,7 @@ def builtins_isinstance(evaluator, objects, types, arguments): 'not %s.' % cls_or_tup analysis.add(lazy_context._context, 'type-error-isinstance', node, message) - return set(compiled.create(evaluator, x) for x in bool_results) + return ContextSet.from_iterable(compiled.create(evaluator, x) for x in bool_results) def collections_namedtuple(evaluator, obj, arguments): @@ -259,7 +261,7 @@ def collections_namedtuple(evaluator, obj, arguments): """ # Namedtuples are not supported on Python 2.6 if not hasattr(collections, '_class_template'): - return set() + return NO_CONTEXTS # Process arguments # TODO here we only use one of the types, we should use all. @@ -274,7 +276,7 @@ def collections_namedtuple(evaluator, obj, arguments): for v in lazy_context.infer() if hasattr(v, 'obj') ] else: - return set() + return NO_CONTEXTS base = collections._class_template base += _NAMEDTUPLE_INIT @@ -293,7 +295,7 @@ def collections_namedtuple(evaluator, obj, arguments): module = evaluator.grammar.parse(source) generated_class = next(module.iter_classdefs()) parent_context = er.ModuleContext(evaluator, module, '') - return set([er.ClassContext(evaluator, generated_class, parent_context)]) + return ContextSet(er.ClassContext(evaluator, generated_class, parent_context)) @argument_clinic('first, /') @@ -314,8 +316,8 @@ _implemented = { 'deepcopy': _return_first_param, }, 'json': { - 'load': lambda *args: set(), - 'loads': lambda *args: set(), + 'load': lambda *args: NO_CONTEXTS, + 'loads': lambda *args: NO_CONTEXTS, }, 'collections': { 'namedtuple': collections_namedtuple,