1
0
forked from VimPlug/jedi
Files
jedi-fork/jedi/evaluate/compiled/__init__.py
2017-12-02 01:59:48 +01:00

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('/', '.')