diff --git a/IPython/quarantine/ipy_completers.py b/IPython/quarantine/ipy_completers.py index f4d9f6e..2542568 100644 --- a/IPython/quarantine/ipy_completers.py +++ b/IPython/quarantine/ipy_completers.py @@ -1,4 +1,3 @@ - """ Implementations for various useful completers See extensions/ipy_stock_completers.py on examples of how to enable a completer, @@ -6,150 +5,21 @@ but the basic idea is to do: ip.set_hook('complete_command', svn_completer, str_key = 'svn') +NOTE: some of the completers that used to be here, the ones used always by +default (loaded before by ipy_stock_completers) have been moved into +core.completerlib, where they will be further cleaned up and maintained. The +rest of this file would need to be well commented, cleaned up and tested for +inclusion into the core. """ -from IPython.core import ipapi -from IPython.core.error import TryNext import glob,os,shlex,sys import inspect from time import time from zipimport import zipimporter -ip = ipapi.get() - -try: - set -except: - from sets import Set as set - -TIMEOUT_STORAGE = 3 #Time in seconds after which the rootmodules will be stored -TIMEOUT_GIVEUP = 20 #Time in seconds after which we give up - -def quick_completer(cmd, completions): - """ Easily create a trivial completer for a command. - - Takes either a list of completions, or all completions in string - (that will be split on whitespace) - - Example:: - - [d:\ipython]|1> import ipy_completers - [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz']) - [d:\ipython]|3> foo b - bar baz - [d:\ipython]|3> foo ba - """ - if isinstance(completions, basestring): - - completions = completions.split() - def do_complete(self,event): - return completions - - ip.set_hook('complete_command',do_complete, str_key = cmd) - -def getRootModules(): - """ - Returns a list containing the names of all the modules available in the - folders of the pythonpath. - """ - modules = [] - if ip.db.has_key('rootmodules'): - return ip.db['rootmodules'] - t = time() - store = False - for path in sys.path: - modules += moduleList(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 - type '%rehashx' to " + \ - "reset cache!)" - print - if time() - t > TIMEOUT_GIVEUP: - print "This is taking too long, we give up." - print - ip.db['rootmodules'] = [] - return [] - - modules += sys.builtin_module_names - - modules = list(set(modules)) - if '__init__' in modules: - modules.remove('__init__') - modules = list(set(modules)) - if store: - ip.db['rootmodules'] = modules - return modules - -def moduleList(path): - """ - Return the list containing the names of the modules available in the given - folder. - """ - 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 = [] - #folder_list = glob.glob(os.path.join(path,'*')) - folder_list = [p for p in folder_list \ - if os.path.exists(os.path.join(path, p,'__init__.py'))\ - or p[-3:] in ('.py','.so')\ - or p[-4:] in ('.pyc','.pyo','.pyd')] - - folder_list = [os.path.basename(p).split('.')[0] for p in folder_list] - return folder_list - -def moduleCompletion(line): - """ - Returns a list containing the completion possibilities for an import line. - The line looks like this : - 'import xml.d' - 'from xml.dom import' - """ - def tryImport(mod, only_modules=False): - def isImportable(module, attr): - if only_modules: - return inspect.ismodule(getattr(module, attr)) - else: - return not(attr[:2] == '__' and attr[-2:] == '__') - try: - m = __import__(mod) - except: - return [] - mods = mod.split('.') - for module in mods[1:]: - m = getattr(m,module) - if (not hasattr(m, '__file__')) or (not only_modules) or\ - (hasattr(m, '__file__') and '__init__' in m.__file__): - completion_list = [attr for attr in dir(m) if isImportable(m, attr)] - completion_list.extend(getattr(m,'__all__',[])) - if hasattr(m, '__file__') and '__init__' in m.__file__: - completion_list.extend(moduleList(os.path.dirname(m.__file__))) - completion_list = list(set(completion_list)) - if '__init__' in completion_list: - completion_list.remove('__init__') - return completion_list - - words = line.split(' ') - if len(words) == 3 and words[0] == 'from': - return ['import '] - if len(words) < 3 and (words[0] in ['import','from']) : - if len(words) == 1: - return getRootModules() - mod = words[1].split('.') - if len(mod) < 2: - return getRootModules() - completion_list = tryImport('.'.join(mod[:-1]), True) - completion_list = ['.'.join(mod[:-1] + [el]) for el in completion_list] - return completion_list - if len(words) >= 3 and words[0] == 'from': - mod = words[1] - return tryImport(mod) +from IPython.core import ipapi +from IPython.core.error import TryNext +ip = ipapi.get() def vcs_completer(commands, event): """ utility to make writing typical version control app completers easier @@ -174,20 +44,6 @@ def vcs_completer(commands, event): return ip.Completer.file_matches(event.symbol) -pkg_cache = None - -def module_completer(self,event): - """ Give completions after user has typed 'import ...' or 'from ...'""" - - # This works in all versions of python. While 2.5 has - # pkgutil.walk_packages(), that particular routine is fairly dangerous, - # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full - # of possibly problematic side effects. - # This search the folders in the sys.path for available modules. - - return moduleCompletion(event.line) - - svn_commands = """\ add blame praise annotate ann cat checkout co cleanup commit ci copy cp delete del remove rm diff di export help ? h import info list ls @@ -252,125 +108,6 @@ def bzr_completer(self,event): return bzr_commands() -def shlex_split(x): - """Helper function to split lines into segments.""" - #shlex.split raise exception if syntax error in sh syntax - #for example if no closing " is found. This function keeps dropping - #the last character of the line until shlex.split does not raise - #exception. Adds end of the line to the result of shlex.split - #example: %run "c:/python -> ['%run','"c:/python'] - endofline=[] - while x!="": - try: - comps=shlex.split(x) - if len(endofline)>=1: - comps.append("".join(endofline)) - return comps - except ValueError: - endofline=[x[-1:]]+endofline - x=x[:-1] - return ["".join(endofline)] - -def runlistpy(self, event): - comps = shlex_split(event.line) - relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"") - - #print "\nev=",event # dbg - #print "rp=",relpath # dbg - #print 'comps=',comps # dbg - - lglob = glob.glob - isdir = os.path.isdir - if relpath.startswith('~'): - relpath = os.path.expanduser(relpath) - dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') - if isdir(f)] - - # Find if the user has already typed the first filename, after which we - # should complete on all files, since after the first one other files may - # be arguments to the input script. - #filter( - if filter(lambda f: f.endswith('.py') or f.endswith('.ipy') or - f.endswith('.pyw'),comps): - pys = [f.replace('\\','/') for f in lglob('*')] - else: - pys = [f.replace('\\','/') - for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') + - lglob(relpath + '*.pyw')] - return dirs + pys - - -greedy_cd_completer = False - -def cd_completer(self, event): - relpath = event.symbol - #print event # dbg - if '-b' in event.line: - # return only bookmark completions - bkms = self.db.get('bookmarks',{}) - return bkms.keys() - - - if event.symbol == '-': - width_dh = str(len(str(len(ip.user_ns['_dh']) + 1))) - # jump in directory history by number - fmt = '-%0' + width_dh +'d [%s]' - ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])] - if len(ents) > 1: - return ents - return [] - - if event.symbol.startswith('--'): - return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']] - - if relpath.startswith('~'): - relpath = os.path.expanduser(relpath).replace('\\','/') - found = [] - for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*') - if os.path.isdir(f)]: - if ' ' in d: - # we don't want to deal with any of that, complex code - # for this is elsewhere - raise TryNext - found.append( d ) - - if not found: - if os.path.isdir(relpath): - return [relpath] - # if no completions so far, try bookmarks - bks = self.db.get('bookmarks',{}).keys() - bkmatches = [s for s in bks if s.startswith(event.symbol)] - if bkmatches: - return bkmatches - - raise TryNext - - - def single_dir_expand(matches): - "Recursively expand match lists containing a single dir." - - if len(matches) == 1 and os.path.isdir(matches[0]): - # Takes care of links to directories also. Use '/' - # explicitly, even under Windows, so that name completions - # don't end up escaped. - d = matches[0] - if d[-1] in ['/','\\']: - d = d[:-1] - - subdirs = [p for p in os.listdir(d) if os.path.isdir( d + '/' + p) and not p.startswith('.')] - if subdirs: - matches = [ (d + '/' + p) for p in subdirs ] - return single_dir_expand(matches) - else: - return matches - else: - return matches - - if greedy_cd_completer: - return single_dir_expand(found) - else: - return found - def apt_get_packages(prefix): out = os.popen('apt-cache pkgnames') for p in out: @@ -399,4 +136,3 @@ def apt_completer(self, event): return apt_commands.split() return list(apt_get_packages(event.symbol)) -