mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-16 02:27:06 +08:00
Use the memoize function for faked arguments only when needed.
It's important to note that memoizing every object would mean that theoretically all objects passed through get_faked would get memoized. This would have been a possible memory leak, which we should avoid. Obviously the previous solution proposed in #649 was still better, but this issue was a new one. Also using str() around keys was not a good idea. Refs #649.
This commit is contained in:
@@ -91,18 +91,6 @@ def memoize_method(method):
|
||||
return wrapper
|
||||
|
||||
|
||||
def memoize_function(obj):
|
||||
""" A normal memoize function for memoizing free functions. """
|
||||
cache = obj.cache = {}
|
||||
|
||||
def memoizer(*args, **kwargs):
|
||||
key = str(args) + str(kwargs)
|
||||
if key not in cache:
|
||||
cache[key] = obj(*args, **kwargs)
|
||||
return cache[key]
|
||||
return memoizer
|
||||
|
||||
|
||||
def cache_star_import(func):
|
||||
@time_cache("star_import_cache_validity")
|
||||
def wrapper(self):
|
||||
|
||||
@@ -222,10 +222,12 @@ class CompiledObject(Base):
|
||||
module = self.get_parent_until()
|
||||
faked_subscopes = []
|
||||
for name in dir(self.obj):
|
||||
f = fake.get_faked(module.obj, self.obj, name)
|
||||
if f:
|
||||
f.parent = self
|
||||
faked_subscopes.append(f)
|
||||
try:
|
||||
faked_subscopes.append(
|
||||
fake.get_faked(module.obj, self.obj, parent=self, name=name)
|
||||
)
|
||||
except fake.FakeDoesNotExist:
|
||||
pass
|
||||
return faked_subscopes
|
||||
|
||||
def is_scope(self):
|
||||
@@ -445,16 +447,15 @@ def _parse_function_doc(doc):
|
||||
|
||||
|
||||
def _create_from_name(evaluator, module, parent, name):
|
||||
faked = fake.get_faked(module.obj, parent.obj, name)
|
||||
# only functions are necessary.
|
||||
if faked is not None:
|
||||
faked.parent = parent
|
||||
return faked
|
||||
try:
|
||||
return fake.get_faked(module.obj, parent.obj, parent=parent, name=name)
|
||||
except fake.FakeDoesNotExist:
|
||||
pass
|
||||
|
||||
try:
|
||||
obj = getattr(parent.obj, name)
|
||||
except AttributeError:
|
||||
# happens e.g. in properties of
|
||||
# Happens e.g. in properties of
|
||||
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
||||
# -> just set it to None
|
||||
obj = None
|
||||
@@ -527,9 +528,9 @@ def create(evaluator, obj, parent=None, module=None):
|
||||
if parent is None and obj != _builtins:
|
||||
return create(evaluator, obj, create(evaluator, _builtins))
|
||||
|
||||
faked = fake.get_faked(module and module.obj, obj)
|
||||
if faked is not None:
|
||||
faked.parent = parent
|
||||
return faked
|
||||
try:
|
||||
return fake.get_faked(module and module.obj, obj, parent=parent)
|
||||
except fake.FakeDoesNotExist:
|
||||
pass
|
||||
|
||||
return CompiledObject(evaluator, obj, parent)
|
||||
|
||||
@@ -9,7 +9,6 @@ import inspect
|
||||
import types
|
||||
|
||||
from jedi._compatibility import is_py3, builtins, unicode, is_py34
|
||||
from jedi.cache import memoize_function
|
||||
from jedi.parser import ParserWithRecovery, load_grammar
|
||||
from jedi.parser import tree as pt
|
||||
from jedi.evaluate.helpers import FakeName
|
||||
@@ -44,6 +43,10 @@ if is_py3:
|
||||
NOT_CLASS_TYPES += (types.DynamicClassAttribute,)
|
||||
|
||||
|
||||
class FakeDoesNotExist(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _load_faked_module(module):
|
||||
module_name = module.__name__
|
||||
if module_name == '__builtin__' and not is_py3:
|
||||
@@ -143,13 +146,35 @@ def _faked(module, obj, name):
|
||||
return search_scope(cls, name)
|
||||
|
||||
|
||||
@memoize_function
|
||||
def get_faked(module, obj, name=None):
|
||||
def memoize_faked(obj):
|
||||
"""
|
||||
A typical memoize function that ignores issues with non hashable results.
|
||||
"""
|
||||
cache = obj.cache = {}
|
||||
|
||||
def memoizer(*args, **kwargs):
|
||||
key = (obj, args, frozenset(kwargs.items()))
|
||||
try:
|
||||
result = cache[key]
|
||||
except TypeError:
|
||||
return obj(*args, **kwargs)
|
||||
except KeyError:
|
||||
result = obj(*args, **kwargs)
|
||||
if result is not None:
|
||||
cache[key] = obj(*args, **kwargs)
|
||||
return result
|
||||
else:
|
||||
return result
|
||||
return memoizer
|
||||
|
||||
|
||||
@memoize_faked
|
||||
def _get_faked(module, obj, name=None):
|
||||
obj = type(obj) if is_class_instance(obj) else obj
|
||||
result = _faked(module, obj, name)
|
||||
if result is None or isinstance(result, pt.Class):
|
||||
# We're not interested in classes. What we want is functions.
|
||||
return None
|
||||
raise FakeDoesNotExist
|
||||
else:
|
||||
# Set the docstr which was previously not set (faked modules don't
|
||||
# contain it).
|
||||
@@ -162,6 +187,12 @@ def get_faked(module, obj, name=None):
|
||||
return result
|
||||
|
||||
|
||||
def get_faked(module, obj, name=None, parent=None):
|
||||
faked = _get_faked(module, obj, name)
|
||||
faked.parent = parent
|
||||
return faked
|
||||
|
||||
|
||||
def is_class_instance(obj):
|
||||
"""Like inspect.* methods."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user