diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index 88a2fde8..dba8a868 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -5,11 +5,11 @@ from jedi.parser import representation as pr from jedi import debug -def fast_parent_copy(obj): +def fast_parent_copy(obj, new_elements_default=None): """ Much, much faster than copy.deepcopy, but just for certain elements. """ - new_elements = {} + new_elements = new_elements_default or {} accept = (pr.Simple, pr.NamePart) def recursion(obj): @@ -18,8 +18,11 @@ def fast_parent_copy(obj): # correctly, don't know why. obj.get_defined_names() - new_obj = copy.copy(obj) - new_elements[obj] = new_obj + try: + return new_elements[obj] + except KeyError: + new_obj = copy.copy(obj) + new_elements[obj] = new_obj try: items = list(new_obj.__dict__.items()) @@ -48,10 +51,7 @@ def fast_parent_copy(obj): elif isinstance(value, (list, tuple)): setattr(new_obj, key, list_or_tuple_rec(value)) elif isinstance(value, accept): - try: - setattr(new_obj, key, new_elements[value]) - except KeyError: - setattr(new_obj, key, recursion(value)) + setattr(new_obj, key, recursion(value)) return new_obj def list_or_tuple_rec(array_obj): @@ -61,10 +61,7 @@ def fast_parent_copy(obj): copied_array = array_obj[:] # lists, tuples, strings, unicode for i, el in enumerate(copied_array): if isinstance(el, accept): - try: - copied_array[i] = new_elements[el] - except KeyError: - copied_array[i] = recursion(el) + copied_array[i] = recursion(el) elif isinstance(el, (tuple, list)): copied_array[i] = list_or_tuple_rec(el) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index fb9d0fad..b10127fd 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -507,6 +507,11 @@ class FunctionExecution(Executed): multiple calls to functions and recursion has to be avoided. But this is responsibility of the decorators. """ + def __init__(self, evaluator, base, *args, **kwargs): + super(FunctionExecution, self).__init__(evaluator, base, *args, **kwargs) + # for fast_parent_copy + self._copy_dict = {base.base_func: self} + @memoize_default(default=()) @recursion.execution_recursion_decorator def get_return_types(self): @@ -571,13 +576,13 @@ class FunctionExecution(Executed): objects = [] for element in attr: if element is None: - copied = element + copied = None else: - copied = helpers.fast_parent_copy(element) - copied.parent = self._scope_copy(copied.parent) + self._scope_copy(element.parent) + copied = helpers.fast_parent_copy(element, self._copy_dict) # TODO remove? Doesn't make sense, at least explain. - if isinstance(copied, pr.Function): - copied = Function(self._evaluator, copied) + #if isinstance(copied, pr.Function): + #copied = Function(self._evaluator, copied) objects.append(copied) return objects @@ -596,8 +601,9 @@ class FunctionExecution(Executed): if scope.start_pos == self.start_pos: return self else: - copied = helpers.fast_parent_copy(scope) - copied.parent = self._scope_copy(copied.parent) + self._scope_copy(scope.parent) + copied = helpers.fast_parent_copy(scope, self._copy_dict) + #copied.parent = self._scope_copy(copied.parent) return copied @common.safe_property diff --git a/test/completion/isinstance.py b/test/completion/isinstance.py index 0a08ca86..e44312f5 100644 --- a/test/completion/isinstance.py +++ b/test/completion/isinstance.py @@ -43,11 +43,12 @@ def fooooo(obj): def fooooo2(obj): - if isinstance(obj, datetime.datetime): + if isinstance(obj, datetime.date): return obj else: return 1 +a # In earlier versions of Jedi, this returned both datetime and int, but now # Jedi does flow checks and realizes that the top return isn't executed. #? int()