forked from VimPlug/jedi
start introducing the compiled.fake module that fakes builtin code
This commit is contained in:
@@ -11,6 +11,7 @@ from jedi import debug
|
|||||||
from jedi.parser.representation import Base
|
from jedi.parser.representation import Base
|
||||||
from jedi.cache import underscore_memoization
|
from jedi.cache import underscore_memoization
|
||||||
from jedi.evaluate.sys_path import get_sys_path
|
from jedi.evaluate.sys_path import get_sys_path
|
||||||
|
from . import fake
|
||||||
|
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
@@ -51,9 +52,7 @@ class PyObject(Base):
|
|||||||
@underscore_memoization
|
@underscore_memoization
|
||||||
def _cls(self):
|
def _cls(self):
|
||||||
# Ensures that a PyObject is returned that is not an instance (like list)
|
# Ensures that a PyObject is returned that is not an instance (like list)
|
||||||
if not (inspect.isclass(self.obj) or inspect.ismodule(self.obj)
|
if fake.is_class_instance(self.obj):
|
||||||
or inspect.isbuiltin(self.obj) or inspect.ismethod(self.obj)
|
|
||||||
or inspect.ismethoddescriptor(self.obj)):
|
|
||||||
return PyObject(self.obj.__class__, self.parent, True)
|
return PyObject(self.obj.__class__, self.parent, True)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -218,5 +217,23 @@ builtin = PyObject(_builtins)
|
|||||||
magic_function_class = PyObject(type(load_module), parent=builtin)
|
magic_function_class = PyObject(type(load_module), parent=builtin)
|
||||||
|
|
||||||
|
|
||||||
def create(obj):
|
def create(obj, parent=builtin, instantiated=False, module=None):
|
||||||
return PyObject(obj, builtin)
|
if module is None:
|
||||||
|
if not inspect.ismodule(obj):
|
||||||
|
module = obj.__class__ if fake.is_class_instance(obj) else obj
|
||||||
|
if not (inspect.isbuiltin(module) or inspect.isclass(module)):
|
||||||
|
module = obj.__objclass__
|
||||||
|
try:
|
||||||
|
imp_plz = obj.__module__
|
||||||
|
except AttributeError:
|
||||||
|
# Unfortunately in some cases like `int` there's no __module__
|
||||||
|
module = builtin
|
||||||
|
else:
|
||||||
|
module = PyObject(__import__(imp_plz))
|
||||||
|
|
||||||
|
faked = fake.get_faked(module.obj, obj)
|
||||||
|
if faked is not None:
|
||||||
|
faked.parent = parent
|
||||||
|
return faked
|
||||||
|
|
||||||
|
return PyObject(obj, parent, instantiated)
|
||||||
|
|||||||
106
jedi/evaluate/compiled/fake.py
Normal file
106
jedi/evaluate/compiled/fake.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
"""
|
||||||
|
Loads functions that are mixed in to the standard library. E.g. builtins are
|
||||||
|
written in C (binaries), but my autocompletion only understands Python code. By
|
||||||
|
mixing in Python code, the autocompletion should work much better for builtins.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
from jedi._compatibility import is_py3k
|
||||||
|
from jedi.parser import Parser
|
||||||
|
|
||||||
|
modules = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _load_fakes(module_name):
|
||||||
|
regex = r'^(def|class)\s+([\w\d]+)'
|
||||||
|
|
||||||
|
def process_code(code, depth=0):
|
||||||
|
funcs = {}
|
||||||
|
matches = list(re.finditer(regex, code, re.MULTILINE))
|
||||||
|
positions = [m.start() for m in matches]
|
||||||
|
for i, pos in enumerate(positions):
|
||||||
|
try:
|
||||||
|
code_block = code[pos:positions[i + 1]]
|
||||||
|
except IndexError:
|
||||||
|
code_block = code[pos:len(code)]
|
||||||
|
structure_name = matches[i].group(1)
|
||||||
|
name = matches[i].group(2)
|
||||||
|
if structure_name == 'def':
|
||||||
|
funcs[name] = code_block
|
||||||
|
elif structure_name == 'class':
|
||||||
|
if depth > 0:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
# remove class line
|
||||||
|
c = re.sub(r'^[^\n]+', '', code_block)
|
||||||
|
# remove whitespace
|
||||||
|
c = re.compile(r'^[ ]{4}', re.MULTILINE).sub('', c)
|
||||||
|
|
||||||
|
funcs[name] = process_code(c)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
return funcs
|
||||||
|
|
||||||
|
# sometimes there are stupid endings like `_sqlite3.cpython-32mu`
|
||||||
|
module_name = re.sub(r'\..*', '', module_name)
|
||||||
|
|
||||||
|
if module_name == '__builtin__' and not is_py3k:
|
||||||
|
module_name = 'builtins'
|
||||||
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
try:
|
||||||
|
with open(os.path.join(path, 'mixin', module_name) + '.pym') as f:
|
||||||
|
s = f.read()
|
||||||
|
except IOError:
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
mixin_dct = process_code(s)
|
||||||
|
if is_py3k and module_name == 'builtins':
|
||||||
|
# in the case of Py3k xrange is now range
|
||||||
|
mixin_dct['range'] = mixin_dct['xrange']
|
||||||
|
return mixin_dct
|
||||||
|
|
||||||
|
|
||||||
|
def _load_module(module):
|
||||||
|
module_name = module.__name__
|
||||||
|
try:
|
||||||
|
return 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:
|
||||||
|
return {}
|
||||||
|
module = Parser(source).module
|
||||||
|
modules[module_name] = module
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
def get_faked(module, obj):
|
||||||
|
def from_scope(scope, obj):
|
||||||
|
for s in scope.subscopes:
|
||||||
|
if s.name == obj.name:
|
||||||
|
return s
|
||||||
|
|
||||||
|
mod = _load_module(module)
|
||||||
|
|
||||||
|
# Having the module as a `parser.representation.module`, we need to scan
|
||||||
|
# for methods.
|
||||||
|
if is_class_instance(obj):
|
||||||
|
obj = obj.__class__
|
||||||
|
if inspect.isbuiltin(obj):
|
||||||
|
return from_scope(mod, obj)
|
||||||
|
elif not inspect.isclass(obj):
|
||||||
|
# object is a method or descriptor
|
||||||
|
cls = obj.__objclass__
|
||||||
|
return from_scope(from_scope(mod, cls), obj)
|
||||||
|
|
||||||
|
|
||||||
|
def is_class_instance(obj):
|
||||||
|
"""Like inspect.* methods."""
|
||||||
|
return not (inspect.isclass(obj) or inspect.ismodule(obj)
|
||||||
|
or inspect.isbuiltin(obj) or inspect.ismethod(obj)
|
||||||
|
or inspect.ismethoddescriptor(obj))
|
||||||
Reference in New Issue
Block a user