forked from VimPlug/jedi
124 lines
3.6 KiB
Python
124 lines
3.6 KiB
Python
import types
|
|
import sys
|
|
import os
|
|
import re
|
|
|
|
from jedi._compatibility import builtins as _builtins
|
|
from jedi.evaluate.compiled.context import CompiledObject, CompiledName, \
|
|
CompiledObjectFilter, CompiledContextName, create_from_access
|
|
from jedi.evaluate.compiled.access import create_access
|
|
from jedi import debug
|
|
|
|
|
|
_sep = os.path.sep
|
|
if os.path.altsep is not None:
|
|
_sep += os.path.altsep
|
|
_path_re = re.compile('(?:\.[^{0}]+|[{0}]__init__\.py)$'.format(re.escape(_sep)))
|
|
del _sep
|
|
|
|
|
|
def builtin_from_name(evaluator, string):
|
|
bltn_obj = getattr(_builtins, string)
|
|
return create(evaluator, bltn_obj)
|
|
|
|
|
|
def create_simple_object(evaluator, obj):
|
|
"""
|
|
Only allows creations of objects that are easily picklable across Python
|
|
versions.
|
|
"""
|
|
assert isinstance(obj, (int, float, str, bytes, slice, complex, type(Ellipsis)))
|
|
return create(evaluator, obj)
|
|
|
|
|
|
def create(evaluator, obj):
|
|
return create_from_access(
|
|
evaluator, create_access(evaluator, obj)
|
|
)
|
|
|
|
|
|
def _a_generator(foo):
|
|
"""Used to have an object to return for generators."""
|
|
yield 42
|
|
yield foo
|
|
|
|
|
|
_SPECIAL_OBJECTS = {
|
|
'FUNCTION_CLASS': types.FunctionType,
|
|
'METHOD_CLASS': type(CompiledObject.is_class),
|
|
'MODULE_CLASS': types.ModuleType,
|
|
'GENERATOR_OBJECT': _a_generator(1.0),
|
|
'BUILTINS': _builtins,
|
|
}
|
|
|
|
|
|
def get_special_object(evaluator, identifier):
|
|
obj = _SPECIAL_OBJECTS[identifier]
|
|
return create(evaluator, obj)
|
|
|
|
|
|
def load_module(evaluator, path=None, name=None):
|
|
sys_path = list(evaluator.project.sys_path)
|
|
if path is not None:
|
|
dotted_path = dotted_from_fs_path(path, sys_path=sys_path)
|
|
else:
|
|
dotted_path = name
|
|
|
|
temp, sys.path = sys.path, sys_path
|
|
try:
|
|
__import__(dotted_path)
|
|
except RuntimeError:
|
|
if 'PySide' in dotted_path or 'PyQt' in dotted_path:
|
|
# RuntimeError: the PyQt4.QtCore and PyQt5.QtCore modules both wrap
|
|
# the QObject class.
|
|
# See https://github.com/davidhalter/jedi/pull/483
|
|
return None
|
|
raise
|
|
except ImportError:
|
|
# If a module is "corrupt" or not really a Python module or whatever.
|
|
debug.warning('Module %s not importable in path %s.', dotted_path, path)
|
|
return None
|
|
finally:
|
|
sys.path = temp
|
|
|
|
# Just access the cache after import, because of #59 as well as the very
|
|
# complicated import structure of Python.
|
|
module = sys.modules[dotted_path]
|
|
|
|
return create(evaluator, module)
|
|
|
|
|
|
def dotted_from_fs_path(fs_path, sys_path):
|
|
"""
|
|
Changes `/usr/lib/python3.4/email/utils.py` to `email.utils`. I.e.
|
|
compares the path with sys.path and then returns the dotted_path. If the
|
|
path is not in the sys.path, just returns None.
|
|
"""
|
|
if os.path.basename(fs_path).startswith('__init__.'):
|
|
# We are calculating the path. __init__ files are not interesting.
|
|
fs_path = os.path.dirname(fs_path)
|
|
|
|
# prefer
|
|
# - UNIX
|
|
# /path/to/pythonX.Y/lib-dynload
|
|
# /path/to/pythonX.Y/site-packages
|
|
# - Windows
|
|
# C:\path\to\DLLs
|
|
# C:\path\to\Lib\site-packages
|
|
# over
|
|
# - UNIX
|
|
# /path/to/pythonX.Y
|
|
# - Windows
|
|
# C:\path\to\Lib
|
|
path = ''
|
|
for s in sys_path:
|
|
if (fs_path.startswith(s) and len(path) < len(s)):
|
|
path = s
|
|
|
|
# - Window
|
|
# X:\path\to\lib-dynload/datetime.pyd => datetime
|
|
module_path = fs_path[len(path):].lstrip(os.path.sep).lstrip('/')
|
|
# - Window
|
|
# Replace like X:\path\to\something/foo/bar.py
|
|
return _path_re.sub('', module_path).replace(os.path.sep, '.').replace('/', '.')
|