mirror of
https://github.com/davidhalter/jedi.git
synced 2026-01-10 22:12:24 +08:00
Merge branch 'dev' of github.com:davidhalter/jedi into dev
This commit is contained in:
@@ -34,8 +34,29 @@ class DummyFile(object):
|
||||
del self.loader
|
||||
|
||||
|
||||
def find_module_py33(string, path=None):
|
||||
loader = importlib.machinery.PathFinder.find_module(string, path)
|
||||
def find_module_py34(string, path=None, fullname=None):
|
||||
implicit_namespace_pkg = False
|
||||
spec = None
|
||||
loader = None
|
||||
|
||||
spec = importlib.machinery.PathFinder.find_spec(string, path)
|
||||
if hasattr(spec, 'origin'):
|
||||
origin = spec.origin
|
||||
implicit_namespace_pkg = origin == 'namespace'
|
||||
|
||||
# We try to disambiguate implicit namespace pkgs with non implicit namespace pkgs
|
||||
if implicit_namespace_pkg:
|
||||
fullname = string if not path else fullname
|
||||
implicit_ns_info = ImplicitNSInfo(fullname, spec.submodule_search_locations._path)
|
||||
return None, implicit_ns_info, False
|
||||
|
||||
# we have found the tail end of the dotted path
|
||||
if hasattr(spec, 'loader'):
|
||||
loader = spec.loader
|
||||
return find_module_py33(string, path, loader)
|
||||
|
||||
def find_module_py33(string, path=None, loader=None, fullname=None):
|
||||
loader = loader or importlib.machinery.PathFinder.find_module(string, path)
|
||||
|
||||
if loader is None and path is None: # Fallback to find builtins
|
||||
try:
|
||||
@@ -81,7 +102,7 @@ def find_module_py33(string, path=None):
|
||||
return module_file, module_path, is_package
|
||||
|
||||
|
||||
def find_module_pre_py33(string, path=None):
|
||||
def find_module_pre_py33(string, path=None, fullname=None):
|
||||
try:
|
||||
module_file, module_path, description = imp.find_module(string, path)
|
||||
module_type = description[2]
|
||||
@@ -121,6 +142,7 @@ def find_module_pre_py33(string, path=None):
|
||||
|
||||
|
||||
find_module = find_module_py33 if is_py33 else find_module_pre_py33
|
||||
find_module = find_module_py34 if is_py34 else find_module
|
||||
find_module.__doc__ = """
|
||||
Provides information about a module.
|
||||
|
||||
@@ -132,6 +154,12 @@ if the module is contained in a package.
|
||||
"""
|
||||
|
||||
|
||||
class ImplicitNSInfo(object):
|
||||
"""Stores information returned from an implicit namespace spec"""
|
||||
def __init__(self, name, paths):
|
||||
self.name = name
|
||||
self.paths = paths
|
||||
|
||||
# unicode function
|
||||
try:
|
||||
unicode = unicode
|
||||
|
||||
@@ -14,8 +14,9 @@ def usages(evaluator, definition_names, mods):
|
||||
if name.api_type == 'module':
|
||||
found = False
|
||||
for context in name.infer():
|
||||
found = True
|
||||
yield context.name
|
||||
if isinstance(context, ModuleContext):
|
||||
found = True
|
||||
yield context.name
|
||||
if not found:
|
||||
yield name
|
||||
else:
|
||||
|
||||
@@ -16,7 +16,7 @@ import os
|
||||
import pkgutil
|
||||
import sys
|
||||
|
||||
from jedi._compatibility import find_module, unicode
|
||||
from jedi._compatibility import find_module, unicode, ImplicitNSInfo
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
from jedi.common import source_to_unicode, unite
|
||||
@@ -306,8 +306,10 @@ class Importer(object):
|
||||
# At the moment we are only using one path. So this is
|
||||
# not important to be correct.
|
||||
try:
|
||||
if not isinstance(path, list):
|
||||
path = [path]
|
||||
module_file, module_path, is_pkg = \
|
||||
find_module(import_parts[-1], [path])
|
||||
find_module(import_parts[-1], path, fullname=module_name)
|
||||
break
|
||||
except ImportError:
|
||||
module_path = None
|
||||
@@ -323,7 +325,7 @@ class Importer(object):
|
||||
sys.path, temp = sys_path, sys.path
|
||||
try:
|
||||
module_file, module_path, is_pkg = \
|
||||
find_module(import_parts[-1])
|
||||
find_module(import_parts[-1], fullname=module_name)
|
||||
finally:
|
||||
sys.path = temp
|
||||
except ImportError:
|
||||
@@ -343,7 +345,12 @@ class Importer(object):
|
||||
source = module_file.read()
|
||||
module_file.close()
|
||||
|
||||
if module_file is None and not module_path.endswith(('.py', '.zip', '.egg')):
|
||||
if isinstance(module_path, ImplicitNSInfo):
|
||||
from jedi.evaluate.representation import ImplicitNamespaceContext
|
||||
fullname, paths = module_path.name, module_path.paths
|
||||
module = ImplicitNamespaceContext(self._evaluator, fullname=fullname)
|
||||
module.paths = paths
|
||||
elif module_file is None and not module_path.endswith(('.py', '.zip', '.egg')):
|
||||
module = compiled.load_module(self._evaluator, module_path)
|
||||
else:
|
||||
module = _load_module(self._evaluator, module_path, source, sys_path, parent_module)
|
||||
@@ -384,7 +391,7 @@ class Importer(object):
|
||||
:param only_modules: Indicates wheter it's possible to import a
|
||||
definition that is not defined in a module.
|
||||
"""
|
||||
from jedi.evaluate.representation import ModuleContext
|
||||
from jedi.evaluate.representation import ModuleContext, ImplicitNamespaceContext
|
||||
names = []
|
||||
if self.import_path:
|
||||
# flask
|
||||
@@ -405,13 +412,16 @@ class Importer(object):
|
||||
# Non-modules are not completable.
|
||||
if context.api_type != 'module': # not a module
|
||||
continue
|
||||
|
||||
# namespace packages
|
||||
if isinstance(context, ModuleContext) and \
|
||||
context.py__file__().endswith('__init__.py'):
|
||||
if isinstance(context, ModuleContext) and context.py__file__().endswith('__init__.py'):
|
||||
paths = context.py__path__()
|
||||
names += self._get_module_names(paths, in_module=context)
|
||||
|
||||
# implicit namespace packages
|
||||
elif isinstance(context, ImplicitNamespaceContext):
|
||||
paths = context.paths
|
||||
names += self._get_module_names(paths)
|
||||
|
||||
if only_modules:
|
||||
# In the case of an import like `from x.` we don't need to
|
||||
# add all the variables.
|
||||
|
||||
@@ -39,6 +39,7 @@ import os
|
||||
import pkgutil
|
||||
import imp
|
||||
import re
|
||||
from itertools import chain
|
||||
|
||||
from jedi._compatibility import use_metaclass
|
||||
from jedi.parser import tree
|
||||
@@ -557,3 +558,65 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
||||
|
||||
def py__class__(self):
|
||||
return compiled.get_special_object(self.evaluator, 'MODULE_CLASS')
|
||||
|
||||
|
||||
class ImplicitNSName(AbstractNameDefinition):
|
||||
"""
|
||||
Accessing names for implicit namespace packages should infer to nothing.
|
||||
This object will prevent Jedi from raising exceptions
|
||||
"""
|
||||
def __init__(self, implicit_ns_context, string_name):
|
||||
self.implicit_ns_context = implicit_ns_context
|
||||
self.string_name = string_name
|
||||
|
||||
def infer(self):
|
||||
return []
|
||||
|
||||
def get_root_context(self):
|
||||
return self.implicit_ns_context
|
||||
|
||||
|
||||
class ImplicitNamespaceContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
||||
"""
|
||||
Provides support for implicit namespace packages
|
||||
"""
|
||||
api_type = 'module'
|
||||
parent_context = None
|
||||
|
||||
def __init__(self, evaluator, fullname):
|
||||
super(ImplicitNamespaceContext, self).__init__(evaluator, parent_context=None)
|
||||
self.evaluator = evaluator
|
||||
self.fullname = fullname
|
||||
|
||||
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
||||
yield DictFilter(self._sub_modules_dict())
|
||||
|
||||
@property
|
||||
@memoize_default()
|
||||
def name(self):
|
||||
string_name = self.py__package__().rpartition('.')[-1]
|
||||
return ImplicitNSName(self, string_name)
|
||||
|
||||
def py__file__(self):
|
||||
return None
|
||||
|
||||
def py__package__(self):
|
||||
"""Return the fullname
|
||||
"""
|
||||
return self.fullname
|
||||
|
||||
@property
|
||||
def py__path__(self):
|
||||
return lambda: [self.paths]
|
||||
|
||||
@memoize_default()
|
||||
def _sub_modules_dict(self):
|
||||
names = {}
|
||||
|
||||
paths = self.paths
|
||||
file_names = chain.from_iterable(os.listdir(path) for path in paths)
|
||||
mods = [file_name.rpartition('.')[0] if '.' in file_name else file_name for file_name in file_names]
|
||||
|
||||
for name in mods:
|
||||
names[name] = imports.SubModuleName(self, name)
|
||||
return names
|
||||
@@ -239,6 +239,8 @@ def generate_tokens(readline, use_exact_op_types=False):
|
||||
if not line:
|
||||
if contstr:
|
||||
yield TokenInfo(ERRORTOKEN, contstr, contstr_start, prefix)
|
||||
if contstr.endswith('\n'):
|
||||
new_line = True
|
||||
break
|
||||
|
||||
lnum += 1
|
||||
|
||||
@@ -317,7 +317,7 @@ class Leaf(Base):
|
||||
|
||||
@utf8_repr
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % (type(self).__name__, self.value)
|
||||
return "<%s: %s start=%s>" % (type(self).__name__, self.value, self.start_pos)
|
||||
|
||||
|
||||
class LeafWithNewLines(Leaf):
|
||||
|
||||
Reference in New Issue
Block a user