##// END OF EJS Templates
Tiny comment fix
Thomas Kluyver -
Show More
@@ -1,344 +1,344 b''
1 1 """Implementations for various useful completers.
2 2
3 3 These are all loaded by default by IPython.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2010-2011 The IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib imports
19 19 import glob
20 20 import inspect
21 21 import os
22 22 import re
23 23 import sys
24 24
25 25 try:
26 # Python 3
26 # Python >= 3.3
27 27 from importlib.machinery import all_suffixes
28 28 _suffixes = all_suffixes()
29 29 except ImportError:
30 30 from imp import get_suffixes
31 31 _suffixes = [ s[0] for s in get_suffixes() ]
32 32
33 33 # Third-party imports
34 34 from time import time
35 35 from zipimport import zipimporter
36 36
37 37 # Our own imports
38 38 from IPython.core.completer import expand_user, compress_user
39 39 from IPython.core.error import TryNext
40 40 from IPython.utils._process_common import arg_split
41 41
42 42 # FIXME: this should be pulled in with the right call via the component system
43 43 from IPython import get_ipython
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Globals and constants
47 47 #-----------------------------------------------------------------------------
48 48
49 49 # Time in seconds after which the rootmodules will be stored permanently in the
50 50 # ipython ip.db database (kept in the user's .ipython dir).
51 51 TIMEOUT_STORAGE = 2
52 52
53 53 # Time in seconds after which we give up
54 54 TIMEOUT_GIVEUP = 20
55 55
56 56 # Regular expression for the python import statement
57 57 import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
58 58 r'(?P<package>[/\\]__init__)?'
59 59 r'(?P<suffix>%s)$' %
60 60 r'|'.join(re.escape(s[0]) for s in _suffixes))
61 61
62 62 # RE for the ipython %run command (python + ipython scripts)
63 63 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Local utilities
67 67 #-----------------------------------------------------------------------------
68 68
69 69 def module_list(path):
70 70 """
71 71 Return the list containing the names of the modules available in the given
72 72 folder.
73 73 """
74 74 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
75 75 if path == '':
76 76 path = '.'
77 77
78 78 # A few local constants to be used in loops below
79 79 pjoin = os.path.join
80 80
81 81 if os.path.isdir(path):
82 82 # Build a list of all files in the directory and all files
83 83 # in its subdirectories. For performance reasons, do not
84 84 # recurse more than one level into subdirectories.
85 85 files = []
86 86 for root, dirs, nondirs in os.walk(path):
87 87 subdir = root[len(path)+1:]
88 88 if subdir:
89 89 files.extend(pjoin(subdir, f) for f in nondirs)
90 90 dirs[:] = [] # Do not recurse into additional subdirectories.
91 91 else:
92 92 files.extend(nondirs)
93 93
94 94 else:
95 95 try:
96 96 files = list(zipimporter(path)._files.keys())
97 97 except:
98 98 files = []
99 99
100 100 # Build a list of modules which match the import_re regex.
101 101 modules = []
102 102 for f in files:
103 103 m = import_re.match(f)
104 104 if m:
105 105 modules.append(m.group('name'))
106 106 return list(set(modules))
107 107
108 108
109 109 def get_root_modules():
110 110 """
111 111 Returns a list containing the names of all the modules available in the
112 112 folders of the pythonpath.
113 113
114 114 ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
115 115 """
116 116 ip = get_ipython()
117 117 rootmodules_cache = ip.db.get('rootmodules_cache', {})
118 118 rootmodules = list(sys.builtin_module_names)
119 119 start_time = time()
120 120 store = False
121 121 for path in sys.path:
122 122 try:
123 123 modules = rootmodules_cache[path]
124 124 except KeyError:
125 125 modules = module_list(path)
126 126 try:
127 127 modules.remove('__init__')
128 128 except ValueError:
129 129 pass
130 130 if path not in ('', '.'): # cwd modules should not be cached
131 131 rootmodules_cache[path] = modules
132 132 if time() - start_time > TIMEOUT_STORAGE and not store:
133 133 store = True
134 134 print("\nCaching the list of root modules, please wait!")
135 135 print("(This will only be done once - type '%rehashx' to "
136 136 "reset cache!)\n")
137 137 sys.stdout.flush()
138 138 if time() - start_time > TIMEOUT_GIVEUP:
139 139 print("This is taking too long, we give up.\n")
140 140 return []
141 141 rootmodules.extend(modules)
142 142 if store:
143 143 ip.db['rootmodules_cache'] = rootmodules_cache
144 144 rootmodules = list(set(rootmodules))
145 145 return rootmodules
146 146
147 147
148 148 def is_importable(module, attr, only_modules):
149 149 if only_modules:
150 150 return inspect.ismodule(getattr(module, attr))
151 151 else:
152 152 return not(attr[:2] == '__' and attr[-2:] == '__')
153 153
154 154
155 155 def try_import(mod, only_modules=False):
156 156 try:
157 157 m = __import__(mod)
158 158 except:
159 159 return []
160 160 mods = mod.split('.')
161 161 for module in mods[1:]:
162 162 m = getattr(m, module)
163 163
164 164 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
165 165
166 166 completions = []
167 167 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
168 168 completions.extend( [attr for attr in dir(m) if
169 169 is_importable(m, attr, only_modules)])
170 170
171 171 completions.extend(getattr(m, '__all__', []))
172 172 if m_is_init:
173 173 completions.extend(module_list(os.path.dirname(m.__file__)))
174 174 completions = set(completions)
175 175 if '__init__' in completions:
176 176 completions.remove('__init__')
177 177 return list(completions)
178 178
179 179
180 180 #-----------------------------------------------------------------------------
181 181 # Completion-related functions.
182 182 #-----------------------------------------------------------------------------
183 183
184 184 def quick_completer(cmd, completions):
185 185 """ Easily create a trivial completer for a command.
186 186
187 187 Takes either a list of completions, or all completions in string (that will
188 188 be split on whitespace).
189 189
190 190 Example::
191 191
192 192 [d:\ipython]|1> import ipy_completers
193 193 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
194 194 [d:\ipython]|3> foo b<TAB>
195 195 bar baz
196 196 [d:\ipython]|3> foo ba
197 197 """
198 198
199 199 if isinstance(completions, basestring):
200 200 completions = completions.split()
201 201
202 202 def do_complete(self, event):
203 203 return completions
204 204
205 205 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
206 206
207 207 def module_completion(line):
208 208 """
209 209 Returns a list containing the completion possibilities for an import line.
210 210
211 211 The line looks like this :
212 212 'import xml.d'
213 213 'from xml.dom import'
214 214 """
215 215
216 216 words = line.split(' ')
217 217 nwords = len(words)
218 218
219 219 # from whatever <tab> -> 'import '
220 220 if nwords == 3 and words[0] == 'from':
221 221 return ['import ']
222 222
223 223 # 'from xy<tab>' or 'import xy<tab>'
224 224 if nwords < 3 and (words[0] in ['import','from']) :
225 225 if nwords == 1:
226 226 return get_root_modules()
227 227 mod = words[1].split('.')
228 228 if len(mod) < 2:
229 229 return get_root_modules()
230 230 completion_list = try_import('.'.join(mod[:-1]), True)
231 231 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
232 232
233 233 # 'from xyz import abc<tab>'
234 234 if nwords >= 3 and words[0] == 'from':
235 235 mod = words[1]
236 236 return try_import(mod)
237 237
238 238 #-----------------------------------------------------------------------------
239 239 # Completers
240 240 #-----------------------------------------------------------------------------
241 241 # These all have the func(self, event) signature to be used as custom
242 242 # completers
243 243
244 244 def module_completer(self,event):
245 245 """Give completions after user has typed 'import ...' or 'from ...'"""
246 246
247 247 # This works in all versions of python. While 2.5 has
248 248 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
249 249 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
250 250 # of possibly problematic side effects.
251 251 # This search the folders in the sys.path for available modules.
252 252
253 253 return module_completion(event.line)
254 254
255 255 # FIXME: there's a lot of logic common to the run, cd and builtin file
256 256 # completers, that is currently reimplemented in each.
257 257
258 258 def magic_run_completer(self, event):
259 259 """Complete files that end in .py or .ipy for the %run command.
260 260 """
261 261 comps = arg_split(event.line, strict=False)
262 262 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
263 263
264 264 #print("\nev=", event) # dbg
265 265 #print("rp=", relpath) # dbg
266 266 #print('comps=', comps) # dbg
267 267
268 268 lglob = glob.glob
269 269 isdir = os.path.isdir
270 270 relpath, tilde_expand, tilde_val = expand_user(relpath)
271 271
272 272 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
273 273
274 274 # Find if the user has already typed the first filename, after which we
275 275 # should complete on all files, since after the first one other files may
276 276 # be arguments to the input script.
277 277
278 278 if filter(magic_run_re.match, comps):
279 279 pys = [f.replace('\\','/') for f in lglob('*')]
280 280 else:
281 281 pys = [f.replace('\\','/')
282 282 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
283 283 lglob(relpath + '*.pyw')]
284 284 #print('run comp:', dirs+pys) # dbg
285 285 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
286 286
287 287
288 288 def cd_completer(self, event):
289 289 """Completer function for cd, which only returns directories."""
290 290 ip = get_ipython()
291 291 relpath = event.symbol
292 292
293 293 #print(event) # dbg
294 294 if event.line.endswith('-b') or ' -b ' in event.line:
295 295 # return only bookmark completions
296 296 bkms = self.db.get('bookmarks', None)
297 297 if bkms:
298 298 return bkms.keys()
299 299 else:
300 300 return []
301 301
302 302 if event.symbol == '-':
303 303 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
304 304 # jump in directory history by number
305 305 fmt = '-%0' + width_dh +'d [%s]'
306 306 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
307 307 if len(ents) > 1:
308 308 return ents
309 309 return []
310 310
311 311 if event.symbol.startswith('--'):
312 312 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
313 313
314 314 # Expand ~ in path and normalize directory separators.
315 315 relpath, tilde_expand, tilde_val = expand_user(relpath)
316 316 relpath = relpath.replace('\\','/')
317 317
318 318 found = []
319 319 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
320 320 if os.path.isdir(f)]:
321 321 if ' ' in d:
322 322 # we don't want to deal with any of that, complex code
323 323 # for this is elsewhere
324 324 raise TryNext
325 325
326 326 found.append(d)
327 327
328 328 if not found:
329 329 if os.path.isdir(relpath):
330 330 return [compress_user(relpath, tilde_expand, tilde_val)]
331 331
332 332 # if no completions so far, try bookmarks
333 333 bks = self.db.get('bookmarks',{}).iterkeys()
334 334 bkmatches = [s for s in bks if s.startswith(event.symbol)]
335 335 if bkmatches:
336 336 return bkmatches
337 337
338 338 raise TryNext
339 339
340 340 return [compress_user(p, tilde_expand, tilde_val) for p in found]
341 341
342 342 def reset_completer(self, event):
343 343 "A completer for %reset magic"
344 344 return '-f -s in out array dhist'.split()
General Comments 0
You need to be logged in to leave comments. Login now