##// END OF EJS Templates
Étiquette Working snapshot ajoutée à la révision 483cfe27e044
Étiquette Working snapshot ajoutée à la révision 483cfe27e044

File last commit:

r0:1aa783210b8e default
r6:068bddcaf0c7 default
Show More
module_completion.py
171 lines | 4.8 KiB | text/x-python | PythonLexer
# -*- coding: utf-8 -*-
""" provide completions for modules 'import',
copied code with some modifications from IPython!"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function
# Stdlib imports
import inspect
import os
import re
import sys
from time import time
from zipimport import zipimporter
#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------
# Time in seconds after which the rootmodules will be stored in (nonpermanent) cache
TIMEOUT_STORAGE = 2
# Time in seconds after which we give up
TIMEOUT_GIVEUP = 20
# Regular expression for the python import statement
import_re = re.compile(r'.*(\.so|\.py[cod]?)$', re.IGNORECASE)
# global cache
cache = dict()
def module_list(path):
"""
Return the list containing the names of the modules available in the given
folder.
"""
# sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
if path == '':
path = '.'
if os.path.isdir(path):
folder_list = os.listdir(path)
elif path.endswith('.egg'):
try:
folder_list = [f for f in zipimporter(path)._files]
except:
folder_list = []
else:
folder_list = []
if not folder_list:
return []
# A few local constants to be used in loops below
isfile = os.path.isfile
pjoin = os.path.join
basename = os.path.basename
def is_importable_file(path):
"""Returns True if the provided path is a valid importable module"""
name, extension = os.path.splitext( path )
return import_re.match(path) # and py3compat.isidentifier(name)
# Now find actual path matches for packages or modules
folder_list = [p for p in folder_list
if isfile(pjoin(path, p,'__init__.py'))
or is_importable_file(p) ]
return [basename(p).split('.')[0] for p in folder_list]
def get_root_modules():
"""
Returns a list containing the names of all the modules available in the
folders of the pythonpath.
"""
global cache
if 'rootmodules' in cache:
return cache['rootmodules']
t = time()
store = False
modules = list(sys.builtin_module_names)
for path in sys.path:
modules += module_list(path)
if time() - t >= TIMEOUT_STORAGE and not store:
store = True
print("\nCaching the list of root modules, please wait!")
print("(This will only be done once.)\n")
sys.stdout.flush()
if time() - t > TIMEOUT_GIVEUP:
print("This is taking too long, we give up.\n")
cache['rootmodules'] = []
return []
modules = set(modules)
if '__init__' in modules:
modules.remove('__init__')
modules = list(modules)
if store:
cache['rootmodules'] = modules
return modules
def is_importable(module, attr, only_modules):
if only_modules:
return inspect.ismodule(getattr(module, attr))
else:
return not(attr[:2] == '__' and attr[-2:] == '__')
def try_import(mod, only_modules=False):
try:
m = __import__(mod)
except:
return []
mods = mod.split('.')
for module in mods[1:]:
m = getattr(m, module)
m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
completions = []
if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
completions.extend( [attr for attr in dir(m) if
is_importable(m, attr, only_modules)])
completions.extend(getattr(m, '__all__', []))
if m_is_init:
completions.extend(module_list(os.path.dirname(m.__file__)))
completions = set(completions)
if '__init__' in completions:
completions.remove('__init__')
return list(completions)
def module_completion(line):
"""
Returns a list containing the completion possibilities for an import line.
The line looks like this :
'import xml.d'
'from xml.dom import'
"""
words = line.split(' ')
nwords = len(words)
# from whatever <tab> -> 'import '
if nwords == 3 and words[0] == 'from':
return ['import ']
# 'from xy<tab>' or 'import xy<tab>'
if nwords < 3 and (words[0] in ['import','from']) :
if nwords == 1:
return get_root_modules()
mod = words[1].split('.')
if len(mod) < 2:
return get_root_modules()
completion_list = try_import('.'.join(mod[:-1]), True)
return ['.'.join(mod[:-1] + [el]) for el in completion_list]
# 'from xyz import abc<tab>'
if nwords >= 3 and words[0] == 'from':
mod = words[1]
return try_import(mod)