##// END OF EJS Templates
Merge in all development done in bzr since February 16 2008....
Fernando Perez -
r1218:6b454030 merge
parent child Browse files
Show More

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

@@ -0,0 +1,2 b''
1 [LF]
2 *.py
@@ -0,0 +1,244 b''
1 """
2 IPython extension: autoreload modules before executing the next line
3
4 Try::
5
6 %autoreload?
7
8 for documentation.
9 """
10
11 # Pauli Virtanen <pav@iki.fi>, 2008.
12 # Thomas Heller, 2000.
13 #
14 # This IPython module is written by Pauli Virtanen, based on the autoreload
15 # code by Thomas Heller.
16
17 #------------------------------------------------------------------------------
18 # Autoreload functionality
19 #------------------------------------------------------------------------------
20
21 import time, os, threading, sys, types, imp, inspect, traceback, atexit
22
23 def _get_compiled_ext():
24 """Official way to get the extension of compiled files (.pyc or .pyo)"""
25 for ext, mode, typ in imp.get_suffixes():
26 if typ == imp.PY_COMPILED:
27 return ext
28
29 PY_COMPILED_EXT = _get_compiled_ext()
30
31 class ModuleReloader(object):
32 skipped = {}
33 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
34
35 modules = {}
36 """Modules specially marked as autoreloadable."""
37
38 skip_modules = {}
39 """Modules specially marked as not autoreloadable."""
40
41 check_all = True
42 """Autoreload all modules, not just those listed in 'modules'"""
43
44 def check(self, check_all=False):
45 """Check whether some modules need to be reloaded."""
46
47 if check_all or self.check_all:
48 modules = sys.modules.keys()
49 else:
50 modules = self.modules.keys()
51
52 for modname in modules:
53 m = sys.modules.get(modname, None)
54
55 if modname in self.skip_modules:
56 continue
57
58 if not hasattr(m, '__file__'):
59 continue
60
61 if m.__name__ == '__main__':
62 # we cannot reload(__main__)
63 continue
64
65 filename = m.__file__
66 dirname = os.path.dirname(filename)
67 path, ext = os.path.splitext(filename)
68
69 if ext.lower() == '.py':
70 ext = PY_COMPILED_EXT
71 filename = os.path.join(dirname, path + PY_COMPILED_EXT)
72
73 if ext != PY_COMPILED_EXT:
74 continue
75
76 try:
77 pymtime = os.stat(filename[:-1]).st_mtime
78 if pymtime <= os.stat(filename).st_mtime:
79 continue
80 if self.skipped.get(filename[:-1], None) == pymtime:
81 continue
82 except OSError:
83 continue
84
85 try:
86 superreload(m)
87 if filename[:-1] in self.skipped:
88 del self.skipped[filename[:-1]]
89 except:
90 self.skipped[filename[:-1]] = pymtime
91
92 def update_function(old, new, attrnames):
93 for name in attrnames:
94 setattr(old, name, getattr(new, name))
95
96 def superreload(module, reload=reload):
97 """Enhanced version of the builtin reload function.
98
99 superreload replaces the class dictionary of every top-level
100 class in the module with the new one automatically,
101 as well as every function's code object.
102
103 """
104
105 module = reload(module)
106
107 # iterate over all objects and update them
108 count = 0
109 for name, new_obj in module.__dict__.items():
110 key = (module.__name__, name)
111 if _old_objects.has_key(key):
112 for old_obj in _old_objects[key]:
113 if type(new_obj) == types.ClassType:
114 old_obj.__dict__.update(new_obj.__dict__)
115 count += 1
116 elif type(new_obj) == types.FunctionType:
117 update_function(old_obj,
118 new_obj,
119 "func_code func_defaults func_doc".split())
120 count += 1
121 elif type(new_obj) == types.MethodType:
122 update_function(old_obj.im_func,
123 new_obj.im_func,
124 "func_code func_defaults func_doc".split())
125 count += 1
126
127 return module
128
129 reloader = ModuleReloader()
130
131 #------------------------------------------------------------------------------
132 # IPython monkey-patching
133 #------------------------------------------------------------------------------
134
135 import IPython.iplib
136
137 autoreload_enabled = False
138
139 def runcode_hook(self):
140 if not autoreload_enabled:
141 raise IPython.ipapi.TryNext
142 try:
143 reloader.check()
144 except:
145 pass
146
147
148 def enable_autoreload():
149 global autoreload_enabled
150 autoreload_enabled = True
151
152
153 def disable_autoreload():
154 global autoreload_enabled
155 autoreload_enabled = False
156
157 #------------------------------------------------------------------------------
158 # IPython connectivity
159 #------------------------------------------------------------------------------
160
161 import IPython.ipapi
162 ip = IPython.ipapi.get()
163
164 def autoreload_f(self, parameter_s=''):
165 r""" %autoreload => Reload modules automatically
166
167 %autoreload
168 Reload all modules (except thoses excluded by %aimport) automatically now.
169
170 %autoreload 1
171 Reload all modules imported with %aimport every time before executing
172 the Python code typed.
173
174 %autoreload 2
175 Reload all modules (except thoses excluded by %aimport) every time
176 before executing the Python code typed.
177
178 Reloading Python modules in a reliable way is in general
179 difficult, and unexpected things may occur. Some of the common
180 caveats relevant for 'autoreload' are:
181
182 - Modules are not reloaded in any specific order, and no dependency
183 analysis is done. For example, modules with 'from xxx import foo'
184 retain old versions of 'foo' when 'xxx' is autoreloaded.
185 - Functions or objects imported from the autoreloaded module to
186 the interactive namespace are not updated.
187 - C extension modules cannot be reloaded, and so cannot be
188 autoreloaded.
189 """
190 if parameter_s == '':
191 reloader.check(True)
192 elif parameter_s == '0':
193 disable_autoreload()
194 elif parameter_s == '1':
195 reloader.check_all = False
196 enable_autoreload()
197 elif parameter_s == '2':
198 reloader.check_all = True
199 enable_autoreload()
200
201 def aimport_f(self, parameter_s=''):
202 """%aimport => Import modules for automatic reloading.
203
204 %aimport
205 List modules to automatically import and not to import.
206
207 %aimport foo
208 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
209
210 %aimport -foo
211 Mark module 'foo' to not be autoreloaded for %autoreload 1
212
213 """
214
215 modname = parameter_s
216 if not modname:
217 to_reload = reloader.modules.keys()
218 to_reload.sort()
219 to_skip = reloader.skip_modules.keys()
220 to_skip.sort()
221 if reloader.check_all:
222 print "Modules to reload:\nall-expect-skipped"
223 else:
224 print "Modules to reload:\n%s" % ' '.join(to_reload)
225 print "\nModules to skip:\n%s" % ' '.join(to_skip)
226 elif modname.startswith('-'):
227 modname = modname[1:]
228 try: del reloader.modules[modname]
229 except KeyError: pass
230 reloader.skip_modules[modname] = True
231 else:
232 try: del reloader.skip_modules[modname]
233 except KeyError: pass
234 reloader.modules[modname] = True
235
236 mod = __import__(modname)
237 ip.to_user_ns({modname: mod})
238
239 def init():
240 ip.expose_magic('autoreload', autoreload_f)
241 ip.expose_magic('aimport', aimport_f)
242 ip.set_hook('pre_runcode_hook', runcode_hook)
243
244 init() No newline at end of file
@@ -0,0 +1,343 b''
1 """ Extension for bzr command tab completer. Supports comlpeting commands and options
2
3 Unlike the core IPython, you should note that this extension is under GPL, not BSD.
4
5 Based on "shell" bzr plugin by Aaron Bentley, license is below. The IPython additions
6 are at the bottom of the file, the rest is left untouched.
7
8 Must be loaded with ip.load('ipy_bzr')
9
10 """
11
12 # Copyright (C) 2004, 2005 Aaron Bentley
13 # <aaron@aaronbentley.com>
14 #
15 # This program is free software; you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation; either version 2 of the License, or
18 # (at your option) any later version.
19 #
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
29 import cmd
30 from itertools import chain
31 import os
32 import shlex
33 import stat
34 import string
35 import sys
36
37 from bzrlib import osutils
38 from bzrlib.branch import Branch
39 from bzrlib.config import config_dir, ensure_config_dir_exists
40 from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
41 from bzrlib.errors import BzrError
42 from bzrlib.workingtree import WorkingTree
43 import bzrlib.plugin
44
45
46 SHELL_BLACKLIST = set(['rm', 'ls'])
47 COMPLETION_BLACKLIST = set(['shell'])
48
49
50 class BlackListedCommand(BzrError):
51 def __init__(self, command):
52 BzrError.__init__(self, "The command %s is blacklisted for shell use" %
53 command)
54
55
56 class CompletionContext(object):
57 def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
58 self.text = text
59 self.command = command
60 self.prev_opt = prev_opt
61 self.arg_pos = None
62
63 def get_completions(self):
64 try:
65 return self.get_completions_or_raise()
66 except Exception, e:
67 print e, type(e)
68 return []
69
70 def get_option_completions(self):
71 try:
72 command_obj = get_cmd_object(self.command)
73 except BzrError:
74 return []
75 opts = [o+" " for o in iter_opt_completions(command_obj)]
76 return list(filter_completions(opts, self.text))
77
78 def get_completions_or_raise(self):
79 if self.command is None:
80 if '/' in self.text:
81 iter = iter_executables(self.text)
82 else:
83 iter = (c+" " for c in iter_command_names() if
84 c not in COMPLETION_BLACKLIST)
85 return list(filter_completions(iter, self.text))
86 if self.prev_opt is None:
87 completions = self.get_option_completions()
88 if self.command == "cd":
89 iter = iter_dir_completions(self.text)
90 completions.extend(list(filter_completions(iter, self.text)))
91 else:
92 iter = iter_file_completions(self.text)
93 completions.extend(filter_completions(iter, self.text))
94 return completions
95
96
97 class PromptCmd(cmd.Cmd):
98
99 def __init__(self):
100 cmd.Cmd.__init__(self)
101 self.prompt = "bzr> "
102 try:
103 self.tree = WorkingTree.open_containing('.')[0]
104 except:
105 self.tree = None
106 self.set_title()
107 self.set_prompt()
108 self.identchars += '-'
109 ensure_config_dir_exists()
110 self.history_file = osutils.pathjoin(config_dir(), 'shell-history')
111 readline.set_completer_delims(string.whitespace)
112 if os.access(self.history_file, os.R_OK) and \
113 os.path.isfile(self.history_file):
114 readline.read_history_file(self.history_file)
115 self.cwd = os.getcwd()
116
117 def write_history(self):
118 readline.write_history_file(self.history_file)
119
120 def do_quit(self, args):
121 self.write_history()
122 raise StopIteration
123
124 def do_exit(self, args):
125 self.do_quit(args)
126
127 def do_EOF(self, args):
128 print
129 self.do_quit(args)
130
131 def postcmd(self, line, bar):
132 self.set_title()
133 self.set_prompt()
134
135 def set_prompt(self):
136 if self.tree is not None:
137 try:
138 prompt_data = (self.tree.branch.nick, self.tree.branch.revno(),
139 self.tree.relpath('.'))
140 prompt = " %s:%d/%s" % prompt_data
141 except:
142 prompt = ""
143 else:
144 prompt = ""
145 self.prompt = "bzr%s> " % prompt
146
147 def set_title(self, command=None):
148 try:
149 b = Branch.open_containing('.')[0]
150 version = "%s:%d" % (b.nick, b.revno())
151 except:
152 version = "[no version]"
153 if command is None:
154 command = ""
155 sys.stdout.write(terminal.term_title("bzr %s %s" % (command, version)))
156
157 def do_cd(self, line):
158 if line == "":
159 line = "~"
160 line = os.path.expanduser(line)
161 if os.path.isabs(line):
162 newcwd = line
163 else:
164 newcwd = self.cwd+'/'+line
165 newcwd = os.path.normpath(newcwd)
166 try:
167 os.chdir(newcwd)
168 self.cwd = newcwd
169 except Exception, e:
170 print e
171 try:
172 self.tree = WorkingTree.open_containing(".")[0]
173 except:
174 self.tree = None
175
176 def do_help(self, line):
177 self.default("help "+line)
178
179 def default(self, line):
180 args = shlex.split(line)
181 alias_args = get_alias(args[0])
182 if alias_args is not None:
183 args[0] = alias_args.pop(0)
184
185 commandname = args.pop(0)
186 for char in ('|', '<', '>'):
187 commandname = commandname.split(char)[0]
188 if commandname[-1] in ('|', '<', '>'):
189 commandname = commandname[:-1]
190 try:
191 if commandname in SHELL_BLACKLIST:
192 raise BlackListedCommand(commandname)
193 cmd_obj = get_cmd_object(commandname)
194 except (BlackListedCommand, BzrError):
195 return os.system(line)
196
197 try:
198 if too_complicated(line):
199 return os.system("bzr "+line)
200 else:
201 return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
202 except BzrError, e:
203 print e
204 except KeyboardInterrupt, e:
205 print "Interrupted"
206 except Exception, e:
207 # print "Unhandled error:\n%s" % errors.exception_str(e)
208 print "Unhandled error:\n%s" % (e)
209
210
211 def completenames(self, text, line, begidx, endidx):
212 return CompletionContext(text).get_completions()
213
214 def completedefault(self, text, line, begidx, endidx):
215 """Perform completion for native commands.
216
217 :param text: The text to complete
218 :type text: str
219 :param line: The entire line to complete
220 :type line: str
221 :param begidx: The start of the text in the line
222 :type begidx: int
223 :param endidx: The end of the text in the line
224 :type endidx: int
225 """
226 (cmd, args, foo) = self.parseline(line)
227 if cmd == "bzr":
228 cmd = None
229 return CompletionContext(text, command=cmd).get_completions()
230
231
232 def run_shell():
233 try:
234 prompt = PromptCmd()
235 try:
236 prompt.cmdloop()
237 finally:
238 prompt.write_history()
239 except StopIteration:
240 pass
241
242
243 def iter_opt_completions(command_obj):
244 for option_name, option in command_obj.options().items():
245 yield "--" + option_name
246 short_name = option.short_name()
247 if short_name:
248 yield "-" + short_name
249
250
251 def iter_file_completions(arg, only_dirs = False):
252 """Generate an iterator that iterates through filename completions.
253
254 :param arg: The filename fragment to match
255 :type arg: str
256 :param only_dirs: If true, match only directories
257 :type only_dirs: bool
258 """
259 cwd = os.getcwd()
260 if cwd != "/":
261 extras = [".", ".."]
262 else:
263 extras = []
264 (dir, file) = os.path.split(arg)
265 if dir != "":
266 listingdir = os.path.expanduser(dir)
267 else:
268 listingdir = cwd
269 for file in chain(os.listdir(listingdir), extras):
270 if dir != "":
271 userfile = dir+'/'+file
272 else:
273 userfile = file
274 if userfile.startswith(arg):
275 if os.path.isdir(listingdir+'/'+file):
276 userfile+='/'
277 yield userfile
278 elif not only_dirs:
279 yield userfile + ' '
280
281
282 def iter_dir_completions(arg):
283 """Generate an iterator that iterates through directory name completions.
284
285 :param arg: The directory name fragment to match
286 :type arg: str
287 """
288 return iter_file_completions(arg, True)
289
290
291 def iter_command_names(hidden=False):
292 for real_cmd_name, cmd_class in get_all_cmds():
293 if not hidden and cmd_class.hidden:
294 continue
295 for name in [real_cmd_name] + cmd_class.aliases:
296 # Don't complete on aliases that are prefixes of the canonical name
297 if name == real_cmd_name or not real_cmd_name.startswith(name):
298 yield name
299
300
301 def iter_executables(path):
302 dirname, partial = os.path.split(path)
303 for filename in os.listdir(dirname):
304 if not filename.startswith(partial):
305 continue
306 fullpath = os.path.join(dirname, filename)
307 mode=os.lstat(fullpath)[stat.ST_MODE]
308 if stat.S_ISREG(mode) and 0111 & mode:
309 yield fullpath + ' '
310
311
312 def filter_completions(iter, arg):
313 return (c for c in iter if c.startswith(arg))
314
315
316 def iter_munged_completions(iter, arg, text):
317 for completion in iter:
318 completion = str(completion)
319 if completion.startswith(arg):
320 yield completion[len(arg)-len(text):]+" "
321
322
323 def too_complicated(line):
324 for char in '|<>*?':
325 if char in line:
326 return True
327 return False
328
329
330 ### IPython mods start
331
332 def init_ipython(ip):
333 def bzr_completer(self,ev):
334 #print "bzr complete"
335 tup = ev.line.split(None,2)
336 if len(tup) > 2:
337 cmd = tup[1]
338 else:
339 cmd = None
340
341 return CompletionContext(ev.symbol, command = cmd).get_completions()
342 bzrlib.plugin.load_plugins()
343 ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
@@ -0,0 +1,75 b''
1 """ Greedy completer extension for IPython
2
3 Normal tab completer refuses to evaluate nonsafe stuff. This will evaluate
4 everything, so you need to consider the consequences of pressing tab
5 yourself!
6
7 Note that this extension simplifies readline interaction by setting
8 only whitespace as completer delimiter. If this works well, we will
9 do the same in default completer.
10
11 """
12 from IPython import generics,ipapi
13 from IPython.genutils import dir2
14
15 def attr_matches(self, text):
16 """Compute matches when text contains a dot.
17
18 MONKEYPATCHED VERSION (ipy_greedycompleter.py)
19
20 Assuming the text is of the form NAME.NAME....[NAME], and is
21 evaluatable in self.namespace or self.global_namespace, it will be
22 evaluated and its attributes (as revealed by dir()) are used as
23 possible completions. (For class instances, class members are are
24 also considered.)
25
26 WARNING: this can still invoke arbitrary C code, if an object
27 with a __getattr__ hook is evaluated.
28
29 """
30 import re
31
32 force_complete = 1
33 # Another option, seems to work great. Catches things like ''.<tab>
34 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
35
36 if m:
37 expr, attr = m.group(1, 3)
38 else:
39 # force match - eval anything that ends with colon
40 if not force_complete:
41 return []
42
43 m2 = re.match(r"(.+)\.(\w*)$", self.lbuf)
44 if not m2:
45 return []
46 expr, attr = m2.group(1,2)
47
48
49 try:
50 obj = eval(expr, self.namespace)
51 except:
52 try:
53 obj = eval(expr, self.global_namespace)
54 except:
55 return []
56
57 words = dir2(obj)
58
59 try:
60 words = generics.complete_object(obj, words)
61 except ipapi.TryNext:
62 pass
63 # Build match list to return
64 n = len(attr)
65 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
66 return res
67
68 def main():
69 import readline
70 readline.set_completer_delims(" \n\t")
71 # monkeypatch - the code will be folded to normal completer later on
72 import IPython.completer
73 IPython.completer.Completer.attr_matches = attr_matches
74
75 main() No newline at end of file
@@ -0,0 +1,311 b''
1 # -*- coding: utf-8 -*-
2 """
3 %jot magic for lightweight persistence.
4
5 Stores variables in Struct with some notes in PicleShare database
6
7
8 """
9
10 from datetime import datetime
11 import IPython.ipapi
12 ip = IPython.ipapi.get()
13
14 import pickleshare
15
16 import inspect,pickle,os,sys,textwrap
17 from IPython.FakeModule import FakeModule
18 from IPython.ipstruct import Struct
19
20
21 def refresh_variables(ip, key=None):
22 db = ip.db
23 if key is None:
24 keys = db.keys('jot/*')
25 else:
26 keys = db.keys('jot/'+key)
27 for key in keys:
28 # strip autorestore
29 justkey = os.path.basename(key)
30 print "Restoring from", justkey, "..."
31 try:
32 obj = db[key]
33 except KeyError:
34 print "Unable to restore variable '%s', ignoring (use %%jot -d to forget!)" % justkey
35 print "The error was:",sys.exc_info()[0]
36 else:
37 #print "restored",justkey,"=",obj #dbg
38 try:
39 origname = obj.name
40 except:
41 ip.user_ns[justkey] = obj
42 print "Restored", justkey
43 else:
44 ip.user_ns[origname] = obj['val']
45 print "Restored", origname
46
47 def read_variables(ip, key=None):
48 db = ip.db
49 if key is None:
50 return None
51 else:
52 keys = db.keys('jot/'+key)
53 for key in keys:
54 # strip autorestore
55 justkey = os.path.basename(key)
56 print "restoring from ", justkey
57 try:
58 obj = db[key]
59 except KeyError:
60 print "Unable to read variable '%s', ignoring (use %%jot -d to forget!)" % justkey
61 print "The error was:",sys.exc_info()[0]
62 else:
63 return obj
64
65
66 def detail_variables(ip, key=None):
67 db, get = ip.db, ip.db.get
68
69 if key is None:
70 keys = db.keys('jot/*')
71 else:
72 keys = db.keys('jot/'+key)
73 if keys:
74 size = max(map(len,keys))
75 else:
76 size = 0
77
78 fmthead = '%-'+str(size)+'s [%s]'
79 fmtbody = 'Comment:\n %s'
80 fmtdata = 'Data:\n %s, %s'
81 for key in keys:
82 v = get(key,'<unavailable>')
83 justkey = os.path.basename(key)
84 try:
85 print fmthead % (justkey, datetime.ctime(v.get('time','<unavailable>')))
86 print fmtbody % (v.get('comment','<unavailable>'))
87 d = v.get('val','unavailable')
88 print fmtdata % (repr(type(d)), '')
89 print repr(d)[0:200]
90 print
91 print
92 except AttributeError:
93 print fmt % (justkey, '<unavailable>', '<unavailable>', repr(v)[:50])
94
95
96 def intm(n):
97 try:
98 return int(n)
99 except:
100 return 0
101
102 def jot_obj(self, obj, name, comment=''):
103 """
104 write obj data to the note database, with whatever that should be noted.
105 """
106 had = self.db.keys('jot/'+name+'*')
107 # if it the same name but a later version, we stupidly add a number to the
108 # so the name doesn't collide. Any better idea?
109 suffix = ''
110 if len(had)>0:
111 pre = os.path.commonprefix(had)
112 suf = [n.split(pre)[1] for n in had]
113 versions = map(intm, suf)
114 suffix = str(max(versions)+1)
115
116 uname = 'jot/'+name+suffix
117
118 # which one works better?
119 #all = ip.IP.shadowhist.all()
120 all = ip.IP.shell.input_hist
121
122 # We may actually want to make snapshot of files that are run-ned.
123
124 # get the comment
125 try:
126 comment = ip.IP.magic_edit('-x').strip()
127 except:
128 print "No comment is recorded."
129 comment = ''
130
131 self.db[uname] = Struct({'val':obj,
132 'time' : datetime.now(),
133 'hist' : all,
134 'name' : name,
135 'comment' : comment,})
136
137 print "Jotted down notes for '%s' (%s)" % (uname, obj.__class__.__name__)
138
139
140
141 def magic_jot(self, parameter_s=''):
142 """Lightweight persistence for python variables.
143
144 Example:
145
146 ville@badger[~]|1> A = ['hello',10,'world']\\
147 ville@badger[~]|2> %jot A\\
148 ville@badger[~]|3> Exit
149
150 (IPython session is closed and started again...)
151
152 ville@badger:~$ ipython -p pysh\\
153 ville@badger[~]|1> print A
154
155 ['hello', 10, 'world']
156
157 Usage:
158
159 %jot - Show list of all variables and their current values\\
160 %jot -l - Show list of all variables and their current values in detail\\
161 %jot -l <var> - Show one variable and its current values in detail\\
162 %jot <var> - Store the *current* value of the variable to disk\\
163 %jot -d <var> - Remove the variable and its value from storage\\
164 %jot -z - Remove all variables from storage (disabled)\\
165 %jot -r <var> - Refresh/Load variable from jot (delete current vals)\\
166 %jot foo >a.txt - Store value of foo to new file a.txt\\
167 %jot foo >>a.txt - Append value of foo to file a.txt\\
168
169 It should be noted that if you change the value of a variable, you
170 need to %note it again if you want to persist the new value.
171
172 Note also that the variables will need to be pickleable; most basic
173 python types can be safely %stored.
174
175 """
176
177 opts,argsl = self.parse_options(parameter_s,'drzl',mode='string')
178 args = argsl.split(None,1)
179 ip = self.getapi()
180 db = ip.db
181 # delete
182 if opts.has_key('d'):
183 try:
184 todel = args[0]
185 except IndexError:
186 error('You must provide the variable to forget')
187 else:
188 try:
189 del db['jot/' + todel]
190 except:
191 error("Can't delete variable '%s'" % todel)
192 # reset the whole database
193 elif opts.has_key('z'):
194 print "reseting the whole database has been disabled."
195 #for k in db.keys('autorestore/*'):
196 # del db[k]
197
198 elif opts.has_key('r'):
199 try:
200 toret = args[0]
201 except:
202 print "restoring all the variables jotted down..."
203 refresh_variables(ip)
204 else:
205 refresh_variables(ip, toret)
206
207 elif opts.has_key('l'):
208 try:
209 tolist = args[0]
210 except:
211 print "List details for all the items."
212 detail_variables(ip)
213 else:
214 print "Details for", tolist, ":"
215 detail_variables(ip, tolist)
216
217 # run without arguments -> list noted variables & notes
218 elif not args:
219 vars = self.db.keys('jot/*')
220 vars.sort()
221 if vars:
222 size = max(map(len,vars)) - 4
223 else:
224 size = 0
225
226 print 'Variables and their in-db values:'
227 fmt = '%-'+str(size)+'s [%s] -> %s'
228 get = db.get
229 for var in vars:
230 justkey = os.path.basename(var)
231 v = get(var,'<unavailable>')
232 try:
233 print fmt % (justkey,\
234 datetime.ctime(v.get('time','<unavailable>')),\
235 v.get('comment','<unavailable>')[:70].replace('\n',' '),)
236 except AttributeError:
237 print fmt % (justkey, '<unavailable>', '<unavailable>', repr(v)[:50])
238
239
240 # default action - store the variable
241 else:
242 # %store foo >file.txt or >>file.txt
243 if len(args) > 1 and args[1].startswith('>'):
244 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
245 if args[1].startswith('>>'):
246 fil = open(fnam,'a')
247 else:
248 fil = open(fnam,'w')
249 obj = ip.ev(args[0])
250 print "Writing '%s' (%s) to file '%s'." % (args[0],
251 obj.__class__.__name__, fnam)
252
253
254 if not isinstance (obj,basestring):
255 from pprint import pprint
256 pprint(obj,fil)
257 else:
258 fil.write(obj)
259 if not obj.endswith('\n'):
260 fil.write('\n')
261
262 fil.close()
263 return
264
265 # %note foo
266 try:
267 obj = ip.user_ns[args[0]]
268 except KeyError:
269 # this should not be alias, for aliases, use %store
270 print
271 print "Error: %s doesn't exist." % args[0]
272 print
273 print "Use %note -r <var> to retrieve variables. This should not be used " +\
274 "to store alias, for saving aliases, use %store"
275 return
276 else:
277 if isinstance(inspect.getmodule(obj), FakeModule):
278 print textwrap.dedent("""\
279 Warning:%s is %s
280 Proper storage of interactively declared classes (or instances
281 of those classes) is not possible! Only instances
282 of classes in real modules on file system can be %%store'd.
283 """ % (args[0], obj) )
284 return
285 #pickled = pickle.dumps(obj)
286 #self.db[ 'jot/' + args[0] ] = obj
287 jot_obj(self, obj, args[0])
288
289
290 def magic_read(self, parameter_s=''):
291 """
292 %read <var> - Load variable from data that is jotted down.\\
293
294 """
295
296 opts,argsl = self.parse_options(parameter_s,'drzl',mode='string')
297 args = argsl.split(None,1)
298 ip = self.getapi()
299 db = ip.db
300 #if opts.has_key('r'):
301 try:
302 toret = args[0]
303 except:
304 print "which record do you want to read out?"
305 return
306 else:
307 return read_variables(ip, toret)
308
309
310 ip.expose_magic('jot',magic_jot)
311 ip.expose_magic('read',magic_read)
@@ -0,0 +1,234 b''
1 """
2 IPython extension: %lookfor command for searching docstrings
3
4 """
5 # Pauli Virtanen <pav@iki.fi>, 2008.
6
7 import re, inspect, pkgutil, pydoc
8
9 #------------------------------------------------------------------------------
10 # Lookfor functionality
11 #------------------------------------------------------------------------------
12
13 # Cache for lookfor: {id(module): {name: (docstring, kind, index), ...}...}
14 # where kind: "func", "class", "module", "object"
15 # and index: index in breadth-first namespace traversal
16 _lookfor_caches = {}
17
18 # regexp whose match indicates that the string may contain a function signature
19 _function_signature_re = re.compile(r"[a-z_]+\(.*[,=].*\)", re.I)
20
21 def lookfor(what, modules=None, import_modules=True, regenerate=False):
22 """
23 Search for objects whose documentation contains all given words.
24 Shows a summary of matching objects, sorted roughly by relevance.
25
26 Parameters
27 ----------
28 what : str
29 String containing words to look for.
30
31 module : str, module
32 Module whose docstrings to go through.
33 import_modules : bool
34 Whether to import sub-modules in packages.
35 Will import only modules in __all__
36 regenerate: bool
37 Re-generate the docstring cache
38
39 """
40 # Cache
41 cache = {}
42 for module in modules:
43 try:
44 c = _lookfor_generate_cache(module, import_modules, regenerate)
45 cache.update(c)
46 except ImportError:
47 pass
48
49 # Search
50 # XXX: maybe using a real stemming search engine would be better?
51 found = []
52 whats = str(what).lower().split()
53 if not whats: return
54
55 for name, (docstring, kind, index) in cache.iteritems():
56 if kind in ('module', 'object'):
57 # don't show modules or objects
58 continue
59 ok = True
60 doc = docstring.lower()
61 for w in whats:
62 if w not in doc:
63 ok = False
64 break
65 if ok:
66 found.append(name)
67
68 # Relevance sort
69 # XXX: this is full Harrison-Stetson heuristics now,
70 # XXX: it probably could be improved
71
72 kind_relevance = {'func': 1000, 'class': 1000,
73 'module': -1000, 'object': -1000}
74
75 def relevance(name, docstr, kind, index):
76 r = 0
77 # do the keywords occur within the start of the docstring?
78 first_doc = "\n".join(docstr.lower().strip().split("\n")[:3])
79 r += sum([200 for w in whats if w in first_doc])
80 # do the keywords occur in the function name?
81 r += sum([30 for w in whats if w in name])
82 # is the full name long?
83 r += -len(name) * 5
84 # is the object of bad type?
85 r += kind_relevance.get(kind, -1000)
86 # is the object deep in namespace hierarchy?
87 r += -name.count('.') * 10
88 r += max(-index / 100, -100)
89 return r
90
91 def relevance_sort(a, b):
92 dr = relevance(b, *cache[b]) - relevance(a, *cache[a])
93 if dr != 0: return dr
94 else: return cmp(a, b)
95 found.sort(relevance_sort)
96
97 # Pretty-print
98 s = "Search results for '%s'" % (' '.join(whats))
99 help_text = [s, "-"*len(s)]
100 for name in found:
101 doc, kind, ix = cache[name]
102
103 doclines = [line.strip() for line in doc.strip().split("\n")
104 if line.strip()]
105
106 # find a suitable short description
107 try:
108 first_doc = doclines[0].strip()
109 if _function_signature_re.search(first_doc):
110 first_doc = doclines[1].strip()
111 except IndexError:
112 first_doc = ""
113 help_text.append("%s\n %s" % (name, first_doc))
114
115 # Output
116 if len(help_text) > 10:
117 pager = pydoc.getpager()
118 pager("\n".join(help_text))
119 else:
120 print "\n".join(help_text)
121
122 def _lookfor_generate_cache(module, import_modules, regenerate):
123 """
124 Generate docstring cache for given module.
125
126 Parameters
127 ----------
128 module : str, None, module
129 Module for which to generate docstring cache
130 import_modules : bool
131 Whether to import sub-modules in packages.
132 Will import only modules in __all__
133 regenerate: bool
134 Re-generate the docstring cache
135
136 Returns
137 -------
138 cache : dict {obj_full_name: (docstring, kind, index), ...}
139 Docstring cache for the module, either cached one (regenerate=False)
140 or newly generated.
141
142 """
143 global _lookfor_caches
144
145 if module is None:
146 module = "numpy"
147
148 if isinstance(module, str):
149 module = __import__(module)
150
151 if id(module) in _lookfor_caches and not regenerate:
152 return _lookfor_caches[id(module)]
153
154 # walk items and collect docstrings
155 cache = {}
156 _lookfor_caches[id(module)] = cache
157 seen = {}
158 index = 0
159 stack = [(module.__name__, module)]
160 while stack:
161 name, item = stack.pop(0)
162 if id(item) in seen: continue
163 seen[id(item)] = True
164
165 index += 1
166 kind = "object"
167
168 if inspect.ismodule(item):
169 kind = "module"
170 try:
171 _all = item.__all__
172 except AttributeError:
173 _all = None
174 # import sub-packages
175 if import_modules and hasattr(item, '__path__'):
176 for m in pkgutil.iter_modules(item.__path__):
177 if _all is not None and m[1] not in _all:
178 continue
179 try:
180 __import__("%s.%s" % (name, m[1]))
181 except ImportError:
182 continue
183 for n, v in inspect.getmembers(item):
184 if _all is not None and n not in _all:
185 continue
186 stack.append(("%s.%s" % (name, n), v))
187 elif inspect.isclass(item):
188 kind = "class"
189 for n, v in inspect.getmembers(item):
190 stack.append(("%s.%s" % (name, n), v))
191 elif callable(item):
192 kind = "func"
193
194 doc = inspect.getdoc(item)
195 if doc is not None:
196 cache[name] = (doc, kind, index)
197
198 return cache
199
200 #------------------------------------------------------------------------------
201 # IPython connectivity
202 #------------------------------------------------------------------------------
203
204 import IPython.ipapi
205 ip = IPython.ipapi.get()
206
207 _lookfor_modules = ['numpy', 'scipy']
208
209 def lookfor_f(self, arg=''):
210 r"""
211 Search for objects whose documentation contains all given words.
212 Shows a summary of matching objects, sorted roughly by relevance.
213
214 Usage
215 -----
216 %lookfor +numpy some words
217 Search module 'numpy'
218
219 %lookfor_modules numpy scipy
220 Set default modules whose docstrings to search
221
222 """
223 lookfor(arg, modules=_lookfor_modules)
224
225 def lookfor_modules_f(self, arg=''):
226 global _lookfor_modules
227 if not arg:
228 print "Modules included in %lookfor search:", _lookfor_modules
229 else:
230 _lookfor_modules = arg.split()
231
232 ip.expose_magic('lookfor', lookfor_f)
233 ip.expose_magic('lookfor_modules', lookfor_modules_f)
234
@@ -0,0 +1,239 b''
1 """ Integration with gvim, by Erich Heine
2
3 Provides a %vim magic command, and reuses the same vim session. Uses
4 unix domain sockets for communication between vim and IPython. ipy.vim is
5 available in doc/examples of the IPython distribution.
6
7 Slightly touched up email announcement (and description how to use it) by
8 Erich Heine is here:
9
10 Ive recently been playing with ipython, and like it quite a bit. I did
11 however discover a bit of frustration, namely with editor interaction.
12 I am a gvim user, and using the command edit on a new file causes
13 ipython to try and run that file as soon as the text editor opens
14 up. The -x command of course fixes this, but its still a bit annoying,
15 switching windows to do a run file, then back to the text
16 editor. Being a heavy tab user in gvim, another annoyance is not being
17 able to specify weather a new tab is how I choose to open the file.
18
19 Not being one to shirk my open source duties (and seeing this as a
20 good excuse to poke around ipython internals), Ive created a script
21 for having gvim and ipython work very nicely together. Ive attached
22 both to this email (hoping of course that the mailing list allows such
23 things).
24
25 There are 2 files:
26
27 ipy_vimserver.py -- this file contains the ipython stuff
28 ipy.vim -- this file contains the gvim stuff
29
30 In combination they allow for a few functionalities:
31
32 #1. the vim magic command. This is a fancy wrapper around the edit
33 magic, that allows for a new option, -t, which opens the text in a new
34 gvim tab. Otherwise it works the same as edit -x. (it internally
35 calls edit -x). This magic command also juggles vim server management,
36 so when it is called when there is not a gvim running, it creates a
37 new gvim instance, named after the ipython session name. Once such a
38 gvim instance is running, it will be used for subsequent uses of the
39 vim command.
40
41 #2. ipython - gvim interaction. Once a file has been opened with the
42 vim magic (and a session set up, see below), pressing the F5 key in
43 vim will cause the calling ipython instance to execute run
44 filename.py. (if you typo like I do, this is very useful)
45
46 #3. ipython server - this is a thread wich listens on a unix domain
47 socket, and runs commands sent to that socket.
48
49 Note, this only works on POSIX systems, that allow for AF_UNIX type
50 sockets. It has only been tested on linux (a fairly recent debian
51 testing distro).
52
53 To install it put, the ipserver.py in your favorite locaion for
54 sourcing ipython scripts. I put the ipy.vim in
55 ~/.vim/after/ftplugin/python/.
56
57 To use (this can be scripted im sure, but i usually have 2 or 3
58 ipythons and corresponding gvims open):
59
60 import ipy_vimserver
61 ipy_vimserver.setup('sessionname')
62
63 (Editors note - you can probably add these to your ipy_user_conf.py)
64
65 Then use ipython as you normally would, until you need to edit
66 something. Instead of edit, use the vim magic. Thats it!
67
68 """
69
70 import IPython.ipapi
71 #import ipythonhooks
72 import socket, select
73 import os, threading, subprocess
74 import re
75
76 ERRCONDS = select.POLLHUP|select.POLLERR
77 SERVER = None
78 ip = IPython.ipapi.get()
79
80 # this listens to a unix domain socket in a separate thread, so that comms
81 # between a vim instance and ipython can happen in a fun and productive way
82 class IpyServer(threading.Thread):
83 def __init__(self, sname):
84 super(IpyServer, self).__init__()
85 self.keep_running = True
86 self.__sname = sname
87 self.socket = socket.socket(socket.AF_UNIX)
88 self.poller = select.poll()
89 self.current_conns = dict()
90 self.setDaemon(True)
91
92 def listen(self):
93 self.socket.bind(self.__sname)
94 self.socket.listen(1)
95
96 def __handle_error(self, socket):
97 if socket == self.socket.fileno():
98 self.keep_running = False
99 for a in self.current_conns.values():
100 a.close()
101 return False
102 else:
103 y = self.current_conns[socket]
104 del self.current_conns[socket]
105 y.close()
106 self.poller.unregister(socket)
107
108 def serve_me(self):
109 self.listen()
110 self.poller.register(self.socket,select.POLLIN|ERRCONDS)
111
112 while self.keep_running:
113 try:
114 avail = self.poller.poll(1)
115 except:
116 continue
117
118 if not avail: continue
119
120 for sock, conds in avail:
121 if conds & (ERRCONDS):
122 if self.__handle_error(sock): continue
123 else: break
124
125 if sock == self.socket.fileno():
126 y = self.socket.accept()[0]
127 self.poller.register(y, select.POLLIN|ERRCONDS)
128 self.current_conns[y.fileno()] = y
129 else: y = self.current_conns.get(sock)
130
131 self.handle_request(y)
132
133 os.remove(self.__sname)
134
135 run = serve_me
136
137 def stop(self):
138 self.keep_running = False
139
140 def handle_request(self,sock):
141 sock.settimeout(1)
142 while self.keep_running:
143 try:
144 x = sock.recv(4096)
145 except socket.timeout:
146 pass
147 else:
148 break
149 self.do_it(x)
150
151 def do_it(self, data):
152 data = data.split('\n')
153 cmds = list()
154 for line in data:
155 cmds.append(line)
156 ip.runlines(cmds)
157
158
159 # try to help ensure that the unix domain socket is cleaned up proper
160 def shutdown_server(self):
161 if SERVER:
162 SERVER.stop()
163 SERVER.join(3)
164 raise IPython.ipapi.TryNext
165
166 ip.set_hook('shutdown_hook', shutdown_server, 10)
167
168 # this fun function exists to make setup easier for all, and makes the
169 # vimhook function ready for instance specific communication
170 def setup(sessionname='',socketdir=os.path.expanduser('~/.ipython/')):
171 global SERVER
172
173 if sessionname:
174 session = sessionname
175 elif os.environ.get('IPY_SESSION'):
176 session = os.environ.get('IPY_SESSION')
177 else:
178 session = 'IPYS'
179 vimhook.vimserver=session
180 vimhook.ipyserver = os.path.join(socketdir, session)
181 if not SERVER:
182 SERVER = IpyServer(vimhook.ipyserver)
183 SERVER.start()
184
185
186
187 # calls gvim, with all ops happening on the correct gvim instance for this
188 # ipython instance. it then calls edit -x (since gvim will return right away)
189 # things of note: it sets up a special environment, so that the ipy.vim script
190 # can connect back to the ipython instance and do fun things, like run the file
191 def vimhook(self, fname, line):
192 env = os.environ.copy()
193 vserver = vimhook.vimserver.upper()
194 check = subprocess.Popen('gvim --serverlist', stdout = subprocess.PIPE,
195 shell=True)
196 check.wait()
197 cval = [l for l in check.stdout.readlines() if vserver in l]
198
199 if cval:
200 vimargs = '--remote%s' % (vimhook.extras,)
201 else:
202 vimargs = ''
203 vimhook.extras = ''
204
205 env['IPY_SESSION'] = vimhook.vimserver
206 env['IPY_SERVER'] = vimhook.ipyserver
207
208 if line is None: line = ''
209 else: line = '+' + line
210 vim_cmd = 'gvim --servername %s %s %s %s' % (vimhook.vimserver, vimargs,
211 line, fname)
212 subprocess.call(vim_cmd, env=env, shell=True)
213
214
215 #default values to keep it sane...
216 vimhook.vimserver = ''
217 vimhook.ipyserver = ''
218
219 ip.set_hook('editor',vimhook)
220
221 # this is set up so more vim specific commands can be added, instead of just
222 # the current -t. all thats required is a compiled regex, a call to do_arg(pat)
223 # and the logic to deal with the new feature
224 newtab = re.compile(r'-t(?:\s|$)')
225 def vim(self, argstr):
226 def do_arg(pat, rarg):
227 x = len(pat.findall(argstr))
228 if x:
229 a = pat.sub('',argstr)
230 return rarg, a
231 else: return '', argstr
232
233 t, argstr = do_arg(newtab, '-tab')
234 vimhook.extras = t
235 argstr = 'edit -x ' + argstr
236 ip.magic(argstr)
237
238 ip.expose_magic('vim', vim)
239
@@ -0,0 +1,73 b''
1 """ Debug a script (like %run -d) in IPython process, Using WinPdb
2
3 Usage:
4
5 %wdb test.py
6 run test.py, with a winpdb breakpoint at start of the file
7
8 %wdb pass
9 Change the password (e.g. if you have forgotten the old one)
10 """
11
12 import os
13
14 import IPython.ipapi
15 import rpdb2
16
17 ip = IPython.ipapi.get()
18
19 rpdb_started = False
20
21 def wdb_f(self, arg):
22 """ Debug a script (like %run -d) in IPython process, Using WinPdb
23
24 Usage:
25
26 %wdb test.py
27 run test.py, with a winpdb breakpoint at start of the file
28
29 %wdb pass
30 Change the password (e.g. if you have forgotten the old one)
31
32 Note that after the script has been run, you need to do "Go" (f5)
33 in WinPdb to resume normal IPython operation.
34 """
35
36 global rpdb_started
37 if not arg.strip():
38 print __doc__
39 return
40
41 if arg.strip() == 'pass':
42 passwd = raw_input('Enter new winpdb session password: ')
43 ip.db['winpdb_pass'] = passwd
44 print "Winpdb password changed"
45 if rpdb_started:
46 print "You need to restart IPython to use the new password"
47 return
48
49 path = os.path.abspath(arg)
50 if not os.path.isfile(path):
51 raise IPython.ipapi.UsageError("%%wdb: file %s does not exist" % path)
52 if not rpdb_started:
53 passwd = ip.db.get('winpdb_pass', None)
54 if passwd is None:
55 import textwrap
56 print textwrap.dedent("""\
57 Winpdb sessions need a password that you use for attaching the external
58 winpdb session. IPython will remember this. You can change the password later
59 by '%wpdb pass'
60 """)
61 passwd = raw_input('Enter new winpdb session password: ')
62 ip.db['winpdb_pass'] = passwd
63
64 print "Starting rpdb2 in IPython process"
65 rpdb2.start_embedded_debugger(passwd, timeout = 0)
66 rpdb_started = True
67
68 rpdb2.set_temp_breakpoint(path)
69 print 'It is time to attach with WinPdb (launch WinPdb if needed, File -> Attach)'
70 ip.magic('%run ' + arg)
71
72
73 ip.expose_magic('wdb', wdb_f)
@@ -0,0 +1,460 b''
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
3 '''
4 Provides IPython remote instance.
5
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
8 @license: BSD
9
10 All rights reserved. This program and the accompanying materials are made
11 available under the terms of the BSD which accompanies this distribution, and
12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 '''
14
15 __version__ = 0.9
16 __author__ = "Laurent Dufrechou"
17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 __license__ = "BSD"
19
20 import re
21 import sys
22 import os
23 import locale
24 import time
25 import pydoc,__builtin__,site
26 from thread_ex import ThreadEx
27 from StringIO import StringIO
28
29 try:
30 import IPython
31 except Exception,e:
32 raise "Error importing IPython (%s)" % str(e)
33
34 ##############################################################################
35 class _Helper(object):
36 """Redefine the built-in 'help'.
37 This is a wrapper around pydoc.help (with a twist).
38 """
39
40 def __init__(self,pager):
41 self._pager = pager
42
43 def __repr__(self):
44 return "Type help() for interactive help, " \
45 "or help(object) for help about object."
46
47 def __call__(self, *args, **kwds):
48 class DummyWriter(object):
49 def __init__(self,pager):
50 self._pager = pager
51
52 def write(self,data):
53 self._pager(data)
54
55 import pydoc
56 pydoc.help.output = DummyWriter(self._pager)
57 pydoc.help.interact = lambda :1
58
59 return pydoc.help(*args, **kwds)
60
61
62 ##############################################################################
63 class _CodeExecutor(ThreadEx):
64
65 def __init__(self, instance, after):
66 ThreadEx.__init__(self)
67 self.instance = instance
68 self._afterExecute=after
69
70 def run(self):
71 try:
72 self.instance._doc_text = None
73 self.instance._help_text = None
74 self.instance._execute()
75 # used for uper class to generate event after execution
76 self._afterExecute()
77
78 except KeyboardInterrupt:
79 pass
80
81
82 ##############################################################################
83 class NonBlockingIPShell(object):
84 '''
85 Create an IPython instance, running the commands in a separate,
86 non-blocking thread.
87 This allows embedding in any GUI without blockage.
88
89 Note: The ThreadEx class supports asynchroneous function call
90 via raise_exc()
91 '''
92
93 def __init__(self,argv=[],user_ns={},user_global_ns=None,
94 cin=None, cout=None, cerr=None,
95 ask_exit_handler=None):
96 '''
97 @param argv: Command line options for IPython
98 @type argv: list
99 @param user_ns: User namespace.
100 @type user_ns: dictionary
101 @param user_global_ns: User global namespace.
102 @type user_global_ns: dictionary.
103 @param cin: Console standard input.
104 @type cin: IO stream
105 @param cout: Console standard output.
106 @type cout: IO stream
107 @param cerr: Console standard error.
108 @type cerr: IO stream
109 @param exit_handler: Replacement for builtin exit() function
110 @type exit_handler: function
111 @param time_loop: Define the sleep time between two thread's loop
112 @type int
113 '''
114 #ipython0 initialisation
115 self.initIpython0(argv, user_ns, user_global_ns,
116 cin, cout, cerr,
117 ask_exit_handler)
118
119 #vars used by _execute
120 self._iter_more = 0
121 self._history_level = 0
122 self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
123 self._prompt = str(self._IP.outputcache.prompt1).strip()
124
125 #thread working vars
126 self._line_to_execute = ''
127
128 #vars that will be checked by GUI loop to handle thread states...
129 #will be replaced later by PostEvent GUI funtions...
130 self._doc_text = None
131 self._help_text = None
132 self._add_button = None
133
134 def initIpython0(self, argv=[], user_ns={}, user_global_ns=None,
135 cin=None, cout=None, cerr=None,
136 ask_exit_handler=None):
137 #first we redefine in/out/error functions of IPython
138 if cin:
139 IPython.Shell.Term.cin = cin
140 if cout:
141 IPython.Shell.Term.cout = cout
142 if cerr:
143 IPython.Shell.Term.cerr = cerr
144
145 # This is to get rid of the blockage that accurs during
146 # IPython.Shell.InteractiveShell.user_setup()
147 IPython.iplib.raw_input = lambda x: None
148
149 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
150
151 excepthook = sys.excepthook
152
153 self._IP = IPython.Shell.make_IPython(
154 argv,user_ns=user_ns,
155 user_global_ns=user_global_ns,
156 embedded=True,
157 shell_class=IPython.Shell.InteractiveShell)
158
159 #we replace IPython default encoding by wx locale encoding
160 loc = locale.getpreferredencoding()
161 if loc:
162 self._IP.stdin_encoding = loc
163 #we replace the ipython default pager by our pager
164 self._IP.set_hook('show_in_pager',self._pager)
165
166 #we replace the ipython default shell command caller by our shell handler
167 self._IP.set_hook('shell_hook',self._shell)
168
169 #we replace the ipython default input command caller by our method
170 IPython.iplib.raw_input_original = self._raw_input
171 #we replace the ipython default exit command by our method
172 self._IP.exit = ask_exit_handler
173 #we replace the help command
174 self._IP.user_ns['help'] = _Helper(self._pager_help)
175
176 #we disable cpase magic... until we found a way to use it properly.
177 #import IPython.ipapi
178 ip = IPython.ipapi.get()
179 def bypassMagic(self, arg):
180 print '%this magic is currently disabled.'
181 ip.expose_magic('cpaste', bypassMagic)
182
183 sys.excepthook = excepthook
184
185 #----------------------- Thread management section ----------------------
186 def doExecute(self,line):
187 """
188 Tell the thread to process the 'line' command
189 """
190
191 self._line_to_execute = line
192 #we launch the ipython line execution in a thread to make it interruptible
193 self.ce = _CodeExecutor(self,self._afterExecute)
194 self.ce.start()
195
196 #----------------------- IPython management section ----------------------
197 def getDocText(self):
198 """
199 Returns the output of the processing that need to be paged (if any)
200
201 @return: The std output string.
202 @rtype: string
203 """
204 return self._doc_text
205
206 def getHelpText(self):
207 """
208 Returns the output of the processing that need to be paged via help pager(if any)
209
210 @return: The std output string.
211 @rtype: string
212 """
213 return self._help_text
214
215 def getBanner(self):
216 """
217 Returns the IPython banner for useful info on IPython instance
218
219 @return: The banner string.
220 @rtype: string
221 """
222 return self._IP.BANNER
223
224 def getPromptCount(self):
225 """
226 Returns the prompt number.
227 Each time a user execute a line in the IPython shell the prompt count is increased
228
229 @return: The prompt number
230 @rtype: int
231 """
232 return self._IP.outputcache.prompt_count
233
234 def getPrompt(self):
235 """
236 Returns current prompt inside IPython instance
237 (Can be In [...]: ot ...:)
238
239 @return: The current prompt.
240 @rtype: string
241 """
242 return self._prompt
243
244 def getIndentation(self):
245 """
246 Returns the current indentation level
247 Usefull to put the caret at the good start position if we want to do autoindentation.
248
249 @return: The indentation level.
250 @rtype: int
251 """
252 return self._IP.indent_current_nsp
253
254 def updateNamespace(self, ns_dict):
255 '''
256 Add the current dictionary to the shell namespace.
257
258 @param ns_dict: A dictionary of symbol-values.
259 @type ns_dict: dictionary
260 '''
261 self._IP.user_ns.update(ns_dict)
262
263 def complete(self, line):
264 '''
265 Returns an auto completed line and/or posibilities for completion.
266
267 @param line: Given line so far.
268 @type line: string
269
270 @return: Line completed as for as possible,
271 and possible further completions.
272 @rtype: tuple
273 '''
274 split_line = self._complete_sep.split(line)
275 possibilities = self._IP.complete(split_line[-1])
276 if possibilities:
277
278 def _commonPrefix(str1, str2):
279 '''
280 Reduction function. returns common prefix of two given strings.
281
282 @param str1: First string.
283 @type str1: string
284 @param str2: Second string
285 @type str2: string
286
287 @return: Common prefix to both strings.
288 @rtype: string
289 '''
290 for i in range(len(str1)):
291 if not str2.startswith(str1[:i+1]):
292 return str1[:i]
293 return str1
294 common_prefix = reduce(_commonPrefix, possibilities)
295 completed = line[:-len(split_line[-1])]+common_prefix
296 else:
297 completed = line
298 return completed, possibilities
299
300 def historyBack(self):
301 '''
302 Provides one history command back.
303
304 @return: The command string.
305 @rtype: string
306 '''
307 history = ''
308 #the below while loop is used to suppress empty history lines
309 while((history == '' or history == '\n') and self._history_level >0):
310 if self._history_level>=1:
311 self._history_level -= 1
312 history = self._getHistory()
313 return history
314
315 def historyForward(self):
316 '''
317 Provides one history command forward.
318
319 @return: The command string.
320 @rtype: string
321 '''
322 history = ''
323 #the below while loop is used to suppress empty history lines
324 while((history == '' or history == '\n') and self._history_level <= self._getHistoryMaxIndex()):
325 if self._history_level < self._getHistoryMaxIndex():
326 self._history_level += 1
327 history = self._getHistory()
328 else:
329 if self._history_level == self._getHistoryMaxIndex():
330 history = self._getHistory()
331 self._history_level += 1
332 else:
333 history = ''
334 return history
335
336 def initHistoryIndex(self):
337 '''
338 set history to last command entered
339 '''
340 self._history_level = self._getHistoryMaxIndex()+1
341
342 #----------------------- IPython PRIVATE management section --------------
343 def _afterExecute(self):
344 '''
345 Can be redefined to generate post event after excution is done
346 '''
347 pass
348
349 #def _askExit(self):
350 # '''
351 # Can be redefined to generate post event to exit the Ipython shell
352 # '''
353 # pass
354
355 def _getHistoryMaxIndex(self):
356 '''
357 returns the max length of the history buffer
358
359 @return: history length
360 @rtype: int
361 '''
362 return len(self._IP.input_hist_raw)-1
363
364 def _getHistory(self):
365 '''
366 Get's the command string of the current history level.
367
368 @return: Historic command stri
369 @rtype: string
370 '''
371 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
372 return rv
373
374 def _pager_help(self,text):
375 '''
376 This function is used as a callback replacment to IPython help pager function
377
378 It puts the 'text' value inside the self._help_text string that can be retrived via getHelpText
379 function.
380 '''
381 if self._help_text == None:
382 self._help_text = text
383 else:
384 self._help_text += text
385
386 def _pager(self,IP,text):
387 '''
388 This function is used as a callback replacment to IPython pager function
389
390 It puts the 'text' value inside the self._doc_text string that can be retrived via getDocText
391 function.
392 '''
393 self._doc_text = text
394
395 def _raw_input(self, prompt=''):
396 '''
397 Custom raw_input() replacement. Get's current line from console buffer.
398
399 @param prompt: Prompt to print. Here for compatability as replacement.
400 @type prompt: string
401
402 @return: The current command line text.
403 @rtype: string
404 '''
405 return self._line_to_execute
406
407 def _execute(self):
408 '''
409 Executes the current line provided by the shell object.
410 '''
411 orig_stdout = sys.stdout
412 sys.stdout = IPython.Shell.Term.cout
413
414 try:
415 line = self._IP.raw_input(None, self._iter_more)
416 if self._IP.autoindent:
417 self._IP.readline_startup_hook(None)
418
419 except KeyboardInterrupt:
420 self._IP.write('\nKeyboardInterrupt\n')
421 self._IP.resetbuffer()
422 # keep cache in sync with the prompt counter:
423 self._IP.outputcache.prompt_count -= 1
424
425 if self._IP.autoindent:
426 self._IP.indent_current_nsp = 0
427 self._iter_more = 0
428 except:
429 self._IP.showtraceback()
430 else:
431 self._iter_more = self._IP.push(line)
432 if (self._IP.SyntaxTB.last_syntax_error and
433 self._IP.rc.autoedit_syntax):
434 self._IP.edit_syntax_error()
435 if self._iter_more:
436 self._prompt = str(self._IP.outputcache.prompt2).strip()
437 if self._IP.autoindent:
438 self._IP.readline_startup_hook(self._IP.pre_readline)
439 else:
440 self._prompt = str(self._IP.outputcache.prompt1).strip()
441 self._IP.indent_current_nsp = 0 #we set indentation to 0
442 sys.stdout = orig_stdout
443
444 def _shell(self, ip, cmd):
445 '''
446 Replacement method to allow shell commands without them blocking.
447
448 @param ip: Ipython instance, same as self._IP
449 @type cmd: Ipython instance
450 @param cmd: Shell command to execute.
451 @type cmd: string
452 '''
453 stdin, stdout = os.popen4(cmd)
454 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
455 #we use print command because the shell command is called inside IPython instance and thus is
456 #redirected to thread cout
457 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
458 print "\x01\x1b[1;36m\x02"+result
459 stdout.close()
460 stdin.close()
@@ -0,0 +1,6 b''
1 completion=IPYTHON
2 background_color=BLACK
3 filter_empty=True
4 filter_magic=True
5 filter_doc=True
6 filter_cmd=True
@@ -0,0 +1,96 b''
1 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
2
3 import thread,inspect
4
5 try:
6 import ctypes
7 HAS_CTYPES = True
8 except ImportError:
9 HAS_CTYPES = False
10
11
12 # Globals
13 # global flag to pass around information about Ctrl-C without exceptions
14 KBINT = False
15
16 # global flag to turn on/off Tk support.
17 USE_TK = False
18
19 # ID for the main thread, used for cross-thread exceptions
20 MAIN_THREAD_ID = thread.get_ident()
21
22 # Tag when runcode() is active, for exception handling
23 CODE_RUN = None
24
25
26 #-----------------------------------------------------------------------------
27 # This class is trivial now, but I want to have it in to publish a clean
28 # interface. Later when the internals are reorganized, code that uses this
29 # shouldn't have to change.
30
31
32 if HAS_CTYPES:
33 # Add async exception support. Trick taken from:
34 # http://sebulba.wikispaces.com/recipe+thread2
35 def _async_raise(tid, exctype):
36 """raises the exception, performs cleanup if needed"""
37 if not inspect.isclass(exctype):
38 raise TypeError("Only types can be raised (not instances)")
39 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
40 ctypes.py_object(exctype))
41 if res == 0:
42 raise ValueError("invalid thread id")
43 elif res != 1:
44 # """if it returns a number greater than one, you're in trouble,
45 # and you should call it again with exc=NULL to revert the effect"""
46 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
47 raise SystemError("PyThreadState_SetAsyncExc failed")
48
49 def sigint_handler (signum,stack_frame):
50 """Sigint handler for threaded apps.
51
52 This is a horrible hack to pass information about SIGINT _without_
53 using exceptions, since I haven't been able to properly manage
54 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
55 done (or at least that's my understanding from a c.l.py thread where
56 this was discussed)."""
57
58 global KBINT
59
60 if CODE_RUN:
61 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
62 else:
63 KBINT = True
64 print '\nKeyboardInterrupt - Press <Enter> to continue.',
65 Term.cout.flush()
66
67 else:
68 def sigint_handler (signum,stack_frame):
69 """Sigint handler for threaded apps.
70
71 This is a horrible hack to pass information about SIGINT _without_
72 using exceptions, since I haven't been able to properly manage
73 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
74 done (or at least that's my understanding from a c.l.py thread where
75 this was discussed)."""
76
77 global KBINT
78
79 print '\nKeyboardInterrupt - Press <Enter> to continue.',
80 Term.cout.flush()
81 # Set global flag so that runsource can know that Ctrl-C was hit
82 KBINT = True
83
84 def run_in_frontend(src):
85 """ Check if source snippet can be run in the REPL thread, as opposed to GUI mainloop
86
87 (to prevent unnecessary hanging of mainloop).
88
89 """
90
91 if src.startswith('_ip.system(') and not '\n' in src:
92 return True
93 return False
94
95
96
@@ -0,0 +1,278 b''
1 import sys
2
3 from twisted.internet import reactor, threads
4
5 from IPython.ipmaker import make_IPython
6 from IPython.iplib import InteractiveShell
7 from IPython.ipstruct import Struct
8 import Queue,thread,threading,signal
9 from signal import signal, SIGINT
10 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
11 import shellglobals
12
13 def install_gtk2():
14 """ Install gtk2 reactor, needs to be called bef """
15 from twisted.internet import gtk2reactor
16 gtk2reactor.install()
17
18
19 def hijack_reactor():
20 """Modifies Twisted's reactor with a dummy so user code does
21 not block IPython. This function returns the original
22 'twisted.internet.reactor' that has been hijacked.
23
24 NOTE: Make sure you call this *AFTER* you've installed
25 the reactor of your choice.
26 """
27 from twisted import internet
28 orig_reactor = internet.reactor
29
30 class DummyReactor(object):
31 def run(self):
32 pass
33 def __getattr__(self, name):
34 return getattr(orig_reactor, name)
35 def __setattr__(self, name, value):
36 return setattr(orig_reactor, name, value)
37
38 internet.reactor = DummyReactor()
39 return orig_reactor
40
41 class TwistedInteractiveShell(InteractiveShell):
42 """Simple multi-threaded shell."""
43
44 # Threading strategy taken from:
45 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
46 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
47 # from the pygtk mailing list, to avoid lockups with system calls.
48
49 # class attribute to indicate whether the class supports threads or not.
50 # Subclasses with thread support should override this as needed.
51 isthreaded = True
52
53 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
54 user_ns=None,user_global_ns=None,banner2='',**kw):
55 """Similar to the normal InteractiveShell, but with threading control"""
56
57 InteractiveShell.__init__(self,name,usage,rc,user_ns,
58 user_global_ns,banner2)
59
60
61 # A queue to hold the code to be executed.
62 self.code_queue = Queue.Queue()
63
64 # Stuff to do at closing time
65 self._kill = None
66 on_kill = kw.get('on_kill', [])
67 # Check that all things to kill are callable:
68 for t in on_kill:
69 if not callable(t):
70 raise TypeError,'on_kill must be a list of callables'
71 self.on_kill = on_kill
72 # thread identity of the "worker thread" (that may execute code directly)
73 self.worker_ident = None
74 self.reactor_started = False
75 self.first_run = True
76
77 def runsource(self, source, filename="<input>", symbol="single"):
78 """Compile and run some source in the interpreter.
79
80 Modified version of code.py's runsource(), to handle threading issues.
81 See the original for full docstring details."""
82
83 # If Ctrl-C was typed, we reset the flag and return right away
84 if shellglobals.KBINT:
85 shellglobals.KBINT = False
86 return False
87
88 if self._kill:
89 # can't queue new code if we are being killed
90 return True
91
92 try:
93 code = self.compile(source, filename, symbol)
94 except (OverflowError, SyntaxError, ValueError):
95 # Case 1
96 self.showsyntaxerror(filename)
97 return False
98
99 if code is None:
100 # Case 2
101 return True
102
103 # shortcut - if we are in worker thread, or the worker thread is not running,
104 # execute directly (to allow recursion and prevent deadlock if code is run early
105 # in IPython construction)
106
107 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
108 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
109 InteractiveShell.runcode(self,code)
110 return
111
112 # Case 3
113 # Store code in queue, so the execution thread can handle it.
114
115 self.first_run = False
116 completed_ev, received_ev = threading.Event(), threading.Event()
117
118 self.code_queue.put((code,completed_ev, received_ev))
119
120 reactor.callLater(0.0,self.runcode)
121 received_ev.wait(5)
122 if not received_ev.isSet():
123 # the mainloop is dead, start executing code directly
124 print "Warning: Timeout for mainloop thread exceeded"
125 print "switching to nonthreaded mode (until mainloop wakes up again)"
126 self.worker_ident = None
127 else:
128 completed_ev.wait()
129
130 return False
131
132 def runcode(self):
133 """Execute a code object.
134
135 Multithreaded wrapper around IPython's runcode()."""
136
137
138 # we are in worker thread, stash out the id for runsource()
139 self.worker_ident = thread.get_ident()
140
141 if self._kill:
142 print >>Term.cout, 'Closing threads...',
143 Term.cout.flush()
144 for tokill in self.on_kill:
145 tokill()
146 print >>Term.cout, 'Done.'
147 # allow kill() to return
148 self._kill.set()
149 return True
150
151 # Install SIGINT handler. We do it every time to ensure that if user
152 # code modifies it, we restore our own handling.
153 try:
154 pass
155 signal(SIGINT,shellglobals.sigint_handler)
156 except SystemError:
157 # This happens under Windows, which seems to have all sorts
158 # of problems with signal handling. Oh well...
159 pass
160
161 # Flush queue of pending code by calling the run methood of the parent
162 # class with all items which may be in the queue.
163 code_to_run = None
164 while 1:
165 try:
166 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
167 except Queue.Empty:
168 break
169 received_ev.set()
170
171
172 # Exceptions need to be raised differently depending on which
173 # thread is active. This convoluted try/except is only there to
174 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
175 # at the wrong time doesn't deadlock everything. The global
176 # CODE_TO_RUN is set to true/false as close as possible to the
177 # runcode() call, so that the KBINT handler is correctly informed.
178 try:
179 try:
180 shellglobals.CODE_RUN = True
181 InteractiveShell.runcode(self,code_to_run)
182 except KeyboardInterrupt:
183 print "Keyboard interrupted in mainloop"
184 while not self.code_queue.empty():
185 code = self.code_queue.get_nowait()
186 break
187 finally:
188 shellglobals.CODE_RUN = False
189 # allow runsource() return from wait
190 completed_ev.set()
191
192 # This MUST return true for gtk threading to work
193 return True
194
195 def kill(self):
196 """Kill the thread, returning when it has been shut down."""
197 self._kill = threading.Event()
198 reactor.callLater(0.0,self.runcode)
199 self._kill.wait()
200
201
202
203 class IPShellTwisted:
204 """Run a Twisted reactor while in an IPython session.
205
206 Python commands can be passed to the thread where they will be
207 executed. This is implemented by periodically checking for
208 passed code using a Twisted reactor callback.
209 """
210
211 TIMEOUT = 0.01 # Millisecond interval between reactor runs.
212
213 def __init__(self, argv=None, user_ns=None, debug=1,
214 shell_class=TwistedInteractiveShell):
215
216 from twisted.internet import reactor
217 self.reactor = hijack_reactor()
218
219 mainquit = self.reactor.stop
220
221 # Make sure IPython keeps going after reactor stop.
222 def reactorstop():
223 pass
224 self.reactor.stop = reactorstop
225 reactorrun_orig = self.reactor.run
226 self.quitting = False
227 def reactorrun():
228 while True and not self.quitting:
229 reactorrun_orig()
230 self.reactor.run = reactorrun
231
232 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
233 shell_class=shell_class,
234 on_kill=[mainquit])
235
236 # threading.Thread.__init__(self)
237
238 def run(self):
239 self.IP.mainloop()
240 self.quitting = True
241 self.IP.kill()
242
243 def mainloop(self):
244 def mainLoopThreadDeath(r):
245 print "mainLoopThreadDeath: ", str(r)
246 def spawnMainloopThread():
247 d=threads.deferToThread(self.run)
248 d.addBoth(mainLoopThreadDeath)
249 reactor.callWhenRunning(spawnMainloopThread)
250 self.IP.reactor_started = True
251 self.reactor.run()
252 print "mainloop ending...."
253
254 exists = True
255
256
257 if __name__ == '__main__':
258 # Sample usage.
259
260 # Create the shell object. This steals twisted.internet.reactor
261 # for its own purposes, to make sure you've already installed a
262 # reactor of your choice.
263 shell = IPShellTwisted(
264 argv=[],
265 user_ns={'__name__': '__example__',
266 'hello': 'world',
267 },
268 )
269
270 # Run the mainloop. This runs the actual reactor.run() method.
271 # The twisted.internet.reactor object at this point is a dummy
272 # object that passes through to the actual reactor, but prevents
273 # run() from being called on it again.
274 shell.mainloop()
275
276 # You must exit IPython to terminate your program.
277 print 'Goodbye!'
278
@@ -0,0 +1,1 b''
1 doc/ipython.el usr/share/emacs/site-lisp
@@ -0,0 +1,52 b''
1 .TH IRUNNER 1 "April 24, 2007" "" ""
2 .SH NAME
3 \fBirunner \- interactive runner interface
4 .SH SYNOPSIS
5 .nf
6 .fam C
7 \fBirunner\fP [\fIoptions\fP] \fIfile_to_run\fP
8 .fam T
9 .fi
10 .SH DESCRIPTION
11 irunner is an interface to the various interactive runners
12 available in IPython's \fBirunner\fP module.
13 .PP
14 The already implemented runners are listed below; adding
15 one for a new program is a trivial task, see the source
16 for examples.
17 .SH OPTIONS
18 .TP
19 .B
20 \-h, \-\-help
21 show this help message and exit
22 .TP
23 .B
24 \-\-ipython
25 IPython interactive runner (default).
26 .TP
27 .B
28 \-\-python
29 Python interactive runner.
30 .TP
31 .B
32 \-\-sage
33 SAGE interactive runner.
34 .SH EXAMPLE
35 irunner.py \-\-python \-\- \-\-help
36 will pass \-\-help to the python runner.
37 Similarly,
38 irunner.py \-\-ipython \-\- \-\-interact script.ipy
39 .SH SEE ALSO
40 .BR ipython(1)
41 .br
42 .SH BUGS
43 The SAGE runner only works if you manually configure your SAGE
44 copy to use 'colors NoColor' in the ipythonrc config file, since
45 currently the prompt matching regexp does not identify color sequences.
46 .SH AUTHOR
47 \fBirunner\fP is an extension of Ken Schutte <kschutte-AT-csail.mit.edu>'s
48 script contributed on the ipython-user list:
49 http://scipy.net/pipermail/ipython-user/2006-May/001705.html
50 .PP
51 This manual page was written by Bernd Zeimetz <bernd@bzed.de>,
52 for the Debian project (but may be used by others).
@@ -0,0 +1,1 b''
1 debian/irunner.1
@@ -0,0 +1,1 b''
1 2
@@ -0,0 +1,2 b''
1 version=3
2 http://ipython.scipy.org/dist/ ipython-(.*)\.tar\.gz
@@ -0,0 +1,74 b''
1 #!/usr/bin/env python
2 """Script to build documentation using Sphinx.
3 """
4
5 import fileinput,os,sys
6
7 def oscmd(c):
8 os.system(c)
9
10 # html manual.
11 oscmd('sphinx-build -d build/doctrees source build/html')
12
13 if sys.platform != 'win32':
14 # LaTeX format.
15 oscmd('sphinx-build -b latex -d build/doctrees source build/latex')
16
17 # Produce pdf.
18 topdir = os.getcwd()
19 os.chdir('build/latex')
20
21 # Change chapter style to section style: allows chapters to start on
22 # the current page. Works much better for the short chapters we have.
23 # This must go in the class file rather than the preamble, so we modify
24 # manual.cls at runtime.
25 chapter_cmds=r'''
26 % Local changes.
27 \renewcommand\chapter{
28 \thispagestyle{plain}
29 \global\@topnum\z@
30 \@afterindentfalse
31 \secdef\@chapter\@schapter
32 }
33 \def\@makechapterhead#1{
34 \vspace*{10\p@}
35 {\raggedright \reset@font \Huge \bfseries \thechapter \quad #1}
36 \par\nobreak
37 \hrulefill
38 \par\nobreak
39 \vspace*{10\p@}
40 }
41 \def\@makeschapterhead#1{
42 \vspace*{10\p@}
43 {\raggedright \reset@font \Huge \bfseries #1}
44 \par\nobreak
45 \hrulefill
46 \par\nobreak
47 \vspace*{10\p@}
48 }
49 '''
50
51 unmodified=True
52 for line in fileinput.FileInput('manual.cls',inplace=1):
53 if 'Support for module synopsis' in line and unmodified:
54 line=chapter_cmds+line
55 elif 'makechapterhead' in line:
56 # Already have altered manual.cls: don't need to again.
57 unmodified=False
58 print line,
59
60 # Copying the makefile produced by sphinx...
61 oscmd('pdflatex ipython.tex')
62 oscmd('pdflatex ipython.tex')
63 oscmd('pdflatex ipython.tex')
64 oscmd('makeindex -s python.ist ipython.idx')
65 oscmd('makeindex -s python.ist modipython.idx')
66 oscmd('pdflatex ipython.tex')
67 oscmd('pdflatex ipython.tex')
68
69 # Create a manual/ directory with final html/pdf output
70 os.chdir(topdir)
71 oscmd('rm -rf manual')
72 oscmd('mkdir manual')
73 oscmd('cp -r build/html/*.html build/html/_static manual/')
74 oscmd('cp build/latex/ipython.pdf manual/')
@@ -0,0 +1,67 b''
1 if !exists("$IPY_SESSION")
2 finish
3 endif
4
5 " set up the python interpreter within vim, to have all the right modules
6 " imported, as well as certain useful globals set
7 python import socket
8 python import os
9 python import vim
10 python IPYSERVER = None
11
12 python << EOF
13 # do we have a connection to the ipython instance?
14 def check_server():
15 global IPYSERVER
16 if IPYSERVER:
17 return True
18 else:
19 return False
20
21 # connect to the ipython server, if we need to
22 def connect():
23 global IPYSERVER
24 if check_server():
25 return
26 try:
27 IPYSERVER = socket.socket(socket.AF_UNIX)
28 IPYSERVER.connect(os.environ.get('IPY_SERVER'))
29 except:
30 IPYSERVER = None
31
32 def disconnect():
33 if IPYSERVER:
34 IPYSERVER.close()
35
36 def send(cmd):
37 x = 0
38 while True:
39 x += IPYSERVER.send(cmd)
40 if x < len(cmd):
41 cmd = cmd[x:]
42 else:
43 break
44
45 def run_this_file():
46 if check_server():
47 send('run %s' % (vim.current.buffer.name,))
48 else:
49 raise Exception, "Not connected to an IPython server"
50 EOF
51
52 fun! <SID>toggle_send_on_save()
53 if exists("s:ssos") && s:ssos == 1
54 let s:ssos = 0
55 au! BufWritePost *.py :py run_this_file()
56 echo "Autosend Off"
57 else
58 let s:ssos = 1
59 au BufWritePost *.py :py run_this_file()
60 echo "Autowsend On"
61 endif
62 endfun
63
64 map <silent> <F5> :python run_this_file()<CR>
65 imap <silent> <C-F5> <ESC><F5>a
66 map <F7> :call <SID>toggle_send_on_save()<CR>
67 py connect()
This diff has been collapsed as it changes many lines, (552 lines changed) Show them Hide them
@@ -0,0 +1,552 b''
1 <?xml version="1.0" encoding="utf-8"?>
2 <?xml-stylesheet ekr_test?>
3 <leo_file>
4 <leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
5 <globals body_outline_ratio="0.307814992026">
6 <global_window_position top="257" left="131" height="627" width="1280"/>
7 <global_log_window_position top="0" left="0" height="0" width="0"/>
8 </globals>
9 <preferences/>
10 <find_panel_settings/>
11 <vnodes>
12 <v t="vivainio.20080222193236" a="E"><vh>Documentation</vh>
13 <v t="vivainio.20080223121915" tnodeList="vivainio.20080223121915,vivainio.20080222193236.1,vivainio.20080223133858,vivainio.20080223133922,vivainio.20080223133947,vivainio.20080223134018,vivainio.20080223134100,vivainio.20080223134118,vivainio.20080223134433,vivainio.20080223142207,vivainio.20080223134136"><vh>@nosent ILeo_doc.txt</vh>
14 <v t="vivainio.20080222193236.1"><vh>Documentation</vh>
15 <v t="vivainio.20080223133858"><vh>Introduction</vh></v>
16 <v t="vivainio.20080223133922"><vh>Installation</vh></v>
17 <v t="vivainio.20080223133947"><vh>Accessing IPython from Leo</vh></v>
18 <v t="vivainio.20080223134018"><vh>Accessing Leo nodes from IPython</vh></v>
19 <v t="vivainio.20080223134100"><vh>Cl definitions</vh></v>
20 <v t="vivainio.20080223134118"><vh>Special node types</vh></v>
21 <v t="vivainio.20080223134433"><vh>Custom push</vh></v>
22 <v t="vivainio.20080223142207" a="E"><vh>Code snippets</vh></v>
23 <v t="vivainio.20080223134136"><vh>Acknowledgements and history</vh></v>
24 </v>
25 </v>
26 </v>
27 <v t="vivainio.20080218184525"><vh>@chapters</vh></v>
28 <v t="vivainio.20080223133721" a="E"><vh>@settings</vh>
29 <v t="vivainio.20080316092617"><vh>@@string ipython_argv = ipython -pylab</vh></v>
30 <v t="vivainio.20080223133721.1"><vh>@enabled-plugins</vh></v>
31 </v>
32 <v t="vivainio.20080218184540"><vh>@ipy-startup</vh>
33 <v t="vivainio.20080218184613.1"><vh>b</vh></v>
34 <v t="vivainio.20080218200031"><vh>Some classes P</vh>
35 <v t="vivainio.20080218190816"><vh>File-like access</vh></v>
36 <v t="vivainio.20080218200106"><vh>csv data</vh></v>
37 <v t="vivainio.20080219225120"><vh>String list</vh></v>
38 <v t="vivainio.20080219230342"><vh>slist to leo</vh></v>
39 </v>
40 </v>
41 <v t="vivainio.20080218195413" a="E"><vh>Class tests</vh>
42 <v t="vivainio.20080218200509"><vh>csvr</vh></v>
43 <v t="vivainio.20080218191007"><vh>tempfile</vh></v>
44 <v t="vivainio.20080218195413.1"><vh>rfile</vh></v>
45 <v t="vivainio.20080219225804"><vh>strlist</vh></v>
46 </v>
47 <v t="vivainio.20080222201226" a="V"><vh>IPython script push tests</vh></v>
48 <v t="vivainio.20080218201219" a="E"><vh>Direct variables</vh>
49 <v t="vivainio.20080218201219.2"><vh>bar</vh></v>
50 </v>
51 <v t="vivainio.20080316144536" a="E"><vh>pylab tests</vh>
52 <v t="vivainio.20080316145539.2"><vh>Generate testarr</vh></v>
53 <v t="vivainio.20080316085925"><vh>testarr</vh></v>
54 <v t="vivainio.20080316085950"><vh>Call plotter on testarr</vh></v>
55 </v>
56 <v t="vivainio.20080222202211"><vh>test stuff</vh></v>
57 <v t="vivainio.20080223142403"><vh>@ipy-results</vh>
58 <v t="vivainio.20080223142403.1"><vh>foo</vh></v>
59 </v>
60 <v t="vivainio.20080222202211.1" a="E"><vh>spam</vh></v>
61 </vnodes>
62 <tnodes>
63 <t tx="vivainio.20080218184525">?</t>
64 <t tx="vivainio.20080218184540">?Direct children of this node will be pushed at ipython bridge startup
65
66 This node itself will *not* be pushed</t>
67 <t tx="vivainio.20080218184613.1">print "world"</t>
68 <t tx="vivainio.20080218190816">def rfile(body,n):
69 """ @cl rfile
70
71 produces a StringIO (file like obj of the rest of the body) """
72
73 import StringIO
74 return StringIO.StringIO(body)
75
76 def tmpfile(body,n):
77 """ @cl tmpfile
78
79 Produces a temporary file, with node body as contents
80
81 """
82 import tempfile
83 h, fname = tempfile.mkstemp()
84 f = open(fname,'w')
85 f.write(body)
86 f.close()
87 return fname
88 </t>
89 <t tx="vivainio.20080218191007">@cl tmpfile
90
91 Hello</t>
92 <t tx="vivainio.20080218195413">?</t>
93 <t tx="vivainio.20080218195413.1">@cl rfile
94 These
95 lines
96 should
97 be
98 readable </t>
99 <t tx="vivainio.20080218200031">@others</t>
100 <t tx="vivainio.20080218200106">def csvdata(body,n):
101 import csv
102 d = csv.Sniffer().sniff(body)
103 reader = csv.reader(body.splitlines(), dialect = d)
104 return reader</t>
105 <t tx="vivainio.20080218200509">@cl csvdata
106
107 a,b,b
108 1,2,2</t>
109 <t tx="vivainio.20080218201219"></t>
110 <t tx="vivainio.20080218201219.2">@cl
111 "hello world"</t>
112 <t tx="vivainio.20080219225120">import IPython.genutils
113 def slist(body,n):
114 return IPython.genutils.SList(body.splitlines())
115 </t>
116 <t tx="vivainio.20080219225804">@cl slist
117 hello
118 world
119 on
120 many
121 lines
122 </t>
123 <t tx="vivainio.20080219230342">import ipy_leo
124 @ipy_leo.format_for_leo.when_type(IPython.genutils.SList)
125 def format_slist(obj):
126 return "@cl slist\n" + obj.n
127 </t>
128 <t tx="vivainio.20080222193236">?</t>
129 <t tx="vivainio.20080222193236.1">@wrap
130 @nocolor</t>
131 <t tx="vivainio.20080222201226"># test ipython script 'cleanup' with complex blocks
132 1+2
133 print "hello"
134 3+4
135
136 def f(x):
137 return x.upper()
138
139
140 if 0:
141 print "foo"
142 else:
143 print "bar"
144
145 def g():
146 pass
147
148 g()
149
150 if 1:
151 if 1:
152 print "hello"
153
154 print "world"
155
156 if 1:
157 print "hello"
158
159 print "word"
160 else:
161 print "foo"
162
163 print "bar"
164 print "baz"
165
166 try:
167 raise Exception
168 except:
169 print "exc ok"</t>
170 <t tx="vivainio.20080222202211"></t>
171 <t tx="vivainio.20080222202211.1" ipython="7d71005506636f6f7264737101284b0c4bde747102732e">@cl rfile
172 hello
173 world
174 and whatever</t>
175 <t tx="vivainio.20080223121915">@others
176 </t>
177 <t tx="vivainio.20080223133721"></t>
178 <t tx="vivainio.20080223133721.1">ipython.py</t>
179 <t tx="vivainio.20080223133858">
180 Introduction
181 ============
182
183 The purpose of ILeo, or leo-ipython bridge, is being a two-way communication
184 channel between Leo and IPython. The level of integration is much deeper than
185 conventional integration in IDEs; most notably, you are able to store *data* in
186 Leo nodes, in addition to mere program code. The possibilities of this are
187 endless, and this degree of integration has not been seen previously in the python
188 world.
189
190 IPython users are accustomed to using things like %edit to produce non-trivial
191 functions/classes (i.e. something that they don't want to enter directly on the
192 interactive prompt, but creating a proper script/module involves too much
193 overhead). In ILeo, this task consists just going to the Leo window, creating a node
194 and writing the code there, and pressing alt+I (push-to-ipython).
195
196 Obviously, you can save the Leo document as usual - this is a great advantage
197 of ILeo over using %edit, you can save your experimental scripts all at one
198 time, without having to organize them into script/module files (before you
199 really want to, of course!)
200 </t>
201 <t tx="vivainio.20080223133922">
202 Installation
203 ============
204
205 You need at least Leo 4.4.7, and the development version of IPython (ILeo
206 will be incorporated to IPython 0.8.3).
207
208 You can get IPython from Launchpad by installing bzr and doing
209
210 bzr branch lp:ipython
211
212 and running "setup.py install".
213
214 You need to enable the 'ipython.py' plugin in Leo:
215
216 - Help -&gt; Open LeoSettings.leo
217
218 - Edit @settings--&gt;Plugins--&gt;@enabled-plugins, add/uncomment 'ipython.py'
219
220 - Alternatively, you can add @settings--&gt;@enabled-plugins with body ipython.py to your leo document.
221
222 - Restart Leo. Be sure that you have the console window open (start leo.py from console, or double-click leo.py on windows)
223
224 - Press alt+5 OR alt-x start-ipython to launch IPython in the console that
225 started leo. You can start entering IPython commands normally, and Leo will keep
226 running at the same time.
227 </t>
228 <t tx="vivainio.20080223133947">
229 Accessing IPython from Leo
230 ==========================
231
232 IPython code
233 ------------
234
235 Just enter IPython commands on a Leo node and press alt-I to execute
236 push-to-ipython in order to execute the script in IPython. 'commands' is
237 interpreted loosely here - you can enter function and class definitions, in
238 addition to the things you would usually enter at IPython prompt - calculations,
239 system commands etc.
240
241 Everything that would be legal to enter on IPython prompt is legal to execute
242 from ILeo.
243
244 Results will be shows in Leo log window for convenience, in addition to the console.
245
246 Suppose that a node had the following contents:
247 {{{
248 1+2
249 print "hello"
250 3+4
251
252 def f(x):
253 return x.upper()
254
255 f('hello world')
256 }}}
257
258 If you press alt+I on that node, you will see the following in Leo log window (IPython tab):
259
260 {{{
261 In: 1+2
262 &lt;2&gt; 3
263 In: 3+4
264 &lt;4&gt; 7
265 In: f('hello world')
266 &lt;6&gt; 'HELLO WORLD'
267 }}}
268
269 (numbers like &lt;6&gt; mean IPython output history indices; the actual object can be
270 referenced with _6 as usual in IPython).
271
272
273 Plain Python code
274 -----------------
275
276 If the headline of the node ends with capital P, alt-I will not run the code
277 through IPython translation mechanism but use the direct python 'exec' statement
278 (in IPython user namespace) to execute the code. It wont be shown in IPython
279 history, and sometimes it is safer (and more efficient) to execute things as
280 plain Python statements. Large class definitions are good candidates for P
281 nodes.
282 </t>
283 <t tx="vivainio.20080223134018">
284 Accessing Leo nodes from IPython
285 ================================
286
287 The real fun starts when you start entering text to leo nodes, and are using
288 that as data (input/output) for your IPython work.
289
290 Accessing Leo nodes happens through the variable 'wb' (short for "WorkBook")
291 that exist in the IPython user namespace. Nodes that are directly accessible are
292 the ones that have simple names which could also be Python variable names;
293 'foo_1' will be accessible directly from IPython, whereas 'my scripts' will not.
294 If you want to access a node with arbitrary headline, add a child node '@a foo'
295 (@a stands for 'anchor'). Then, the parent of '@a foo' is accessible through
296 'wb.foo'.
297
298 You can see what nodes are accessible be entering (in IPython) wb.&lt;TAB&gt;. Example:
299
300 [C:leo/src]|12&gt; wb.
301 wb.b wb.tempfile wb.rfile wb.NewHeadline
302 wb.bar wb.Docs wb.strlist wb.csvr
303 [C:leo/src]|12&gt; wb.tempfile
304 &lt;12&gt; &lt;ipy_leo.LeoNode object at 0x044B6D90&gt;
305
306 So here, we meet the 'LeoNode' class that is your key to manipulating Leo
307 content from IPython!
308
309 LeoNode
310 -------
311
312 Suppose that we had a node with headline 'spam' and body:
313
314 ['12',2222+32]
315
316 we can access it from IPython (or from scripts entered into other Leo nodes!) by doing:
317
318 C:leo/src]|19&gt; wb.spam.v
319 &lt;19&gt; ['12', 2254]
320
321 'v' attribute stands for 'value', which means the node contents will be run
322 through 'eval' and everything you would be able to enter into IPython prompt
323 will be converted to objects. This mechanism can be extended far beyond direct
324 evaluation (see '@cl definitions').
325
326 'v' attribute also has a setter, i.e. you can do:
327
328 wb.spam.v = "mystring"
329
330 Which will result in the node 'spam' having the following text:
331
332 'mystring'
333
334 What assignment to 'v' does can be configured through generic functions
335 ('simplegeneric' module, will be explained later).
336
337 Besides v, you can set the body text directly through
338
339 wb.spam.b = "some\nstring",
340
341 headline by
342
343 wb.spam.h = 'new_headline'
344
345 (obviously you must access the node through wb.new_headline from that point
346 onwards), and access the contents as string list (IPython SList) through
347 'wb.spam.l'.
348
349 If you do 'wb.foo.v = 12' when node named 'foo' does not exist, the node titled
350 'foo' will be automatically created and assigned body 12.
351
352 LeoNode also supports go() that focuses the node in the Leo window, and ipush()
353 that simulates pressing alt+I on the node.
354
355 You can access unknownAttributes by .uA property dictionary. Unknown attributes
356 allow you to store arbitrary (pickleable) python objects in the Leo nodes; the
357 attributes are stored when you save the .leo document, and recreated when you
358 open the document again. The attributes are not visible anywhere, but can be
359 used for domain-specific metatada. Example:
360
361 [C:leo/src]|12&gt; wb.spam.uA['coords'] = (12,222)
362 [C:leo/src]|13&gt; wb.spam.uA
363 &lt;13&gt; {'coords': (12, 222)}
364
365 Accessing children with iteration and dict notation
366 ---------------------------------------------------
367
368 Sometimes, you may want to treat a node as a 'database', where the nodes
369 children represent elements in the database. You can create a new child node for
370 node 'spam', with headline 'foo bar' like this:
371
372 wb.spam['foo bar'] = "Hello"
373
374 And assign a new value for it by doing
375
376 wb.spam['foo bar'].v = "Hello again"
377
378 Note how you can't use .v when you first create the node - i.e. the node needs
379 to be initialized by simple assignment, that will be interpreted as assignment
380 to '.v'. This is a conscious design choice.
381
382 If you try to do wb.spam['bar'] = 'Hello', ILeo will assign '@k bar' as the
383 headline for the child instead, because 'bar' is a legal python name (and as
384 such would be incorporated in the workbook namespace). This is done to avoid
385 crowding the workbook namespace with extraneous items. The item will still be
386 accessible as wb.spam['bar']
387
388 LeoNodes are iterable, so to see the headlines of all the children of 'spam' do:
389
390 for n in wb.spam:
391 print n.h
392 </t>
393 <t tx="vivainio.20080223134100">
394 @cl definitions
395 ===============
396
397 If the first line in the body text is of the form '@cl sometext', IPython will
398 evaluate 'sometext' and call the result with the rest of the body when you do
399 'wb.foo.v'. An example is in place here. Suppose that we have defined a class (I
400 use the term class in a non-python sense here)
401
402 {{{
403 def rfile(body,node):
404 """ @cl rfile
405
406 produces a StringIO (file like obj) of the rest of the body """
407
408 import StringIO
409 return StringIO.StringIO(body)
410 }}}
411
412 (note that node is ignored here - but it could be used to access headline,
413 children etc.),
414
415 Now, let's say you have node 'spam' with text
416
417 {{{
418 @cl rfile
419 hello
420 world
421 and whatever
422 }}}
423
424 Now, in IPython, we can do this:
425
426 {{{
427 [C:leo/src]|22&gt; f = wb.spam.v
428 [C:leo/src]|23&gt; f
429 &lt;23&gt; &lt;StringIO.StringIO instance at 0x04E7E490&gt;
430 [C:leo/src]|24&gt; f.readline()
431 &lt;24&gt; u'hello\n'
432 [C:leo/src]|25&gt; f.readline()
433 &lt;25&gt; u'world\n'
434 [C:leo/src]|26&gt; f.readline()
435 &lt;26&gt; u'and whatever'
436 [C:leo/src]|27&gt; f.readline()
437 &lt;27&gt; u''
438 }}}
439
440 You should declare new @cl types to make ILeo as convenient your problem domain
441 as possible. For example, a "@cl etree" could return the elementtree object for
442 xml content.
443 </t>
444 <t tx="vivainio.20080223134118">
445 Special node types
446 ==================
447
448 @ipy-startup
449 ------------
450
451 If this node exist, the *direct children* of this will be pushed to IPython when
452 ILeo is started (you press alt+5). Use it to push your own @cl definitions etc.
453 The contents of of the node itself will be ignored.
454
455 @ipy-results
456 ------------
457
458 When you create a new node (wb.foo.v = 'stuff'), the node foo will be created as
459 a child of this node. If @ipy-results does not exist, the new node will be created after the currently selected node.
460
461 @a nodes
462 --------
463
464 You can attach these as children of existing nodes to provide a way to access
465 nodes with arbitrary headlines, or to provide aliases to other nodes. If
466 multiple @a nodes are attached as children of a node, all the names can be used
467 to access the same object.
468 </t>
469 <t tx="vivainio.20080223134136">
470 Acknowledgements &amp; History
471 ==========================
472
473 This idea got started when I (Ville) saw this post by Edward Ream (the author of
474 Leo) on IPython developer mailing list:
475
476 http://lists.ipython.scipy.org/pipermail/ipython-dev/2008-January/003551.html
477
478 I was using FreeMind as mind mapping software, and so I had an immediate use
479 case for Leo (which, incidentally, is superior to FreeMind as mind mapper). The
480 wheels started rolling, I got obsessed with the power of this concept
481 (everything clicked together), and Edwards excitement paralleled mine.
482 Everything was mind-bogglingly easy/trivial, something that is typical of all
483 revolutionary technologies (think Python here).
484
485 The discussion that "built" ILeo is here:
486 http://sourceforge.net/forum/forum.php?thread_id=1911662&amp;forum_id=10226
487
488 ?</t>
489 <t tx="vivainio.20080223134433">
490 Declaring custom push-to-ipython handlers
491 =========================================
492
493 Sometimes, you might want to configure what alt+I on a node does. You can do
494 that by creating your own push function and expose it using
495 ipy_leo.expose_ileo_push(f, priority). The function should check whether the
496 node should by handled by the function and raise IPython.ipapi.TryNext if it
497 will not do the handling, giving the next function in the chain a chance to see
498 whether it should handle the push.
499
500 This example would print an uppercase version of node body if the node headline ends
501 with U (yes, this is completely useless!):
502
503 {{{
504 def push_upcase(node):
505 if not node.h.endswith('U'):
506 raise TryNext
507 print node.b.upper()
508
509 ipy_leo.expose_ileo_push(push_upcase, 12)
510 }}}
511
512 (the priority should be between 0-100 - typically, you don't need to care about
513 it and can usually omit the argument altogether)
514 </t>
515 <t tx="vivainio.20080223142207">
516 Example code snippets
517 =====================
518
519 Get list of all headlines of all the nodes in leo:
520
521 [node.h for node in wb]
522
523 Create node with headline 'baz', empty body:
524 wb.baz
525
526 Create 10 child nodes for baz, where i is headline and 'Hello ' + i is body:
527
528 for i in range(10):
529 wb.baz[i] = 'Hello %d' % i
530
531
532 </t>
533 <t tx="vivainio.20080223142403"></t>
534 <t tx="vivainio.20080223142403.1">12</t>
535 <t tx="vivainio.20080316085925">array([[ 0, 1, 2],
536 [ 3, 4, 5],
537 [ 6, 7, 8],
538 [ 9, 10, 11]])</t>
539 <t tx="vivainio.20080316085950"># press alt+i here to plot testarr
540
541 plot(wb.testarr.v)</t>
542 <t tx="vivainio.20080316092617"></t>
543 <t tx="vivainio.20080316144536">Quickstart:
544 easy_install numpy
545 easy_install matplotlib
546
547 Make sure you have '@string ipython-argv = ipython -pylab' in @settings. We currently recommend using TkAgg as the backend (it's also the default)</t>
548 <t tx="vivainio.20080316145539.2">#press alt+i here to generate an array for plotter
549
550 wb.testarr.v = arange(12).reshape(4,3)</t>
551 </tnodes>
552 </leo_file>
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,86 +1,86 b''
1 <?xml version='1.0' encoding='iso-8859-1'?>
1 <?xml version='1.0' encoding='iso-8859-1'?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html>
3 <html>
4 <head>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
7 <title>igrid help</title>
7 <title>igrid help</title>
8 </head>
8 </head>
9 <body>
9 <body>
10 <h1>igrid help</h1>
10 <h1>igrid help</h1>
11
11
12
12
13 <h2>Commands</h2>
13 <h2>Commands</h2>
14
14
15
15
16 <h3>pick (P)</h3>
16 <h3>pick (P)</h3>
17 <p>Pick the whole row (object is available as "_")</p>
17 <p>Pick the whole row (object is available as "_")</p>
18
18
19 <h3>pickattr (Shift-P)</h3>
19 <h3>pickattr (Shift-P)</h3>
20 <p>Pick the attribute under the cursor</p>
20 <p>Pick the attribute under the cursor</p>
21
21
22 <h3>pickallattrs (Shift-C)</h3>
22 <h3>pickallattrs (Shift-C)</h3>
23 <p>Pick' the complete column under the cursor (i.e. the attribute under the
23 <p>Pick' the complete column under the cursor (i.e. the attribute under the
24 cursor) from all currently fetched objects. These attributes will be returned
24 cursor) from all currently fetched objects. These attributes will be returned
25 as a list.</p>
25 as a list.</p>
26
26
27 <h3>enter (E)</h3>
27 <h3>enter (E)</h3>
28 <p>Enter the object under the cursor. (what this mean depends on the object
28 <p>Enter the object under the cursor. (what this mean depends on the object
29 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
29 itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
30
30
31 <h3>enterattr (Shift-E)</h3>
31 <h3>enterattr (Shift-E)</h3>
32 <p>Enter the attribute under the cursor.</p>
32 <p>Enter the attribute under the cursor.</p>
33
33
34 <h3>detail (D)</h3>
34 <h3>detail (D)</h3>
35 <p>Show a detail view of the object under the cursor. This shows the name,
35 <p>Show a detail view of the object under the cursor. This shows the name,
36 type, doc string and value of the object attributes (and it might show more
36 type, doc string and value of the object attributes (and it might show more
37 attributes than in the list view, depending on the object).</p>
37 attributes than in the list view, depending on the object).</p>
38
38
39 <h3>detailattr (Shift-D)</h3>
39 <h3>detailattr (Shift-D)</h3>
40 <p>Show a detail view of the attribute under the cursor.</p>
40 <p>Show a detail view of the attribute under the cursor.</p>
41
41
42 <h3>pickrows (M)</h3>
42 <h3>pickrows (M)</h3>
43 <p>Pick multiple selected rows (M)</p>
43 <p>Pick multiple selected rows (M)</p>
44
44
45 <h3>pickrowsattr (CTRL-M)</h3>
45 <h3>pickrowsattr (CTRL-M)</h3>
46 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
46 <p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
47
47
48 <h3>find (CTRL-F)</h3>
48 <h3>find (CTRL-F)</h3>
49 <p>Find text</p>
49 <p>Find text</p>
50
50
51 <h3>find_next (F3)</h3>
51 <h3>find_next (F3)</h3>
52 <p>Find next occurrence of the searchtext</p>
52 <p>Find next occurrence of the searchtext</p>
53
53
54 <h3>find_previous (Shift-F3)</h3>
54 <h3>find_previous (Shift-F3)</h3>
55 <p>Find previous occurrence of the searchtext </p>
55 <p>Find previous occurrence of the searchtext </p>
56
56
57 <h3>sortattrasc (V)</h3>
57 <h3>sortattrasc (V)</h3>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
59
59
60 <h3>sortattrdesc (Shift-V)</h3>
60 <h3>sortattrdesc (Shift-V)</h3>
61 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
61 <p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
62
62
63 <h3>leave (Backspace, DEL, X)</h3>
63 <h3>leave (Backspace, DEL, X)</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
65
65
66 <h3>quit (ESC,Q)</h3>
66 <h3>quit (ESC,Q)</h3>
67 <p>Quit igrid and return to the IPython prompt.</p>
67 <p>Quit igrid and return to the IPython prompt.</p>
68
68
69
69
70 <h2>Navigation</h2>
70 <h2>Navigation</h2>
71
71
72
72
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
74
74
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
76
76
77 <h3>Move the cursor one column to the left (&lt;)</h3>
77 <h3>Move the cursor one column to the left (&lt;)</h3>
78
78
79 <h3>Move the cursor one column to the right (&gt;)</h3>
79 <h3>Move the cursor one column to the right (&gt;)</h3>
80
80
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
82
82
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
84
84
85 </body>
85 </body>
86 </html>
86 </html>
@@ -14,4 +14,6 b' from ipy_completers import *'
14 ip.set_hook('complete_command', apt_completer, re_key = '.*apt-get')
14 ip.set_hook('complete_command', apt_completer, re_key = '.*apt-get')
15 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
15 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
16 ip.set_hook('complete_command', hg_completer, str_key = 'hg')
16 ip.set_hook('complete_command', hg_completer, str_key = 'hg')
17 ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
17
18 # the old bzr completer is deprecated, we recommend ipy_bzr
19 #ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
@@ -1,4 +1,3 b''
1 #!/usr/bin/env python
2
1
3 """ Implementations for various useful completers
2 """ Implementations for various useful completers
4
3
@@ -12,6 +11,7 b' import IPython.ipapi'
12 import glob,os,shlex,sys
11 import glob,os,shlex,sys
13 import inspect
12 import inspect
14 from time import time
13 from time import time
14 from zipimport import zipimporter
15 ip = IPython.ipapi.get()
15 ip = IPython.ipapi.get()
16
16
17 try:
17 try:
@@ -86,13 +86,18 b' def moduleList(path):'
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'):
90 try:
91 folder_list = [f for f in zipimporter(path)._files]
92 except:
93 folder_list = []
89 else:
94 else:
90 folder_list = []
95 folder_list = []
91 #folder_list = glob.glob(os.path.join(path,'*'))
96 #folder_list = glob.glob(os.path.join(path,'*'))
92 folder_list = [p for p in folder_list \
97 folder_list = [p for p in folder_list \
93 if os.path.exists(os.path.join(path, p,'__init__.py'))\
98 if os.path.exists(os.path.join(path, p,'__init__.py'))\
94 or p[-3:] in ('.py','.so')\
99 or p[-3:] in ('.py','.so')\
95 or p[-4:] in ('.pyc','.pyo')]
100 or p[-4:] in ('.pyc','.pyo','.pyd')]
96
101
97 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]
98 return folder_list
103 return folder_list
@@ -211,15 +216,15 b' def hg_completer(self,event):'
211
216
212
217
213
218
214 bzr_commands = """
219 __bzr_commands = None
215 add annotate bind branch break-lock bundle-revisions cat check
220
216 checkout commit conflicts deleted diff export gannotate gbranch
221 def bzr_commands():
217 gcommit gdiff help ignore ignored info init init-repository inventory
222 global __bzr_commands
218 log merge missing mkdir mv nick pull push reconcile register-branch
223 if __bzr_commands is not None:
219 remerge remove renames resolve revert revno root serve sign-my-commits
224 return __bzr_commands
220 status testament unbind uncommit unknowns update upgrade version
225 out = os.popen('bzr help commands')
221 version-info visualise whoami
226 __bzr_commands = [l.split()[0] for l in out]
222 """
227 return __bzr_commands
223
228
224 def bzr_completer(self,event):
229 def bzr_completer(self,event):
225 """ Completer for bazaar commands """
230 """ Completer for bazaar commands """
@@ -232,7 +237,7 b' def bzr_completer(self,event):'
232 param = cmd_param[-1]
237 param = cmd_param[-1]
233 output_file = (param == '--output=')
238 output_file = (param == '--output=')
234 if cmd == 'help':
239 if cmd == 'help':
235 return bzr_commands.split()
240 return bzr_commands()
236 elif cmd in ['bundle-revisions','conflicts',
241 elif cmd in ['bundle-revisions','conflicts',
237 'deleted','nick','register-branch',
242 'deleted','nick','register-branch',
238 'serve','unbind','upgrade','version',
243 'serve','unbind','upgrade','version',
@@ -242,7 +247,7 b' def bzr_completer(self,event):'
242 # the rest are probably file names
247 # the rest are probably file names
243 return ip.IP.Completer.file_matches(event.symbol)
248 return ip.IP.Completer.file_matches(event.symbol)
244
249
245 return bzr_commands.split()
250 return bzr_commands()
246
251
247
252
248 def shlex_split(x):
253 def shlex_split(x):
@@ -326,7 +331,29 b' def cd_completer(self, event):'
326 if os.path.isdir(relpath):
331 if os.path.isdir(relpath):
327 return [relpath]
332 return [relpath]
328 raise IPython.ipapi.TryNext
333 raise IPython.ipapi.TryNext
329 return found
334
335
336 def single_dir_expand(matches):
337 "Recursively expand match lists containing a single dir."
338
339 if len(matches) == 1 and os.path.isdir(matches[0]):
340 # Takes care of links to directories also. Use '/'
341 # explicitly, even under Windows, so that name completions
342 # don't end up escaped.
343 d = matches[0]
344 if d[-1] in ['/','\\']:
345 d = d[:-1]
346
347 subdirs = [p for p in os.listdir(d) if os.path.isdir( d + '/' + p)]
348 if subdirs:
349 matches = [ (d + '/' + p) for p in subdirs ]
350 return single_dir_expand(matches)
351 else:
352 return matches
353 else:
354 return matches
355
356 return single_dir_expand(found)
330
357
331 def apt_get_packages(prefix):
358 def apt_get_packages(prefix):
332 out = os.popen('apt-cache pkgnames')
359 out = os.popen('apt-cache pkgnames')
This diff has been collapsed as it changes many lines, (840 lines changed) Show them Hide them
@@ -1,248 +1,592 b''
1 """ Leo plugin for IPython
1 """ ILeo - Leo plugin for IPython
2
2
3 Example use:
3
4
4 """
5 nodes.foo = "hello world"
5 import IPython.ipapi
6
6 import IPython.genutils
7 -> create '@ipy foo' node with text "hello world"
7 import IPython.generics
8
8 from IPython.hooks import CommandChainDispatcher
9 Access works also, and so does tab completion.
9 import re
10
10 import UserDict
11 """
11 from IPython.ipapi import TryNext
12 import IPython.ipapi
12 import IPython.macro
13 import IPython.genutils
13 import IPython.Shell
14 import IPython.generics
14
15 import re
15 def init_ipython(ipy):
16
16 """ This will be run by _ip.load('ipy_leo')
17
17
18
18 Leo still needs to run update_commander() after this.
19 ip = IPython.ipapi.get()
19
20 leo = ip.user_ns['leox']
20 """
21 c,g = leo.c, leo.g
21 global ip
22
22 ip = ipy
23 # will probably be overwritten by user, but handy for experimentation early on
23 IPython.Shell.hijack_tk()
24 ip.user_ns['c'] = c
24 ip.set_hook('complete_command', mb_completer, str_key = '%mb')
25 ip.user_ns['g'] = g
25 ip.expose_magic('mb',mb_f)
26
26 ip.expose_magic('lee',lee_f)
27
27 ip.expose_magic('leoref',leoref_f)
28 from IPython.external.simplegeneric import generic
28 expose_ileo_push(push_cl_node,100)
29 import pprint
29 # this should be the LAST one that will be executed, and it will never raise TryNext
30
30 expose_ileo_push(push_ipython_script, 1000)
31 @generic
31 expose_ileo_push(push_plain_python, 100)
32 def format_for_leo(obj):
32 expose_ileo_push(push_ev_node, 100)
33 """ Convert obj to string representiation (for editing in Leo)"""
33 global wb
34 return pprint.pformat(obj)
34 wb = LeoWorkbook()
35
35 ip.user_ns['wb'] = wb
36 @format_for_leo.when_type(list)
36
37 def format_list(obj):
37 show_welcome()
38 return "\n".join(str(s) for s in obj)
38
39
39
40 nodename_re = r'(@ipy?[\w-]+)?\s?(\w+)'
40 def update_commander(new_leox):
41
41 """ Set the Leo commander to use
42 def all_cells():
42
43 d = {}
43 This will be run every time Leo does ipython-launch; basically,
44 for p in c.allNodes_iter():
44 when the user switches the document he is focusing on, he should do
45 h = p.headString()
45 ipython-launch to tell ILeo what document the commands apply to.
46 if h.startswith('@') and len(h.split()) == 1:
46
47 continue
47 """
48 mo = re.match(nodename_re, h)
48
49 if not mo:
49 global c,g
50 continue
50 c,g = new_leox.c, new_leox.g
51 d[mo.group(2)] = p.copy()
51 print "Set Leo Commander:",c.frame.getTitle()
52 return d
52
53
53 # will probably be overwritten by user, but handy for experimentation early on
54
54 ip.user_ns['c'] = c
55 class TrivialLeoWorkbook:
55 ip.user_ns['g'] = g
56 """ class to find cells with simple syntax
56 ip.user_ns['_leo'] = new_leox
57
57
58 """
58 new_leox.push = push_position_from_leo
59 def __getattr__(self, key):
59 run_leo_startup_node()
60 cells = all_cells()
60
61 p = cells[key]
61 from IPython.external.simplegeneric import generic
62 body = p.bodyString()
62 import pprint
63 return eval_body(body)
63
64 def __setattr__(self,key,val):
64 def es(s):
65 cells = all_cells()
65 g.es(s, tabName = 'IPython')
66 p = cells.get(key,None)
66 pass
67 if p is None:
67
68 add_var(key,val)
68 @generic
69 else:
69 def format_for_leo(obj):
70 c.setBodyString(p,format_for_leo(val))
70 """ Convert obj to string representiation (for editing in Leo)"""
71 def __str__(self):
71 return pprint.pformat(obj)
72 return "<TrivialLeoWorkbook>"
72
73 __repr__ = __str__
73 @format_for_leo.when_type(list)
74
74 def format_list(obj):
75 ip.user_ns['nodes'] = TrivialLeoWorkbook()
75 return "\n".join(str(s) for s in obj)
76
76
77
77
78 class LeoNode(object):
78 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
79 def __init__(self,p):
79 def valid_attribute(s):
80 self.p = p.copy()
80 return attribute_re.match(s)
81
81
82 def get_h(self): return self.p.headString()
82 _rootnode = None
83 def set_h(self,val):
83 def rootnode():
84 print "set head",val
84 """ Get ileo root node (@ipy-root)
85 c.beginUpdate()
85
86 try:
86 if node has become invalid or has not been set, return None
87 c.setHeadString(self.p,val)
87
88 finally:
88 Note that the root is the *first* @ipy-root item found
89 c.endUpdate()
89 """
90
90 global _rootnode
91 h = property( get_h, set_h)
91 if _rootnode is None:
92
92 return None
93 def get_b(self): return self.p.bodyString()
93 if c.positionExists(_rootnode.p):
94 def set_b(self,val):
94 return _rootnode
95 print "set body",val
95 _rootnode = None
96 c.beginUpdate()
96 return None
97 try:
97
98 c.setBodyString(self.p, val)
98 def all_cells():
99 finally:
99 global _rootnode
100 c.endUpdate()
100 d = {}
101
101 r = rootnode()
102 b = property(get_b, set_b)
102 if r is not None:
103
103 nodes = r.p.children_iter()
104 def set_val(self, val):
104 else:
105 self.b = pprint.pformat(val)
105 nodes = c.allNodes_iter()
106
106
107 v = property(lambda self: ip.ev(self.b.strip()), set_val)
107 for p in nodes:
108
108 h = p.headString()
109 def set_l(self,val):
109 if h.strip() == '@ipy-root':
110 self.b = '\n'.join(val )
110 # update root node (found it for the first time)
111 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
111 _rootnode = LeoNode(p)
112 set_l)
112 # the next recursive call will use the children of new root
113
113 return all_cells()
114 def __iter__(self):
114
115 return (LeoNode(p) for p in self.p.children_iter())
115 if h.startswith('@a '):
116
116 d[h.lstrip('@a ').strip()] = p.parent().copy()
117
117 elif not valid_attribute(h):
118 class LeoWorkbook:
118 continue
119 """ class for 'advanced' node access """
119 d[h] = p.copy()
120 def __getattr__(self, key):
120 return d
121 if key.startswith('_') or key == 'trait_names':
121
122 raise AttributeError
122 def eval_node(n):
123 cells = all_cells()
123 body = n.b
124 p = cells.get(key, None)
124 if not body.startswith('@cl'):
125 if p is None:
125 # plain python repr node, just eval it
126 p = add_var(key,None)
126 return ip.ev(n.b)
127
127 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
128 return LeoNode(p)
128 first, rest = body.split('\n',1)
129
129 tup = first.split(None, 1)
130 def __str__(self):
130 # @cl alone SPECIAL USE-> dump var to user_ns
131 return "<LeoWorkbook>"
131 if len(tup) == 1:
132 __repr__ = __str__
132 val = ip.ev(rest)
133 ip.user_ns['wb'] = LeoWorkbook()
133 ip.user_ns[n.h] = val
134
134 es("%s = %s" % (n.h, repr(val)[:20] ))
135
135 return val
136 _dummyval = object()
136
137 @IPython.generics.complete_object.when_type(LeoWorkbook)
137 cl, hd = tup
138 def workbook_complete(obj, prev):
138
139 return all_cells().keys()
139 xformer = ip.ev(hd.strip())
140
140 es('Transform w/ %s' % repr(xformer))
141
141 return xformer(rest, n)
142 def add_var(varname, value = _dummyval):
142
143 c.beginUpdate()
143 class LeoNode(object, UserDict.DictMixin):
144 try:
144 """ Node in Leo outline
145
145
146 nodename = '@ipy-var ' + varname
146 Most important attributes (getters/setters available:
147 p2 = g.findNodeAnywhere(c,nodename)
147 .v - evaluate node, can also be alligned
148 if not c.positionExists(p2):
148 .b, .h - body string, headline string
149 p2 = c.currentPosition().insertAfter()
149 .l - value as string list
150 c.setHeadString(p2,'@ipy ' + varname)
150
151
151 Also supports iteration,
152 c.setCurrentPosition(p2)
152
153 if value is _dummyval:
153 setitem / getitem (indexing):
154 val = ip.user_ns[varname]
154 wb.foo['key'] = 12
155 else:
155 assert wb.foo['key'].v == 12
156 val = value
156
157 if val is not None:
157 Note the asymmetry on setitem and getitem! Also other
158 formatted = format_for_leo(val)
158 dict methods are available.
159 c.setBodyString(p2,formatted)
159
160 return p2
160 .ipush() - run push-to-ipython
161 finally:
161
162 c.endUpdate()
162 Minibuffer command access (tab completion works):
163
163
164 def add_file(self,fname):
164 mb save-to-file
165 p2 = c.currentPosition().insertAfter()
165
166
166 """
167 def push_script(p):
167 def __init__(self,p):
168 c.beginUpdate()
168 self.p = p.copy()
169 try:
169
170 ohist = ip.IP.output_hist
170 def __str__(self):
171 hstart = len(ip.IP.input_hist)
171 return "<LeoNode %s>" % str(self.p)
172 script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
172
173
173 __repr__ = __str__
174 script = g.splitLines(script + '\n')
174
175 script = ''.join(z for z in script if z.strip())
175 def __get_h(self): return self.p.headString()
176
176 def __set_h(self,val):
177 ip.runlines(script)
177 print "set head",val
178
178 c.beginUpdate()
179 has_output = False
179 try:
180 for idx in range(hstart,len(ip.IP.input_hist)):
180 c.setHeadString(self.p,val)
181 val = ohist.get(idx,None)
181 finally:
182 if val is None:
182 c.endUpdate()
183 continue
183
184 has_output = True
184 h = property( __get_h, __set_h, doc = "Node headline string")
185 inp = ip.IP.input_hist[idx]
185
186 if inp.strip():
186 def __get_b(self): return self.p.bodyString()
187 g.es('In: %s' % (inp[:40], ), tabName = 'IPython')
187 def __set_b(self,val):
188
188 print "set body",val
189 g.es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)), tabName = 'IPython')
189 c.beginUpdate()
190
190 try:
191 if not has_output:
191 c.setBodyString(self.p, val)
192 g.es('ipy run: %s' %( p.headString(),), tabName = 'IPython')
192 finally:
193 finally:
193 c.endUpdate()
194 c.endUpdate()
194
195
195 b = property(__get_b, __set_b, doc = "Nody body string")
196
196
197 def eval_body(body):
197 def __set_val(self, val):
198 try:
198 self.b = format_for_leo(val)
199 val = ip.ev(body)
199
200 except:
200 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
201 # just use stringlist if it's not completely legal python expression
201
202 val = IPython.genutils.SList(body.splitlines())
202 def __set_l(self,val):
203 return val
203 self.b = '\n'.join(val )
204
204 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
205 def push_variable(p,varname):
205 __set_l, doc = "Node value as string list")
206 body = p.bodyString()
206
207 val = eval_body(body.strip())
207 def __iter__(self):
208 ip.user_ns[varname] = val
208 """ Iterate through nodes direct children """
209 g.es('ipy var: %s' % (varname,), tabName = "IPython")
209
210
210 return (LeoNode(p) for p in self.p.children_iter())
211 def push_from_leo(p):
211
212 tup = p.headString().split(None,1)
212 def __children(self):
213 # @ipy foo is variable foo
213 d = {}
214 if len(tup) == 2 and tup[0] == '@ipy':
214 for child in self:
215 varname = tup[1]
215 head = child.h
216 push_variable(p,varname)
216 tup = head.split(None,1)
217 return
217 if len(tup) > 1 and tup[0] == '@k':
218
218 d[tup[1]] = child
219 push_script(p)
219 continue
220 return
220
221
221 if not valid_attribute(head):
222
222 d[head] = child
223 ip.user_ns['leox'].push = push_from_leo
223 continue
224
224 return d
225 def leo_f(self,s):
225 def keys(self):
226 """ open file(s) in Leo
226 d = self.__children()
227
227 return d.keys()
228 Takes an mglob pattern, e.g. '%leo *.cpp' or %leo 'rec:*.cpp'
228 def __getitem__(self, key):
229 """
229 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
230 import os
230
231 from IPython.external import mglob
231 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
232
232 """
233 files = mglob.expand(s)
233 key = str(key)
234 c.beginUpdate()
234 d = self.__children()
235 try:
235 return d[key]
236 for fname in files:
236 def __setitem__(self, key, val):
237 p = g.findNodeAnywhere(c,'@auto ' + fname)
237 """ You can do wb.foo['My Stuff'] = 12 to create children
238 if not p:
238
239 p = c.currentPosition().insertAfter()
239 This will create 'My Stuff' as a child of foo (if it does not exist), and
240
240 do .v = 12 assignment.
241 p.setHeadString('@auto ' + fname)
241
242 if os.path.isfile(fname):
242 Exception:
243 c.setBodyString(p,open(fname).read())
243
244 c.selectPosition(p)
244 wb.foo['bar'] = 12
245 finally:
245
246 c.endUpdate()
246 will create a child with headline '@k bar', because bar is a valid python name
247
247 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
248 ip.expose_magic('leo',leo_f)
248 """
249 key = str(key)
250 d = self.__children()
251 if key in d:
252 d[key].v = val
253 return
254
255 if not valid_attribute(key):
256 head = key
257 else:
258 head = '@k ' + key
259 p = c.createLastChildNode(self.p, head, '')
260 LeoNode(p).v = val
261
262 def ipush(self):
263 """ Does push-to-ipython on the node """
264 push_from_leo(self)
265
266 def go(self):
267 """ Set node as current node (to quickly see it in Outline) """
268 c.beginUpdate()
269 try:
270 c.setCurrentPosition(self.p)
271 finally:
272 c.endUpdate()
273
274 def script(self):
275 """ Method to get the 'tangled' contents of the node
276
277 (parse @others, << section >> references etc.)
278 """
279 return g.getScript(c,self.p,useSelectedText=False,useSentinels=False)
280
281 def __get_uA(self):
282 p = self.p
283 # Create the uA if necessary.
284 if not hasattr(p.v.t,'unknownAttributes'):
285 p.v.t.unknownAttributes = {}
286
287 d = p.v.t.unknownAttributes.setdefault('ipython', {})
288 return d
289
290 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
291
292
293 class LeoWorkbook:
294 """ class for 'advanced' node access
295
296 Has attributes for all "discoverable" nodes. Node is discoverable if it
297 either
298
299 - has a valid python name (Foo, bar_12)
300 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
301
302 """
303 def __getattr__(self, key):
304 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
305 raise AttributeError
306 cells = all_cells()
307 p = cells.get(key, None)
308 if p is None:
309 return add_var(key)
310
311 return LeoNode(p)
312
313 def __str__(self):
314 return "<LeoWorkbook>"
315 def __setattr__(self,key, val):
316 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
317
318 __repr__ = __str__
319
320 def __iter__(self):
321 """ Iterate all (even non-exposed) nodes """
322 cells = all_cells()
323 return (LeoNode(p) for p in c.allNodes_iter())
324
325 current = property(lambda self: LeoNode(c.currentPosition()), doc = "Currently selected node")
326
327 def match_h(self, regex):
328 cmp = re.compile(regex)
329 for node in self:
330 if re.match(cmp, node.h, re.IGNORECASE):
331 yield node
332 return
333
334 @IPython.generics.complete_object.when_type(LeoWorkbook)
335 def workbook_complete(obj, prev):
336 return all_cells().keys() + [s for s in prev if not s.startswith('_')]
337
338
339 def add_var(varname):
340 c.beginUpdate()
341 r = rootnode()
342 try:
343 if r is None:
344 p2 = g.findNodeAnywhere(c,varname)
345 else:
346 p2 = g.findNodeInChildren(c, r.p, varname)
347 if p2:
348 return LeoNode(p2)
349
350 if r is not None:
351 p2 = r.p.insertAsLastChild()
352
353 else:
354 p2 = c.currentPosition().insertAfter()
355
356 c.setHeadString(p2,varname)
357 return LeoNode(p2)
358 finally:
359 c.endUpdate()
360
361 def add_file(self,fname):
362 p2 = c.currentPosition().insertAfter()
363
364 push_from_leo = CommandChainDispatcher()
365
366 def expose_ileo_push(f, prio = 0):
367 push_from_leo.add(f, prio)
368
369 def push_ipython_script(node):
370 """ Execute the node body in IPython, as if it was entered in interactive prompt """
371 c.beginUpdate()
372 try:
373 ohist = ip.IP.output_hist
374 hstart = len(ip.IP.input_hist)
375 script = node.script()
376
377 ip.user_ns['_p'] = node
378 ip.runlines(script)
379 ip.user_ns.pop('_p',None)
380
381 has_output = False
382 for idx in range(hstart,len(ip.IP.input_hist)):
383 val = ohist.get(idx,None)
384 if val is None:
385 continue
386 has_output = True
387 inp = ip.IP.input_hist[idx]
388 if inp.strip():
389 es('In: %s' % (inp[:40], ))
390
391 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
392
393 if not has_output:
394 es('ipy run: %s (%d LL)' %( node.h,len(script)))
395 finally:
396 c.endUpdate()
397
398
399 def eval_body(body):
400 try:
401 val = ip.ev(body)
402 except:
403 # just use stringlist if it's not completely legal python expression
404 val = IPython.genutils.SList(body.splitlines())
405 return val
406
407 def push_plain_python(node):
408 if not node.h.endswith('P'):
409 raise TryNext
410 script = node.script()
411 lines = script.count('\n')
412 try:
413 exec script in ip.user_ns
414 except:
415 print " -- Exception in script:\n"+script + "\n --"
416 raise
417 es('ipy plain: %s (%d LL)' % (node.h,lines))
418
419
420 def push_cl_node(node):
421 """ If node starts with @cl, eval it
422
423 The result is put as last child of @ipy-results node, if it exists
424 """
425 if not node.b.startswith('@cl'):
426 raise TryNext
427
428 p2 = g.findNodeAnywhere(c,'@ipy-results')
429 val = node.v
430 if p2:
431 es("=> @ipy-results")
432 LeoNode(p2).v = val
433 es(val)
434
435 def push_ev_node(node):
436 """ If headline starts with @ev, eval it and put result in body """
437 if not node.h.startswith('@ev '):
438 raise TryNext
439 expr = node.h.lstrip('@ev ')
440 es('ipy eval ' + expr)
441 res = ip.ev(expr)
442 node.v = res
443
444
445 def push_position_from_leo(p):
446 try:
447 push_from_leo(LeoNode(p))
448 except AttributeError,e:
449 if e.args == ("Commands instance has no attribute 'frame'",):
450 es("Error: ILeo not associated with .leo document")
451 es("Press alt+shift+I to fix!")
452 else:
453 raise
454
455 @generic
456 def edit_object_in_leo(obj, varname):
457 """ Make it @cl node so it can be pushed back directly by alt+I """
458 node = add_var(varname)
459 formatted = format_for_leo(obj)
460 if not formatted.startswith('@cl'):
461 formatted = '@cl\n' + formatted
462 node.b = formatted
463 node.go()
464
465 @edit_object_in_leo.when_type(IPython.macro.Macro)
466 def edit_macro(obj,varname):
467 bod = '_ip.defmacro("""\\\n' + obj.value + '""")'
468 node = add_var('Macro_' + varname)
469 node.b = bod
470 node.go()
471
472 def get_history(hstart = 0):
473 res = []
474 ohist = ip.IP.output_hist
475
476 for idx in range(hstart, len(ip.IP.input_hist)):
477 val = ohist.get(idx,None)
478 has_output = True
479 inp = ip.IP.input_hist_raw[idx]
480 if inp.strip():
481 res.append('In [%d]: %s' % (idx, inp))
482 if val:
483 res.append(pprint.pformat(val))
484 res.append('\n')
485 return ''.join(res)
486
487
488 def lee_f(self,s):
489 """ Open file(s)/objects in Leo
490
491 - %lee hist -> open full session history in leo
492 - Takes an object. l = [1,2,"hello"]; %lee l. Alt+I in leo pushes the object back
493 - Takes an mglob pattern, e.g. '%lee *.cpp' or %lee 'rec:*.cpp'
494 - Takes input history indices: %lee 4 6-8 10 12-47
495 """
496 import os
497
498 c.beginUpdate()
499 try:
500 if s == 'hist':
501 wb.ipython_history.b = get_history()
502 wb.ipython_history.go()
503 return
504
505
506 if s and s[0].isdigit():
507 # numbers; push input slices to leo
508 lines = self.extract_input_slices(s.strip().split(), True)
509 v = add_var('stored_ipython_input')
510 v.b = '\n'.join(lines)
511 return
512
513
514 # try editing the object directly
515 obj = ip.user_ns.get(s, None)
516 if obj is not None:
517 edit_object_in_leo(obj,s)
518 return
519
520
521 # if it's not object, it's a file name / mglob pattern
522 from IPython.external import mglob
523
524 files = (os.path.abspath(f) for f in mglob.expand(s))
525 for fname in files:
526 p = g.findNodeAnywhere(c,'@auto ' + fname)
527 if not p:
528 p = c.currentPosition().insertAfter()
529
530 p.setHeadString('@auto ' + fname)
531 if os.path.isfile(fname):
532 c.setBodyString(p,open(fname).read())
533 c.selectPosition(p)
534 print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes"
535 finally:
536 c.endUpdate()
537
538
539
540 def leoref_f(self,s):
541 """ Quick reference for ILeo """
542 import textwrap
543 print textwrap.dedent("""\
544 %leoe file/object - open file / object in leo
545 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
546 wb.foo.v = 12 - assign to body of node foo
547 wb.foo.b - read or write the body of node foo
548 wb.foo.l - body of node foo as string list
549
550 for el in wb.foo:
551 print el.v
552
553 """
554 )
555
556
557
558 def mb_f(self, arg):
559 """ Execute leo minibuffer commands
560
561 Example:
562 mb save-to-file
563 """
564 c.executeMinibufferCommand(arg)
565
566 def mb_completer(self,event):
567 """ Custom completer for minibuffer """
568 cmd_param = event.line.split()
569 if event.line.endswith(' '):
570 cmd_param.append('')
571 if len(cmd_param) > 2:
572 return ip.IP.Completer.file_matches(event.symbol)
573 cmds = c.commandsDict.keys()
574 cmds.sort()
575 return cmds
576
577 def show_welcome():
578 print "------------------"
579 print "Welcome to Leo-enabled IPython session!"
580 print "Try %leoref for quick reference."
581 import IPython.platutils
582 IPython.platutils.set_term_title('ILeo')
583 IPython.platutils.freeze_term_title()
584
585 def run_leo_startup_node():
586 p = g.findNodeAnywhere(c,'@ipy-startup')
587 if p:
588 print "Running @ipy-startup nodes"
589 for n in LeoNode(p):
590 push_from_leo(n)
591
592
@@ -43,11 +43,13 b' def main():'
43 # %store foo
43 # %store foo
44 # %store bar
44 # %store bar
45 import ipy_rehashdir
45 import ipy_rehashdir
46 import ipy_signals
46
47 # does not work without subprocess module!
48 #import ipy_signals
47
49
48 ip.ex('import os')
50 ip.ex('import os')
49 ip.ex("def up(): os.chdir('..')")
51 ip.ex("def up(): os.chdir('..')")
50
52 ip.user_ns['LA'] = LastArgFinder()
51 # Nice prompt
53 # Nice prompt
52
54
53 o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
55 o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
@@ -117,6 +119,29 b' def main():'
117
119
118 extend_shell_behavior(ip)
120 extend_shell_behavior(ip)
119
121
122 class LastArgFinder:
123 """ Allow $LA to work as "last argument of previous command", like $! in bash
124
125 To call this in normal IPython code, do LA()
126 """
127 def __call__(self, hist_idx = None):
128 ip = ipapi.get()
129 if hist_idx is None:
130 return str(self)
131 return ip.IP.input_hist_raw[hist_idx].strip().split()[-1]
132 def __str__(self):
133 ip = ipapi.get()
134 for cmd in reversed(ip.IP.input_hist_raw):
135 parts = cmd.strip().split()
136 if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']:
137 continue
138 return parts[-1]
139 return ""
140
141
142
143
144
120 # XXX You do not need to understand the next function!
145 # XXX You do not need to understand the next function!
121 # This should probably be moved out of profile
146 # This should probably be moved out of profile
122
147
@@ -41,8 +41,9 b' Now launch a new IPython prompt and kill the process:'
41 (you don't need to specify PID for %kill if only one task is running)
41 (you don't need to specify PID for %kill if only one task is running)
42 """
42 """
43
43
44 from subprocess import Popen,PIPE
44 from subprocess import *
45 import os,shlex,sys,time
45 import os,shlex,sys,time
46 import threading,Queue
46
47
47 from IPython import genutils
48 from IPython import genutils
48
49
@@ -71,15 +72,70 b' def startjob(job):'
71 p.line = job
72 p.line = job
72 return p
73 return p
73
74
75 class AsyncJobQ(threading.Thread):
76 def __init__(self):
77 threading.Thread.__init__(self)
78 self.q = Queue.Queue()
79 self.output = []
80 self.stop = False
81 def run(self):
82 while 1:
83 cmd,cwd = self.q.get()
84 if self.stop:
85 self.output.append("** Discarding: '%s' - %s" % (cmd,cwd))
86 continue
87 self.output.append("** Task started: '%s' - %s" % (cmd,cwd))
88
89 p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd = cwd)
90 out = p.stdout.read()
91 self.output.append("** Task complete: '%s'\n" % cmd)
92 self.output.append(out)
93
94 def add(self,cmd):
95 self.q.put_nowait((cmd, os.getcwd()))
96
97 def dumpoutput(self):
98 while self.output:
99 item = self.output.pop(0)
100 print item
101
102 _jobq = None
103
104 def jobqueue_f(self, line):
105
106 global _jobq
107 if not _jobq:
108 print "Starting jobqueue - do '&some_long_lasting_system_command' to enqueue"
109 _jobq = AsyncJobQ()
110 _jobq.setDaemon(True)
111 _jobq.start()
112 ip.jobq = _jobq.add
113 return
114 if line.strip() == 'stop':
115 print "Stopping and clearing jobqueue, %jobqueue start to start again"
116 _jobq.stop = True
117 return
118 if line.strip() == 'start':
119 _jobq.stop = False
120 return
121
74 def jobctrl_prefilter_f(self,line):
122 def jobctrl_prefilter_f(self,line):
75 if line.startswith('&'):
123 if line.startswith('&'):
76 pre,fn,rest = self.split_user_input(line[1:])
124 pre,fn,rest = self.split_user_input(line[1:])
77
125
78 line = ip.IP.expand_aliases(fn,rest)
126 line = ip.IP.expand_aliases(fn,rest)
79 return '_ip.startjob(%s)' % genutils.make_quoted_expr(line)
127 if not _jobq:
128 return '_ip.startjob(%s)' % genutils.make_quoted_expr(line)
129 return '_ip.jobq(%s)' % genutils.make_quoted_expr(line)
80
130
81 raise IPython.ipapi.TryNext
131 raise IPython.ipapi.TryNext
82
132
133 def jobq_output_hook(self):
134 if not _jobq:
135 return
136 _jobq.dumpoutput()
137
138
83
139
84 def job_list(ip):
140 def job_list(ip):
85 keys = ip.db.keys('tasks/*')
141 keys = ip.db.keys('tasks/*')
@@ -91,8 +147,16 b' def magic_tasks(self,line):'
91
147
92 A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled.
148 A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled.
93 Tasks can be killed with %kill.
149 Tasks can be killed with %kill.
150
151 '%tasks clear' clears the task list (from stale tasks)
94 """
152 """
95 ip = self.getapi()
153 ip = self.getapi()
154 if line.strip() == 'clear':
155 for k in ip.db.keys('tasks/*'):
156 print "Clearing",ip.db[k]
157 del ip.db[k]
158 return
159
96 ents = job_list(ip)
160 ents = job_list(ip)
97 if not ents:
161 if not ents:
98 print "No tasks running"
162 print "No tasks running"
@@ -125,7 +189,7 b' def magic_kill(self,line):'
125 magic_tasks(self,line)
189 magic_tasks(self,line)
126
190
127 if sys.platform == 'win32':
191 if sys.platform == 'win32':
128 shell_internal_commands = 'break chcp cls copy ctty date del erase dir md mkdir path prompt rd rmdir time type ver vol'.split()
192 shell_internal_commands = 'break chcp cls copy ctty date del erase dir md mkdir path prompt rd rmdir start time type ver vol'.split()
129 else:
193 else:
130 # todo linux commands
194 # todo linux commands
131 shell_internal_commands = []
195 shell_internal_commands = []
@@ -133,20 +197,33 b' else:'
133
197
134 def jobctrl_shellcmd(ip,cmd):
198 def jobctrl_shellcmd(ip,cmd):
135 """ os.system replacement that stores process info to db['tasks/t1234'] """
199 """ os.system replacement that stores process info to db['tasks/t1234'] """
200 cmd = cmd.strip()
136 cmdname = cmd.split(None,1)[0]
201 cmdname = cmd.split(None,1)[0]
137 if cmdname in shell_internal_commands:
202 if cmdname in shell_internal_commands or '|' in cmd or '>' in cmd or '<' in cmd:
138 use_shell = True
203 use_shell = True
139 else:
204 else:
140 use_shell = False
205 use_shell = False
141
206
142 p = Popen(cmd,shell = use_shell)
207 jobentry = None
143 jobentry = 'tasks/t' + str(p.pid)
144
145 try:
208 try:
209 try:
210 p = Popen(cmd,shell = use_shell)
211 except WindowsError:
212 if use_shell:
213 # try with os.system
214 os.system(cmd)
215 return
216 else:
217 # have to go via shell, sucks
218 p = Popen(cmd,shell = True)
219
220 jobentry = 'tasks/t' + str(p.pid)
146 ip.db[jobentry] = (p.pid,cmd,os.getcwd(),time.time())
221 ip.db[jobentry] = (p.pid,cmd,os.getcwd(),time.time())
147 p.communicate()
222 p.communicate()
223
148 finally:
224 finally:
149 del ip.db[jobentry]
225 if jobentry:
226 del ip.db[jobentry]
150
227
151
228
152 def install():
229 def install():
@@ -158,5 +235,6 b' def install():'
158 ip.set_hook('shell_hook', jobctrl_shellcmd)
235 ip.set_hook('shell_hook', jobctrl_shellcmd)
159 ip.expose_magic('kill',magic_kill)
236 ip.expose_magic('kill',magic_kill)
160 ip.expose_magic('tasks',magic_tasks)
237 ip.expose_magic('tasks',magic_tasks)
161
238 ip.expose_magic('jobqueue',jobqueue_f)
239 ip.set_hook('pre_prompt_hook', jobq_output_hook)
162 install()
240 install()
@@ -94,8 +94,16 b' def matchorfail(text, pos):'
94 match = tokenprog.match(text, pos)
94 match = tokenprog.match(text, pos)
95 if match is None:
95 if match is None:
96 raise ItplError(text, pos)
96 raise ItplError(text, pos)
97
97 return match, match.end()
98 return match, match.end()
98
99
100 try:
101 itpl_encoding = sys.stdin.encoding or 'ascii'
102 except AttributeError:
103 itpl_encoding = 'ascii'
104
105
106
99 class Itpl:
107 class Itpl:
100 """Class representing a string with interpolation abilities.
108 """Class representing a string with interpolation abilities.
101
109
@@ -104,7 +112,7 b' class Itpl:'
104 evaluation and substitution happens in the namespace of the
112 evaluation and substitution happens in the namespace of the
105 caller when str(instance) is called."""
113 caller when str(instance) is called."""
106
114
107 def __init__(self, format,codec=sys.stdin.encoding,encoding_errors='backslashreplace'):
115 def __init__(self, format,codec=itpl_encoding,encoding_errors='backslashreplace'):
108 """The single mandatory argument to this constructor is a format
116 """The single mandatory argument to this constructor is a format
109 string.
117 string.
110
118
@@ -115,9 +115,9 b' class Magic:'
115
115
116 def profile_missing_notice(self, *args, **kwargs):
116 def profile_missing_notice(self, *args, **kwargs):
117 error("""\
117 error("""\
118 The profile module could not be found. If you are a Debian user,
118 The profile module could not be found. It has been removed from the standard
119 it has been removed from the standard Debian package because of its non-free
119 python packages because of its non-free license. To use profiling, install the
120 license. To use profiling, please install"python2.3-profiler" from non-free.""")
120 python-profiler package from non-free.""")
121
121
122 def default_option(self,fn,optstr):
122 def default_option(self,fn,optstr):
123 """Make an entry in the options_table for fn, with value optstr"""
123 """Make an entry in the options_table for fn, with value optstr"""
@@ -147,7 +147,7 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
147 filter(inst_magic,self.__dict__.keys()) + \
147 filter(inst_magic,self.__dict__.keys()) + \
148 filter(inst_bound_magic,self.__class__.__dict__.keys())
148 filter(inst_bound_magic,self.__class__.__dict__.keys())
149 out = []
149 out = []
150 for fn in magics:
150 for fn in Set(magics):
151 out.append(fn.replace('magic_','',1))
151 out.append(fn.replace('magic_','',1))
152 out.sort()
152 out.sort()
153 return out
153 return out
@@ -386,7 +386,10 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
386 return None
386 return None
387
387
388 def magic_magic(self, parameter_s = ''):
388 def magic_magic(self, parameter_s = ''):
389 """Print information about the magic function system."""
389 """Print information about the magic function system.
390
391 Supported formats: -latex, -brief, -rest
392 """
390
393
391 mode = ''
394 mode = ''
392 try:
395 try:
@@ -394,6 +397,9 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
394 mode = 'latex'
397 mode = 'latex'
395 if parameter_s.split()[0] == '-brief':
398 if parameter_s.split()[0] == '-brief':
396 mode = 'brief'
399 mode = 'brief'
400 if parameter_s.split()[0] == '-rest':
401 mode = 'rest'
402 rest_docs = []
397 except:
403 except:
398 pass
404 pass
399
405
@@ -409,14 +415,26 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
409 break
415 break
410 if mode == 'brief':
416 if mode == 'brief':
411 # only first line
417 # only first line
412 fndoc = fn.__doc__.split('\n',1)[0]
418 if fn.__doc__:
419 fndoc = fn.__doc__.split('\n',1)[0]
420 else:
421 fndoc = 'No documentation'
422 else:
423 fndoc = fn.__doc__.rstrip()
424
425 if mode == 'rest':
426 rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(self.shell.ESC_MAGIC,
427 fname,fndoc))
428
413 else:
429 else:
414 fndoc = fn.__doc__
430 magic_docs.append('%s%s:\n\t%s\n' %(self.shell.ESC_MAGIC,
431 fname,fndoc))
415
432
416 magic_docs.append('%s%s:\n\t%s\n' %(self.shell.ESC_MAGIC,
417 fname,fndoc))
418 magic_docs = ''.join(magic_docs)
433 magic_docs = ''.join(magic_docs)
419
434
435 if mode == 'rest':
436 return "".join(rest_docs)
437
420 if mode == 'latex':
438 if mode == 'latex':
421 print self.format_latex(magic_docs)
439 print self.format_latex(magic_docs)
422 return
440 return
@@ -2612,7 +2630,7 b' Defaulting color scheme to \'NoColor\'"""'
2612 os.chdir(pdir)
2630 os.chdir(pdir)
2613 for ff in os.listdir(pdir):
2631 for ff in os.listdir(pdir):
2614 base, ext = os.path.splitext(ff)
2632 base, ext = os.path.splitext(ff)
2615 if isexec(ff) and base not in self.shell.no_alias:
2633 if isexec(ff) and base.lower() not in self.shell.no_alias:
2616 if ext.lower() == '.exe':
2634 if ext.lower() == '.exe':
2617 ff = base
2635 ff = base
2618 alias_table[base.lower()] = (0,ff)
2636 alias_table[base.lower()] = (0,ff)
@@ -2667,6 +2685,7 b' Defaulting color scheme to \'NoColor\'"""'
2667 parameter_s = parameter_s.strip()
2685 parameter_s = parameter_s.strip()
2668 #bkms = self.shell.persist.get("bookmarks",{})
2686 #bkms = self.shell.persist.get("bookmarks",{})
2669
2687
2688 oldcwd = os.getcwd()
2670 numcd = re.match(r'(-)(\d+)$',parameter_s)
2689 numcd = re.match(r'(-)(\d+)$',parameter_s)
2671 # jump in directory history by number
2690 # jump in directory history by number
2672 if numcd:
2691 if numcd:
@@ -2705,7 +2724,7 b' Defaulting color scheme to \'NoColor\'"""'
2705
2724
2706 # at this point ps should point to the target dir
2725 # at this point ps should point to the target dir
2707 if ps:
2726 if ps:
2708 try:
2727 try:
2709 os.chdir(os.path.expanduser(ps))
2728 os.chdir(os.path.expanduser(ps))
2710 if self.shell.rc.term_title:
2729 if self.shell.rc.term_title:
2711 #print 'set term title:',self.shell.rc.term_title # dbg
2730 #print 'set term title:',self.shell.rc.term_title # dbg
@@ -2716,8 +2735,9 b' Defaulting color scheme to \'NoColor\'"""'
2716 else:
2735 else:
2717 cwd = os.getcwd()
2736 cwd = os.getcwd()
2718 dhist = self.shell.user_ns['_dh']
2737 dhist = self.shell.user_ns['_dh']
2719 dhist.append(cwd)
2738 if oldcwd != cwd:
2720 self.db['dhist'] = compress_dhist(dhist)[-100:]
2739 dhist.append(cwd)
2740 self.db['dhist'] = compress_dhist(dhist)[-100:]
2721
2741
2722 else:
2742 else:
2723 os.chdir(self.shell.home_dir)
2743 os.chdir(self.shell.home_dir)
@@ -2725,8 +2745,10 b' Defaulting color scheme to \'NoColor\'"""'
2725 platutils.set_term_title("IPy ~")
2745 platutils.set_term_title("IPy ~")
2726 cwd = os.getcwd()
2746 cwd = os.getcwd()
2727 dhist = self.shell.user_ns['_dh']
2747 dhist = self.shell.user_ns['_dh']
2728 dhist.append(cwd)
2748
2729 self.db['dhist'] = compress_dhist(dhist)[-100:]
2749 if oldcwd != cwd:
2750 dhist.append(cwd)
2751 self.db['dhist'] = compress_dhist(dhist)[-100:]
2730 if not 'q' in opts and self.shell.user_ns['_dh']:
2752 if not 'q' in opts and self.shell.user_ns['_dh']:
2731 print self.shell.user_ns['_dh'][-1]
2753 print self.shell.user_ns['_dh'][-1]
2732
2754
@@ -3118,7 +3140,7 b' Defaulting color scheme to \'NoColor\'"""'
3118 screen_lines=self.shell.rc.screen_length)
3140 screen_lines=self.shell.rc.screen_length)
3119
3141
3120 def magic_cpaste(self, parameter_s=''):
3142 def magic_cpaste(self, parameter_s=''):
3121 """Allows you to paste & execute a pre-formatted code block from clipboard
3143 """Allows you to paste & execute a pre-formatted code block from clipboard.
3122
3144
3123 You must terminate the block with '--' (two minus-signs) alone on the
3145 You must terminate the block with '--' (two minus-signs) alone on the
3124 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
3146 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
@@ -3126,13 +3148,14 b' Defaulting color scheme to \'NoColor\'"""'
3126
3148
3127 The block is dedented prior to execution to enable execution of method
3149 The block is dedented prior to execution to enable execution of method
3128 definitions. '>' and '+' characters at the beginning of a line are
3150 definitions. '>' and '+' characters at the beginning of a line are
3129 ignored, to allow pasting directly from e-mails or diff files. The
3151 ignored, to allow pasting directly from e-mails, diff files and
3152 doctests (the '...' continuation prompt is also stripped). The
3130 executed block is also assigned to variable named 'pasted_block' for
3153 executed block is also assigned to variable named 'pasted_block' for
3131 later editing with '%edit pasted_block'.
3154 later editing with '%edit pasted_block'.
3132
3155
3133 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
3156 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
3134 This assigns the pasted block to variable 'foo' as string, without
3157 This assigns the pasted block to variable 'foo' as string, without
3135 dedenting or executing it.
3158 dedenting or executing it (preceding >>> and + is still stripped)
3136
3159
3137 Do not be alarmed by garbled output on Windows (it's a readline bug).
3160 Do not be alarmed by garbled output on Windows (it's a readline bug).
3138 Just press enter and type -- (and press enter again) and the block
3161 Just press enter and type -- (and press enter again) and the block
@@ -3143,6 +3166,15 b' Defaulting color scheme to \'NoColor\'"""'
3143 opts,args = self.parse_options(parameter_s,'s:',mode='string')
3166 opts,args = self.parse_options(parameter_s,'s:',mode='string')
3144 par = args.strip()
3167 par = args.strip()
3145 sentinel = opts.get('s','--')
3168 sentinel = opts.get('s','--')
3169
3170 # Regular expressions that declare text we strip from the input:
3171 strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt
3172 r'^\s*(\s?>)+', # Python input prompt
3173 r'^\s*\.{3,}', # Continuation prompts
3174 r'^\++',
3175 ]
3176
3177 strip_from_start = map(re.compile,strip_re)
3146
3178
3147 from IPython import iplib
3179 from IPython import iplib
3148 lines = []
3180 lines = []
@@ -3151,7 +3183,11 b' Defaulting color scheme to \'NoColor\'"""'
3151 l = iplib.raw_input_original(':')
3183 l = iplib.raw_input_original(':')
3152 if l ==sentinel:
3184 if l ==sentinel:
3153 break
3185 break
3154 lines.append(l.lstrip('>').lstrip('+'))
3186
3187 for pat in strip_from_start:
3188 l = pat.sub('',l)
3189 lines.append(l)
3190
3155 block = "\n".join(lines) + '\n'
3191 block = "\n".join(lines) + '\n'
3156 #print "block:\n",block
3192 #print "block:\n",block
3157 if not par:
3193 if not par:
@@ -404,7 +404,13 b' class Inspector:'
404 # Filename where object was defined
404 # Filename where object was defined
405 binary_file = False
405 binary_file = False
406 try:
406 try:
407 fname = inspect.getabsfile(obj)
407 try:
408 fname = inspect.getabsfile(obj)
409 except TypeError:
410 # For an instance, the file that matters is where its class was
411 # declared.
412 if hasattr(obj,'__class__'):
413 fname = inspect.getabsfile(obj.__class__)
408 if fname.endswith('<string>'):
414 if fname.endswith('<string>'):
409 fname = 'Dynamically generated function. No source code available.'
415 fname = 'Dynamically generated function. No source code available.'
410 if (fname.endswith('.so') or fname.endswith('.dll')):
416 if (fname.endswith('.so') or fname.endswith('.dll')):
@@ -432,8 +438,13 b' class Inspector:'
432 linecache.checkcache()
438 linecache.checkcache()
433 source_success = False
439 source_success = False
434 try:
440 try:
435 source = self.format(getsource(obj,binary_file))
441 try:
436 if source:
442 src = getsource(obj,binary_file)
443 except TypeError:
444 if hasattr(obj,'__class__'):
445 src = getsource(obj.__class__,binary_file)
446 if src is not None:
447 source = self.format(src)
437 out.write(header('Source:\n')+source.rstrip())
448 out.write(header('Source:\n')+source.rstrip())
438 source_success = True
449 source_success = True
439 except Exception, msg:
450 except Exception, msg:
@@ -22,9 +22,15 b" name = 'ipython'"
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
23 # bdist_deb does not accept underscores (a Debian convention).
23 # bdist_deb does not accept underscores (a Debian convention).
24
24
25 revision = '3001'
25 revision = '128'
26 branch = 'ipython'
26
27
27 version = '0.8.3.svn.r' + revision.rstrip('M')
28 if branch == 'ipython':
29 version = '0.8.4.bzr.r' + revision
30 else:
31 version = '0.8.4.bzr.r%s.%s' % (revision,branch)
32
33 version = '0.8.4'
28
34
29 description = "An enhanced interactive Python shell."
35 description = "An enhanced interactive Python shell."
30
36
@@ -46,6 +46,13 b' from IPython.ipmaker import make_IPython'
46 from IPython.Magic import Magic
46 from IPython.Magic import Magic
47 from IPython.ipstruct import Struct
47 from IPython.ipstruct import Struct
48
48
49 try: # Python 2.3 compatibility
50 set
51 except NameError:
52 import sets
53 set = sets.Set
54
55
49 # Globals
56 # Globals
50 # global flag to pass around information about Ctrl-C without exceptions
57 # global flag to pass around information about Ctrl-C without exceptions
51 KBINT = False
58 KBINT = False
@@ -358,36 +365,37 b' class MTInteractiveShell(InteractiveShell):'
358 InteractiveShell.__init__(self,name,usage,rc,user_ns,
365 InteractiveShell.__init__(self,name,usage,rc,user_ns,
359 user_global_ns,banner2)
366 user_global_ns,banner2)
360
367
361 # Locking control variable.
362 self.thread_ready = threading.Condition(threading.RLock())
363
368
364 # A queue to hold the code to be executed. A scalar variable is NOT
369 # A queue to hold the code to be executed.
365 # enough, because uses like macros cause reentrancy.
366 self.code_queue = Queue.Queue()
370 self.code_queue = Queue.Queue()
367
371
368 # Stuff to do at closing time
372 # Stuff to do at closing time
369 self._kill = False
373 self._kill = None
370 on_kill = kw.get('on_kill')
374 on_kill = kw.get('on_kill', [])
371 if on_kill is None:
372 on_kill = []
373 # Check that all things to kill are callable:
375 # Check that all things to kill are callable:
374 for t in on_kill:
376 for t in on_kill:
375 if not callable(t):
377 if not callable(t):
376 raise TypeError,'on_kill must be a list of callables'
378 raise TypeError,'on_kill must be a list of callables'
377 self.on_kill = on_kill
379 self.on_kill = on_kill
378
380 # thread identity of the "worker thread" (that may execute code directly)
381 self.worker_ident = None
382
379 def runsource(self, source, filename="<input>", symbol="single"):
383 def runsource(self, source, filename="<input>", symbol="single"):
380 """Compile and run some source in the interpreter.
384 """Compile and run some source in the interpreter.
381
385
382 Modified version of code.py's runsource(), to handle threading issues.
386 Modified version of code.py's runsource(), to handle threading issues.
383 See the original for full docstring details."""
387 See the original for full docstring details."""
384
388
385 global KBINT
389 global KBINT
386
390
387 # If Ctrl-C was typed, we reset the flag and return right away
391 # If Ctrl-C was typed, we reset the flag and return right away
388 if KBINT:
392 if KBINT:
389 KBINT = False
393 KBINT = False
390 return False
394 return False
395
396 if self._kill:
397 # can't queue new code if we are being killed
398 return True
391
399
392 try:
400 try:
393 code = self.compile(source, filename, symbol)
401 code = self.compile(source, filename, symbol)
@@ -400,29 +408,40 b' class MTInteractiveShell(InteractiveShell):'
400 # Case 2
408 # Case 2
401 return True
409 return True
402
410
411 # shortcut - if we are in worker thread, or the worker thread is not running,
412 # execute directly (to allow recursion and prevent deadlock if code is run early
413 # in IPython construction)
414
415 if (self.worker_ident is None or self.worker_ident == thread.get_ident()):
416 InteractiveShell.runcode(self,code)
417 return
418
403 # Case 3
419 # Case 3
404 # Store code in queue, so the execution thread can handle it.
420 # Store code in queue, so the execution thread can handle it.
405
421
406 # Note that with macros and other applications, we MAY re-enter this
422 completed_ev, received_ev = threading.Event(), threading.Event()
407 # section, so we have to acquire the lock with non-blocking semantics,
423
408 # else we deadlock.
424 self.code_queue.put((code,completed_ev, received_ev))
409 got_lock = self.thread_ready.acquire()
425 # first make sure the message was received, with timeout
410 self.code_queue.put(code)
426 received_ev.wait(5)
411 if got_lock:
427 if not received_ev.isSet():
412 self.thread_ready.wait() # Wait until processed in timeout interval
428 # the mainloop is dead, start executing code directly
413 self.thread_ready.release()
429 print "Warning: Timeout for mainloop thread exceeded"
414
430 print "switching to nonthreaded mode (until mainloop wakes up again)"
431 self.worker_ident = None
432 else:
433 completed_ev.wait()
415 return False
434 return False
416
435
417 def runcode(self):
436 def runcode(self):
418 """Execute a code object.
437 """Execute a code object.
419
438
420 Multithreaded wrapper around IPython's runcode()."""
439 Multithreaded wrapper around IPython's runcode()."""
421
440
422 global CODE_RUN
441 global CODE_RUN
423
442
424 # lock thread-protected stuff
443 # we are in worker thread, stash out the id for runsource()
425 got_lock = self.thread_ready.acquire()
444 self.worker_ident = thread.get_ident()
426
445
427 if self._kill:
446 if self._kill:
428 print >>Term.cout, 'Closing threads...',
447 print >>Term.cout, 'Closing threads...',
@@ -430,6 +449,9 b' class MTInteractiveShell(InteractiveShell):'
430 for tokill in self.on_kill:
449 for tokill in self.on_kill:
431 tokill()
450 tokill()
432 print >>Term.cout, 'Done.'
451 print >>Term.cout, 'Done.'
452 # allow kill() to return
453 self._kill.set()
454 return True
433
455
434 # Install sigint handler. We do it every time to ensure that if user
456 # Install sigint handler. We do it every time to ensure that if user
435 # code modifies it, we restore our own handling.
457 # code modifies it, we restore our own handling.
@@ -445,10 +467,11 b' class MTInteractiveShell(InteractiveShell):'
445 code_to_run = None
467 code_to_run = None
446 while 1:
468 while 1:
447 try:
469 try:
448 code_to_run = self.code_queue.get_nowait()
470 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
449 except Queue.Empty:
471 except Queue.Empty:
450 break
472 break
451
473 received_ev.set()
474
452 # Exceptions need to be raised differently depending on which
475 # Exceptions need to be raised differently depending on which
453 # thread is active. This convoluted try/except is only there to
476 # thread is active. This convoluted try/except is only there to
454 # protect against asynchronous exceptions, to ensure that a KBINT
477 # protect against asynchronous exceptions, to ensure that a KBINT
@@ -462,28 +485,23 b' class MTInteractiveShell(InteractiveShell):'
462 except KeyboardInterrupt:
485 except KeyboardInterrupt:
463 print "Keyboard interrupted in mainloop"
486 print "Keyboard interrupted in mainloop"
464 while not self.code_queue.empty():
487 while not self.code_queue.empty():
465 self.code_queue.get_nowait()
488 code, ev1,ev2 = self.code_queue.get_nowait()
489 ev1.set()
490 ev2.set()
466 break
491 break
467 finally:
492 finally:
468 if got_lock:
493 CODE_RUN = False
469 CODE_RUN = False
494 # allow runsource() return from wait
470
495 completed_ev.set()
471 # We're done with thread-protected variables
496
472 if code_to_run is not None:
497
473 self.thread_ready.notify()
474 self.thread_ready.release()
475
476 # We're done...
477 CODE_RUN = False
478 # This MUST return true for gtk threading to work
498 # This MUST return true for gtk threading to work
479 return True
499 return True
480
500
481 def kill(self):
501 def kill(self):
482 """Kill the thread, returning when it has been shut down."""
502 """Kill the thread, returning when it has been shut down."""
483 got_lock = self.thread_ready.acquire(False)
503 self._kill = threading.Event()
484 self._kill = True
504 self._kill.wait()
485 if got_lock:
486 self.thread_ready.release()
487
505
488 class MatplotlibShellBase:
506 class MatplotlibShellBase:
489 """Mixin class to provide the necessary modifications to regular IPython
507 """Mixin class to provide the necessary modifications to regular IPython
@@ -1051,7 +1069,9 b' def _load_pylab(user_ns):'
1051
1069
1052 ip = IPython.ipapi.get()
1070 ip = IPython.ipapi.get()
1053 if ip.options.pylab_import_all:
1071 if ip.options.pylab_import_all:
1054 exec "from matplotlib.pylab import *" in user_ns
1072 ip.ex("from matplotlib.pylab import *")
1073 ip.IP.user_config_ns.update(ip.user_ns)
1074
1055
1075
1056 class IPShellMatplotlib(IPShell):
1076 class IPShellMatplotlib(IPShell):
1057 """Subclass IPShell with MatplotlibShell as the internal shell.
1077 """Subclass IPShell with MatplotlibShell as the internal shell.
@@ -1144,7 +1164,7 b' def _select_shell(argv):'
1144 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1164 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1145 'tkthread'])
1165 'tkthread'])
1146 user_opts = set([s.replace('-','') for s in argv[:3]])
1166 user_opts = set([s.replace('-','') for s in argv[:3]])
1147 special_opts = user_opts & all_opts
1167 special_opts = user_opts & all_opts
1148
1168
1149 if 'tk' in special_opts:
1169 if 'tk' in special_opts:
1150 USE_TK = True
1170 USE_TK = True
@@ -72,6 +72,27 b' def main():'
72 #o.autoexec.append('%colors NoColor')
72 #o.autoexec.append('%colors NoColor')
73 #o.autoexec.append('%colors Linux')
73 #o.autoexec.append('%colors Linux')
74
74
75 # for sane integer division that converts to float (1/2 == 0.5)
76 #o.autoexec.append('from __future__ import division')
77
78 # For %tasks and %kill
79 #import jobctrl
80
81 # For autoreloading of modules (%autoreload, %aimport)
82 #import ipy_autoreload
83
84 # For winpdb support (%wdb)
85 #import ipy_winpdb
86
87 # For bzr completer, requires bzrlib (the python installation of bzr)
88 #ip.load('ipy_bzr')
89
90 # Tab completer that is not quite so picky (i.e.
91 # "foo".<TAB> and str(2).<TAB> will work). Complete
92 # at your own risk!
93 #import ipy_greedycompleter
94
95
75
96
76 # some config helper functions you can use
97 # some config helper functions you can use
77 def import_all(modules):
98 def import_all(modules):
@@ -321,7 +321,7 b' class IPCompleter(Completer):'
321 # don't want to treat as delimiters in filename matching
321 # don't want to treat as delimiters in filename matching
322 # when escaped with backslash
322 # when escaped with backslash
323
323
324 protectables = ' ()[]{}'
324 protectables = ' '
325
325
326 if text.startswith('!'):
326 if text.startswith('!'):
327 text = text[1:]
327 text = text[1:]
@@ -32,7 +32,9 b' import imp'
32 import sys
32 import sys
33
33
34 # Replacement for __import__()
34 # Replacement for __import__()
35 def deep_import_hook(name, globals=None, locals=None, fromlist=None):
35 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
36 # For now level is ignored, it's just there to prevent crash
37 # with from __future__ import absolute_import
36 parent = determine_parent(globals)
38 parent = determine_parent(globals)
37 q, tail = find_head_package(parent, name)
39 q, tail = find_head_package(parent, name)
38 m = load_tail(q, tail)
40 m = load_tail(q, tail)
@@ -34,35 +34,35 b' License: MIT Open Source license'
34 #Assigned in variable for "usage" printing convenience"
34 #Assigned in variable for "usage" printing convenience"
35
35
36 globsyntax = """\
36 globsyntax = """\
37 This program allows specifying filenames with "mglob" mechanism.
37 This program allows specifying filenames with "mglob" mechanism.
38 Supported syntax in globs (wilcard matching patterns)::
38 Supported syntax in globs (wilcard matching patterns)::
39
39
40 *.cpp ?ellowo*
40 *.cpp ?ellowo*
41 - obvious. Differs from normal glob in that dirs are not included.
41 - obvious. Differs from normal glob in that dirs are not included.
42 Unix users might want to write this as: "*.cpp" "?ellowo*"
42 Unix users might want to write this as: "*.cpp" "?ellowo*"
43 rec:/usr/share=*.txt,*.doc
43 rec:/usr/share=*.txt,*.doc
44 - get all *.txt and *.doc under /usr/share,
44 - get all *.txt and *.doc under /usr/share,
45 recursively
45 recursively
46 rec:/usr/share
46 rec:/usr/share
47 - All files under /usr/share, recursively
47 - All files under /usr/share, recursively
48 rec:*.py
48 rec:*.py
49 - All .py files under current working dir, recursively
49 - All .py files under current working dir, recursively
50 foo
50 foo
51 - File or dir foo
51 - File or dir foo
52 !*.bak readme*
52 !*.bak readme*
53 - readme*, exclude files ending with .bak
53 - readme*, exclude files ending with .bak
54 !.svn/ !.hg/ !*_Data/ rec:.
54 !.svn/ !.hg/ !*_Data/ rec:.
55 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
55 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
56 Trailing / is the key, \ does not work!
56 Trailing / is the key, \ does not work!
57 dir:foo
57 dir:foo
58 - the directory foo if it exists (not files in foo)
58 - the directory foo if it exists (not files in foo)
59 dir:*
59 dir:*
60 - all directories in current folder
60 - all directories in current folder
61 foo.py bar.* !h* rec:*.py
61 foo.py bar.* !h* rec:*.py
62 - Obvious. !h* exclusion only applies for rec:*.py.
62 - Obvious. !h* exclusion only applies for rec:*.py.
63 foo.py is *not* included twice.
63 foo.py is *not* included twice.
64 @filelist.txt
64 @filelist.txt
65 - All files listed in 'filelist.txt' file, on separate lines.
65 - All files listed in 'filelist.txt' file, on separate lines.
66 """
66 """
67
67
68
68
@@ -29,7 +29,10 b' Date: 9 Mar 2007'
29
29
30 from __future__ import generators
30 from __future__ import generators
31
31
32 import sys, warnings, os, fnmatch, glob, shutil, codecs, md5
32 import sys, warnings, os, fnmatch, glob, shutil, codecs
33 # deprecated in python 2.6
34 warnings.filterwarnings('ignore', r'.*md5.*')
35 import md5
33
36
34 __version__ = '2.2'
37 __version__ = '2.2'
35 __all__ = ['path']
38 __all__ = ['path']
@@ -22,7 +22,10 b' __license__ = Release.license'
22 # required modules from the Python standard library
22 # required modules from the Python standard library
23 import __main__
23 import __main__
24 import commands
24 import commands
25 import doctest
25 try:
26 import doctest
27 except ImportError:
28 pass
26 import os
29 import os
27 import re
30 import re
28 import shlex
31 import shlex
@@ -33,6 +36,18 b' import time'
33 import types
36 import types
34 import warnings
37 import warnings
35
38
39 # Curses and termios are Unix-only modules
40 try:
41 import curses
42 # We need termios as well, so if its import happens to raise, we bail on
43 # using curses altogether.
44 import termios
45 except ImportError:
46 USE_CURSES = False
47 else:
48 # Curses on Solaris may not be complete, so we can't use it there
49 USE_CURSES = hasattr(curses,'initscr')
50
36 # Other IPython utilities
51 # Other IPython utilities
37 import IPython
52 import IPython
38 from IPython.Itpl import Itpl,itpl,printpl
53 from IPython.Itpl import Itpl,itpl,printpl
@@ -1052,25 +1067,40 b' class SList(list):'
1052
1067
1053 p = paths = property(get_paths)
1068 p = paths = property(get_paths)
1054
1069
1055 def grep(self, pattern, prune = False):
1070 def grep(self, pattern, prune = False, field = None):
1056 """ Return all strings matching 'pattern' (a regex or callable)
1071 """ Return all strings matching 'pattern' (a regex or callable)
1057
1072
1058 This is case-insensitive. If prune is true, return all items
1073 This is case-insensitive. If prune is true, return all items
1059 NOT matching the pattern.
1074 NOT matching the pattern.
1060
1075
1076 If field is specified, the match must occur in the specified
1077 whitespace-separated field.
1078
1061 Examples::
1079 Examples::
1062
1080
1063 a.grep( lambda x: x.startswith('C') )
1081 a.grep( lambda x: x.startswith('C') )
1064 a.grep('Cha.*log', prune=1)
1082 a.grep('Cha.*log', prune=1)
1083 a.grep('chm', field=-1)
1065 """
1084 """
1085
1086 def match_target(s):
1087 if field is None:
1088 return s
1089 parts = s.split()
1090 try:
1091 tgt = parts[field]
1092 return tgt
1093 except IndexError:
1094 return ""
1095
1066 if isinstance(pattern, basestring):
1096 if isinstance(pattern, basestring):
1067 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1097 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1068 else:
1098 else:
1069 pred = pattern
1099 pred = pattern
1070 if not prune:
1100 if not prune:
1071 return SList([el for el in self if pred(el)])
1101 return SList([el for el in self if pred(match_target(el))])
1072 else:
1102 else:
1073 return SList([el for el in self if not pred(el)])
1103 return SList([el for el in self if not pred(match_target(el))])
1074 def fields(self, *fields):
1104 def fields(self, *fields):
1075 """ Collect whitespace-separated fields from string list
1105 """ Collect whitespace-separated fields from string list
1076
1106
@@ -1083,6 +1113,7 b' class SList(list):'
1083 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1113 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1084 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1114 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1085 (note the joining by space).
1115 (note the joining by space).
1116 a.fields(-1) is ['ChangeLog', 'IPython']
1086
1117
1087 IndexErrors are ignored.
1118 IndexErrors are ignored.
1088
1119
@@ -1532,26 +1563,30 b' def page(strng,start=0,screen_lines=0,pager_cmd = None):'
1532 # auto-determine screen size
1563 # auto-determine screen size
1533 if screen_lines <= 0:
1564 if screen_lines <= 0:
1534 if TERM=='xterm':
1565 if TERM=='xterm':
1535 try:
1566 use_curses = USE_CURSES
1536 import curses
1537 if hasattr(curses,'initscr'):
1538 use_curses = 1
1539 else:
1540 use_curses = 0
1541 except ImportError:
1542 use_curses = 0
1543 else:
1567 else:
1544 # curses causes problems on many terminals other than xterm.
1568 # curses causes problems on many terminals other than xterm.
1545 use_curses = 0
1569 use_curses = False
1546 if use_curses:
1570 if use_curses:
1547 scr = curses.initscr()
1571 # There is a bug in curses, where *sometimes* it fails to properly
1548 screen_lines_real,screen_cols = scr.getmaxyx()
1572 # initialize, and then after the endwin() call is made, the
1549 curses.endwin()
1573 # terminal is left in an unusable state. Rather than trying to
1550 screen_lines += screen_lines_real
1574 # check everytime for this (by requesting and comparing termios
1551 #print '***Screen size:',screen_lines_real,'lines x',\
1575 # flags each time), we just save the initial terminal state and
1552 #screen_cols,'columns.' # dbg
1576 # unconditionally reset it every time. It's cheaper than making
1577 # the checks.
1578 term_flags = termios.tcgetattr(sys.stdout)
1579 scr = curses.initscr()
1580 screen_lines_real,screen_cols = scr.getmaxyx()
1581 curses.endwin()
1582 # Restore terminal state in case endwin() didn't.
1583 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
1584 # Now we have what we needed: the screen size in rows/columns
1585 screen_lines += screen_lines_real
1586 #print '***Screen size:',screen_lines_real,'lines x',\
1587 #screen_cols,'columns.' # dbg
1553 else:
1588 else:
1554 screen_lines += screen_lines_def
1589 screen_lines += screen_lines_def
1555
1590
1556 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1591 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1557 if numlines <= screen_lines :
1592 if numlines <= screen_lines :
@@ -28,10 +28,30 b' class IPythonHistoryPanel(wx.Panel):'
28 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
28 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30
30
31 self.filter_empty.SetValue(flt_empty)
31 self.options={'filter_empty':{'value':'True',
32 self.filter_doc.SetValue(flt_doc)
32 'checkbox':self.filter_empty,'True':True,'False':False,
33 self.filter_cmd.SetValue(flt_cmd)
33 'setfunc':lambda x:None},
34 self.filter_magic.SetValue(flt_magic)
34 'filter_doc':{'value':'True',
35 'checkbox':self.filter_doc,'True':True,'False':False,
36 'setfunc':lambda x:None},
37 'filter_cmd':{'value':'True',
38 'checkbox':self.filter_cmd,'True':True,'False':False,
39 'setfunc':lambda x:None},
40 'filter_magic':{'value':'True',
41 'checkbox':self.filter_magic,'True':True,'False':False,
42 'setfunc':lambda x:None},
43 }
44 self.reloadOptions(self.options)
45
46 self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
47 self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
48 self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
49 self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
50
51 #self.filter_empty.SetValue(flt_empty)
52 #self.filter_doc.SetValue(flt_doc)
53 #self.filter_cmd.SetValue(flt_cmd)
54 #self.filter_magic.SetValue(flt_magic)
35
55
36 sizer = wx.BoxSizer(wx.VERTICAL)
56 sizer = wx.BoxSizer(wx.VERTICAL)
37
57
@@ -70,10 +90,54 b' class IPythonHistoryPanel(wx.Panel):'
70 add = False
90 add = False
71 if self.filter_magic.GetValue() == True and history_line[0] == '%':
91 if self.filter_magic.GetValue() == True and history_line[0] == '%':
72 add = False
92 add = False
73 if add:
93 if add:
74 self.text_ctrl.AppendText(history_line+'\n')
94 self.text_ctrl.AppendText(history_line+'\n')
95
96 #------------------------ Option Section -----------------------------------
97 def processOptionCheckedEvt(self, event, name):
98 if event.IsChecked():
99 self.options[name]['value']='True'
100 else:
101 self.options[name]['value']='False'
102 self.updateOptionTracker(name,
103 self.options[name]['value'])
104
105 def evtCheckEmptyFilter(self, event):
106 self.processOptionCheckedEvt(event, 'filter_empty')
107
108 def evtCheckDocFilter(self, event):
109 self.processOptionCheckedEvt(event, 'filter_doc')
75
110
111 def evtCheckCmdFilter(self, event):
112 self.processOptionCheckedEvt(event, 'filter_cmd')
76
113
114 def evtCheckMagicFilter(self, event):
115 self.processOptionCheckedEvt(event, 'filter_magic')
116
117 def getOptions(self):
118 return self.options
119
120 def reloadOptions(self,options):
121 self.options = options
122 for key in self.options.keys():
123 value = self.options[key]['value']
124 self.options[key]['checkbox'].SetValue(self.options[key][value])
125 self.options[key]['setfunc'](value)
126
127 #------------------------ Hook Section -----------------------------------
128 def updateOptionTracker(self,name,value):
129 '''
130 Default history tracker (does nothing)
131 '''
132 pass
133
134 def setOptionTrackerHook(self,func):
135 '''
136 Define a new history tracker
137 '''
138 self.updateOptionTracker = func
139
140
77 #----------------------------------------------------------------------
141 #----------------------------------------------------------------------
78 # Font definition for Styled Text Control
142 # Font definition for Styled Text Control
79
143
This diff has been collapsed as it changes many lines, (1147 lines changed) Show them Hide them
@@ -1,7 +1,7 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
2 # -*- coding: iso-8859-15 -*-
3 '''
3 '''
4 Provides IPython WX console widget.
4 Provides IPython WX console widgets.
5
5
6 @author: Laurent Dufrechou
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
7 laurent.dufrechou _at_ gmail.com
@@ -26,433 +26,88 b' __license__ = "BSD"'
26
26
27 import wx
27 import wx
28 import wx.stc as stc
28 import wx.stc as stc
29 import wx.lib.newevent
30
29
31 import re
30 import re
32 import sys
31 import sys
33 import os
34 import locale
32 import locale
35 import time
36 from ThreadEx import Thread
37 from StringIO import StringIO
33 from StringIO import StringIO
38
39 try:
34 try:
40 import IPython
35 import IPython
41 except Exception,e:
36 except Exception,e:
42 raise "Error importing IPython (%s)" % str(e)
37 raise "Error importing IPython (%s)" % str(e)
43
38
44 class IterableIPShell(Thread):
39 from ipshell_nonblocking import NonBlockingIPShell
40
41 class WxNonBlockingIPShell(NonBlockingIPShell):
45 '''
42 '''
46 Create an IPython instance inside a dedicated thread.
43 An NonBlockingIPShell Thread that is WX dependent.
47 Does not start a blocking event loop, instead allow single iterations.
48 This allows embedding in any GUI without blockage.
49 The thread is a slave one, in that it doesn't interact directly with the GUI.
50 Note Thread class comes from ThreadEx that supports asynchroneous function call
51 via raise_exc()
52 '''
44 '''
53
45 def __init__(self, parent,
54 def __init__(self,argv=[],user_ns=None,user_global_ns=None,
46 argv=[],user_ns={},user_global_ns=None,
55 cin=None, cout=None, cerr=None,
47 cin=None, cout=None, cerr=None,
56 exit_handler=None,time_loop = 0.1):
48 ask_exit_handler=None):
57 '''
58 @param argv: Command line options for IPython
59 @type argv: list
60 @param user_ns: User namespace.
61 @type user_ns: dictionary
62 @param user_global_ns: User global namespace.
63 @type user_global_ns: dictionary.
64 @param cin: Console standard input.
65 @type cin: IO stream
66 @param cout: Console standard output.
67 @type cout: IO stream
68 @param cerr: Console standard error.
69 @type cerr: IO stream
70 @param exit_handler: Replacement for builtin exit() function
71 @type exit_handler: function
72 @param time_loop: Define the sleep time between two thread's loop
73 @type int
74 '''
75 Thread.__init__(self)
76
77 #first we redefine in/out/error functions of IPython
78 if cin:
79 IPython.Shell.Term.cin = cin
80 if cout:
81 IPython.Shell.Term.cout = cout
82 if cerr:
83 IPython.Shell.Term.cerr = cerr
84
85 # This is to get rid of the blockage that accurs during
86 # IPython.Shell.InteractiveShell.user_setup()
87 IPython.iplib.raw_input = lambda x: None
88
89 self._term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
90
91 excepthook = sys.excepthook
92 self._IP = IPython.Shell.make_IPython(
93 argv,user_ns=user_ns,
94 user_global_ns=user_global_ns,
95 embedded=True,
96 shell_class=IPython.Shell.InteractiveShell)
97
98 #we replace IPython default encoding by wx locale encoding
99 loc = locale.getpreferredencoding()
100 if loc:
101 self._IP.stdin_encoding = loc
102 #we replace the ipython default pager by our pager
103 self._IP.set_hook('show_in_pager',self._pager)
104
105 #we replace the ipython default shell command caller by our shell handler
106 self._IP.set_hook('shell_hook',self._shell)
107
108 #we replace the ipython default input command caller by our method
109 IPython.iplib.raw_input_original = self._raw_input
110 #we replace the ipython default exit command by our method
111 self._IP.exit = self._setAskExit
112
113 sys.excepthook = excepthook
114
115 self._iter_more = 0
116 self._history_level = 0
117 self._complete_sep = re.compile('[\s\{\}\[\]\(\)]')
118 self._prompt = str(self._IP.outputcache.prompt1).strip()
119
120 #thread working vars
121 self._terminate = False
122 self._time_loop = time_loop
123 self._has_doc = False
124 self._do_execute = False
125 self._line_to_execute = ''
126 self._doc_text = None
127 self._ask_exit = False
128
129 #----------------------- Thread management section ----------------------
130 def run (self):
131 """
132 Thread main loop
133 The thread will run until self._terminate will be set to True via shutdown() function
134 Command processing can be interrupted with Instance.raise_exc(KeyboardInterrupt) call in the
135 GUI thread.
136 """
137 while(not self._terminate):
138 try:
139 if self._do_execute:
140 self._doc_text = None
141 self._execute()
142 self._do_execute = False
143
144 except KeyboardInterrupt:
145 pass
146
147 time.sleep(self._time_loop)
148
149 def shutdown(self):
150 """
151 Shutdown the tread
152 """
153 self._terminate = True
154
155 def doExecute(self,line):
156 """
157 Tell the thread to process the 'line' command
158 """
159 self._do_execute = True
160 self._line_to_execute = line
161
162 def isExecuteDone(self):
163 """
164 Returns the processing state
165 """
166 return not self._do_execute
167
168 #----------------------- IPython management section ----------------------
169 def getAskExit(self):
170 '''
171 returns the _ask_exit variable that can be checked by GUI to see if
172 IPython request an exit handling
173 '''
174 return self._ask_exit
175
176 def clearAskExit(self):
177 '''
178 clear the _ask_exit var when GUI as handled the request.
179 '''
180 self._ask_exit = False
181
182 def getDocText(self):
183 """
184 Returns the output of the processing that need to be paged (if any)
185
186 @return: The std output string.
187 @rtype: string
188 """
189 return self._doc_text
190
191 def getBanner(self):
192 """
193 Returns the IPython banner for useful info on IPython instance
194
195 @return: The banner string.
196 @rtype: string
197 """
198 return self._IP.BANNER
199
200 def getPromptCount(self):
201 """
202 Returns the prompt number.
203 Each time a user execute a line in the IPython shell the prompt count is increased
204
205 @return: The prompt number
206 @rtype: int
207 """
208 return self._IP.outputcache.prompt_count
209
210 def getPrompt(self):
211 """
212 Returns current prompt inside IPython instance
213 (Can be In [...]: ot ...:)
214
215 @return: The current prompt.
216 @rtype: string
217 """
218 return self._prompt
219
220 def getIndentation(self):
221 """
222 Returns the current indentation level
223 Usefull to put the caret at the good start position if we want to do autoindentation.
224
225 @return: The indentation level.
226 @rtype: int
227 """
228 return self._IP.indent_current_nsp
229
49
230 def updateNamespace(self, ns_dict):
50 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
231 '''
51 cin, cout, cerr,
232 Add the current dictionary to the shell namespace.
52 ask_exit_handler)
233
53
234 @param ns_dict: A dictionary of symbol-values.
54 self.parent = parent
235 @type ns_dict: dictionary
236 '''
237 self._IP.user_ns.update(ns_dict)
238
55
239 def complete(self, line):
56 self.ask_exit_callback = ask_exit_handler
240 '''
57 self._IP.exit = self._askExit
241 Returns an auto completed line and/or posibilities for completion.
242
58
243 @param line: Given line so far.
59 def addGUIShortcut(self,text,func):
244 @type line: string
60 wx.CallAfter(self.parent.add_button_handler,
61 button_info={ 'text':text,
62 'func':self.parent.doExecuteLine(func)})
245
63
246 @return: Line completed as for as possible,
64 def _askExit(self):
247 and possible further completions.
65 wx.CallAfter(self.ask_exit_callback, ())
248 @rtype: tuple
249 '''
250 split_line = self._complete_sep.split(line)
251 possibilities = self._IP.complete(split_line[-1])
252 if possibilities:
253
254 def _commonPrefix(str1, str2):
255 '''
256 Reduction function. returns common prefix of two given strings.
257
258 @param str1: First string.
259 @type str1: string
260 @param str2: Second string
261 @type str2: string
262
263 @return: Common prefix to both strings.
264 @rtype: string
265 '''
266 for i in range(len(str1)):
267 if not str2.startswith(str1[:i+1]):
268 return str1[:i]
269 return str1
270 common_prefix = reduce(_commonPrefix, possibilities)
271 completed = line[:-len(split_line[-1])]+common_prefix
272 else:
273 completed = line
274 return completed, possibilities
275
66
276 def historyBack(self):
67 def _afterExecute(self):
277 '''
68 wx.CallAfter(self.parent.evtStateExecuteDone, ())
278 Provides one history command back.
279
69
280 @return: The command string.
281 @rtype: string
282 '''
283 history = ''
284 #the below while loop is used to suppress empty history lines
285 while((history == '' or history == '\n') and self._history_level >0):
286 if self._history_level>=1:
287 self._history_level -= 1
288 history = self._getHistory()
289 return history
290
291 def historyForward(self):
292 '''
293 Provides one history command forward.
294
295 @return: The command string.
296 @rtype: string
297 '''
298 history = ''
299 #the below while loop is used to suppress empty history lines
300 while((history == '' or history == '\n') and self._history_level <= self._getHistoryMaxIndex()):
301 if self._history_level < self._getHistoryMaxIndex():
302 self._history_level += 1
303 history = self._getHistory()
304 else:
305 if self._history_level == self._getHistoryMaxIndex():
306 history = self._getHistory()
307 self._history_level += 1
308 else:
309 history = ''
310 return history
311
312 def initHistoryIndex(self):
313 '''
314 set history to last command entered
315 '''
316 self._history_level = self._getHistoryMaxIndex()+1
317
318 #----------------------- IPython PRIVATE management section ----------------------
319 def _setAskExit(self):
320 '''
321 set the _ask_exit variable that can be cjhecked by GUI to see if
322 IPython request an exit handling
323 '''
324 self._ask_exit = True
325
326 def _getHistoryMaxIndex(self):
327 '''
328 returns the max length of the history buffer
329
330 @return: history length
331 @rtype: int
332 '''
333 return len(self._IP.input_hist_raw)-1
334
335 def _getHistory(self):
336 '''
337 Get's the command string of the current history level.
338
339 @return: Historic command string.
340 @rtype: string
341 '''
342 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
343 return rv
344
345 def _pager(self,IP,text):
346 '''
347 This function is used as a callback replacment to IPython pager function
348
349 It puts the 'text' value inside the self._doc_text string that can be retrived via getDocText
350 function.
351 '''
352 self._doc_text = text
353
354 def _raw_input(self, prompt=''):
355 '''
356 Custom raw_input() replacement. Get's current line from console buffer.
357
358 @param prompt: Prompt to print. Here for compatability as replacement.
359 @type prompt: string
360
361 @return: The current command line text.
362 @rtype: string
363 '''
364 return self._line_to_execute
365
366 def _execute(self):
367 '''
368 Executes the current line provided by the shell object.
369 '''
370 orig_stdout = sys.stdout
371 sys.stdout = IPython.Shell.Term.cout
372
70
373 try:
374 line = self._IP.raw_input(None, self._iter_more)
375 if self._IP.autoindent:
376 self._IP.readline_startup_hook(None)
377
378 except KeyboardInterrupt:
379 self._IP.write('\nKeyboardInterrupt\n')
380 self._IP.resetbuffer()
381 # keep cache in sync with the prompt counter:
382 self._IP.outputcache.prompt_count -= 1
383
384 if self._IP.autoindent:
385 self._IP.indent_current_nsp = 0
386 self._iter_more = 0
387 except:
388 self._IP.showtraceback()
389 else:
390 self._iter_more = self._IP.push(line)
391 if (self._IP.SyntaxTB.last_syntax_error and
392 self._IP.rc.autoedit_syntax):
393 self._IP.edit_syntax_error()
394 if self._iter_more:
395 self._prompt = str(self._IP.outputcache.prompt2).strip()
396 if self._IP.autoindent:
397 self._IP.readline_startup_hook(self._IP.pre_readline)
398 else:
399 self._prompt = str(self._IP.outputcache.prompt1).strip()
400 self._IP.indent_current_nsp = 0 #we set indentation to 0
401 sys.stdout = orig_stdout
402
403 def _shell(self, ip, cmd):
404 '''
405 Replacement method to allow shell commands without them blocking.
406
407 @param ip: Ipython instance, same as self._IP
408 @type cmd: Ipython instance
409 @param cmd: Shell command to execute.
410 @type cmd: string
411 '''
412 stdin, stdout = os.popen4(cmd)
413 result = stdout.read().decode('cp437').encode(locale.getpreferredencoding())
414 #we use print command because the shell command is called inside IPython instance and thus is
415 #redirected to thread cout
416 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
417 print "\x01\x1b[1;36m\x02"+result
418 stdout.close()
419 stdin.close()
420
421 class WxConsoleView(stc.StyledTextCtrl):
71 class WxConsoleView(stc.StyledTextCtrl):
422 '''
72 '''
423 Specialized styled text control view for console-like workflow.
73 Specialized styled text control view for console-like workflow.
424 We use here a scintilla frontend thus it can be reused in any GUI taht supports
74 We use here a scintilla frontend thus it can be reused in any GUI that
425 scintilla with less work.
75 supports scintilla with less work.
426
76
427 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.(with Black background)
77 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
78 (with Black background)
428 @type ANSI_COLORS_BLACK: dictionary
79 @type ANSI_COLORS_BLACK: dictionary
429
80
430 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.(with White background)
81 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
82 (with White background)
431 @type ANSI_COLORS_WHITE: dictionary
83 @type ANSI_COLORS_WHITE: dictionary
432
84
433 @ivar color_pat: Regex of terminal color pattern
85 @ivar color_pat: Regex of terminal color pattern
434 @type color_pat: _sre.SRE_Pattern
86 @type color_pat: _sre.SRE_Pattern
435 '''
87 '''
436 ANSI_STYLES_BLACK ={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
88 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
437 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
89 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
438 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
90 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
439 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
91 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
440 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
92 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
441 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
93 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
442 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
94 '1;34': [12,'LIGHT BLUE'], '1;35':
443 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
95 [13,'MEDIUM VIOLET RED'],
444
96 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
445 ANSI_STYLES_WHITE ={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
97
446 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
98 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
447 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
99 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
448 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
100 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
449 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
101 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
450 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
102 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
451 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
103 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
452 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
104 '1;34': [12,'LIGHT BLUE'], '1;35':
453
105 [13,'MEDIUM VIOLET RED'],
454 def __init__(self,parent,prompt,intro="",background_color="BLACK",pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
106 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
455 style=0):
107
108 def __init__(self,parent,prompt,intro="",background_color="BLACK",
109 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
110 style=0, autocomplete_mode = 'IPYTHON'):
456 '''
111 '''
457 Initialize console view.
112 Initialize console view.
458
113
@@ -464,15 +119,61 b' class WxConsoleView(stc.StyledTextCtrl):'
464 @param background_color: Can be BLACK or WHITE
119 @param background_color: Can be BLACK or WHITE
465 @type background_color: string
120 @type background_color: string
466 @param other: init param of styledTextControl (can be used as-is)
121 @param other: init param of styledTextControl (can be used as-is)
122 @param autocomplete_mode: Can be 'IPYTHON' or 'STC'
123 'IPYTHON' show autocompletion the ipython way
124 'STC" show it scintilla text control way
467 '''
125 '''
468 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
126 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
469
127
470 ####### Scintilla configuration ##################################################
128 ####### Scintilla configuration ###################################
471
129
472 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside the widget
130 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
131 # the widget
473 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
132 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
474 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
133 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
475
134
135 #We draw a line at position 80
136 self.SetEdgeMode(stc.STC_EDGE_LINE)
137 self.SetEdgeColumn(80)
138 self.SetEdgeColour(wx.LIGHT_GREY)
139
140 #self.SetViewWhiteSpace(True)
141 #self.SetViewEOL(True)
142 self.SetEOLMode(stc.STC_EOL_CRLF)
143 #self.SetWrapMode(stc.STC_WRAP_CHAR)
144 #self.SetWrapMode(stc.STC_WRAP_WORD)
145 self.SetBufferedDraw(True)
146 #self.SetUseAntiAliasing(True)
147 self.SetLayoutCache(stc.STC_CACHE_PAGE)
148 self.SetUndoCollection(False)
149 self.SetUseTabs(True)
150 self.SetIndent(4)
151 self.SetTabWidth(4)
152
153 self.EnsureCaretVisible()
154
155 self.SetMargins(3,3) #text is moved away from border with 3px
156 # Suppressing Scintilla margins
157 self.SetMarginWidth(0,0)
158 self.SetMarginWidth(1,0)
159 self.SetMarginWidth(2,0)
160
161 self.background_color = background_color
162 self.buildStyles()
163
164 self.indent = 0
165 self.prompt_count = 0
166 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
167
168 self.write(intro)
169 self.setPrompt(prompt)
170 self.showPrompt()
171
172 self.autocomplete_mode = autocomplete_mode
173
174 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
175
176 def buildStyles(self):
476 #we define platform specific fonts
177 #we define platform specific fonts
477 if wx.Platform == '__WXMSW__':
178 if wx.Platform == '__WXMSW__':
478 faces = { 'times': 'Times New Roman',
179 faces = { 'times': 'Times New Roman',
@@ -499,61 +200,64 b' class WxConsoleView(stc.StyledTextCtrl):'
499 'size2': 8,
200 'size2': 8,
500 }
201 }
501
202
502 #We draw a line at position 80
503 self.SetEdgeMode(stc.STC_EDGE_LINE)
504 self.SetEdgeColumn(80)
505 self.SetEdgeColour(wx.LIGHT_GREY)
506
507 #self.SetViewWhiteSpace(True)
508 #self.SetViewEOL(True)
509 self.SetEOLMode(stc.STC_EOL_CRLF)
510 #self.SetWrapMode(stc.STC_WRAP_CHAR)
511 #self.SetWrapMode(stc.STC_WRAP_WORD)
512 self.SetBufferedDraw(True)
513 #self.SetUseAntiAliasing(True)
514 self.SetLayoutCache(stc.STC_CACHE_PAGE)
515
516 self.EnsureCaretVisible()
517
518 self.SetMargins(3,3) #text is moved away from border with 3px
519 # Suppressing Scintilla margins
520 self.SetMarginWidth(0,0)
521 self.SetMarginWidth(1,0)
522 self.SetMarginWidth(2,0)
523
524 # make some styles
203 # make some styles
525 if background_color != "BLACK":
204 if self.background_color != "BLACK":
526 self.background_color = "WHITE"
205 self.background_color = "WHITE"
527 self.SetCaretForeground("BLACK")
206 self.SetCaretForeground("BLACK")
528 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
207 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
529 else:
208 else:
530 self.background_color = background_color
531 self.SetCaretForeground("WHITE")
209 self.SetCaretForeground("WHITE")
532 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
210 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
533
211
534 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:%s,back:%s,size:%d,face:%s" % (self.ANSI_STYLES['0;30'][1],
212 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
535 self.background_color,
213 "fore:%s,back:%s,size:%d,face:%s"
536 faces['size'], faces['mono']))
214 % (self.ANSI_STYLES['0;30'][1],
215 self.background_color,
216 faces['size'], faces['mono']))
537 self.StyleClearAll()
217 self.StyleClearAll()
538 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FF0000,back:#0000FF,bold")
218 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
539 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
219 "fore:#FF0000,back:#0000FF,bold")
540
220 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
221 "fore:#000000,back:#FF0000,bold")
222
541 for style in self.ANSI_STYLES.values():
223 for style in self.ANSI_STYLES.values():
542 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
224 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
543
225
544 #######################################################################
226 #######################################################################
545
227
546 self.indent = 0
228 def setBackgroundColor(self,color):
547 self.prompt_count = 0
229 self.background_color = color
548 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
230 self.buildStyles()
231
232 def getBackgroundColor(self,color):
233 return self.background_color
549
234
550 self.write(intro)
235 def asyncWrite(self, text):
551 self.setPrompt(prompt)
236 '''
552 self.showPrompt()
237 Write given text to buffer in an asynchroneous way.
238 It is used from another thread to be able to acces the GUI.
239 @param text: Text to append
240 @type text: string
241 '''
242 try:
243 #print >>sys.__stdout__,'entering'
244 wx.MutexGuiEnter()
245 #print >>sys.__stdout__,'locking the GUI'
246
247 #be sure not to be interrutpted before the MutexGuiLeave!
248 self.write(text)
249
250 #print >>sys.__stdout__,'done'
251
252 except KeyboardInterrupt:
253 #print >>sys.__stdout__,'got keyboard interrupt'
254 wx.MutexGuiLeave()
255 #print >>sys.__stdout__,'interrupt unlock the GUI'
256 raise KeyboardInterrupt
257 wx.MutexGuiLeave()
258 #print >>sys.__stdout__,'normal unlock the GUI'
553
259
554 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
260
555 #self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
556
557 def write(self, text):
261 def write(self, text):
558 '''
262 '''
559 Write given text to buffer.
263 Write given text to buffer.
@@ -641,18 +345,6 b' class WxConsoleView(stc.StyledTextCtrl):'
641 return self.GetTextRange(self.getCurrentPromptStart(),
345 return self.GetTextRange(self.getCurrentPromptStart(),
642 self.getCurrentLineEnd())
346 self.getCurrentLineEnd())
643
347
644 def showReturned(self, text):
645 '''
646 Show returned text from last command and print new prompt.
647
648 @param text: Text to show.
649 @type text: string
650 '''
651 self.write('\n'+text)
652 if text:
653 self.write('\n')
654 self.showPrompt()
655
656 def moveCursorOnNewValidKey(self):
348 def moveCursorOnNewValidKey(self):
657 #If cursor is at wrong position put it at last line...
349 #If cursor is at wrong position put it at last line...
658 if self.GetCurrentPos() < self.getCurrentPromptStart():
350 if self.GetCurrentPos() < self.getCurrentPromptStart():
@@ -679,33 +371,53 b' class WxConsoleView(stc.StyledTextCtrl):'
679 def writeHistory(self,history):
371 def writeHistory(self,history):
680 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
372 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
681 self.changeLine(history)
373 self.changeLine(history)
374
375 def setCompletionMethod(self, completion):
376 if completion in ['IPYTHON','STC']:
377 self.autocomplete_mode = completion
378 else:
379 raise AttributeError
380
381 def getCompletionMethod(self, completion):
382 return self.autocomplete_mode
682
383
683 def writeCompletion(self, possibilities):
384 def writeCompletion(self, possibilities):
684 max_len = len(max(possibilities,key=len))
385 if self.autocomplete_mode == 'IPYTHON':
685 max_symbol =' '*max_len
386 max_len = len(max(possibilities,key=len))
686
387 max_symbol =' '*max_len
687 #now we check how much symbol we can put on a line...
388
688 cursor_pos = self.getCursorPos()
389 #now we check how much symbol we can put on a line...
689 test_buffer = max_symbol + ' '*4
390 cursor_pos = self.getCursorPos()
690 current_lines = self.GetLineCount()
391 test_buffer = max_symbol + ' '*4
691
392 current_lines = self.GetLineCount()
692 allowed_symbols = 80/len(test_buffer)
393
693 if allowed_symbols == 0:
394 allowed_symbols = 80/len(test_buffer)
694 allowed_symbols = 1
395 if allowed_symbols == 0:
396 allowed_symbols = 1
397
398 pos = 1
399 buf = ''
400 for symbol in possibilities:
401 #buf += symbol+'\n'#*spaces)
402 if pos<allowed_symbols:
403 spaces = max_len - len(symbol) + 4
404 buf += symbol+' '*spaces
405 pos += 1
406 else:
407 buf+=symbol+'\n'
408 pos = 1
409 self.write(buf)
410 else:
411 possibilities.sort() # Python sorts are case sensitive
412 self.AutoCompSetIgnoreCase(False)
413 self.AutoCompSetAutoHide(False)
414 #let compute the length ot last word
415 splitter = [' ','(','[','{']
416 last_word = self.getCurrentLine()
417 for breaker in splitter:
418 last_word = last_word.split(breaker)[-1]
419 self.AutoCompShow(len(last_word), " ".join(possibilities))
695
420
696 pos = 1
697 buf = ''
698 for symbol in possibilities:
699 #buf += symbol+'\n'#*spaces)
700 if pos<allowed_symbols:
701 spaces = max_len - len(symbol) + 4
702 buf += symbol+' '*spaces
703 pos += 1
704 else:
705 buf+=symbol+'\n'
706 pos = 1
707 self.write(buf)
708
709 def _onKeypress(self, event, skip=True):
421 def _onKeypress(self, event, skip=True):
710 '''
422 '''
711 Key press callback used for correcting behavior for console-like
423 Key press callback used for correcting behavior for console-like
@@ -720,42 +432,45 b' class WxConsoleView(stc.StyledTextCtrl):'
720 @return: Return True if event as been catched.
432 @return: Return True if event as been catched.
721 @rtype: boolean
433 @rtype: boolean
722 '''
434 '''
723
724 if event.GetKeyCode() == wx.WXK_HOME:
725 if event.Modifiers == wx.MOD_NONE:
726 self.moveCursorOnNewValidKey()
727 self.moveCursor(self.getCurrentPromptStart())
728 return True
729 elif event.Modifiers == wx.MOD_SHIFT:
730 self.moveCursorOnNewValidKey()
731 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
732 return True
733 else:
734 return False
735
435
736 elif event.GetKeyCode() == wx.WXK_LEFT:
436 if not self.AutoCompActive():
737 if event.Modifiers == wx.MOD_NONE:
437 if event.GetKeyCode() == wx.WXK_HOME:
738 self.moveCursorOnNewValidKey()
438 if event.Modifiers == wx.MOD_NONE:
739
439 self.moveCursorOnNewValidKey()
740 self.moveCursor(self.getCursorPos()-1)
741 if self.getCursorPos() < self.getCurrentPromptStart():
742 self.moveCursor(self.getCurrentPromptStart())
440 self.moveCursor(self.getCurrentPromptStart())
743 return True
441 return True
744
442 elif event.Modifiers == wx.MOD_SHIFT:
745 elif event.GetKeyCode() == wx.WXK_BACK:
443 self.moveCursorOnNewValidKey()
746 self.moveCursorOnNewValidKey()
444 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
747 if self.getCursorPos() > self.getCurrentPromptStart():
445 return True
748 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
446 else:
749 return True
447 return False
750
448
751 if skip:
449 elif event.GetKeyCode() == wx.WXK_LEFT:
752 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
450 if event.Modifiers == wx.MOD_NONE:
451 self.moveCursorOnNewValidKey()
452
453 self.moveCursor(self.getCursorPos()-1)
454 if self.getCursorPos() < self.getCurrentPromptStart():
455 self.moveCursor(self.getCurrentPromptStart())
456 return True
457
458 elif event.GetKeyCode() == wx.WXK_BACK:
753 self.moveCursorOnNewValidKey()
459 self.moveCursorOnNewValidKey()
754
460 if self.getCursorPos() > self.getCurrentPromptStart():
461 event.Skip()
462 return True
463
464 if skip:
465 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
466 self.moveCursorOnNewValidKey()
467
468 event.Skip()
469 return True
470 return False
471 else:
755 event.Skip()
472 event.Skip()
756 return True
473
757 return False
758
759 def OnUpdateUI(self, evt):
474 def OnUpdateUI(self, evt):
760 # check for matching braces
475 # check for matching braces
761 braceAtCaret = -1
476 braceAtCaret = -1
@@ -791,49 +506,90 b' class WxConsoleView(stc.StyledTextCtrl):'
791 #print pt
506 #print pt
792 #self.Refresh(False)
507 #self.Refresh(False)
793
508
794 class WxIPythonViewPanel(wx.Panel):
509 class IPShellWidget(wx.Panel):
795 '''
510 '''
796 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
511 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
797 If you want to port this to any other GUI toolkit, just replace the WxConsoleView
512 If you want to port this to any other GUI toolkit, just replace the
798 by YOURGUIConsoleView and make YOURGUIIPythonView derivate from whatever container you want.
513 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
799 I've choosed to derivate from a wx.Panel because it seems to be ore usefull
514 from whatever container you want. I've choosed to derivate from a wx.Panel
800 Any idea to make it more 'genric' welcomed.
515 because it seems to be more useful
516 Any idea to make it more 'generic' welcomed.
801 '''
517 '''
802 def __init__(self,parent,exit_handler=None,intro=None,background_color="BLACK"):
518
519 def __init__(self, parent, intro=None,
520 background_color="BLACK", add_button_handler=None,
521 wx_ip_shell=None, user_ns={},user_global_ns=None,
522 ):
803 '''
523 '''
804 Initialize.
524 Initialize.
805 Instanciate an IPython thread.
525 Instanciate an IPython thread.
806 Instanciate a WxConsoleView.
526 Instanciate a WxConsoleView.
807 Redirect I/O to console.
527 Redirect I/O to console.
808 '''
528 '''
809 wx.Panel.__init__(self,parent,-1)
529 wx.Panel.__init__(self,parent,wx.ID_ANY)
810
530
811 ### IPython thread instanciation ###
531 self.parent = parent
532 ### IPython non blocking shell instanciation ###
812 self.cout = StringIO()
533 self.cout = StringIO()
813 self.IP = IterableIPShell(cout=self.cout,cerr=self.cout,
534 self.add_button_handler = add_button_handler
814 exit_handler = exit_handler,
535
815 time_loop = 0.1)
536 if wx_ip_shell is not None:
816 self.IP.start()
537 self.IP = wx_ip_shell
817
538 else:
539 self.IP = WxNonBlockingIPShell(self,
540 cout = self.cout, cerr = self.cout,
541 ask_exit_handler = self.askExitCallback)
542
818 ### IPython wx console view instanciation ###
543 ### IPython wx console view instanciation ###
819 #If user didn't defined an intro text, we create one for him
544 #If user didn't defined an intro text, we create one for him
820 #If you really wnat an empty intrp just call wxIPythonViewPanel with intro=''
545 #If you really wnat an empty intro just call wxIPythonViewPanel
821 if intro == None:
546 #with intro=''
547 if intro is None:
822 welcome_text = "Welcome to WxIPython Shell.\n\n"
548 welcome_text = "Welcome to WxIPython Shell.\n\n"
823 welcome_text+= self.IP.getBanner()
549 welcome_text+= self.IP.getBanner()
824 welcome_text+= "!command -> Execute command in shell\n"
550 welcome_text+= "!command -> Execute command in shell\n"
825 welcome_text+= "TAB -> Autocompletion\n"
551 welcome_text+= "TAB -> Autocompletion\n"
552 else:
553 welcome_text = intro
826
554
827 self.text_ctrl = WxConsoleView(self,
555 self.text_ctrl = WxConsoleView(self,
828 self.IP.getPrompt(),
556 self.IP.getPrompt(),
829 intro=welcome_text,
557 intro=welcome_text,
830 background_color=background_color)
558 background_color=background_color)
831
832 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
833
559
560 self.cout.write = self.text_ctrl.asyncWrite
561
562 option_text = wx.StaticText(self, -1, "Options:")
563 self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
564 #self.completion_option.SetValue(False)
565 self.background_option = wx.CheckBox(self, -1, "White Background")
566 #self.background_option.SetValue(False)
567
568 self.options={'completion':{'value':'IPYTHON',
569 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
570 'setfunc':self.text_ctrl.setCompletionMethod},
571 'background_color':{'value':'BLACK',
572 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
573 'setfunc':self.text_ctrl.setBackgroundColor},
574 }
575 self.reloadOptions(self.options)
576
577 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
578 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
579 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
580
834 ### making the layout of the panel ###
581 ### making the layout of the panel ###
835 sizer = wx.BoxSizer(wx.VERTICAL)
582 sizer = wx.BoxSizer(wx.VERTICAL)
836 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
583 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
584 option_sizer = wx.BoxSizer(wx.HORIZONTAL)
585 sizer.Add(option_sizer, 0)
586 option_sizer.AddMany([(10, 20),
587 (option_text, 0, wx.ALIGN_CENTER_VERTICAL),
588 (5, 5),
589 (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
590 (8, 8),
591 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL)
592 ])
837 self.SetAutoLayout(True)
593 self.SetAutoLayout(True)
838 sizer.Fit(self)
594 sizer.Fit(self)
839 sizer.SetSizeHints(self)
595 sizer.SetSizeHints(self)
@@ -841,158 +597,151 b' class WxIPythonViewPanel(wx.Panel):'
841 #and we focus on the widget :)
597 #and we focus on the widget :)
842 self.SetFocus()
598 self.SetFocus()
843
599
844 ### below are the thread communication variable ###
600 #widget state management (for key handling different cases)
845 # the IPython thread is managed via unidirectional communication.
601 self.setCurrentState('IDLE')
846 # It's a thread slave that can't interact by itself with the GUI.
602 self.pager_state = 'DONE'
847 # When the GUI event loop is done runStateMachine() is called and the thread sate is then
603 self.raw_input_current_line = 0
848 # managed.
604
849
605 def askExitCallback(self, event):
850 #Initialize the state machine #kept for information
606 self.askExitHandler(event)
851 #self.states = ['IDLE',
607
852 # 'DO_EXECUTE_LINE',
608 #---------------------- IPython Thread Management ------------------------
853 # 'WAIT_END_OF_EXECUTION',
609 def stateDoExecuteLine(self):
854 # 'SHOW_DOC',
610 lines=self.text_ctrl.getCurrentLine()
855 # 'SHOW_PROMPT']
611 self.text_ctrl.write('\n')
856
612 lines_to_execute = lines.replace('\t',' '*4)
857 self.cur_state = 'IDLE'
613 lines_to_execute = lines_to_execute.replace('\r','')
858 self.pager_state = 'DONE'
614 self.IP.doExecute(lines_to_execute.encode('cp1252'))
859 #wx.CallAfter(self.runStateMachine)
615 self.updateHistoryTracker(lines)
616 self.setCurrentState('WAIT_END_OF_EXECUTION')
617
618 def evtStateExecuteDone(self,evt):
619 self.doc = self.IP.getDocText()
620 self.help = self.IP.getHelpText()
621 if self.doc:
622 self.pager_lines = self.doc[7:].split('\n')
623 self.pager_state = 'INIT'
624 self.setCurrentState('SHOW_DOC')
625 self.pager(self.doc)
626 elif self.help:
627 self.pager_lines = self.help.split('\n')
628 self.pager_state = 'INIT'
629 self.setCurrentState('SHOW_DOC')
630 self.pager(self.help)
631 else:
632 self.stateShowPrompt()
633
634 def stateShowPrompt(self):
635 self.setCurrentState('SHOW_PROMPT')
636 self.text_ctrl.setPrompt(self.IP.getPrompt())
637 self.text_ctrl.setIndentation(self.IP.getIndentation())
638 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
639 self.text_ctrl.showPrompt()
640 self.IP.initHistoryIndex()
641 self.setCurrentState('IDLE')
642
643 def setCurrentState(self, state):
644 self.cur_state = state
645 self.updateStatusTracker(self.cur_state)
860
646
861 # This creates a new Event class and a EVT binder function
647 def pager(self,text):
862 (self.AskExitEvent, EVT_ASK_EXIT) = wx.lib.newevent.NewEvent()
863
648
864 self.Bind(wx.EVT_IDLE, self.runStateMachine)
649 if self.pager_state == 'INIT':
865 self.Bind(EVT_ASK_EXIT, exit_handler)
650 #print >>sys.__stdout__,"PAGER state:",self.pager_state
866
651 self.pager_nb_lines = len(self.pager_lines)
867 def __del__(self):
652 self.pager_index = 0
868 self.IP.shutdown()
653 self.pager_do_remove = False
869 self.IP.join()
654 self.text_ctrl.write('\n')
870 WxConsoleView.__del__()
655 self.pager_state = 'PROCESS_LINES'
871
656
872 #---------------------------- IPython Thread Management ---------------------------------------
657 if self.pager_state == 'PROCESS_LINES':
873 def runStateMachine(self,event):
658 #print >>sys.__stdout__,"PAGER state:",self.pager_state
874 #print >>self.sys_stdout,"state:",self.cur_state
659 if self.pager_do_remove == True:
875 self.updateStatusTracker(self.cur_state)
660 self.text_ctrl.removeCurrentLine()
876
661 self.pager_do_remove = False
877 if self.cur_state == 'DO_EXECUTE_LINE':
662
878 #print >>self.sys_stdout,"command:",self.getCurrentLine()
663 if self.pager_nb_lines > 10:
879 self.IP.doExecute(self.text_ctrl.getCurrentLine().replace('\t',' '*4))
664 #print >>sys.__stdout__,"PAGER processing 10 lines"
880 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
665 if self.pager_index > 0:
881 self.cur_state = 'WAIT_END_OF_EXECUTION'
666 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
882
667 else:
883 if self.cur_state == 'WAIT_END_OF_EXECUTION':
668 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
884 if self.IP.isExecuteDone():
669
885 self.doc = self.IP.getDocText()
670 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
886 if self.IP.getAskExit():
671 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
887 evt = self.AskExitEvent()
672 self.pager_index += 10
888 wx.PostEvent(self, evt)
673 self.pager_nb_lines -= 10
889 self.IP.clearAskExit()
674 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
890 if self.doc:
675 self.pager_do_remove = True
891 self.pager_state = 'INIT'
676 self.pager_state = 'WAITING'
892 self.cur_state = 'SHOW_DOC'
677 return
893 else:
678 else:
894 self.cur_state = 'SHOW_PROMPT'
679 #print >>sys.__stdout__,"PAGER processing last lines"
895
680 if self.pager_nb_lines > 0:
896 if self.cur_state == 'SHOW_PROMPT':
681 if self.pager_index > 0:
897 self.text_ctrl.setPrompt(self.IP.getPrompt())
682 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
898 self.text_ctrl.setIndentation(self.IP.getIndentation())
683 else:
899 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
684 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
900 rv = self.cout.getvalue()
685
901 if rv: rv = rv.strip('\n')
686 self.pager_index += 1
902 self.text_ctrl.showReturned(rv)
903 self.cout.truncate(0)
904 self.IP.initHistoryIndex()
905 self.cur_state = 'IDLE'
906
907 if self.cur_state == 'SHOW_DOC':
908 self.pager(self.doc)
909 if self.pager_state == 'DONE':
910 self.cur_state = 'SHOW_PROMPT'
911
912 event.Skip()
913
914 #---------------------------- IPython pager ---------------------------------------
915 def pager(self,text):#,start=0,screen_lines=0,pager_cmd = None):
916 if self.pager_state == 'WAITING':
917 #print >>self.sys_stdout,"PAGER waiting"
918 return
919
920 if self.pager_state == 'INIT':
921 #print >>self.sys_stdout,"PAGER state:",self.pager_state
922 self.pager_lines = text[7:].split('\n')
923 self.pager_nb_lines = len(self.pager_lines)
924 self.pager_index = 0
925 self.pager_do_remove = False
926 self.text_ctrl.write('\n')
927 self.pager_state = 'PROCESS_LINES'
928
929 if self.pager_state == 'PROCESS_LINES':
930 #print >>self.sys_stdout,"PAGER state:",self.pager_state
931 if self.pager_do_remove == True:
932 self.text_ctrl.removeCurrentLine()
933 self.pager_do_remove = False
934
935 if self.pager_nb_lines > 10:
936 #print >>self.sys_stdout,"PAGER processing 10 lines"
937 if self.pager_index > 0:
938 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
939 else:
940 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
941
942 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
943 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
944 self.pager_index += 10
945 self.pager_nb_lines -= 10
946 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
947 self.pager_do_remove = True
948 self.pager_state = 'WAITING'
949 return
950 else:
951 #print >>self.sys_stdout,"PAGER processing last lines"
952 if self.pager_nb_lines > 0:
953 if self.pager_index > 0:
954 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
955 else:
956 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
957
958 self.pager_index += 1
959 self.pager_nb_lines -= 1
687 self.pager_nb_lines -= 1
960 if self.pager_nb_lines > 0:
688 if self.pager_nb_lines > 0:
961 for line in self.pager_lines[self.pager_index:]:
689 for line in self.pager_lines[self.pager_index:]:
962 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
690 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
963 self.pager_nb_lines = 0
691 self.pager_nb_lines = 0
964 self.pager_state = 'DONE'
692 self.pager_state = 'DONE'
693 self.stateShowPrompt()
965
694
966 #---------------------------- Key Handler --------------------------------------------
695 #------------------------ Key Handler ------------------------------------
967 def keyPress(self, event):
696 def keyPress(self, event):
968 '''
697 '''
969 Key press callback with plenty of shell goodness, like history,
698 Key press callback with plenty of shell goodness, like history,
970 autocompletions, etc.
699 autocompletions, etc.
971 '''
700 '''
972
973 if event.GetKeyCode() == ord('C'):
701 if event.GetKeyCode() == ord('C'):
974 if event.Modifiers == wx.MOD_CONTROL:
702 if event.Modifiers == wx.MOD_CONTROL or event.Modifiers == wx.MOD_ALT:
975 if self.cur_state == 'WAIT_END_OF_EXECUTION':
703 if self.cur_state == 'WAIT_END_OF_EXECUTION':
976 #we raise an exception inside the IPython thread container
704 #we raise an exception inside the IPython thread container
977 self.IP.raise_exc(KeyboardInterrupt)
705 self.IP.ce.raise_exc(KeyboardInterrupt)
978 return
706 return
979
707
708 #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
709 #mode if AutoComp has been set as inactive
710 if self.cur_state == 'COMPLETING':
711 if not self.text_ctrl.AutoCompActive():
712 self.cur_state = 'IDLE'
713 else:
714 event.Skip()
715
980 if event.KeyCode == wx.WXK_RETURN:
716 if event.KeyCode == wx.WXK_RETURN:
981 if self.cur_state == 'IDLE':
717 if self.cur_state == 'IDLE':
982 #we change the state ot the state machine
718 #we change the state ot the state machine
983 self.cur_state = 'DO_EXECUTE_LINE'
719 self.setCurrentState('DO_EXECUTE_LINE')
720 self.stateDoExecuteLine()
984 return
721 return
722
985 if self.pager_state == 'WAITING':
723 if self.pager_state == 'WAITING':
986 self.pager_state = 'PROCESS_LINES'
724 self.pager_state = 'PROCESS_LINES'
725 self.pager(self.doc)
987 return
726 return
988
727
728 if self.cur_state == 'WAITING_USER_INPUT':
729 line=self.text_ctrl.getCurrentLine()
730 self.text_ctrl.write('\n')
731 self.setCurrentState('WAIT_END_OF_EXECUTION')
732 return
733
989 if event.GetKeyCode() in [ord('q'),ord('Q')]:
734 if event.GetKeyCode() in [ord('q'),ord('Q')]:
990 if self.pager_state == 'WAITING':
735 if self.pager_state == 'WAITING':
991 self.pager_state = 'DONE'
736 self.pager_state = 'DONE'
737 self.text_ctrl.write('\n')
738 self.stateShowPrompt()
992 return
739 return
740
741 if self.cur_state == 'WAITING_USER_INPUT':
742 event.Skip()
993
743
994 #scroll_position = self.text_ctrl.GetScrollPos(wx.VERTICAL)
744 if self.cur_state == 'IDLE':
995 if self.cur_state == 'IDLE':
996 if event.KeyCode == wx.WXK_UP:
745 if event.KeyCode == wx.WXK_UP:
997 history = self.IP.historyBack()
746 history = self.IP.historyBack()
998 self.text_ctrl.writeHistory(history)
747 self.text_ctrl.writeHistory(history)
@@ -1008,19 +757,68 b' class WxIPythonViewPanel(wx.Panel):'
1008 return
757 return
1009 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
758 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
1010 if len(possibilities) > 1:
759 if len(possibilities) > 1:
1011 cur_slice = self.text_ctrl.getCurrentLine()
760 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
1012 self.text_ctrl.write('\n')
761 cur_slice = self.text_ctrl.getCurrentLine()
1013 self.text_ctrl.writeCompletion(possibilities)
762 self.text_ctrl.write('\n')
1014 self.text_ctrl.write('\n')
763 self.text_ctrl.writeCompletion(possibilities)
1015
764 self.text_ctrl.write('\n')
1016 self.text_ctrl.showPrompt()
765
1017 self.text_ctrl.write(cur_slice)
766 self.text_ctrl.showPrompt()
1018 self.text_ctrl.changeLine(completed or cur_slice)
767 self.text_ctrl.write(cur_slice)
1019
768 self.text_ctrl.changeLine(completed or cur_slice)
769 else:
770 self.cur_state = 'COMPLETING'
771 self.text_ctrl.writeCompletion(possibilities)
772 else:
773 self.text_ctrl.changeLine(completed or cur_slice)
1020 return
774 return
1021 event.Skip()
775 event.Skip()
1022
776
1023 #---------------------------- Hook Section --------------------------------------------
777 #------------------------ Option Section ---------------------------------
778 def evtCheckOptionCompletion(self, event):
779 if event.IsChecked():
780 self.options['completion']['value']='STC'
781 else:
782 self.options['completion']['value']='IPYTHON'
783 self.text_ctrl.setCompletionMethod(self.options['completion']['value'])
784 self.updateOptionTracker('completion',
785 self.options['completion']['value'])
786 self.text_ctrl.SetFocus()
787
788 def evtCheckOptionBackgroundColor(self, event):
789 if event.IsChecked():
790 self.options['background_color']['value']='WHITE'
791 else:
792 self.options['background_color']['value']='BLACK'
793 self.text_ctrl.setBackgroundColor(self.options['background_color']['value'])
794 self.updateOptionTracker('background_color',
795 self.options['background_color']['value'])
796 self.text_ctrl.SetFocus()
797
798 def getOptions(self):
799 return self.options
800
801 def reloadOptions(self,options):
802 self.options = options
803 for key in self.options.keys():
804 value = self.options[key]['value']
805 self.options[key]['checkbox'].SetValue(self.options[key][value])
806 self.options[key]['setfunc'](value)
807
808
809 #------------------------ Hook Section -----------------------------------
810 def updateOptionTracker(self,name,value):
811 '''
812 Default history tracker (does nothing)
813 '''
814 pass
815
816 def setOptionTrackerHook(self,func):
817 '''
818 Define a new history tracker
819 '''
820 self.updateOptionTracker = func
821
1024 def updateHistoryTracker(self,command_line):
822 def updateHistoryTracker(self,command_line):
1025 '''
823 '''
1026 Default history tracker (does nothing)
824 Default history tracker (does nothing)
@@ -1032,6 +830,7 b' class WxIPythonViewPanel(wx.Panel):'
1032 Define a new history tracker
830 Define a new history tracker
1033 '''
831 '''
1034 self.updateHistoryTracker = func
832 self.updateHistoryTracker = func
833
1035 def updateStatusTracker(self,status):
834 def updateStatusTracker(self,status):
1036 '''
835 '''
1037 Default status tracker (does nothing)
836 Default status tracker (does nothing)
@@ -1043,4 +842,36 b' class WxIPythonViewPanel(wx.Panel):'
1043 Define a new status tracker
842 Define a new status tracker
1044 '''
843 '''
1045 self.updateStatusTracker = func
844 self.updateStatusTracker = func
1046
845
846 def askExitHandler(self, event):
847 '''
848 Default exit handler
849 '''
850 self.text_ctrl.write('\nExit callback has not been set.')
851
852 def setAskExitHandler(self, func):
853 '''
854 Define an exit handler
855 '''
856 self.askExitHandler = func
857
858 if __name__ == '__main__':
859 # Some simple code to test the shell widget.
860 class MainWindow(wx.Frame):
861 def __init__(self, parent, id, title):
862 wx.Frame.__init__(self, parent, id, title, size=(300,250))
863 self._sizer = wx.BoxSizer(wx.VERTICAL)
864 self.shell = IPShellWidget(self)
865 self._sizer.Add(self.shell, 1, wx.EXPAND)
866 self.SetSizer(self._sizer)
867 self.SetAutoLayout(1)
868 self.Show(True)
869
870 app = wx.PySimpleApp()
871 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
872 frame.SetSize((780, 460))
873 shell = frame.shell
874
875 app.MainLoop()
876
877
@@ -1,45 +1,50 b''
1 import threading
1 """
2 import inspect
2 Thread subclass that can deal with asynchronously function calls via
3 import ctypes
3 raise_exc.
4
4 """
5
5
6 def _async_raise(tid, exctype):
6 import threading
7 """raises the exception, performs cleanup if needed"""
7 import inspect
8 if not inspect.isclass(exctype):
8 import ctypes
9 raise TypeError("Only types can be raised (not instances)")
9
10 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
10
11 if res == 0:
11 def _async_raise(tid, exctype):
12 raise ValueError("invalid thread id")
12 """raises the exception, performs cleanup if needed"""
13 elif res != 1:
13 if not inspect.isclass(exctype):
14 # """if it returns a number greater than one, you're in trouble,
14 raise TypeError("Only types can be raised (not instances)")
15 # and you should call it again with exc=NULL to revert the effect"""
15 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
16 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
16 if res == 0:
17 raise SystemError("PyThreadState_SetAsyncExc failed")
17 raise ValueError("invalid thread id")
18
18 elif res != 1:
19
19 # """if it returns a number greater than one, you're in trouble,
20 class Thread(threading.Thread):
20 # and you should call it again with exc=NULL to revert the effect"""
21 def _get_my_tid(self):
21 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
22 """determines this (self's) thread id"""
22 raise SystemError("PyThreadState_SetAsyncExc failed")
23 if not self.isAlive():
23
24 raise threading.ThreadError("the thread is not active")
24
25
25 class ThreadEx(threading.Thread):
26 # do we have it cached?
26 def _get_my_tid(self):
27 if hasattr(self, "_thread_id"):
27 """determines this (self's) thread id"""
28 return self._thread_id
28 if not self.isAlive():
29
29 raise threading.ThreadError("the thread is not active")
30 # no, look for it in the _active dict
30
31 for tid, tobj in threading._active.items():
31 # do we have it cached?
32 if tobj is self:
32 if hasattr(self, "_thread_id"):
33 self._thread_id = tid
33 return self._thread_id
34 return tid
34
35
35 # no, look for it in the _active dict
36 raise AssertionError("could not determine the thread's id")
36 for tid, tobj in threading._active.items():
37
37 if tobj is self:
38 def raise_exc(self, exctype):
38 self._thread_id = tid
39 """raises the given exception type in the context of this thread"""
39 return tid
40 _async_raise(self._get_my_tid(), exctype)
40
41
41 raise AssertionError("could not determine the thread's id")
42 def kill(self):
42
43 """raises SystemExit in the context of the given thread, which should
43 def raise_exc(self, exctype):
44 cause the thread to exit silently (unless caught)"""
44 """raises the given exception type in the context of this thread"""
45 self.raise_exc(SystemExit)
45 _async_raise(self._get_my_tid(), exctype)
46
47 def kill(self):
48 """raises SystemExit in the context of the given thread, which should
49 cause the thread to exit silently (unless caught)"""
50 self.raise_exc(SystemExit)
@@ -2,11 +2,13 b''
2 # -*- coding: iso-8859-15 -*-
2 # -*- coding: iso-8859-15 -*-
3
3
4 import wx.aui
4 import wx.aui
5 import wx.py
5
6 #used for about dialog
6 from wx.lib.wordwrap import wordwrap
7 from wx.lib.wordwrap import wordwrap
7
8
8 from ipython_view import *
9 #used for ipython GUI objects
9 from ipython_history import *
10 from IPython.gui.wx.ipython_view import IPShellWidget
11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
10
12
11 __version__ = 0.8
13 __version__ = 0.8
12 __author__ = "Laurent Dufrechou"
14 __author__ = "Laurent Dufrechou"
@@ -20,7 +22,8 b' __license__ = "BSD"'
20 class MyFrame(wx.Frame):
22 class MyFrame(wx.Frame):
21 """Creating one main frame for our
23 """Creating one main frame for our
22 application with movables windows"""
24 application with movables windows"""
23 def __init__(self, parent=None, id=-1, title="WxIPython", pos=wx.DefaultPosition,
25 def __init__(self, parent=None, id=-1, title="WxIPython",
26 pos=wx.DefaultPosition,
24 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
27 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
25 wx.Frame.__init__(self, parent, id, title, pos, size, style)
28 wx.Frame.__init__(self, parent, id, title, pos, size, style)
26 self._mgr = wx.aui.AuiManager()
29 self._mgr = wx.aui.AuiManager()
@@ -30,15 +33,18 b' class MyFrame(wx.Frame):'
30
33
31 #create differents panels and make them persistant
34 #create differents panels and make them persistant
32 self.history_panel = IPythonHistoryPanel(self)
35 self.history_panel = IPythonHistoryPanel(self)
36
37 self.history_panel.setOptionTrackerHook(self.optionSave)
33
38
34 self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
39 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
35 background_color = "BLACK")
40 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
36
41
37 #self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
38 # background_color = "WHITE")
39
40 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
42 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
41 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
43 self.ipython_panel.setStatusTrackerHook(self.updateStatus)
44 self.ipython_panel.setAskExitHandler(self.OnExitDlg)
45 self.ipython_panel.setOptionTrackerHook(self.optionSave)
46
47 self.optionLoad()
42
48
43 self.statusbar = self.createStatus()
49 self.statusbar = self.createStatus()
44 self.createMenu()
50 self.createMenu()
@@ -48,13 +54,11 b' class MyFrame(wx.Frame):'
48 # main panels
54 # main panels
49 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
55 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
50 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
56 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
51
57
52 # now we specify some panel characteristics
58 # now we specify some panel characteristics
53 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
59 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
54 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
60 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
55 self._mgr.GetPane(self.history_panel).MinSize((200,400));
61 self._mgr.GetPane(self.history_panel).MinSize((200,400));
56
57
58
62
59 # tell the manager to "commit" all the changes just made
63 # tell the manager to "commit" all the changes just made
60 self._mgr.Update()
64 self._mgr.Update()
@@ -66,7 +70,7 b' class MyFrame(wx.Frame):'
66 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
70 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
67 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
71 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
68 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
72 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
69
73
70 warn_text = 'Hello from IPython and wxPython.\n'
74 warn_text = 'Hello from IPython and wxPython.\n'
71 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
75 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
72 warn_text +='It does NOT emulate currently all the IPython functions.\n'
76 warn_text +='It does NOT emulate currently all the IPython functions.\n'
@@ -78,7 +82,41 b' class MyFrame(wx.Frame):'
78 )
82 )
79 dlg.ShowModal()
83 dlg.ShowModal()
80 dlg.Destroy()
84 dlg.Destroy()
81
85
86 def optionSave(self, name, value):
87 opt = open('options.conf','w')
88
89 try:
90 options_ipython_panel = self.ipython_panel.getOptions()
91 options_history_panel = self.history_panel.getOptions()
92
93 for key in options_ipython_panel.keys():
94 opt.write(key + '=' + options_ipython_panel[key]['value']+'\n')
95 for key in options_history_panel.keys():
96 opt.write(key + '=' + options_history_panel[key]['value']+'\n')
97 finally:
98 opt.close()
99
100 def optionLoad(self):
101 opt = open('options.conf','r')
102 lines = opt.readlines()
103 opt.close()
104
105 options_ipython_panel = self.ipython_panel.getOptions()
106 options_history_panel = self.history_panel.getOptions()
107
108 for line in lines:
109 key = line.split('=')[0]
110 value = line.split('=')[1].replace('\n','').replace('\r','')
111 if key in options_ipython_panel.keys():
112 options_ipython_panel[key]['value'] = value
113 elif key in options_history_panel.keys():
114 options_history_panel[key]['value'] = value
115 else:
116 print >>sys.__stdout__,"Warning: key ",key,"not found in widget options. Check Options.conf"
117 self.ipython_panel.reloadOptions(options_ipython_panel)
118 self.history_panel.reloadOptions(options_history_panel)
119
82 def createMenu(self):
120 def createMenu(self):
83 """local method used to create one menu bar"""
121 """local method used to create one menu bar"""
84
122
@@ -121,6 +159,7 b' class MyFrame(wx.Frame):'
121 states = {'IDLE':'Idle',
159 states = {'IDLE':'Idle',
122 'DO_EXECUTE_LINE':'Send command',
160 'DO_EXECUTE_LINE':'Send command',
123 'WAIT_END_OF_EXECUTION':'Running command',
161 'WAIT_END_OF_EXECUTION':'Running command',
162 'WAITING_USER_INPUT':'Waiting user input',
124 'SHOW_DOC':'Showing doc',
163 'SHOW_DOC':'Showing doc',
125 'SHOW_PROMPT':'Showing prompt'}
164 'SHOW_PROMPT':'Showing prompt'}
126 self.statusbar.SetStatusText(states[text], 0)
165 self.statusbar.SetStatusText(states[text], 0)
@@ -56,7 +56,7 b' from pprint import PrettyPrinter'
56 __all__ = ['editor', 'fix_error_editor', 'result_display',
56 __all__ = ['editor', 'fix_error_editor', 'result_display',
57 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
57 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
58 'generate_prompt', 'generate_output_prompt','shell_hook',
58 'generate_prompt', 'generate_output_prompt','shell_hook',
59 'show_in_pager']
59 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook']
60
60
61 pformat = PrettyPrinter().pformat
61 pformat = PrettyPrinter().pformat
62
62
@@ -227,11 +227,17 b' def show_in_pager(self,s):'
227 # raising TryNext here will use the default paging functionality
227 # raising TryNext here will use the default paging functionality
228 raise ipapi.TryNext
228 raise ipapi.TryNext
229
229
230 def pre_command_hook(self,cmd):
230 def pre_prompt_hook(self):
231 """" Executed before starting to execute a command """
231 """ Run before displaying the next prompt
232
233 Use this e.g. to display output from asynchronous operations (in order
234 to not mess up text entry)
235 """
236
232 return None
237 return None
233
238
234 def post_command_hook(self,cmd):
239 def pre_runcode_hook(self):
235 """ Executed after executing a command """
240 """ Executed before running the (prefiltered) code in IPython """
241 return None
236
242
237
243
@@ -273,15 +273,27 b' class IPApi:'
273 """
273 """
274 res = []
274 res = []
275 lines = script.splitlines()
275 lines = script.splitlines()
276
276 level = 0
277 level = 0
277 for l in lines:
278 for l in lines:
278 stripped = l.lstrip()
279 lstripped = l.lstrip()
279 if not l.strip():
280 stripped = l.strip()
281 if not stripped:
280 continue
282 continue
281 newlevel = len(l) - len(stripped)
283 newlevel = len(l) - len(lstripped)
282 if level > 0 and newlevel == 0:
284 def is_secondary_block_start(s):
285 if not s.endswith(':'):
286 return False
287 if (s.startswith('elif') or
288 s.startswith('else') or
289 s.startswith('except') or
290 s.startswith('finally')):
291 return True
292
293 if level > 0 and newlevel == 0 and not is_secondary_block_start(stripped):
283 # add empty line
294 # add empty line
284 res.append('')
295 res.append('')
296
285 res.append(l)
297 res.append(l)
286 level = newlevel
298 level = newlevel
287 return '\n'.join(res) + '\n'
299 return '\n'.join(res) + '\n'
@@ -291,7 +303,7 b' class IPApi:'
291 else:
303 else:
292 script = '\n'.join(lines)
304 script = '\n'.join(lines)
293 clean=cleanup_ipy_script(script)
305 clean=cleanup_ipy_script(script)
294
306 # print "_ip.runlines() script:\n",clean #dbg
295 self.IP.runlines(clean)
307 self.IP.runlines(clean)
296 def to_user_ns(self,vars, interactive = True):
308 def to_user_ns(self,vars, interactive = True):
297 """Inject a group of variables into the IPython user namespace.
309 """Inject a group of variables into the IPython user namespace.
@@ -533,7 +545,7 b' class DebugTools:'
533 if name in self.hotnames:
545 if name in self.hotnames:
534 self.debug_stack( "HotName '%s' caught" % name)
546 self.debug_stack( "HotName '%s' caught" % name)
535
547
536 def launch_new_instance(user_ns = None):
548 def launch_new_instance(user_ns = None,shellclass = None):
537 """ Make and start a new ipython instance.
549 """ Make and start a new ipython instance.
538
550
539 This can be called even without having an already initialized
551 This can be called even without having an already initialized
@@ -542,7 +554,7 b' def launch_new_instance(user_ns = None):'
542 This is also used as the egg entry point for the 'ipython' script.
554 This is also used as the egg entry point for the 'ipython' script.
543
555
544 """
556 """
545 ses = make_session(user_ns)
557 ses = make_session(user_ns,shellclass)
546 ses.mainloop()
558 ses.mainloop()
547
559
548
560
@@ -578,7 +590,7 b' def make_user_global_ns(ns = None):'
578 return ns
590 return ns
579
591
580
592
581 def make_session(user_ns = None):
593 def make_session(user_ns = None, shellclass = None):
582 """Makes, but does not launch an IPython session.
594 """Makes, but does not launch an IPython session.
583
595
584 Later on you can call obj.mainloop() on the returned object.
596 Later on you can call obj.mainloop() on the returned object.
@@ -591,6 +603,6 b' def make_session(user_ns = None):'
591 WARNING: This should *not* be run when a session exists already."""
603 WARNING: This should *not* be run when a session exists already."""
592
604
593 import IPython.Shell
605 import IPython.Shell
594 return IPython.Shell.start(user_ns)
606 if shellclass is None:
595
607 return IPython.Shell.start(user_ns)
596
608 return shellclass(user_ns = user_ns)
@@ -6,7 +6,6 b' Requires Python 2.3 or newer.'
6
6
7 This file contains all the classes and helper functions specific to IPython.
7 This file contains all the classes and helper functions specific to IPython.
8
8
9 $Id: iplib.py 3005 2008-02-01 16:43:34Z vivainio $
10 """
9 """
11
10
12 #*****************************************************************************
11 #*****************************************************************************
@@ -55,6 +54,8 b' import sys'
55 import tempfile
54 import tempfile
56 import traceback
55 import traceback
57 import types
56 import types
57 import warnings
58 warnings.filterwarnings('ignore', r'.*sets module*')
58 from sets import Set
59 from sets import Set
59 from pprint import pprint, pformat
60 from pprint import pprint, pformat
60
61
@@ -377,7 +378,10 b' class InteractiveShell(object,Magic):'
377 # Get system encoding at startup time. Certain terminals (like Emacs
378 # Get system encoding at startup time. Certain terminals (like Emacs
378 # under Win32 have it set to None, and we need to have a known valid
379 # under Win32 have it set to None, and we need to have a known valid
379 # encoding to use in the raw_input() method
380 # encoding to use in the raw_input() method
380 self.stdin_encoding = sys.stdin.encoding or 'ascii'
381 try:
382 self.stdin_encoding = sys.stdin.encoding or 'ascii'
383 except AttributeError:
384 self.stdin_encoding = 'ascii'
381
385
382 # dict of things NOT to alias (keywords, builtins and some magics)
386 # dict of things NOT to alias (keywords, builtins and some magics)
383 no_alias = {}
387 no_alias = {}
@@ -698,7 +702,10 b' class InteractiveShell(object,Magic):'
698
702
699 # Do a proper resetting of doctest, including the necessary displayhook
703 # Do a proper resetting of doctest, including the necessary displayhook
700 # monkeypatching
704 # monkeypatching
701 doctest_reload()
705 try:
706 doctest_reload()
707 except ImportError:
708 warn("doctest module does not exist.")
702
709
703 # Set user colors (don't do it in the constructor above so that it
710 # Set user colors (don't do it in the constructor above so that it
704 # doesn't crash if colors option is invalid)
711 # doesn't crash if colors option is invalid)
@@ -1266,8 +1273,12 b' want to merge them back into the new files.""" % locals()'
1266 """Reload the input history from disk file."""
1273 """Reload the input history from disk file."""
1267
1274
1268 if self.has_readline:
1275 if self.has_readline:
1269 self.readline.clear_history()
1276 try:
1270 self.readline.read_history_file(self.shell.histfile)
1277 self.readline.clear_history()
1278 self.readline.read_history_file(self.shell.histfile)
1279 except AttributeError:
1280 pass
1281
1271
1282
1272 def history_saving_wrapper(self, func):
1283 def history_saving_wrapper(self, func):
1273 """ Wrap func for readline history saving
1284 """ Wrap func for readline history saving
@@ -1744,6 +1755,7 b' want to merge them back into the new files.""" % locals()'
1744 # exit_now is set by a call to %Exit or %Quit
1755 # exit_now is set by a call to %Exit or %Quit
1745
1756
1746 while not self.exit_now:
1757 while not self.exit_now:
1758 self.hooks.pre_prompt_hook()
1747 if more:
1759 if more:
1748 try:
1760 try:
1749 prompt = self.hooks.generate_prompt(True)
1761 prompt = self.hooks.generate_prompt(True)
@@ -2009,7 +2021,7 b' want to merge them back into the new files.""" % locals()'
2009
2021
2010 try:
2022 try:
2011 code = self.compile(source,filename,symbol)
2023 code = self.compile(source,filename,symbol)
2012 except (OverflowError, SyntaxError, ValueError):
2024 except (OverflowError, SyntaxError, ValueError, TypeError):
2013 # Case 1
2025 # Case 1
2014 self.showsyntaxerror(filename)
2026 self.showsyntaxerror(filename)
2015 return None
2027 return None
@@ -2053,6 +2065,7 b' want to merge them back into the new files.""" % locals()'
2053 outflag = 1 # happens in more places, so it's easier as default
2065 outflag = 1 # happens in more places, so it's easier as default
2054 try:
2066 try:
2055 try:
2067 try:
2068 self.hooks.pre_runcode_hook()
2056 # Embedded instances require separate global/local namespaces
2069 # Embedded instances require separate global/local namespaces
2057 # so they can see both the surrounding (local) namespace and
2070 # so they can see both the surrounding (local) namespace and
2058 # the module-level globals when called inside another function.
2071 # the module-level globals when called inside another function.
@@ -58,6 +58,14 b' from IPython.iplib import InteractiveShell'
58 from IPython.usage import cmd_line_usage,interactive_usage
58 from IPython.usage import cmd_line_usage,interactive_usage
59 from IPython.genutils import *
59 from IPython.genutils import *
60
60
61 def force_import(modname):
62 if modname in sys.modules:
63 print "reload",modname
64 reload(sys.modules[modname])
65 else:
66 __import__(modname)
67
68
61 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
62 def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,
70 def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,
63 rc_override=None,shell_class=InteractiveShell,
71 rc_override=None,shell_class=InteractiveShell,
@@ -95,9 +103,12 b' def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,'
95 embedded=embedded,**kw)
103 embedded=embedded,**kw)
96
104
97 # Put 'help' in the user namespace
105 # Put 'help' in the user namespace
98 from site import _Helper
106 try:
107 from site import _Helper
108 IP.user_ns['help'] = _Helper()
109 except ImportError:
110 warn('help() not available - check site.py')
99 IP.user_config_ns = {}
111 IP.user_config_ns = {}
100 IP.user_ns['help'] = _Helper()
101
112
102
113
103 if DEVDEBUG:
114 if DEVDEBUG:
@@ -176,10 +187,10 b" object? -> Details about 'object'. ?object also works, ?? prints more."
176
187
177 # Options that can *only* appear at the cmd line (not in rcfiles).
188 # Options that can *only* appear at the cmd line (not in rcfiles).
178
189
179 # The "ignore" option is a kludge so that Emacs buffers don't crash, since
180 # the 'C-c !' command in emacs automatically appends a -i option at the end.
181 cmdline_only = ('help interact|i ipythondir=s Version upgrade '
190 cmdline_only = ('help interact|i ipythondir=s Version upgrade '
182 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk!')
191 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk! '
192 # 'twisted!' # disabled for now.
193 )
183
194
184 # Build the actual name list to be used by DPyGetOpt
195 # Build the actual name list to be used by DPyGetOpt
185 opts_names = qw(cmdline_opts) + qw(cmdline_only)
196 opts_names = qw(cmdline_opts) + qw(cmdline_only)
@@ -203,7 +214,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
203 editor = '0',
214 editor = '0',
204 gthread = 0,
215 gthread = 0,
205 help = 0,
216 help = 0,
206 interact = 1,
217 interact = 0,
207 ipythondir = ipythondir_def,
218 ipythondir = ipythondir_def,
208 log = 0,
219 log = 0,
209 logfile = '',
220 logfile = '',
@@ -237,6 +248,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
237 system_verbose = 0,
248 system_verbose = 0,
238 term_title = 1,
249 term_title = 1,
239 tk = 0,
250 tk = 0,
251 #twisted= 0, # disabled for now
240 upgrade = 0,
252 upgrade = 0,
241 Version = 0,
253 Version = 0,
242 wildcards_case_sensitive = 1,
254 wildcards_case_sensitive = 1,
@@ -633,15 +645,17 b" object? -> Details about 'object'. ?object also works, ?? prints more."
633 if opts_all.profile and not profile_handled_by_legacy:
645 if opts_all.profile and not profile_handled_by_legacy:
634 profmodname = 'ipy_profile_' + opts_all.profile
646 profmodname = 'ipy_profile_' + opts_all.profile
635 try:
647 try:
636 __import__(profmodname)
648
649 force_import(profmodname)
637 except:
650 except:
638 IP.InteractiveTB()
651 IP.InteractiveTB()
639 print "Error importing",profmodname,"- perhaps you should run %upgrade?"
652 print "Error importing",profmodname,"- perhaps you should run %upgrade?"
640 import_fail_info(profmodname)
653 import_fail_info(profmodname)
641 else:
654 else:
642 import ipy_profile_none
655 force_import('ipy_profile_none')
643 try:
656 try:
644 import ipy_user_conf
657
658 force_import('ipy_user_conf')
645
659
646 except:
660 except:
647 conf = opts_all.ipythondir + "/ipy_user_conf.py"
661 conf = opts_all.ipythondir + "/ipy_user_conf.py"
@@ -23,12 +23,17 b' __license__ = Release.license'
23 import sys
23 import sys
24 import os
24 import os
25
25
26 ignore_termtitle = False
26
27
27 def _dummy_op(*a, **b):
28 def _dummy_op(*a, **b):
28 """ A no-op function """
29 """ A no-op function """
29
30
30 def _set_term_title_xterm(title):
31 def _set_term_title_xterm(title):
31 """ Change virtual terminal title in xterm-workalikes """
32 """ Change virtual terminal title in xterm-workalikes """
33
34 if ignore_termtitle:
35 return
36
32 sys.stdout.write('\033]%d;%s\007' % (0,title))
37 sys.stdout.write('\033]%d;%s\007' % (0,title))
33
38
34
39
@@ -37,4 +42,6 b" if os.environ.get('TERM','') == 'xterm':"
37 else:
42 else:
38 set_term_title = _dummy_op
43 set_term_title = _dummy_op
39
44
40
45 def freeze_term_title():
46 global ignore_termtitle
47 ignore_termtitle = True
@@ -50,4 +50,7 b' def set_term_title(title):'
50 return
50 return
51 _set_term_title(title)
51 _set_term_title(title)
52
52
53 def freeze_term_title():
54 global ignore_termtitle
55 ignore_termtitle = 1
53
56
@@ -377,8 +377,8 b' class ListTB(TBTools):'
377
377
378 def __call__(self, etype, value, elist):
378 def __call__(self, etype, value, elist):
379 Term.cout.flush()
379 Term.cout.flush()
380 Term.cerr.flush()
381 print >> Term.cerr, self.text(etype,value,elist)
380 print >> Term.cerr, self.text(etype,value,elist)
381 Term.cerr.flush()
382
382
383 def text(self,etype, value, elist,context=5):
383 def text(self,etype, value, elist,context=5):
384 """Return a color formatted string with the traceback info."""
384 """Return a color formatted string with the traceback info."""
@@ -855,8 +855,8 b' class VerboseTB(TBTools):'
855 (etype, evalue, etb) = info or sys.exc_info()
855 (etype, evalue, etb) = info or sys.exc_info()
856 self.tb = etb
856 self.tb = etb
857 Term.cout.flush()
857 Term.cout.flush()
858 Term.cerr.flush()
859 print >> Term.cerr, self.text(etype, evalue, etb)
858 print >> Term.cerr, self.text(etype, evalue, etb)
859 Term.cerr.flush()
860
860
861 # Changed so an instance can just be called as VerboseTB_inst() and print
861 # Changed so an instance can just be called as VerboseTB_inst() and print
862 # out the right info on its own.
862 # out the right info on its own.
@@ -977,13 +977,13 b' class AutoFormattedTB(FormattedTB):'
977 if out is None:
977 if out is None:
978 out = Term.cerr
978 out = Term.cerr
979 Term.cout.flush()
979 Term.cout.flush()
980 out.flush()
981 if tb_offset is not None:
980 if tb_offset is not None:
982 tb_offset, self.tb_offset = self.tb_offset, tb_offset
981 tb_offset, self.tb_offset = self.tb_offset, tb_offset
983 print >> out, self.text(etype, evalue, etb)
982 print >> out, self.text(etype, evalue, etb)
984 self.tb_offset = tb_offset
983 self.tb_offset = tb_offset
985 else:
984 else:
986 print >> out, self.text(etype, evalue, etb)
985 print >> out, self.text(etype, evalue, etb)
986 out.flush()
987 try:
987 try:
988 self.debugger()
988 self.debugger()
989 except KeyboardInterrupt:
989 except KeyboardInterrupt:
@@ -9,22 +9,23 b' graft setupext'
9 graft IPython/UserConfig
9 graft IPython/UserConfig
10
10
11 graft doc
11 graft doc
12 exclude doc/\#*
12 exclude doc/*.1
13 exclude doc/*.1
13 exclude doc/manual_base*
14 exclude doc/ChangeLog.*
14 exclude doc/ChangeLog.*
15 exclude doc/\#*
16 exclude doc/update_magic.sh
17 exclude doc/update_version.sh
15 exclude doc/update_version.sh
18 exclude doc/manual_base*
16
19 exclude doc/manual/WARNINGS
17 # There seems to be no way of excluding whole subdirectories, other than
20 exclude doc/manual/*.aux
18 # manually excluding all their subdirs. distutils really is horrible...
21 exclude doc/manual/*.log
19 exclude doc/attic/*
22 exclude doc/manual/*.out
20 exclude doc/build/doctrees/*
23 exclude doc/manual/*.pl
21 exclude doc/build/html/_sources/*
24 exclude doc/manual/*.tex
22 exclude doc/build/html/_static/*
23 exclude doc/build/html/*
24 exclude doc/build/latex/*
25
25
26 global-exclude *~
26 global-exclude *~
27 global-exclude *.flc
27 global-exclude *.flc
28 global-exclude *.pyc
28 global-exclude *.pyc
29 global-exclude .dircopy.log
29 global-exclude .dircopy.log
30 global-exclude .svn
30 global-exclude .svn
31 global-exclude .bzr
@@ -1,8 +1,330 b''
1 ipython (0.8.1-2) unstable; urgency=low
2
3 [ Piotr Ożarowski ]
4 * Homepage field added
5 * Rename XS-Vcs-* fields to Vcs-* (dpkg supports them now)
6 * Add 04_remove_shebang patch
7 * Removing lintian overrides, adding proper patches instead.
8
9 [ Bernd Zeimetz ]
10 * Replacing Recommends by Suggests to stop ipython from installing ~500MB
11 of dependencies. Thanks to Marcela Tiznado (Closes: #451887).
12
13 -- Bernd Zeimetz <bernd@bzed.de> Mon, 19 Nov 2007 19:10:14 +0100
14
15 ipython (0.8.1-1) unstable; urgency=low
16
17 [ Bernd Zeimetz ]
18 * debian/control:
19 - adding python-matplotlib to Recommends because
20 it is needed to run ipython -pylab
21
22 [ Norbert Tretkowski ]
23 * New upstream release. (closes: #428398)
24
25 [ Reinhard Tartler ]
26 * Install ipython.el properly.
27
28 -- Norbert Tretkowski <nobse@debian.org> Mon, 11 Jun 2007 20:05:30 +0200
29
30 ipython (0.8.0-2) unstable; urgency=low
31
32 * debian/changelog:
33 - adding missing colons to Closes entries to fix two
34 lintian warnings
35 * debian/compat:
36 - bumping compat level to 5
37 * debian/control:
38 - adding XS-Vcs-Browser
39 - remove no longer needed X*-Python-Version fields
40 - moving python-pexpect from Recommends to Depends because
41 /usr/bin/irunner is not useable without it
42 - moving debhelper and dpatch from Build-Depends-Indep to
43 Build-Depends, fixing the following lintian errors:
44 - clean-should-be-satisfied-by-build-depends debhelper
45 - clean-should-be-satisfied-by-build-depends dpatch
46 - removing unnecessary Build-Depends-Indep on python-all-dev,
47 adding python to Build-Depends instead
48 - replacing python-central by python-support to be able to
49 fix #420134 without hassle
50 - adding ${misc:Depends}
51 - adding the missing identation for Homepage:
52 - adding cdbs as Build-Depends
53 - adding myself to Uploaders
54 - removing the short description from the long description
55 * debian/patches/03_ipy_gnuglobal.dpatch:
56 - fix the location of the global binary - we're not on windows
57 * debian/rules:
58 - removing old crust, using cdbs to make things clear again
59 - using python-support instead of python-central to make
60 modules for 2.5 avaiable now. (Closes: #420134)
61 - making sure the bogus /usr/IPython directory is not
62 included in the package again
63 - do not remove docs/ipython.el (Closes: #198505, #415427)
64 * adding lintian ovverrides for several scripts included in the
65 IPython/Extensions directory.
66 * adding a manpage for /usr/bin/irunner
67
68 -- Bernd Zeimetz <bernd@bzed.de> Tue, 24 Apr 2007 02:47:26 +0200
69
70 ipython (0.8.0-1) unstable; urgency=low
71
72 * New upstream release. (closes: #419716)
73 * Removed patches merged upstream.
74
75 -- Norbert Tretkowski <nobse@debian.org> Tue, 17 Apr 2007 20:26:43 +0200
76
77 ipython (0.7.3-2) unstable; urgency=low
78
79 * Added a new patch from svn to fix jobctrl to work properly on posix.
80
81 -- Norbert Tretkowski <nobse@debian.org> Thu, 21 Dec 2006 20:13:57 +0100
82
83 ipython (0.7.3-1) unstable; urgency=low
84
85 * New upstream release.
86
87 -- Norbert Tretkowski <nobse@debian.org> Mon, 18 Dec 2006 22:23:55 +0100
88
89 ipython (0.7.3~rc2-1) experimental; urgency=low
90
91 * New upstream release candidate.
92
93 -- Norbert Tretkowski <nobse@debian.org> Sat, 16 Dec 2006 02:20:13 +0100
94
95 ipython (0.7.3~beta2-1) experimental; urgency=low
96
97 * New upstream beta release.
98
99 -- Norbert Tretkowski <nobse@debian.org> Fri, 8 Dec 2006 08:02:16 +0100
100
101 ipython (0.7.3~beta1-1) experimental; urgency=low
102
103 * New upstream beta release.
104 * Removed backported patch added in 0.7.2-5 to workaround bugs in python
105 2.3's inspect module.
106
107 -- Norbert Tretkowski <nobse@debian.org> Wed, 29 Nov 2006 12:35:22 +0100
108
109 ipython (0.7.2-6) UNRELEASED; urgency=low
110
111 * Added XS-Vcs-Svn field.
112
113 -- Piotr Ozarowski <ozarow@gmail.com> Thu, 23 Nov 2006 14:44:43 +0100
114
115 ipython (0.7.2-5) unstable; urgency=low
116
117 * Added a new patch from svn to workaround bugs in python 2.3's inspect
118 module. (closes: #374625)
119
120 -- Norbert Tretkowski <nobse@debian.org> Thu, 10 Aug 2006 18:36:12 +0200
121
122 ipython (0.7.2-4) unstable; urgency=low
123
124 * Fixed spelling error in description. (closes: #363976)
125 * Ack NMU 0.7.2-3.1, thanks Matthias. (closes: #377787)
126
127 -- Norbert Tretkowski <nobse@debian.org> Tue, 1 Aug 2006 22:45:11 +0200
128
129 ipython (0.7.2-3.1) unstable; urgency=medium
130
131 * NMU.
132 * Convert to updated Python policy. (closes: #377787)
133
134 -- Matthias Klose <doko@debian.org> Thu, 13 Jul 2006 17:42:06 +0000
135
136 ipython (0.7.2-3ubuntu1) edgy; urgency=low
137
138 * Synchronize with Debian unstable.
139 * Convert to updated Python policy. Collapse all packages into one
140 ipython package, don't handle ipython using alternatives.
141
142 -- Matthias Klose <doko@ubuntu.com> Tue, 11 Jul 2006 09:47:37 +0000
143
144 ipython (0.7.2-3) unstable; urgency=low
145
146 * Removed alternative for irunner manpage.
147
148 -- Norbert Tretkowski <nobse@debian.org> Sat, 17 Jun 2006 09:49:10 +0200
149
150 ipython (0.7.2-2) unstable; urgency=medium
151
152 * Fixed conflict in irunner. (closes: #373874)
153 * Added recommendation for python-pexpect. (closes: #373794)
154
155 -- Norbert Tretkowski <nobse@debian.org> Fri, 16 Jun 2006 10:43:45 +0200
156
157 ipython (0.7.2-1) unstable; urgency=low
158
159 [ Piotr Ozarowski ]
160 * Added watch file.
161
162 [ Norbert Tretkowski ]
163 * New upstream release.
164
165 -- Norbert Tretkowski <nobse@debian.org> Thu, 8 Jun 2006 23:36:03 +0200
166
167 ipython (0.7.1.fix1+0.7.2.rc1-1) experimental; urgency=low
168
169 * New upstream release candidate.
170 * Updated Standards-Version to 3.7.2.0, no changes required.
171
172 -- Norbert Tretkowski <nobse@debian.org> Sat, 27 May 2006 14:49:24 +0200
173
174 ipython (0.7.1.fix1-2) unstable; urgency=low
175
176 * Set maintainer to Debian Python modules team and added myself to
177 uploaders.
178
179 -- Norbert Tretkowski <nobse@debian.org> Sun, 16 Apr 2006 15:53:43 +0200
180
181 ipython (0.7.1.fix1-1) unstable; urgency=low
182
183 * New upstream bugfix release.
184 * Removed backported patch which was added in 0.7.1-3 to catch
185 KeyboardInterrupt exceptions properly, it's part of this release.
186 * Fixed names of pdfs in doc-base file to shut up linda.
187
188 -- Norbert Tretkowski <nobse@debian.org> Tue, 14 Feb 2006 23:51:17 +0100
189
190 ipython (0.7.1-3) unstable; urgency=low
191
192 * Added a new patch from upstream to catch KeyboardInterrupt exceptions
193 properly.
194
195 -- Norbert Tretkowski <nobse@debian.org> Mon, 30 Jan 2006 19:42:31 +0100
196
197 ipython (0.7.1-2) unstable; urgency=low
198
199 * Really remove alternatives on purge, thanks Lars Wirzenius for finding
200 the problem. (closes: #317269)
201
202 -- Norbert Tretkowski <nobse@debian.org> Sun, 29 Jan 2006 23:11:28 +0100
203
204 ipython (0.7.1-1) unstable; urgency=low
205
206 * New upstream release.
207
208 -- Norbert Tretkowski <nobse@debian.org> Tue, 24 Jan 2006 21:42:33 +0100
209
210 ipython (0.7.0-2) unstable; urgency=low
211
212 * Fixed circular dependencies (closes: #341980)
213 * Added version to dependency on ipython dummy package. (closes: #320235)
214 * Removed python2.2 package, ipython now depends on python >= 2.3.
215 * Bumped up standards-version, no changes needed.
216
217 -- Norbert Tretkowski <nobse@debian.org> Sat, 21 Jan 2006 23:27:53 +0100
218
219 ipython (0.7.0-1) unstable; urgency=low
220
221 * New upstream release.
222 * Updated 01_docdir-base.dpatch and 02_profiler-message.dpatch.
223
224 -- Norbert Tretkowski <nobse@debian.org> Sat, 21 Jan 2006 20:08:23 +0100
225
226 ipython (0.6.15-2) unstable; urgency=low
227
228 * New maintainer, thanks Jack for your work.
229
230 -- Norbert Tretkowski <nobse@debian.org> Sun, 28 Aug 2005 19:57:09 +0200
231
232 ipython (0.6.15-1) unstable; urgency=low
233
234 * New upstream release.
235
236 -- Norbert Tretkowski <nobse@debian.org> Thu, 2 Jun 2005 23:51:45 +0200
237
238 ipython (0.6.14-1) unstable; urgency=low
239
240 * New upstream release.
241
242 -- Norbert Tretkowski <nobse@debian.org> Tue, 31 May 2005 22:53:25 +0200
243
244 ipython (0.6.13-1) unstable; urgency=low
245
246 * New upstream release.
247 * Removed backported patch which was added in 0.6.12-3 to fix misleading
248 prompt, it's part of this release.
249
250 -- Norbert Tretkowski <nobse@debian.org> Fri, 15 Apr 2005 09:42:35 +0200
251
252 ipython (0.6.12-4) unstable; urgency=medium
253
254 * Re-added python build-dependency, it got lost in 0.6.12-2.
255 (closes: #301636)
256
257 -- Norbert Tretkowski <nobse@debian.org> Sun, 27 Mar 2005 14:28:26 +0200
258
259 ipython (0.6.12-3) unstable; urgency=low
260
261 * Added a new patch from cvs to fix misleading prompt2. (closes: #300847)
262
263 -- Norbert Tretkowski <nobse@debian.org> Sun, 27 Mar 2005 00:05:26 +0100
264
265 ipython (0.6.12-2) unstable; urgency=low
266
267 * Added packages for python2.2 and python2.4, ipython package is now a dummy
268 package depending on ipython built for Debians default python.
269 (closes: #292537)
270 * Split out generic files into separate ipython-common package.
271 * Enhanced package descriptions.
272 * Removed CFLAGS settings from debian/rules, not required.
273 * Tweaked message displayed when profiler support is missing.
274 * Suggest the python-profiler package.
275
276 -- Norbert Tretkowski <nobse@debian.org> Fri, 25 Mar 2005 20:24:36 +0100
277
278 ipython (0.6.12-1) unstable; urgency=low
279
280 * New upstream release.
281 * Removed patch which was added in 0.6.5-1.1 to make profiling support
282 optional, it was merged upstream.
283
284 -- Norbert Tretkowski <nobse@debian.org> Wed, 2 Mar 2005 12:15:09 +0100
285
286 ipython (0.6.11-1) unstable; urgency=low
287
288 * New upstream release.
289 + Fixed broken profiling support unless -D is specified. (closes: #295779)
290 * Acknowledged NMUs. (closes: #206653, #294500, #294861, #280505)
291 * New co-maintainer, added myself to uploaders.
292
293 -- Norbert Tretkowski <nobse@debian.org> Tue, 1 Mar 2005 12:40:33 +0100
294
295 ipython (0.6.5-1.2) unstable; urgency=low
296
297 * Non-maintainer upload.
298 * Rebuild with a python version that is actually in Debian.
299
300 -- Wichert Akkerman <wichert@wiggy.net> Thu, 17 Feb 2005 23:08:52 +0100
301
302 ipython (0.6.5-1.1) unstable; urgency=low
303
304 * NMU to apply patch making profiling support optional (provided by
305 Torsten Marek). (closes: #294500)
306
307 -- Steven R. Baker <srbaker@debian.org> Thu, 17 Feb 2005 05:02:55 -0400
308
309 ipython (0.6.5-1) unstable; urgency=low
310
311 * New upstream release
312
313 -- Jack Moffitt <jack@xiph.org> Thu, 2 Dec 2004 15:49:27 -0700
314
315 ipython (0.6.4-1.1) unstable; urgency=low
316
317 * NMU from BSP Frankfurt:
318 - Added Build-Depends on dpatch (Closes: #280505)
319
320 -- Joerg Jaspert <joerg@debian.org> Sat, 27 Nov 2004 18:28:17 +0100
321
1 ipython (0.6.4-1) unstable; urgency=low
322 ipython (0.6.4-1) unstable; urgency=low
2
323
3 * Fix dpatch dependency (Closes: #280505)
324 * New upstream release
325 * Updated debian/rules to use dpatch and added debian/patches/*
4
326
5 -- Fernando Perez <fperez@colorado.edu> Wed Nov 17 22:54:23 MST 2004
327 -- Jack Moffitt <jack@xiph.org> Tue, 9 Nov 2004 10:38:51 -0700
6
328
7 ipython (0.6.3-1) unstable; urgency=low
329 ipython (0.6.3-1) unstable; urgency=low
8
330
@@ -27,8 +349,8 b' ipython (0.4.0-1.1) unstable; urgency=low'
27
349
28 ipython (0.4.0-1) unstable; urgency=low
350 ipython (0.4.0-1) unstable; urgency=low
29
351
30 * New upstream release (Closes #195215)
352 * New upstream release (Closes: #195215)
31 * Updated Build-Depends (Closes #200021)
353 * Updated Build-Depends (Closes: #200021)
32
354
33 -- Jack Moffitt <jack@xiph.org> Fri, 25 Jul 2003 10:16:12 -0600
355 -- Jack Moffitt <jack@xiph.org> Fri, 25 Jul 2003 10:16:12 -0600
34
356
@@ -1,1 +1,1 b''
1 4
1 5
@@ -1,21 +1,26 b''
1 Source: ipython
1 Source: ipython
2 Section: devel
2 Section: python
3 Priority: optional
3 Priority: optional
4 Maintainer: Jack Moffitt <jack@xiph.org>
4 Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
5 Build-Depends-Indep: debhelper (>> 4.1.65), dpatch, python-dev
5 Uploaders: Norbert Tretkowski <nobse@debian.org>, Bernd Zeimetz <bernd@bzed.de>
6 Standards-Version: 3.6.1
6 Build-Depends: debhelper (>= 5.0.37.2), dpatch (>= 2.0.10), cdbs (>= 0.4.43), python, python-support (>= 0.4)
7 Homepage: http://ipython.scipy.org/
8 Vcs-Svn: svn://svn.debian.org/python-modules/packages/ipython/trunk/
9 Vcs-Browser: http://svn.debian.org/wsvn/python-modules/packages/ipython/trunk/
10 Standards-Version: 3.7.2.2
7
11
8 Package: ipython
12 Package: ipython
9 Architecture: all
13 Architecture: all
10 Depends: ${python:Depends}
14 Depends: ${python:Depends}, ${misc:Depends}, python-pexpect
11 Recommends: python-numeric, python-numeric-ext
15 Conflicts: python2.3-ipython, python2.4-ipython, ipython-common
12 Description: An enhanced interactive Python shell
16 Replaces: python2.3-ipython, python2.4-ipython, ipython-common
13 IPython is an enhanced interactive Python shell. It can be used as a
17 Suggests: python-profiler, python-numeric, python-numeric-ext, python-matplotlib
14 replacement for the standard Python shell, or it can be used as a
18 Description: enhanced interactive Python shell
15 complete working environment for scientific computing (like Matlab or
19 IPython can be used as a replacement for the standard Python shell,
16 Mathematica) when paired with the standard Python scientific and
20 or it can be used as a complete working environment for scientific
17 numerical tools. It supports dynamic object introspections, numbered
21 computing (like Matlab or Mathematica) when paired with the standard
18 input/output prompts, a macro system, session logging, session
22 Python scientific and numerical tools. It supports dynamic object
19 restoring, complete system shell access, verbose and colored
23 introspections, numbered input/output prompts, a macro system,
20 traceback reports, auto-parentheses, auto-quoting, and is
24 session logging, session restoring, complete system shell access,
21 embeddedable in other Python programs.
25 verbose and colored traceback reports, auto-parentheses, auto-quoting,
26 and is embeddable in other Python programs.
@@ -4,51 +4,15 b' Wed, 12 Mar 2003 20:38:14 -0700.'
4 It was downloaded from http://ipython.scipy.org/
4 It was downloaded from http://ipython.scipy.org/
5
5
6 Upstream Author: Fernando Perez <fperez@colorado.edu>,
6 Upstream Author: Fernando Perez <fperez@colorado.edu>,
7 Janko Hauser <jhauser@zscout.de>,
7 Janko Hauser <jhauser@ifm.uni-kiel.de>,
8 Nathaniel Gray <n8gray@caltech.edu>
8 Nathaniel Gray <n8gray@caltech.edu>
9
9
10 Copyright:
10 Copyright:
11
11
12 Most IPython code is copyright (C) 2001-2004 by Fernando Perez, Janko Hauser,
12 Most IPython code is copyright (C) 2001 by Fernando Perez, Janko
13 and Nathaniel Gray. All code is licensed under a BSD-type License except as
13 Hauser, and Nathaniel Gray. All code is licensed under the GNU Lesser
14 explicitly mentioned below. The full IPython license is:
14 General Public License (LGPL) except as explicitly mentioned below.
15
15 Its full text is included in the file /usr/share/common-licenses/LGPL.
16 IPython is released under a BSD-type license.
17
18 Copyright (c) 2001, 2002, 2003, 2004 Fernando Perez <fperez@colorado.edu>.
19
20 Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
21 <n8gray@caltech.edu>.
22
23 All rights reserved.
24
25 Redistribution and use in source and binary forms, with or without
26 modification, are permitted provided that the following conditions are met:
27
28 a. Redistributions of source code must retain the above copyright notice,
29 this list of conditions and the following disclaimer.
30
31 b. Redistributions in binary form must reproduce the above copyright
32 notice, this list of conditions and the following disclaimer in the
33 documentation and/or other materials provided with the distribution.
34
35 c. Neither the name of the copyright holders nor the names of any
36 contributors to this software may be used to endorse or promote products
37 derived from this software without specific prior written permission.
38
39
40 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
44 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
50 DAMAGE.
51
52
16
53 DPyGetOpt.py is copyright (C) 2001 by Bill Bumgarner <bbum@friday.com>
17 DPyGetOpt.py is copyright (C) 2001 by Bill Bumgarner <bbum@friday.com>
54 and is licensed under the MIT license, reproduced below:
18 and is licensed under the MIT license, reproduced below:
@@ -1,98 +1,25 b''
1 #!/usr/bin/make -f
1 #!/usr/bin/make -f
2 # Sample debian/rules that uses debhelper.
2 # ipython debian/rules file
3 # GNU copyright 1997 to 1999 by Joey Hess.
3 DEB_PYTHON_SYSTEM=pysupport
4
4 include /usr/share/cdbs/1/rules/debhelper.mk
5 # Uncomment this to turn on verbose mode.
5 include /usr/share/cdbs/1/class/python-distutils.mk
6 #export DH_VERBOSE=1
6 include /usr/share/cdbs/1/rules/dpatch.mk
7
7
8
8 install/ipython::
9
9 # remove documentation
10
10 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/COPYING
11 CFLAGS = -Wall -g
11 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/ChangeLog
12
12 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/README_Windows.txt
13 ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
13 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/pycon.ico
14 CFLAGS += -O0
14
15 else
16 CFLAGS += -O2
17 endif
18 ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
19 INSTALL_PROGRAM += -s
20 endif
21
22 configure: configure-stamp
23 configure-stamp:
24 dh_testdir
25
26 python setup.py config
27
28 touch configure-stamp
29
30
31 build: build-stamp
32
33 build-stamp: configure-stamp
34 dh_testdir
35
36 python setup.py build
37
38 touch build-stamp
39
40 clean:
41 dh_testdir
42 dh_testroot
43 rm -f build-stamp configure-stamp
44
45 -python setup.py clean --all
46 rm -f setupext/*.pyc
47
48 dh_clean
49
50 install: build
51 dh_testdir
52 dh_testroot
53 dh_clean -k
54 dh_installdirs
55
56 python setup.py install --prefix $(CURDIR)/debian/ipython/usr
57
58 # remove extra license docs that get installed
59 rm -f $(CURDIR)/debian/ipython/usr/share/doc/ipython/COPYING
60 #rm -f $(CURDIR)/debian/ipython/usr/share/doc/ipython/GNU-LGPL
61
62 # change permission on scripts
15 # change permission on scripts
63 chmod 755 $(CURDIR)/debian/ipython/usr/share/doc/ipython/examples/example-embed.py
16 chmod a-x $(CURDIR)/debian/ipython/usr/share/doc/ipython/examples/*
64 chmod 755 $(CURDIR)/debian/ipython/usr/share/doc/ipython/examples/example-gnuplot.py
17
65
18 # removing bogus usr/IPython directory
66 binary-indep: build install
19 rm -rf $(CURDIR)/debian/ipython/usr/IPython
67 dh_testdir
20
68 dh_testroot
21 binary-fixup/ipython::
69 dh_installchangelogs doc/ChangeLog
22 # fix lintian warnings (see also patches/04_remove_shebang.dpatch)
70 dh_installdocs
23 chmod +x $(CURDIR)/debian/ipython/usr/share/python-support/ipython/IPython/upgrade_dir.py
71 # dh_installexamples
24 chmod +x $(CURDIR)/debian/ipython/usr/share/python-support/ipython/IPython/Extensions/pickleshare.py
72 dh_install
25 chmod +x $(CURDIR)/debian/ipython/usr/share/python-support/ipython/IPython/irunner.py
73 # dh_installmenu
74 # dh_installdebconf
75 # dh_installlogrotate
76 # dh_installemacsen
77 # dh_installpam
78 # dh_installmime
79 # dh_installinit
80 # dh_installcron
81 # dh_installinfo
82 dh_installman doc/ipython.1.gz doc/pycolor.1.gz
83 dh_compress
84 dh_fixperms
85 dh_python
86 # dh_makeshlibs
87 dh_installdeb
88 # dh_shlibdeps
89 dh_gencontrol
90 dh_md5sums
91 dh_builddeb
92
93 # Build architecture-dependent files here.
94 binary-arch: build install
95 # We have nothing to do by default.
96
97 binary: binary-indep binary-arch
98 .PHONY: build clean binary-indep binary-arch binary install configure
@@ -1,11 +1,232 b''
1 2008-05-31 *** Released version 0.8.4
2
3 2008-05-31 Fernando Perez <Fernando.Perez@berkeley.edu>
4
5 * IPython/ipmaker.py (make_IPython): The -twisted option is fully
6 disabled.
7
8 * IPython/Shell.py (_select_shell): completely disable -twisted.
9 This code is of dubious quality and normal users should not
10 encounter it until we can clarify things further, even under
11 win32. Since we need a quick emergency 0.8.4 release, it is now
12 disabled completely. Users who want to run it can use the
13 following command (it's easy to put it in an alias or script):
14
15 python -c"from IPython import twshell;twshell.IPShellTwisted().mainloop()"
16
17 2008-05-30 Ville Vainio <vivainio@gmail.com>
18
19 * shell.py: disable -twisted on non-win32 platforms.
20 import sets module on python 2.3.
21
22 * ipy_profile_sh.py: disable ipy_signals. Now, ipython
23 is verified to work with python 2.3
24
25 * Release.py: update version to 0.8.4 for quick point fix
26
27 2008-05-28 *** Released version 0.8.3
28
29 2008-05-28 Fernando Perez <Fernando.Perez@berkeley.edu>
30
31 * ../win32_manual_post_install.py (run): Fix the windows installer
32 so the links to the docs are correct.
33
34 * IPython/ultraTB.py: flush stderr after writing to it to fix
35 problems with exception traceback ordering in some platforms.
36 Thanks to a report/fix by Jie Tang <jietang86-AT-gmail.com>.
37
38 * IPython/Magic.py (magic_cpaste): add stripping of continuation
39 prompts, feature requested by Stefan vdW.
40
41 * ../setup.py: updates to build and release tools in preparation
42 for 0.8.3 release.
43
44 2008-05-27 Ville Vainio <vivainio@gmail.com>
45
46 * iplib.py, ipmaker.py: survive lack of doctest and site._Helper
47 for minimal environments (e.g. Maemo sdk python)
48
49 * Magic.py: cpaste strips whitespace before >>> (allow pasting
50 doctests)
51
52 * ipy_completers.py: cd completer now does recursive path expand
53 (old behaviour is buggy on some readline versions)
54
55 2008-05-14 Ville Vainio <vivainio@gmail.com>
56
57 * Extensions/ipy_greedycompleter.py:
58 New extension that enables a bit more "relaxed" tab
59 completer that evaluates code without safety checks
60 (i.e. there can be side effects like function calls)
61
62 2008-04-20 Ville Vainio <vivainio@gmail.com>
63
64 * Extensions/ipy_lookfor.py: add %lookfor magic command
65 (search docstrings for words) by Pauli Virtanen. Close #245.
66
67 * Extension/ipy_jot.py: %jot and %read magics, analogous
68 to %store but you can specify some notes. Not read
69 in automatically on startup, you need %read.
70 Contributed by Yichun Wei.
71
72 2008-04-18 Fernando Perez <Fernando.Perez@berkeley.edu>
73
74 * IPython/genutils.py (page): apply workaround to curses bug that
75 can leave terminal corrupted after a call to initscr().
76
77 2008-04-15 Ville Vainio <vivainio@gmail.com>
78
79 * genutils.py: SList.grep supports 'field' argument
80
81 * ipy_completers.py: module completer looks inside
82 .egg zip files (patch by mc). Close #196.
83
84 2008-04-09 Ville Vainio <vivainio@gmail.com>
85
86 * deep_reload.py: do not crash on from __future__ import
87 absolute_import. Close #244.
88
89 2008-04-02 Ville Vainio <vivainio@gmail.com>
90
91 * ipy_winpdb.py: New extension for winpdb integration. %wdb
92 test.py is winpdb equivalent of %run -d test.py. winpdb is a
93 crossplatform remote GUI debugger based on wxpython.
94
95 2008-03-29 Ville Vainio <vivainio@gmail.com>
96
97 * ipython.rst, do_sphinx.py: New documentation base, based on
98 reStucturedText and Sphinx (html/pdf generation). The old Lyx
99 based documentation will not be updated anymore.
100
101 * jobctrl.py: Use shell in Popen for 'start' command (in windows).
102
103 2008-03-24 Ville Vainio <vivainio@gmail.com>
104
105 * ipython.rst, do_sphinx.py: New documentation base, based on
106 reStucturedText and Sphinx (html/pdf generation). The old Lyx
107 based documentation will not be updated anymore.
108
109 ipython.rst has up to date documentation on matters that were not
110 documented at all, and it also removes various
111 misdocumented/deprecated features.
112
113 2008-03-22 Ville Vainio <vivainio@gmail.com>
114
115 * Shell.py: Merge mtexp branch:
116 https://code.launchpad.net/~ipython/ipython/mtexp
117
118 Privides simpler and more robust MTInteractiveShell that won't
119 deadlock, even when the worker thread (GUI) stops doing runcode()
120 regularly. r71.
121
122 2008-03-20 Ville Vainio <vivainio@gmail.com>
123
124 * twshell.py: New shell that runs IPython code in Twisted reactor.
125 Launch by doing ipython -twisted. r67.
126
127 2008-03-19 Ville Vainio <vivainio@gmail.com>
128
129 * Magic.py: %rehashx works correctly when shadowed system commands
130 have upper case characters (e.g. Print.exe). r64.
131
132 * ipy_bzr.py, ipy_app_completers.py: new bzr completer that also
133 knows options to commands, based on bzrtools. Uses bzrlib
134 directly. r66.
135
136 2008-03-16 Ville Vainio <vivainio@gmail.com>
137
138 * make_tarball.py: Fixed for bzr.
139
140 * ipapi.py: Better _ip.runlines() script cleanup. r56,r79.
141
142 * ipy_vimserver.py, ipy.vim: New extension for vim server mode,
143 by Erich Heine.
144
145 2008-03-12 Ville Vainio <vivainio@gmail.com>
146
147 * ipmaker.py: Force (reload?) import of ipy_user_conf and
148 ipy_profile_foo, so that embedded instances can be relaunched and
149 configuration is still done. r50
150
151 * ipapi.py, test_embed.py: Allow specifying shell class in
152 launch_new_instance & make_new instance. Use this in
153 test_embed.py. r51.
154
155 test_embed.py is also a good and simple demo of embedding IPython.
156
157
158 2008-03-10 Ville Vainio <vivainio@gmail.com>
159
160 * tool/update_revnum.py: Change to bzr revisioning scheme in
161 revision numbers.
162
163 * Shell.py: Threading improvements:
164
165 In multithreaded shells, do not hang on macros and o.autoexec
166 commands (or anything executed with _ip.runlines()) anymore. Allow
167 recursive execution of IPython code in
168 MTInteractiveShell.runsource by checking if we are already in
169 worker thread, and execute code directly if we are. r48.
170
171 MTInteractiveShell.runsource: execute code directly if worker
172 thread is not running yet (this is the case in config files). r49.
173
174 2008-03-09 Ville Vainio <vivainio@gmail.com>
175
176 * ipy_profile_sh.py: You can now use $LA or LA() to refer to last
177 argument of previous command in sh profile. Similar to bash '!$'.
178 LA(3) or $LA(3) stands for last argument of input history command
179 3.
180
181 * Shell.py: -pylab names don't clutter %whos listing.
182
183 2008-03-07 Ville Vainio <vivainio@gmail.com>
184
185 * ipy_autoreload.py: new extension (by Pauli Virtanen) for
186 autoreloading modules; try %autoreload and %aimport. Close #154.
187 Uses the new pre_runcode_hook.
188
189 2008-02-24 Ville Vainio <vivainio@gmail.com>
190
191 * platutils_posix.py: freeze_term_title works
192
193 2008-02-21 Ville Vainio <vivainio@gmail.com>
194
195 * Magic.py: %quickref does not crash with empty docstring
196
197 2008-02-20 Ville Vainio <vivainio@gmail.com>
198
199 * completer.py: do not treat [](){} as protectable chars anymore,
200 close #233.
201
202 * completer.py: do not treat [](){} as protectable chars anymore
203
204 * magic.py, test_cpaste.py: Allow different prefix for pasting
205 from email
206
207 2008-02-17 Ville Vainio <vivainio@gmail.com>
208
209 * Switched over to Launchpad/bzr as primary VCS.
210
211 2008-02-14 Ville Vainio <vivainio@gmail.com>
212
213 * ipapi.py: _ip.runlines() is now much more liberal about
214 indentation - it cleans up the scripts it gets
215
216 2008-02-14 Ville Vainio <vivainio@gmail.com>
217
218 * Extensions/ipy_leo.py: created 'ILeo' IPython-Leo bridge.
219 Changes to it (later on) are too numerous to list in ChangeLog
220 until it stabilizes
221
1 2008-02-07 Darren Dale <darren.dale@cornell.edu>
222 2008-02-07 Darren Dale <darren.dale@cornell.edu>
2
223
3 * IPython/Shell.py: Call QtCore.pyqtRemoveInputHook() when creating
224 * IPython/Shell.py: Call QtCore.pyqtRemoveInputHook() when creating
4 an IPShellQt4. PyQt4-4.2.1 and later uses PyOS_InputHook to improve
225 an IPShellQt4. PyQt4-4.2.1 and later uses PyOS_InputHook to improve
5 interaction in the interpreter (like Tkinter does), but it seems to
226 interaction in the interpreter (like Tkinter does), but it seems to
6 partially interfere with the IPython implementation and exec_()
227 partially interfere with the IPython implementation and exec_()
7 still seems to block. So we disable the PyQt implementation and
228 still seems to block. So we disable the PyQt implementation and
8 stick with the IPython one for now.
229 stick with the IPython one for now.
9
230
10 2008-02-02 Walter Doerwald <walter@livinglogic.de>
231 2008-02-02 Walter Doerwald <walter@livinglogic.de>
11
232
1 NO CONTENT: file renamed from doc/ipnb_google_soc.lyx to doc/attic/ipnb_google_soc.lyx
NO CONTENT: file renamed from doc/ipnb_google_soc.lyx to doc/attic/ipnb_google_soc.lyx
1 NO CONTENT: file renamed from doc/nbexample.py to doc/attic/nbexample.py
NO CONTENT: file renamed from doc/nbexample.py to doc/attic/nbexample.py
1 NO CONTENT: file renamed from doc/nbexample_latex.py to doc/attic/nbexample_latex.py
NO CONTENT: file renamed from doc/nbexample_latex.py to doc/attic/nbexample_latex.py
1 NO CONTENT: file renamed from doc/nbexample_output.py to doc/attic/nbexample_output.py
NO CONTENT: file renamed from doc/nbexample_output.py to doc/attic/nbexample_output.py
1 NO CONTENT: file renamed from doc/new_design.lyx to doc/attic/new_design.lyx
NO CONTENT: file renamed from doc/new_design.lyx to doc/attic/new_design.lyx
@@ -1,20 +1,20 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 import IPython.ipapi
3 import IPython.ipapi
4 ip = IPython.ipapi.get()
4 ip = IPython.ipapi.get()
5
5
6 def ${name}_f(self, arg):
6 def ${name}_f(self, arg):
7 r""" Short explanation
7 r""" Short explanation
8
8
9 Long explanation, examples
9 Long explanation, examples
10
10
11 """
11 """
12
12
13 # opts,args = self.parse_options(arg,'rx')
13 # opts,args = self.parse_options(arg,'rx')
14 # if 'r' in opts: pass
14 # if 'r' in opts: pass
15
15
16
16
17
17
18 ip.expose_magic("${name}",${name}_f)
18 ip.expose_magic("${name}",${name}_f)
19
19
20
20
@@ -1,6 +1,6 b''
1 Windows Registry Editor Version 5.00
1 Windows Registry Editor Version 5.00
2
2
3 [HKEY_CLASSES_ROOT\Directory\shell\IPython here]
3 [HKEY_CLASSES_ROOT\Directory\shell\IPython here]
4
4
5 [HKEY_CLASSES_ROOT\Directory\shell\IPython here\Command]
5 [HKEY_CLASSES_ROOT\Directory\shell\IPython here\Command]
6 @="cmd.exe /C ipython.py -p sh -i -c \"%cd %1\"" No newline at end of file
6 @="cmd.exe /C ipython.py -p sh -i -c \"%cd %1\""
@@ -36,11 +36,11 b' The following special options are ONLY valid at the beginning of the command'
36 line, and not later. This is because they control the initialization of
36 line, and not later. This is because they control the initialization of
37 ipython itself, before the normal option-handling mechanism is active.
37 ipython itself, before the normal option-handling mechanism is active.
38 .TP
38 .TP
39 .B \-gthread, \-qthread, \-q4thread, \-wthread, \-pylab
39 .B \-gthread, \-qthread, \-q4thread, \-wthread, \-pylab, \-twisted
40 Only ONE of these can be given, and it can only be given as the first option
40 Only ONE of these can be given, and it can only be given as the first option
41 passed to IPython (it will have no effect in any other position). They provide
41 passed to IPython (it will have no effect in any other position). They provide
42 threading support for the GTK, QT3, QT4 and WXWidgets toolkits, and for the
42 threading support for the GTK, QT3, QT4 and WXWidgets toolkits, for the
43 matplotlib library.
43 matplotlib library and Twisted reactor.
44 .br
44 .br
45 .sp 1
45 .sp 1
46 With any of the first four options, IPython starts running a separate thread
46 With any of the first four options, IPython starts running a separate thread
@@ -56,6 +56,10 b' request a specific version of wx to be used. This requires that you have the'
56 distributions.
56 distributions.
57 .br
57 .br
58 .sp 1
58 .sp 1
59 If \-twisted is given, IPython start a Twisted reactor and runs IPython mainloop
60 in a dedicated thread, passing commands to be run inside the Twisted reactor.
61 .br
62 .sp 1
59 If \-pylab is given, IPython loads special support for the matplotlib library
63 If \-pylab is given, IPython loads special support for the matplotlib library
60 (http://matplotlib.sourceforge.net), allowing interactive usage of any of its
64 (http://matplotlib.sourceforge.net), allowing interactive usage of any of its
61 backends as defined in the user's .matplotlibrc file. It automatically
65 backends as defined in the user's .matplotlibrc file. It automatically
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
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 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
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 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
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 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
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 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
The requested commit or file is too big and content was truncated. Show full diff
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 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
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 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100644 => 100755
NO CONTENT: modified file chmod 100644 => 100755
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now