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