mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-19 12:01:12 +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
|
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):
|
def cache_star_import(func):
|
||||||
@time_cache("star_import_cache_validity")
|
@time_cache("star_import_cache_validity")
|
||||||
def wrapper(self):
|
def wrapper(self):
|
||||||
|
|||||||
@@ -222,10 +222,12 @@ class CompiledObject(Base):
|
|||||||
module = self.get_parent_until()
|
module = self.get_parent_until()
|
||||||
faked_subscopes = []
|
faked_subscopes = []
|
||||||
for name in dir(self.obj):
|
for name in dir(self.obj):
|
||||||
f = fake.get_faked(module.obj, self.obj, name)
|
try:
|
||||||
if f:
|
faked_subscopes.append(
|
||||||
f.parent = self
|
fake.get_faked(module.obj, self.obj, parent=self, name=name)
|
||||||
faked_subscopes.append(f)
|
)
|
||||||
|
except fake.FakeDoesNotExist:
|
||||||
|
pass
|
||||||
return faked_subscopes
|
return faked_subscopes
|
||||||
|
|
||||||
def is_scope(self):
|
def is_scope(self):
|
||||||
@@ -445,16 +447,15 @@ def _parse_function_doc(doc):
|
|||||||
|
|
||||||
|
|
||||||
def _create_from_name(evaluator, module, parent, name):
|
def _create_from_name(evaluator, module, parent, name):
|
||||||
faked = fake.get_faked(module.obj, parent.obj, name)
|
try:
|
||||||
# only functions are necessary.
|
return fake.get_faked(module.obj, parent.obj, parent=parent, name=name)
|
||||||
if faked is not None:
|
except fake.FakeDoesNotExist:
|
||||||
faked.parent = parent
|
pass
|
||||||
return faked
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = getattr(parent.obj, name)
|
obj = getattr(parent.obj, name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# happens e.g. in properties of
|
# Happens e.g. in properties of
|
||||||
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
||||||
# -> just set it to None
|
# -> just set it to None
|
||||||
obj = None
|
obj = None
|
||||||
@@ -527,9 +528,9 @@ def create(evaluator, obj, parent=None, module=None):
|
|||||||
if parent is None and obj != _builtins:
|
if parent is None and obj != _builtins:
|
||||||
return create(evaluator, obj, create(evaluator, _builtins))
|
return create(evaluator, obj, create(evaluator, _builtins))
|
||||||
|
|
||||||
faked = fake.get_faked(module and module.obj, obj)
|
try:
|
||||||
if faked is not None:
|
return fake.get_faked(module and module.obj, obj, parent=parent)
|
||||||
faked.parent = parent
|
except fake.FakeDoesNotExist:
|
||||||
return faked
|
pass
|
||||||
|
|
||||||
return CompiledObject(evaluator, obj, parent)
|
return CompiledObject(evaluator, obj, parent)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import inspect
|
|||||||
import types
|
import types
|
||||||
|
|
||||||
from jedi._compatibility import is_py3, builtins, unicode, is_py34
|
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 ParserWithRecovery, load_grammar
|
||||||
from jedi.parser import tree as pt
|
from jedi.parser import tree as pt
|
||||||
from jedi.evaluate.helpers import FakeName
|
from jedi.evaluate.helpers import FakeName
|
||||||
@@ -44,6 +43,10 @@ if is_py3:
|
|||||||
NOT_CLASS_TYPES += (types.DynamicClassAttribute,)
|
NOT_CLASS_TYPES += (types.DynamicClassAttribute,)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDoesNotExist(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _load_faked_module(module):
|
def _load_faked_module(module):
|
||||||
module_name = module.__name__
|
module_name = module.__name__
|
||||||
if module_name == '__builtin__' and not is_py3:
|
if module_name == '__builtin__' and not is_py3:
|
||||||
@@ -143,13 +146,35 @@ def _faked(module, obj, name):
|
|||||||
return search_scope(cls, name)
|
return search_scope(cls, name)
|
||||||
|
|
||||||
|
|
||||||
@memoize_function
|
def memoize_faked(obj):
|
||||||
def get_faked(module, obj, name=None):
|
"""
|
||||||
|
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
|
obj = type(obj) if is_class_instance(obj) else obj
|
||||||
result = _faked(module, obj, name)
|
result = _faked(module, obj, name)
|
||||||
if result is None or isinstance(result, pt.Class):
|
if result is None or isinstance(result, pt.Class):
|
||||||
# We're not interested in classes. What we want is functions.
|
# We're not interested in classes. What we want is functions.
|
||||||
return None
|
raise FakeDoesNotExist
|
||||||
else:
|
else:
|
||||||
# Set the docstr which was previously not set (faked modules don't
|
# Set the docstr which was previously not set (faked modules don't
|
||||||
# contain it).
|
# contain it).
|
||||||
@@ -162,6 +187,12 @@ def get_faked(module, obj, name=None):
|
|||||||
return result
|
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):
|
def is_class_instance(obj):
|
||||||
"""Like inspect.* methods."""
|
"""Like inspect.* methods."""
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user