##// END OF EJS Templates
use cd --foo instead of cd -foo. also cd --<TAB> works. changes.txt
Ville M. Vainio -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,391 +1,394 b''
1
1
2 """ Implementations for various useful completers
2 """ Implementations for various useful completers
3
3
4 See Extensions/ipy_stock_completers.py on examples of how to enable a completer,
4 See Extensions/ipy_stock_completers.py on examples of how to enable a completer,
5 but the basic idea is to do:
5 but the basic idea is to do:
6
6
7 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
7 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
8
8
9 """
9 """
10 import IPython.ipapi
10 import IPython.ipapi
11 import glob,os,shlex,sys
11 import glob,os,shlex,sys
12 import inspect
12 import inspect
13 from time import time
13 from time import time
14 from zipimport import zipimporter
14 from zipimport import zipimporter
15 ip = IPython.ipapi.get()
15 ip = IPython.ipapi.get()
16
16
17 try:
17 try:
18 set
18 set
19 except:
19 except:
20 from sets import Set as set
20 from sets import Set as set
21
21
22 TIMEOUT_STORAGE = 3 #Time in seconds after which the rootmodules will be stored
22 TIMEOUT_STORAGE = 3 #Time in seconds after which the rootmodules will be stored
23 TIMEOUT_GIVEUP = 20 #Time in seconds after which we give up
23 TIMEOUT_GIVEUP = 20 #Time in seconds after which we give up
24
24
25 def quick_completer(cmd, completions):
25 def quick_completer(cmd, completions):
26 """ Easily create a trivial completer for a command.
26 """ Easily create a trivial completer for a command.
27
27
28 Takes either a list of completions, or all completions in string
28 Takes either a list of completions, or all completions in string
29 (that will be split on whitespace)
29 (that will be split on whitespace)
30
30
31 Example::
31 Example::
32
32
33 [d:\ipython]|1> import ipy_completers
33 [d:\ipython]|1> import ipy_completers
34 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
34 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
35 [d:\ipython]|3> foo b<TAB>
35 [d:\ipython]|3> foo b<TAB>
36 bar baz
36 bar baz
37 [d:\ipython]|3> foo ba
37 [d:\ipython]|3> foo ba
38 """
38 """
39 if isinstance(completions, basestring):
39 if isinstance(completions, basestring):
40
40
41 completions = completions.split()
41 completions = completions.split()
42 def do_complete(self,event):
42 def do_complete(self,event):
43 return completions
43 return completions
44
44
45 ip.set_hook('complete_command',do_complete, str_key = cmd)
45 ip.set_hook('complete_command',do_complete, str_key = cmd)
46
46
47 def getRootModules():
47 def getRootModules():
48 """
48 """
49 Returns a list containing the names of all the modules available in the
49 Returns a list containing the names of all the modules available in the
50 folders of the pythonpath.
50 folders of the pythonpath.
51 """
51 """
52 modules = []
52 modules = []
53 if ip.db.has_key('rootmodules'):
53 if ip.db.has_key('rootmodules'):
54 return ip.db['rootmodules']
54 return ip.db['rootmodules']
55 t = time()
55 t = time()
56 store = False
56 store = False
57 for path in sys.path:
57 for path in sys.path:
58 modules += moduleList(path)
58 modules += moduleList(path)
59 if time() - t >= TIMEOUT_STORAGE and not store:
59 if time() - t >= TIMEOUT_STORAGE and not store:
60 store = True
60 store = True
61 print "\nCaching the list of root modules, please wait!"
61 print "\nCaching the list of root modules, please wait!"
62 print "(This will only be done once - type '%rehashx' to " + \
62 print "(This will only be done once - type '%rehashx' to " + \
63 "reset cache!)"
63 "reset cache!)"
64 print
64 print
65 if time() - t > TIMEOUT_GIVEUP:
65 if time() - t > TIMEOUT_GIVEUP:
66 print "This is taking too long, we give up."
66 print "This is taking too long, we give up."
67 print
67 print
68 ip.db['rootmodules'] = []
68 ip.db['rootmodules'] = []
69 return []
69 return []
70
70
71 modules += sys.builtin_module_names
71 modules += sys.builtin_module_names
72
72
73 modules = list(set(modules))
73 modules = list(set(modules))
74 if '__init__' in modules:
74 if '__init__' in modules:
75 modules.remove('__init__')
75 modules.remove('__init__')
76 modules = list(set(modules))
76 modules = list(set(modules))
77 if store:
77 if store:
78 ip.db['rootmodules'] = modules
78 ip.db['rootmodules'] = modules
79 return modules
79 return modules
80
80
81 def moduleList(path):
81 def moduleList(path):
82 """
82 """
83 Return the list containing the names of the modules available in the given
83 Return the list containing the names of the modules available in the given
84 folder.
84 folder.
85 """
85 """
86
86
87 if os.path.isdir(path):
87 if os.path.isdir(path):
88 folder_list = os.listdir(path)
88 folder_list = os.listdir(path)
89 elif path.endswith('.egg'):
89 elif path.endswith('.egg'):
90 try:
90 try:
91 folder_list = [f for f in zipimporter(path)._files]
91 folder_list = [f for f in zipimporter(path)._files]
92 except:
92 except:
93 folder_list = []
93 folder_list = []
94 else:
94 else:
95 folder_list = []
95 folder_list = []
96 #folder_list = glob.glob(os.path.join(path,'*'))
96 #folder_list = glob.glob(os.path.join(path,'*'))
97 folder_list = [p for p in folder_list \
97 folder_list = [p for p in folder_list \
98 if os.path.exists(os.path.join(path, p,'__init__.py'))\
98 if os.path.exists(os.path.join(path, p,'__init__.py'))\
99 or p[-3:] in ('.py','.so')\
99 or p[-3:] in ('.py','.so')\
100 or p[-4:] in ('.pyc','.pyo','.pyd')]
100 or p[-4:] in ('.pyc','.pyo','.pyd')]
101
101
102 folder_list = [os.path.basename(p).split('.')[0] for p in folder_list]
102 folder_list = [os.path.basename(p).split('.')[0] for p in folder_list]
103 return folder_list
103 return folder_list
104
104
105 def moduleCompletion(line):
105 def moduleCompletion(line):
106 """
106 """
107 Returns a list containing the completion possibilities for an import line.
107 Returns a list containing the completion possibilities for an import line.
108 The line looks like this :
108 The line looks like this :
109 'import xml.d'
109 'import xml.d'
110 'from xml.dom import'
110 'from xml.dom import'
111 """
111 """
112 def tryImport(mod, only_modules=False):
112 def tryImport(mod, only_modules=False):
113 def isImportable(module, attr):
113 def isImportable(module, attr):
114 if only_modules:
114 if only_modules:
115 return inspect.ismodule(getattr(module, attr))
115 return inspect.ismodule(getattr(module, attr))
116 else:
116 else:
117 return not(attr[:2] == '__' and attr[-2:] == '__')
117 return not(attr[:2] == '__' and attr[-2:] == '__')
118 try:
118 try:
119 m = __import__(mod)
119 m = __import__(mod)
120 except:
120 except:
121 return []
121 return []
122 mods = mod.split('.')
122 mods = mod.split('.')
123 for module in mods[1:]:
123 for module in mods[1:]:
124 m = getattr(m,module)
124 m = getattr(m,module)
125 if (not hasattr(m, '__file__')) or (not only_modules) or\
125 if (not hasattr(m, '__file__')) or (not only_modules) or\
126 (hasattr(m, '__file__') and '__init__' in m.__file__):
126 (hasattr(m, '__file__') and '__init__' in m.__file__):
127 completion_list = [attr for attr in dir(m) if isImportable(m, attr)]
127 completion_list = [attr for attr in dir(m) if isImportable(m, attr)]
128 completion_list.extend(getattr(m,'__all__',[]))
128 completion_list.extend(getattr(m,'__all__',[]))
129 if hasattr(m, '__file__') and '__init__' in m.__file__:
129 if hasattr(m, '__file__') and '__init__' in m.__file__:
130 completion_list.extend(moduleList(os.path.dirname(m.__file__)))
130 completion_list.extend(moduleList(os.path.dirname(m.__file__)))
131 completion_list = list(set(completion_list))
131 completion_list = list(set(completion_list))
132 if '__init__' in completion_list:
132 if '__init__' in completion_list:
133 completion_list.remove('__init__')
133 completion_list.remove('__init__')
134 return completion_list
134 return completion_list
135
135
136 words = line.split(' ')
136 words = line.split(' ')
137 if len(words) == 3 and words[0] == 'from':
137 if len(words) == 3 and words[0] == 'from':
138 return ['import ']
138 return ['import ']
139 if len(words) < 3 and (words[0] in ['import','from']) :
139 if len(words) < 3 and (words[0] in ['import','from']) :
140 if len(words) == 1:
140 if len(words) == 1:
141 return getRootModules()
141 return getRootModules()
142 mod = words[1].split('.')
142 mod = words[1].split('.')
143 if len(mod) < 2:
143 if len(mod) < 2:
144 return getRootModules()
144 return getRootModules()
145 completion_list = tryImport('.'.join(mod[:-1]), True)
145 completion_list = tryImport('.'.join(mod[:-1]), True)
146 completion_list = ['.'.join(mod[:-1] + [el]) for el in completion_list]
146 completion_list = ['.'.join(mod[:-1] + [el]) for el in completion_list]
147 return completion_list
147 return completion_list
148 if len(words) >= 3 and words[0] == 'from':
148 if len(words) >= 3 and words[0] == 'from':
149 mod = words[1]
149 mod = words[1]
150 return tryImport(mod)
150 return tryImport(mod)
151
151
152 def vcs_completer(commands, event):
152 def vcs_completer(commands, event):
153 """ utility to make writing typical version control app completers easier
153 """ utility to make writing typical version control app completers easier
154
154
155 VCS command line apps typically have the format:
155 VCS command line apps typically have the format:
156
156
157 [sudo ]PROGNAME [help] [command] file file...
157 [sudo ]PROGNAME [help] [command] file file...
158
158
159 """
159 """
160
160
161
161
162 cmd_param = event.line.split()
162 cmd_param = event.line.split()
163 if event.line.endswith(' '):
163 if event.line.endswith(' '):
164 cmd_param.append('')
164 cmd_param.append('')
165
165
166 if cmd_param[0] == 'sudo':
166 if cmd_param[0] == 'sudo':
167 cmd_param = cmd_param[1:]
167 cmd_param = cmd_param[1:]
168
168
169 if len(cmd_param) == 2 or 'help' in cmd_param:
169 if len(cmd_param) == 2 or 'help' in cmd_param:
170 return commands.split()
170 return commands.split()
171
171
172 return ip.IP.Completer.file_matches(event.symbol)
172 return ip.IP.Completer.file_matches(event.symbol)
173
173
174
174
175 pkg_cache = None
175 pkg_cache = None
176
176
177 def module_completer(self,event):
177 def module_completer(self,event):
178 """ Give completions after user has typed 'import ...' or 'from ...'"""
178 """ Give completions after user has typed 'import ...' or 'from ...'"""
179
179
180 # This works in all versions of python. While 2.5 has
180 # This works in all versions of python. While 2.5 has
181 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
181 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
182 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
182 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
183 # of possibly problematic side effects.
183 # of possibly problematic side effects.
184 # This search the folders in the sys.path for available modules.
184 # This search the folders in the sys.path for available modules.
185
185
186 return moduleCompletion(event.line)
186 return moduleCompletion(event.line)
187
187
188
188
189 svn_commands = """\
189 svn_commands = """\
190 add blame praise annotate ann cat checkout co cleanup commit ci copy
190 add blame praise annotate ann cat checkout co cleanup commit ci copy
191 cp delete del remove rm diff di export help ? h import info list ls
191 cp delete del remove rm diff di export help ? h import info list ls
192 lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit
192 lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit
193 pe propget pget pg proplist plist pl propset pset ps resolved revert
193 pe propget pget pg proplist plist pl propset pset ps resolved revert
194 status stat st switch sw unlock update
194 status stat st switch sw unlock update
195 """
195 """
196
196
197 def svn_completer(self,event):
197 def svn_completer(self,event):
198 return vcs_completer(svn_commands, event)
198 return vcs_completer(svn_commands, event)
199
199
200
200
201 hg_commands = """
201 hg_commands = """
202 add addremove annotate archive backout branch branches bundle cat
202 add addremove annotate archive backout branch branches bundle cat
203 clone commit copy diff export grep heads help identify import incoming
203 clone commit copy diff export grep heads help identify import incoming
204 init locate log manifest merge outgoing parents paths pull push
204 init locate log manifest merge outgoing parents paths pull push
205 qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport
205 qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport
206 qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave
206 qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave
207 qselect qseries qtop qunapplied recover remove rename revert rollback
207 qselect qseries qtop qunapplied recover remove rename revert rollback
208 root serve showconfig status strip tag tags tip unbundle update verify
208 root serve showconfig status strip tag tags tip unbundle update verify
209 version
209 version
210 """
210 """
211
211
212 def hg_completer(self,event):
212 def hg_completer(self,event):
213 """ Completer for mercurial commands """
213 """ Completer for mercurial commands """
214
214
215 return vcs_completer(hg_commands, event)
215 return vcs_completer(hg_commands, event)
216
216
217
217
218
218
219 __bzr_commands = None
219 __bzr_commands = None
220
220
221 def bzr_commands():
221 def bzr_commands():
222 global __bzr_commands
222 global __bzr_commands
223 if __bzr_commands is not None:
223 if __bzr_commands is not None:
224 return __bzr_commands
224 return __bzr_commands
225 out = os.popen('bzr help commands')
225 out = os.popen('bzr help commands')
226 __bzr_commands = [l.split()[0] for l in out]
226 __bzr_commands = [l.split()[0] for l in out]
227 return __bzr_commands
227 return __bzr_commands
228
228
229 def bzr_completer(self,event):
229 def bzr_completer(self,event):
230 """ Completer for bazaar commands """
230 """ Completer for bazaar commands """
231 cmd_param = event.line.split()
231 cmd_param = event.line.split()
232 if event.line.endswith(' '):
232 if event.line.endswith(' '):
233 cmd_param.append('')
233 cmd_param.append('')
234
234
235 if len(cmd_param) > 2:
235 if len(cmd_param) > 2:
236 cmd = cmd_param[1]
236 cmd = cmd_param[1]
237 param = cmd_param[-1]
237 param = cmd_param[-1]
238 output_file = (param == '--output=')
238 output_file = (param == '--output=')
239 if cmd == 'help':
239 if cmd == 'help':
240 return bzr_commands()
240 return bzr_commands()
241 elif cmd in ['bundle-revisions','conflicts',
241 elif cmd in ['bundle-revisions','conflicts',
242 'deleted','nick','register-branch',
242 'deleted','nick','register-branch',
243 'serve','unbind','upgrade','version',
243 'serve','unbind','upgrade','version',
244 'whoami'] and not output_file:
244 'whoami'] and not output_file:
245 return []
245 return []
246 else:
246 else:
247 # the rest are probably file names
247 # the rest are probably file names
248 return ip.IP.Completer.file_matches(event.symbol)
248 return ip.IP.Completer.file_matches(event.symbol)
249
249
250 return bzr_commands()
250 return bzr_commands()
251
251
252
252
253 def shlex_split(x):
253 def shlex_split(x):
254 """Helper function to split lines into segments."""
254 """Helper function to split lines into segments."""
255 #shlex.split raise exception if syntax error in sh syntax
255 #shlex.split raise exception if syntax error in sh syntax
256 #for example if no closing " is found. This function keeps dropping
256 #for example if no closing " is found. This function keeps dropping
257 #the last character of the line until shlex.split does not raise
257 #the last character of the line until shlex.split does not raise
258 #exception. Adds end of the line to the result of shlex.split
258 #exception. Adds end of the line to the result of shlex.split
259 #example: %run "c:/python -> ['%run','"c:/python']
259 #example: %run "c:/python -> ['%run','"c:/python']
260 endofline=[]
260 endofline=[]
261 while x!="":
261 while x!="":
262 try:
262 try:
263 comps=shlex.split(x)
263 comps=shlex.split(x)
264 if len(endofline)>=1:
264 if len(endofline)>=1:
265 comps.append("".join(endofline))
265 comps.append("".join(endofline))
266 return comps
266 return comps
267 except ValueError:
267 except ValueError:
268 endofline=[x[-1:]]+endofline
268 endofline=[x[-1:]]+endofline
269 x=x[:-1]
269 x=x[:-1]
270 return ["".join(endofline)]
270 return ["".join(endofline)]
271
271
272 def runlistpy(self, event):
272 def runlistpy(self, event):
273 comps = shlex_split(event.line)
273 comps = shlex_split(event.line)
274 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
274 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
275
275
276 #print "\nev=",event # dbg
276 #print "\nev=",event # dbg
277 #print "rp=",relpath # dbg
277 #print "rp=",relpath # dbg
278 #print 'comps=',comps # dbg
278 #print 'comps=',comps # dbg
279
279
280 lglob = glob.glob
280 lglob = glob.glob
281 isdir = os.path.isdir
281 isdir = os.path.isdir
282 if relpath.startswith('~'):
282 if relpath.startswith('~'):
283 relpath = os.path.expanduser(relpath)
283 relpath = os.path.expanduser(relpath)
284 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
284 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
285 if isdir(f)]
285 if isdir(f)]
286
286
287 # Find if the user has already typed the first filename, after which we
287 # Find if the user has already typed the first filename, after which we
288 # should complete on all files, since after the first one other files may
288 # should complete on all files, since after the first one other files may
289 # be arguments to the input script.
289 # be arguments to the input script.
290 #filter(
290 #filter(
291 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy') or
291 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy') or
292 f.endswith('.pyw'),comps):
292 f.endswith('.pyw'),comps):
293 pys = [f.replace('\\','/') for f in lglob('*')]
293 pys = [f.replace('\\','/') for f in lglob('*')]
294 else:
294 else:
295 pys = [f.replace('\\','/')
295 pys = [f.replace('\\','/')
296 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
296 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
297 lglob(relpath + '*.pyw')]
297 lglob(relpath + '*.pyw')]
298 return dirs + pys
298 return dirs + pys
299
299
300
300
301 greedy_cd_completer = False
301 greedy_cd_completer = False
302
302
303 def cd_completer(self, event):
303 def cd_completer(self, event):
304 relpath = event.symbol
304 relpath = event.symbol
305 #print event # dbg
305 #print event # dbg
306 if '-b' in event.line:
306 if '-b' in event.line:
307 # return only bookmark completions
307 # return only bookmark completions
308 bkms = self.db.get('bookmarks',{})
308 bkms = self.db.get('bookmarks',{})
309 return bkms.keys()
309 return bkms.keys()
310
310
311
311
312 if event.symbol == '-':
312 if event.symbol == '-':
313 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
313 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
314 # jump in directory history by number
314 # jump in directory history by number
315 fmt = '-%0' + width_dh +'d [%s]'
315 fmt = '-%0' + width_dh +'d [%s]'
316 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
316 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
317 if len(ents) > 1:
317 if len(ents) > 1:
318 return ents
318 return ents
319 return []
319 return []
320
320
321 if event.symbol.startswith('--'):
322 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
323
321 if relpath.startswith('~'):
324 if relpath.startswith('~'):
322 relpath = os.path.expanduser(relpath).replace('\\','/')
325 relpath = os.path.expanduser(relpath).replace('\\','/')
323 found = []
326 found = []
324 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
327 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
325 if os.path.isdir(f)]:
328 if os.path.isdir(f)]:
326 if ' ' in d:
329 if ' ' in d:
327 # we don't want to deal with any of that, complex code
330 # we don't want to deal with any of that, complex code
328 # for this is elsewhere
331 # for this is elsewhere
329 raise IPython.ipapi.TryNext
332 raise IPython.ipapi.TryNext
330 found.append( d )
333 found.append( d )
331
334
332 if not found:
335 if not found:
333 if os.path.isdir(relpath):
336 if os.path.isdir(relpath):
334 return [relpath]
337 return [relpath]
335 raise IPython.ipapi.TryNext
338 raise IPython.ipapi.TryNext
336
339
337
340
338 def single_dir_expand(matches):
341 def single_dir_expand(matches):
339 "Recursively expand match lists containing a single dir."
342 "Recursively expand match lists containing a single dir."
340
343
341 if len(matches) == 1 and os.path.isdir(matches[0]):
344 if len(matches) == 1 and os.path.isdir(matches[0]):
342 # Takes care of links to directories also. Use '/'
345 # Takes care of links to directories also. Use '/'
343 # explicitly, even under Windows, so that name completions
346 # explicitly, even under Windows, so that name completions
344 # don't end up escaped.
347 # don't end up escaped.
345 d = matches[0]
348 d = matches[0]
346 if d[-1] in ['/','\\']:
349 if d[-1] in ['/','\\']:
347 d = d[:-1]
350 d = d[:-1]
348
351
349 subdirs = [p for p in os.listdir(d) if os.path.isdir( d + '/' + p) and not p.startswith('.')]
352 subdirs = [p for p in os.listdir(d) if os.path.isdir( d + '/' + p) and not p.startswith('.')]
350 if subdirs:
353 if subdirs:
351 matches = [ (d + '/' + p) for p in subdirs ]
354 matches = [ (d + '/' + p) for p in subdirs ]
352 return single_dir_expand(matches)
355 return single_dir_expand(matches)
353 else:
356 else:
354 return matches
357 return matches
355 else:
358 else:
356 return matches
359 return matches
357
360
358 if greedy_cd_completer:
361 if greedy_cd_completer:
359 return single_dir_expand(found)
362 return single_dir_expand(found)
360 else:
363 else:
361 return found
364 return found
362
365
363 def apt_get_packages(prefix):
366 def apt_get_packages(prefix):
364 out = os.popen('apt-cache pkgnames')
367 out = os.popen('apt-cache pkgnames')
365 for p in out:
368 for p in out:
366 if p.startswith(prefix):
369 if p.startswith(prefix):
367 yield p.rstrip()
370 yield p.rstrip()
368
371
369
372
370 apt_commands = """\
373 apt_commands = """\
371 update upgrade install remove purge source build-dep dist-upgrade
374 update upgrade install remove purge source build-dep dist-upgrade
372 dselect-upgrade clean autoclean check"""
375 dselect-upgrade clean autoclean check"""
373
376
374 def apt_completer(self, event):
377 def apt_completer(self, event):
375 """ Completer for apt-get (uses apt-cache internally)
378 """ Completer for apt-get (uses apt-cache internally)
376
379
377 """
380 """
378
381
379
382
380 cmd_param = event.line.split()
383 cmd_param = event.line.split()
381 if event.line.endswith(' '):
384 if event.line.endswith(' '):
382 cmd_param.append('')
385 cmd_param.append('')
383
386
384 if cmd_param[0] == 'sudo':
387 if cmd_param[0] == 'sudo':
385 cmd_param = cmd_param[1:]
388 cmd_param = cmd_param[1:]
386
389
387 if len(cmd_param) == 2 or 'help' in cmd_param:
390 if len(cmd_param) == 2 or 'help' in cmd_param:
388 return apt_commands.split()
391 return apt_commands.split()
389
392
390 return list(apt_get_packages(event.symbol))
393 return list(apt_get_packages(event.symbol))
391
394
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,195 +1,200 b''
1 .. _changes:
1 .. _changes:
2
2
3 ==========
3 ==========
4 What's new
4 What's new
5 ==========
5 ==========
6
6
7 .. contents::
7 .. contents::
8
8
9 Release 0.9
9 Release 0.9
10 ===========
10 ===========
11
11
12 New features
12 New features
13 ------------
13 ------------
14
14
15 * The notion of a task has been completely reworked. An `ITask` interface has
15 * The notion of a task has been completely reworked. An `ITask` interface has
16 been created. This interface defines the methods that tasks need to implement.
16 been created. This interface defines the methods that tasks need to implement.
17 These methods are now responsible for things like submitting tasks and processing
17 These methods are now responsible for things like submitting tasks and processing
18 results. There are two basic task types: :class:`IPython.kernel.task.StringTask`
18 results. There are two basic task types: :class:`IPython.kernel.task.StringTask`
19 (this is the old `Task` object, but renamed) and the new
19 (this is the old `Task` object, but renamed) and the new
20 :class:`IPython.kernel.task.MapTask`, which is based on a function.
20 :class:`IPython.kernel.task.MapTask`, which is based on a function.
21 * A new interface, :class:`IPython.kernel.mapper.IMapper` has been defined to
21 * A new interface, :class:`IPython.kernel.mapper.IMapper` has been defined to
22 standardize the idea of a `map` method. This interface has a single
22 standardize the idea of a `map` method. This interface has a single
23 `map` method that has the same syntax as the built-in `map`. We have also defined
23 `map` method that has the same syntax as the built-in `map`. We have also defined
24 a `mapper` factory interface that creates objects that implement
24 a `mapper` factory interface that creates objects that implement
25 :class:`IPython.kernel.mapper.IMapper` for different controllers. Both
25 :class:`IPython.kernel.mapper.IMapper` for different controllers. Both
26 the multiengine and task controller now have mapping capabilties.
26 the multiengine and task controller now have mapping capabilties.
27 * The parallel function capabilities have been reworks. The major changes are that
27 * The parallel function capabilities have been reworks. The major changes are that
28 i) there is now an `@parallel` magic that creates parallel functions, ii)
28 i) there is now an `@parallel` magic that creates parallel functions, ii)
29 the syntax for mulitple variable follows that of `map`, iii) both the
29 the syntax for mulitple variable follows that of `map`, iii) both the
30 multiengine and task controller now have a parallel function implementation.
30 multiengine and task controller now have a parallel function implementation.
31 * All of the parallel computing capabilities from `ipython1-dev` have been merged into
31 * All of the parallel computing capabilities from `ipython1-dev` have been merged into
32 IPython proper. This resulted in the following new subpackages:
32 IPython proper. This resulted in the following new subpackages:
33 :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`,
33 :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`,
34 :mod:`IPython.tools` and :mod:`IPython.testing`.
34 :mod:`IPython.tools` and :mod:`IPython.testing`.
35 * As part of merging in the `ipython1-dev` stuff, the `setup.py` script and friends
35 * As part of merging in the `ipython1-dev` stuff, the `setup.py` script and friends
36 have been completely refactored. Now we are checking for dependencies using
36 have been completely refactored. Now we are checking for dependencies using
37 the approach that matplotlib uses.
37 the approach that matplotlib uses.
38 * The documentation has been completely reorganized to accept the documentation
38 * The documentation has been completely reorganized to accept the documentation
39 from `ipython1-dev`.
39 from `ipython1-dev`.
40 * We have switched to using Foolscap for all of our network protocols in
40 * We have switched to using Foolscap for all of our network protocols in
41 :mod:`IPython.kernel`. This gives us secure connections that are both encrypted
41 :mod:`IPython.kernel`. This gives us secure connections that are both encrypted
42 and authenticated.
42 and authenticated.
43 * We have a brand new `COPYING.txt` files that describes the IPython license
43 * We have a brand new `COPYING.txt` files that describes the IPython license
44 and copyright. The biggest change is that we are putting "The IPython
44 and copyright. The biggest change is that we are putting "The IPython
45 Development Team" as the copyright holder. We give more details about exactly
45 Development Team" as the copyright holder. We give more details about exactly
46 what this means in this file. All developer should read this and use the new
46 what this means in this file. All developer should read this and use the new
47 banner in all IPython source code files.
47 banner in all IPython source code files.
48 * sh profile: ./foo runs foo as system command, no need to do !./foo anymore
48 * sh profile: ./foo runs foo as system command, no need to do !./foo anymore
49 * String lists now support 'sort(field, nums = True)' method (to easily
49 * String lists now support 'sort(field, nums = True)' method (to easily
50 sort system command output). Try it with 'a = !ls -l ; a.sort(1, nums=1)'
50 sort system command output). Try it with 'a = !ls -l ; a.sort(1, nums=1)'
51 * '%cpaste foo' now assigns the pasted block as string list, instead of string
51 * '%cpaste foo' now assigns the pasted block as string list, instead of string
52 * The ipcluster script now run by default with no security. This is done because
52 * The ipcluster script now run by default with no security. This is done because
53 the main usage of the script is for starting things on localhost. Eventually
53 the main usage of the script is for starting things on localhost. Eventually
54 when ipcluster is able to start things on other hosts, we will put security
54 when ipcluster is able to start things on other hosts, we will put security
55 back.
55 back.
56 * 'cd --foo' searches directory history for string foo, and jumps to that dir.
57 Last part of dir name is checked first. If no matches for that are found,
58 look at the whole path.
56
59
57 Bug fixes
60 Bug fixes
58 ---------
61 ---------
59
62
60 * The colors escapes in the multiengine client are now turned off on win32 as they
63 * The colors escapes in the multiengine client are now turned off on win32 as they
61 don't print correctly.
64 don't print correctly.
62 * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing mpi_import_statement
65 * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing mpi_import_statement
63 incorrectly, which was leading the engine to crash when mpi was enabled.
66 incorrectly, which was leading the engine to crash when mpi was enabled.
64 * A few subpackages has missing `__init__.py` files.
67 * A few subpackages has missing `__init__.py` files.
65 * The documentation is only created is Sphinx is found. Previously, the `setup.py`
68 * The documentation is only created is Sphinx is found. Previously, the `setup.py`
66 script would fail if it was missing.
69 script would fail if it was missing.
70 * Greedy 'cd' completion has been disabled again (it was enabled in 0.8.4)
71
67
72
68 Backwards incompatible changes
73 Backwards incompatible changes
69 ------------------------------
74 ------------------------------
70
75
71 * :class:`IPython.kernel.client.Task` has been renamed
76 * :class:`IPython.kernel.client.Task` has been renamed
72 :class:`IPython.kernel.client.StringTask` to make way for new task types.
77 :class:`IPython.kernel.client.StringTask` to make way for new task types.
73 * The keyword argument `style` has been renamed `dist` in `scatter`, `gather`
78 * The keyword argument `style` has been renamed `dist` in `scatter`, `gather`
74 and `map`.
79 and `map`.
75 * Renamed the values that the rename `dist` keyword argument can have from
80 * Renamed the values that the rename `dist` keyword argument can have from
76 `'basic'` to `'b'`.
81 `'basic'` to `'b'`.
77 * IPython has a larger set of dependencies if you want all of its capabilities.
82 * IPython has a larger set of dependencies if you want all of its capabilities.
78 See the `setup.py` script for details.
83 See the `setup.py` script for details.
79 * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and
84 * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and
80 :class:`IPython.kernel.client.TaskClient` no longer take the (ip,port) tuple.
85 :class:`IPython.kernel.client.TaskClient` no longer take the (ip,port) tuple.
81 Instead they take the filename of a file that contains the FURL for that
86 Instead they take the filename of a file that contains the FURL for that
82 client. If the FURL file is in your IPYTHONDIR, it will be found automatically
87 client. If the FURL file is in your IPYTHONDIR, it will be found automatically
83 and the constructor can be left empty.
88 and the constructor can be left empty.
84 * The asynchronous clients in :mod:`IPython.kernel.asyncclient` are now created
89 * The asynchronous clients in :mod:`IPython.kernel.asyncclient` are now created
85 using the factory functions :func:`get_multiengine_client` and
90 using the factory functions :func:`get_multiengine_client` and
86 :func:`get_task_client`. These return a `Deferred` to the actual client.
91 :func:`get_task_client`. These return a `Deferred` to the actual client.
87 * The command line options to `ipcontroller` and `ipengine` have changed to
92 * The command line options to `ipcontroller` and `ipengine` have changed to
88 reflect the new Foolscap network protocol and the FURL files. Please see the
93 reflect the new Foolscap network protocol and the FURL files. Please see the
89 help for these scripts for details.
94 help for these scripts for details.
90 * The configuration files for the kernel have changed because of the Foolscap stuff.
95 * The configuration files for the kernel have changed because of the Foolscap stuff.
91 If you were using custom config files before, you should delete them and regenerate
96 If you were using custom config files before, you should delete them and regenerate
92 new ones.
97 new ones.
93
98
94 Changes merged in from IPython1
99 Changes merged in from IPython1
95 -------------------------------
100 -------------------------------
96
101
97 New features
102 New features
98 ............
103 ............
99
104
100 * Much improved ``setup.py`` and ``setupegg.py`` scripts. Because Twisted
105 * Much improved ``setup.py`` and ``setupegg.py`` scripts. Because Twisted
101 and zope.interface are now easy installable, we can declare them as dependencies
106 and zope.interface are now easy installable, we can declare them as dependencies
102 in our setupegg.py script.
107 in our setupegg.py script.
103 * IPython is now compatible with Twisted 2.5.0 and 8.x.
108 * IPython is now compatible with Twisted 2.5.0 and 8.x.
104 * Added a new example of how to use :mod:`ipython1.kernel.asynclient`.
109 * Added a new example of how to use :mod:`ipython1.kernel.asynclient`.
105 * Initial draft of a process daemon in :mod:`ipython1.daemon`. This has not
110 * Initial draft of a process daemon in :mod:`ipython1.daemon`. This has not
106 been merged into IPython and is still in `ipython1-dev`.
111 been merged into IPython and is still in `ipython1-dev`.
107 * The ``TaskController`` now has methods for getting the queue status.
112 * The ``TaskController`` now has methods for getting the queue status.
108 * The ``TaskResult`` objects not have information about how long the task
113 * The ``TaskResult`` objects not have information about how long the task
109 took to run.
114 took to run.
110 * We are attaching additional attributes to exceptions ``(_ipython_*)`` that
115 * We are attaching additional attributes to exceptions ``(_ipython_*)`` that
111 we use to carry additional info around.
116 we use to carry additional info around.
112 * New top-level module :mod:`asyncclient` that has asynchronous versions (that
117 * New top-level module :mod:`asyncclient` that has asynchronous versions (that
113 return deferreds) of the client classes. This is designed to users who want
118 return deferreds) of the client classes. This is designed to users who want
114 to run their own Twisted reactor
119 to run their own Twisted reactor
115 * All the clients in :mod:`client` are now based on Twisted. This is done by
120 * All the clients in :mod:`client` are now based on Twisted. This is done by
116 running the Twisted reactor in a separate thread and using the
121 running the Twisted reactor in a separate thread and using the
117 :func:`blockingCallFromThread` function that is in recent versions of Twisted.
122 :func:`blockingCallFromThread` function that is in recent versions of Twisted.
118 * Functions can now be pushed/pulled to/from engines using
123 * Functions can now be pushed/pulled to/from engines using
119 :meth:`MultiEngineClient.push_function` and :meth:`MultiEngineClient.pull_function`.
124 :meth:`MultiEngineClient.push_function` and :meth:`MultiEngineClient.pull_function`.
120 * Gather/scatter are now implemented in the client to reduce the work load
125 * Gather/scatter are now implemented in the client to reduce the work load
121 of the controller and improve performance.
126 of the controller and improve performance.
122 * Complete rewrite of the IPython docuementation. All of the documentation
127 * Complete rewrite of the IPython docuementation. All of the documentation
123 from the IPython website has been moved into docs/source as restructured
128 from the IPython website has been moved into docs/source as restructured
124 text documents. PDF and HTML documentation are being generated using
129 text documents. PDF and HTML documentation are being generated using
125 Sphinx.
130 Sphinx.
126 * New developer oriented documentation: development guidelines and roadmap.
131 * New developer oriented documentation: development guidelines and roadmap.
127 * Traditional ``ChangeLog`` has been changed to a more useful ``changes.txt`` file
132 * Traditional ``ChangeLog`` has been changed to a more useful ``changes.txt`` file
128 that is organized by release and is meant to provide something more relevant
133 that is organized by release and is meant to provide something more relevant
129 for users.
134 for users.
130
135
131 Bug fixes
136 Bug fixes
132 .........
137 .........
133
138
134 * Created a proper ``MANIFEST.in`` file to create source distributions.
139 * Created a proper ``MANIFEST.in`` file to create source distributions.
135 * Fixed a bug in the ``MultiEngine`` interface. Previously, multi-engine
140 * Fixed a bug in the ``MultiEngine`` interface. Previously, multi-engine
136 actions were being collected with a :class:`DeferredList` with
141 actions were being collected with a :class:`DeferredList` with
137 ``fireononeerrback=1``. This meant that methods were returning
142 ``fireononeerrback=1``. This meant that methods were returning
138 before all engines had given their results. This was causing extremely odd
143 before all engines had given their results. This was causing extremely odd
139 bugs in certain cases. To fix this problem, we have 1) set
144 bugs in certain cases. To fix this problem, we have 1) set
140 ``fireononeerrback=0`` to make sure all results (or exceptions) are in
145 ``fireononeerrback=0`` to make sure all results (or exceptions) are in
141 before returning and 2) introduced a :exc:`CompositeError` exception
146 before returning and 2) introduced a :exc:`CompositeError` exception
142 that wraps all of the engine exceptions. This is a huge change as it means
147 that wraps all of the engine exceptions. This is a huge change as it means
143 that users will have to catch :exc:`CompositeError` rather than the actual
148 that users will have to catch :exc:`CompositeError` rather than the actual
144 exception.
149 exception.
145
150
146 Backwards incompatible changes
151 Backwards incompatible changes
147 ..............................
152 ..............................
148
153
149 * All names have been renamed to conform to the lowercase_with_underscore
154 * All names have been renamed to conform to the lowercase_with_underscore
150 convention. This will require users to change references to all names like
155 convention. This will require users to change references to all names like
151 ``queueStatus`` to ``queue_status``.
156 ``queueStatus`` to ``queue_status``.
152 * Previously, methods like :meth:`MultiEngineClient.push` and
157 * Previously, methods like :meth:`MultiEngineClient.push` and
153 :meth:`MultiEngineClient.push` used ``*args`` and ``**kwargs``. This was
158 :meth:`MultiEngineClient.push` used ``*args`` and ``**kwargs``. This was
154 becoming a problem as we weren't able to introduce new keyword arguments into
159 becoming a problem as we weren't able to introduce new keyword arguments into
155 the API. Now these methods simple take a dict or sequence. This has also allowed
160 the API. Now these methods simple take a dict or sequence. This has also allowed
156 us to get rid of the ``*All`` methods like :meth:`pushAll` and :meth:`pullAll`.
161 us to get rid of the ``*All`` methods like :meth:`pushAll` and :meth:`pullAll`.
157 These things are now handled with the ``targets`` keyword argument that defaults
162 These things are now handled with the ``targets`` keyword argument that defaults
158 to ``'all'``.
163 to ``'all'``.
159 * The :attr:`MultiEngineClient.magicTargets` has been renamed to
164 * The :attr:`MultiEngineClient.magicTargets` has been renamed to
160 :attr:`MultiEngineClient.targets`.
165 :attr:`MultiEngineClient.targets`.
161 * All methods in the MultiEngine interface now accept the optional keyword argument
166 * All methods in the MultiEngine interface now accept the optional keyword argument
162 ``block``.
167 ``block``.
163 * Renamed :class:`RemoteController` to :class:`MultiEngineClient` and
168 * Renamed :class:`RemoteController` to :class:`MultiEngineClient` and
164 :class:`TaskController` to :class:`TaskClient`.
169 :class:`TaskController` to :class:`TaskClient`.
165 * Renamed the top-level module from :mod:`api` to :mod:`client`.
170 * Renamed the top-level module from :mod:`api` to :mod:`client`.
166 * Most methods in the multiengine interface now raise a :exc:`CompositeError` exception
171 * Most methods in the multiengine interface now raise a :exc:`CompositeError` exception
167 that wraps the user's exceptions, rather than just raising the raw user's exception.
172 that wraps the user's exceptions, rather than just raising the raw user's exception.
168 * Changed the ``setupNS`` and ``resultNames`` in the ``Task`` class to ``push``
173 * Changed the ``setupNS`` and ``resultNames`` in the ``Task`` class to ``push``
169 and ``pull``.
174 and ``pull``.
170
175
171 Release 0.8.4
176 Release 0.8.4
172 =============
177 =============
173
178
174 Someone needs to describe what went into 0.8.4.
179 Someone needs to describe what went into 0.8.4.
175
180
176 Release 0.8.2
181 Release 0.8.2
177 =============
182 =============
178
183
179 * %pushd/%popd behave differently; now "pushd /foo" pushes CURRENT directory
184 * %pushd/%popd behave differently; now "pushd /foo" pushes CURRENT directory
180 and jumps to /foo. The current behaviour is closer to the documented
185 and jumps to /foo. The current behaviour is closer to the documented
181 behaviour, and should not trip anyone.
186 behaviour, and should not trip anyone.
182
187
183 Release 0.8.3
188 Release 0.8.3
184 =============
189 =============
185
190
186 * pydb is now disabled by default (due to %run -d problems). You can enable
191 * pydb is now disabled by default (due to %run -d problems). You can enable
187 it by passing -pydb command line argument to IPython. Note that setting
192 it by passing -pydb command line argument to IPython. Note that setting
188 it in config file won't work.
193 it in config file won't work.
189
194
190 Older releases
195 Older releases
191 ==============
196 ==============
192
197
193 Changes in earlier releases of IPython are described in the older file ``ChangeLog``.
198 Changes in earlier releases of IPython are described in the older file ``ChangeLog``.
194 Please refer to this document for details.
199 Please refer to this document for details.
195
200
General Comments 0
You need to be logged in to leave comments. Login now