forked from VimPlug/jedi
Add an access abstraction (only array tests work, yet)
The access abstraction will be the new way of accessing builtin objects. This way it will be easier to move that to another process
This commit is contained in:
@@ -6,72 +6,60 @@ mixing in Python code, the autocompletion should work much better for builtins.
|
||||
|
||||
import os
|
||||
import inspect
|
||||
import types
|
||||
from itertools import chain
|
||||
|
||||
from parso.python import tree
|
||||
|
||||
from jedi._compatibility import is_py3, builtins, unicode, is_py34
|
||||
from jedi._compatibility import is_py3, builtins, unicode
|
||||
|
||||
modules = {}
|
||||
fake_modules = {}
|
||||
|
||||
|
||||
MethodDescriptorType = type(str.replace)
|
||||
# These are not considered classes and access is granted even though they have
|
||||
# a __class__ attribute.
|
||||
NOT_CLASS_TYPES = (
|
||||
types.BuiltinFunctionType,
|
||||
types.CodeType,
|
||||
types.FrameType,
|
||||
types.FunctionType,
|
||||
types.GeneratorType,
|
||||
types.GetSetDescriptorType,
|
||||
types.LambdaType,
|
||||
types.MemberDescriptorType,
|
||||
types.MethodType,
|
||||
types.ModuleType,
|
||||
types.TracebackType,
|
||||
MethodDescriptorType
|
||||
)
|
||||
def _get_path_dict():
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
base_path = os.path.join(path, 'fake')
|
||||
dct = {}
|
||||
for file_name in os.listdir(base_path):
|
||||
if file_name.endswith('.pym'):
|
||||
dct[file_name[:-4]] = os.path.join(base_path, file_name)
|
||||
return dct
|
||||
|
||||
if is_py3:
|
||||
NOT_CLASS_TYPES += (
|
||||
types.MappingProxyType,
|
||||
types.SimpleNamespace
|
||||
)
|
||||
if is_py34:
|
||||
NOT_CLASS_TYPES += (types.DynamicClassAttribute,)
|
||||
|
||||
_path_dict = _get_path_dict()
|
||||
|
||||
|
||||
class FakeDoesNotExist(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _load_faked_module(grammar, module):
|
||||
module_name = module.__name__
|
||||
def _load_faked_module(grammar, module_name):
|
||||
if module_name == '__builtin__' and not is_py3:
|
||||
module_name = 'builtins'
|
||||
|
||||
try:
|
||||
return modules[module_name]
|
||||
return fake_modules[module_name]
|
||||
except KeyError:
|
||||
path = os.path.dirname(os.path.abspath(__file__))
|
||||
try:
|
||||
with open(os.path.join(path, 'fake', module_name) + '.pym') as f:
|
||||
source = f.read()
|
||||
except IOError:
|
||||
modules[module_name] = None
|
||||
return
|
||||
modules[module_name] = m = grammar.parse(unicode(source))
|
||||
pass
|
||||
|
||||
if module_name == 'builtins' and not is_py3:
|
||||
# There are two implementations of `open` for either python 2/3.
|
||||
# -> Rename the python2 version (`look at fake/builtins.pym`).
|
||||
open_func = _search_scope(m, 'open')
|
||||
open_func.children[1].value = 'open_python3'
|
||||
open_func = _search_scope(m, 'open_python2')
|
||||
open_func.children[1].value = 'open'
|
||||
return m
|
||||
try:
|
||||
path = _path_dict[module_name]
|
||||
except KeyError:
|
||||
fake_modules[module_name] = None
|
||||
return
|
||||
|
||||
with open(path) as f:
|
||||
source = f.read()
|
||||
|
||||
fake_modules[module_name] = m = grammar.parse(unicode(source))
|
||||
|
||||
if module_name == 'builtins' and not is_py3:
|
||||
# There are two implementations of `open` for either python 2/3.
|
||||
# -> Rename the python2 version (`look at fake/builtins.pym`).
|
||||
open_func = _search_scope(m, 'open')
|
||||
open_func.children[1].value = 'open_python3'
|
||||
open_func = _search_scope(m, 'open_python2')
|
||||
open_func.children[1].value = 'open'
|
||||
return m
|
||||
|
||||
|
||||
def _search_scope(scope, obj_name):
|
||||
@@ -80,31 +68,6 @@ def _search_scope(scope, obj_name):
|
||||
return s
|
||||
|
||||
|
||||
def _get_module(obj):
|
||||
if inspect.ismodule(obj):
|
||||
return obj
|
||||
try:
|
||||
obj = obj.__objclass__
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
imp_plz = obj.__module__
|
||||
except AttributeError:
|
||||
# Unfortunately in some cases like `int` there's no __module__
|
||||
return builtins
|
||||
else:
|
||||
if imp_plz is None:
|
||||
# Happens for example in `(_ for _ in []).send.__module__`.
|
||||
return builtins
|
||||
else:
|
||||
try:
|
||||
return __import__(imp_plz)
|
||||
except ImportError:
|
||||
# __module__ can be something arbitrary that doesn't exist.
|
||||
return builtins
|
||||
|
||||
|
||||
def _faked(grammar, module, obj, name):
|
||||
# Crazy underscore actions to try to escape all the internal madness.
|
||||
if module is None:
|
||||
@@ -188,26 +151,24 @@ def _get_faked(grammar, module, obj, name=None):
|
||||
return result, fake_module
|
||||
|
||||
|
||||
def get_faked(evaluator, module, obj, name=None, parent_context=None):
|
||||
if parent_context and parent_context.tree_node is not None:
|
||||
def get_faked_with_parent_context(parent_context, name):
|
||||
if parent_context.tree_node is not None:
|
||||
# Try to search in already clearly defined stuff.
|
||||
found = _search_scope(parent_context.tree_node, name)
|
||||
if found is not None:
|
||||
return found
|
||||
else:
|
||||
raise FakeDoesNotExist
|
||||
|
||||
|
||||
def get_faked_tree_nodes(grammar, string_names):
|
||||
module = base = _load_faked_module(grammar, string_names[0])
|
||||
if module is None:
|
||||
raise FakeDoesNotExist
|
||||
|
||||
tree_nodes = [module]
|
||||
for name in string_names[1:]:
|
||||
base = _search_scope(base, name)
|
||||
if base is None:
|
||||
raise FakeDoesNotExist
|
||||
|
||||
faked, fake_module = _get_faked(evaluator.latest_grammar, module and module.obj, obj, name)
|
||||
if module is not None:
|
||||
module.get_used_names = fake_module.get_used_names
|
||||
return faked
|
||||
|
||||
|
||||
def is_class_instance(obj):
|
||||
"""Like inspect.* methods."""
|
||||
try:
|
||||
cls = obj.__class__
|
||||
except AttributeError:
|
||||
return False
|
||||
else:
|
||||
return cls != type and not issubclass(cls, NOT_CLASS_TYPES)
|
||||
tree_nodes.append(base)
|
||||
return tree_nodes
|
||||
|
||||
Reference in New Issue
Block a user