##// 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
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'?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
7 <title>igrid help</title>
8 </head>
9 <body>
10 <h1>igrid help</h1>
11
12
13 <h2>Commands</h2>
14
15
16 <h3>pick (P)</h3>
17 <p>Pick the whole row (object is available as "_")</p>
18
19 <h3>pickattr (Shift-P)</h3>
20 <p>Pick the attribute under the cursor</p>
21
22 <h3>pickallattrs (Shift-C)</h3>
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
25 as a list.</p>
26
27 <h3>enter (E)</h3>
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>
30
31 <h3>enterattr (Shift-E)</h3>
32 <p>Enter the attribute under the cursor.</p>
33
34 <h3>detail (D)</h3>
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
37 attributes than in the list view, depending on the object).</p>
38
39 <h3>detailattr (Shift-D)</h3>
40 <p>Show a detail view of the attribute under the cursor.</p>
41
42 <h3>pickrows (M)</h3>
43 <p>Pick multiple selected rows (M)</p>
44
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>
47
48 <h3>find (CTRL-F)</h3>
49 <p>Find text</p>
50
51 <h3>find_next (F3)</h3>
52 <p>Find next occurrence of the searchtext</p>
53
54 <h3>find_previous (Shift-F3)</h3>
55 <p>Find previous occurrence of the searchtext </p>
56
57 <h3>sortattrasc (V)</h3>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
59
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>
62
63 <h3>leave (Backspace, DEL, X)</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
65
66 <h3>quit (ESC,Q)</h3>
67 <p>Quit igrid and return to the IPython prompt.</p>
68
69
70 <h2>Navigation</h2>
71
72
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
74
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
76
77 <h3>Move the cursor one column to the left (&lt;)</h3>
78
79 <h3>Move the cursor one column to the right (&gt;)</h3>
80
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
82
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
84
85 </body>
86 </html>
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">
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
6 <link rel="stylesheet" href="igrid_help.css" type="text/css" />
7 <title>igrid help</title>
8 </head>
9 <body>
10 <h1>igrid help</h1>
11
12
13 <h2>Commands</h2>
14
15
16 <h3>pick (P)</h3>
17 <p>Pick the whole row (object is available as "_")</p>
18
19 <h3>pickattr (Shift-P)</h3>
20 <p>Pick the attribute under the cursor</p>
21
22 <h3>pickallattrs (Shift-C)</h3>
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
25 as a list.</p>
26
27 <h3>enter (E)</h3>
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>
30
31 <h3>enterattr (Shift-E)</h3>
32 <p>Enter the attribute under the cursor.</p>
33
34 <h3>detail (D)</h3>
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
37 attributes than in the list view, depending on the object).</p>
38
39 <h3>detailattr (Shift-D)</h3>
40 <p>Show a detail view of the attribute under the cursor.</p>
41
42 <h3>pickrows (M)</h3>
43 <p>Pick multiple selected rows (M)</p>
44
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>
47
48 <h3>find (CTRL-F)</h3>
49 <p>Find text</p>
50
51 <h3>find_next (F3)</h3>
52 <p>Find next occurrence of the searchtext</p>
53
54 <h3>find_previous (Shift-F3)</h3>
55 <p>Find previous occurrence of the searchtext </p>
56
57 <h3>sortattrasc (V)</h3>
58 <p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
59
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>
62
63 <h3>leave (Backspace, DEL, X)</h3>
64 <p>Close current tab (and all the tabs to the right of the current one).</h3>
65
66 <h3>quit (ESC,Q)</h3>
67 <p>Quit igrid and return to the IPython prompt.</p>
68
69
70 <h2>Navigation</h2>
71
72
73 <h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
74
75 <h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
76
77 <h3>Move the cursor one column to the left (&lt;)</h3>
78
79 <h3>Move the cursor one column to the right (&gt;)</h3>
80
81 <h3>Jump to the first row in the current column (CTRL-Up)</h3>
82
83 <h3>Jump to the last row in the current column (CTRL-Down)</h3>
84
85 </body>
86 </html>
@@ -14,4 +14,6 b' from ipy_completers import *'
14 14 ip.set_hook('complete_command', apt_completer, re_key = '.*apt-get')
15 15 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
16 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 2 """ Implementations for various useful completers
4 3
@@ -12,6 +11,7 b' import IPython.ipapi'
12 11 import glob,os,shlex,sys
13 12 import inspect
14 13 from time import time
14 from zipimport import zipimporter
15 15 ip = IPython.ipapi.get()
16 16
17 17 try:
@@ -86,13 +86,18 b' def moduleList(path):'
86 86
87 87 if os.path.isdir(path):
88 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 94 else:
90 95 folder_list = []
91 96 #folder_list = glob.glob(os.path.join(path,'*'))
92 97 folder_list = [p for p in folder_list \
93 98 if os.path.exists(os.path.join(path, p,'__init__.py'))\
94 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 102 folder_list = [os.path.basename(p).split('.')[0] for p in folder_list]
98 103 return folder_list
@@ -211,15 +216,15 b' def hg_completer(self,event):'
211 216
212 217
213 218
214 bzr_commands = """
215 add annotate bind branch break-lock bundle-revisions cat check
216 checkout commit conflicts deleted diff export gannotate gbranch
217 gcommit gdiff help ignore ignored info init init-repository inventory
218 log merge missing mkdir mv nick pull push reconcile register-branch
219 remerge remove renames resolve revert revno root serve sign-my-commits
220 status testament unbind uncommit unknowns update upgrade version
221 version-info visualise whoami
222 """
219 __bzr_commands = None
220
221 def bzr_commands():
222 global __bzr_commands
223 if __bzr_commands is not None:
224 return __bzr_commands
225 out = os.popen('bzr help commands')
226 __bzr_commands = [l.split()[0] for l in out]
227 return __bzr_commands
223 228
224 229 def bzr_completer(self,event):
225 230 """ Completer for bazaar commands """
@@ -232,7 +237,7 b' def bzr_completer(self,event):'
232 237 param = cmd_param[-1]
233 238 output_file = (param == '--output=')
234 239 if cmd == 'help':
235 return bzr_commands.split()
240 return bzr_commands()
236 241 elif cmd in ['bundle-revisions','conflicts',
237 242 'deleted','nick','register-branch',
238 243 'serve','unbind','upgrade','version',
@@ -242,7 +247,7 b' def bzr_completer(self,event):'
242 247 # the rest are probably file names
243 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 253 def shlex_split(x):
@@ -326,7 +331,29 b' def cd_completer(self, event):'
326 331 if os.path.isdir(relpath):
327 332 return [relpath]
328 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 358 def apt_get_packages(prefix):
332 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
2
3 Example use:
4
5 nodes.foo = "hello world"
6
7 -> create '@ipy foo' node with text "hello world"
8
9 Access works also, and so does tab completion.
10
11 """
12 import IPython.ipapi
13 import IPython.genutils
14 import IPython.generics
15 import re
16
17
18
19 ip = IPython.ipapi.get()
20 leo = ip.user_ns['leox']
21 c,g = leo.c, leo.g
22
23 # will probably be overwritten by user, but handy for experimentation early on
24 ip.user_ns['c'] = c
25 ip.user_ns['g'] = g
26
27
28 from IPython.external.simplegeneric import generic
29 import pprint
30
31 @generic
32 def format_for_leo(obj):
33 """ Convert obj to string representiation (for editing in Leo)"""
34 return pprint.pformat(obj)
35
36 @format_for_leo.when_type(list)
37 def format_list(obj):
38 return "\n".join(str(s) for s in obj)
39
40 nodename_re = r'(@ipy?[\w-]+)?\s?(\w+)'
41
42 def all_cells():
43 d = {}
44 for p in c.allNodes_iter():
45 h = p.headString()
46 if h.startswith('@') and len(h.split()) == 1:
47 continue
48 mo = re.match(nodename_re, h)
49 if not mo:
50 continue
51 d[mo.group(2)] = p.copy()
52 return d
53
54
55 class TrivialLeoWorkbook:
56 """ class to find cells with simple syntax
57
58 """
59 def __getattr__(self, key):
60 cells = all_cells()
61 p = cells[key]
62 body = p.bodyString()
63 return eval_body(body)
64 def __setattr__(self,key,val):
65 cells = all_cells()
66 p = cells.get(key,None)
67 if p is None:
68 add_var(key,val)
69 else:
70 c.setBodyString(p,format_for_leo(val))
71 def __str__(self):
72 return "<TrivialLeoWorkbook>"
73 __repr__ = __str__
74
75 ip.user_ns['nodes'] = TrivialLeoWorkbook()
76
77
78 class LeoNode(object):
79 def __init__(self,p):
80 self.p = p.copy()
81
82 def get_h(self): return self.p.headString()
83 def set_h(self,val):
84 print "set head",val
85 c.beginUpdate()
86 try:
87 c.setHeadString(self.p,val)
88 finally:
89 c.endUpdate()
90
91 h = property( get_h, set_h)
92
93 def get_b(self): return self.p.bodyString()
94 def set_b(self,val):
95 print "set body",val
96 c.beginUpdate()
97 try:
98 c.setBodyString(self.p, val)
99 finally:
100 c.endUpdate()
101
102 b = property(get_b, set_b)
103
104 def set_val(self, val):
105 self.b = pprint.pformat(val)
106
107 v = property(lambda self: ip.ev(self.b.strip()), set_val)
108
109 def set_l(self,val):
110 self.b = '\n'.join(val )
111 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
112 set_l)
113
114 def __iter__(self):
115 return (LeoNode(p) for p in self.p.children_iter())
116
117
118 class LeoWorkbook:
119 """ class for 'advanced' node access """
120 def __getattr__(self, key):
121 if key.startswith('_') or key == 'trait_names':
122 raise AttributeError
123 cells = all_cells()
124 p = cells.get(key, None)
125 if p is None:
126 p = add_var(key,None)
127
128 return LeoNode(p)
129
130 def __str__(self):
131 return "<LeoWorkbook>"
132 __repr__ = __str__
133 ip.user_ns['wb'] = LeoWorkbook()
134
135
136 _dummyval = object()
137 @IPython.generics.complete_object.when_type(LeoWorkbook)
138 def workbook_complete(obj, prev):
139 return all_cells().keys()
140
141
142 def add_var(varname, value = _dummyval):
143 c.beginUpdate()
144 try:
145
146 nodename = '@ipy-var ' + varname
147 p2 = g.findNodeAnywhere(c,nodename)
148 if not c.positionExists(p2):
149 p2 = c.currentPosition().insertAfter()
150 c.setHeadString(p2,'@ipy ' + varname)
151
152 c.setCurrentPosition(p2)
153 if value is _dummyval:
154 val = ip.user_ns[varname]
155 else:
156 val = value
157 if val is not None:
158 formatted = format_for_leo(val)
159 c.setBodyString(p2,formatted)
160 return p2
161 finally:
162 c.endUpdate()
163
164 def add_file(self,fname):
165 p2 = c.currentPosition().insertAfter()
166
167 def push_script(p):
168 c.beginUpdate()
169 try:
170 ohist = ip.IP.output_hist
171 hstart = len(ip.IP.input_hist)
172 script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
173
174 script = g.splitLines(script + '\n')
175 script = ''.join(z for z in script if z.strip())
176
177 ip.runlines(script)
178
179 has_output = False
180 for idx in range(hstart,len(ip.IP.input_hist)):
181 val = ohist.get(idx,None)
182 if val is None:
183 continue
184 has_output = True
185 inp = ip.IP.input_hist[idx]
186 if inp.strip():
187 g.es('In: %s' % (inp[:40], ), tabName = 'IPython')
188
189 g.es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)), tabName = 'IPython')
190
191 if not has_output:
192 g.es('ipy run: %s' %( p.headString(),), tabName = 'IPython')
193 finally:
194 c.endUpdate()
195
196
197 def eval_body(body):
198 try:
199 val = ip.ev(body)
200 except:
201 # just use stringlist if it's not completely legal python expression
202 val = IPython.genutils.SList(body.splitlines())
203 return val
204
205 def push_variable(p,varname):
206 body = p.bodyString()
207 val = eval_body(body.strip())
208 ip.user_ns[varname] = val
209 g.es('ipy var: %s' % (varname,), tabName = "IPython")
210
211 def push_from_leo(p):
212 tup = p.headString().split(None,1)
213 # @ipy foo is variable foo
214 if len(tup) == 2 and tup[0] == '@ipy':
215 varname = tup[1]
216 push_variable(p,varname)
217 return
218
219 push_script(p)
220 return
221
222
223 ip.user_ns['leox'].push = push_from_leo
224
225 def leo_f(self,s):
226 """ open file(s) in Leo
227
228 Takes an mglob pattern, e.g. '%leo *.cpp' or %leo 'rec:*.cpp'
229 """
230 import os
231 from IPython.external import mglob
232
233 files = mglob.expand(s)
234 c.beginUpdate()
235 try:
236 for fname in files:
237 p = g.findNodeAnywhere(c,'@auto ' + fname)
238 if not p:
239 p = c.currentPosition().insertAfter()
240
241 p.setHeadString('@auto ' + fname)
242 if os.path.isfile(fname):
243 c.setBodyString(p,open(fname).read())
244 c.selectPosition(p)
245 finally:
246 c.endUpdate()
247
248 ip.expose_magic('leo',leo_f)
1 """ ILeo - Leo plugin for IPython
2
3
4 """
5 import IPython.ipapi
6 import IPython.genutils
7 import IPython.generics
8 from IPython.hooks import CommandChainDispatcher
9 import re
10 import UserDict
11 from IPython.ipapi import TryNext
12 import IPython.macro
13 import IPython.Shell
14
15 def init_ipython(ipy):
16 """ This will be run by _ip.load('ipy_leo')
17
18 Leo still needs to run update_commander() after this.
19
20 """
21 global ip
22 ip = ipy
23 IPython.Shell.hijack_tk()
24 ip.set_hook('complete_command', mb_completer, str_key = '%mb')
25 ip.expose_magic('mb',mb_f)
26 ip.expose_magic('lee',lee_f)
27 ip.expose_magic('leoref',leoref_f)
28 expose_ileo_push(push_cl_node,100)
29 # this should be the LAST one that will be executed, and it will never raise TryNext
30 expose_ileo_push(push_ipython_script, 1000)
31 expose_ileo_push(push_plain_python, 100)
32 expose_ileo_push(push_ev_node, 100)
33 global wb
34 wb = LeoWorkbook()
35 ip.user_ns['wb'] = wb
36
37 show_welcome()
38
39
40 def update_commander(new_leox):
41 """ Set the Leo commander to use
42
43 This will be run every time Leo does ipython-launch; basically,
44 when the user switches the document he is focusing on, he should do
45 ipython-launch to tell ILeo what document the commands apply to.
46
47 """
48
49 global c,g
50 c,g = new_leox.c, new_leox.g
51 print "Set Leo Commander:",c.frame.getTitle()
52
53 # will probably be overwritten by user, but handy for experimentation early on
54 ip.user_ns['c'] = c
55 ip.user_ns['g'] = g
56 ip.user_ns['_leo'] = new_leox
57
58 new_leox.push = push_position_from_leo
59 run_leo_startup_node()
60
61 from IPython.external.simplegeneric import generic
62 import pprint
63
64 def es(s):
65 g.es(s, tabName = 'IPython')
66 pass
67
68 @generic
69 def format_for_leo(obj):
70 """ Convert obj to string representiation (for editing in Leo)"""
71 return pprint.pformat(obj)
72
73 @format_for_leo.when_type(list)
74 def format_list(obj):
75 return "\n".join(str(s) for s in obj)
76
77
78 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
79 def valid_attribute(s):
80 return attribute_re.match(s)
81
82 _rootnode = None
83 def rootnode():
84 """ Get ileo root node (@ipy-root)
85
86 if node has become invalid or has not been set, return None
87
88 Note that the root is the *first* @ipy-root item found
89 """
90 global _rootnode
91 if _rootnode is None:
92 return None
93 if c.positionExists(_rootnode.p):
94 return _rootnode
95 _rootnode = None
96 return None
97
98 def all_cells():
99 global _rootnode
100 d = {}
101 r = rootnode()
102 if r is not None:
103 nodes = r.p.children_iter()
104 else:
105 nodes = c.allNodes_iter()
106
107 for p in nodes:
108 h = p.headString()
109 if h.strip() == '@ipy-root':
110 # update root node (found it for the first time)
111 _rootnode = LeoNode(p)
112 # the next recursive call will use the children of new root
113 return all_cells()
114
115 if h.startswith('@a '):
116 d[h.lstrip('@a ').strip()] = p.parent().copy()
117 elif not valid_attribute(h):
118 continue
119 d[h] = p.copy()
120 return d
121
122 def eval_node(n):
123 body = n.b
124 if not body.startswith('@cl'):
125 # plain python repr node, just eval it
126 return ip.ev(n.b)
127 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
128 first, rest = body.split('\n',1)
129 tup = first.split(None, 1)
130 # @cl alone SPECIAL USE-> dump var to user_ns
131 if len(tup) == 1:
132 val = ip.ev(rest)
133 ip.user_ns[n.h] = val
134 es("%s = %s" % (n.h, repr(val)[:20] ))
135 return val
136
137 cl, hd = tup
138
139 xformer = ip.ev(hd.strip())
140 es('Transform w/ %s' % repr(xformer))
141 return xformer(rest, n)
142
143 class LeoNode(object, UserDict.DictMixin):
144 """ Node in Leo outline
145
146 Most important attributes (getters/setters available:
147 .v - evaluate node, can also be alligned
148 .b, .h - body string, headline string
149 .l - value as string list
150
151 Also supports iteration,
152
153 setitem / getitem (indexing):
154 wb.foo['key'] = 12
155 assert wb.foo['key'].v == 12
156
157 Note the asymmetry on setitem and getitem! Also other
158 dict methods are available.
159
160 .ipush() - run push-to-ipython
161
162 Minibuffer command access (tab completion works):
163
164 mb save-to-file
165
166 """
167 def __init__(self,p):
168 self.p = p.copy()
169
170 def __str__(self):
171 return "<LeoNode %s>" % str(self.p)
172
173 __repr__ = __str__
174
175 def __get_h(self): return self.p.headString()
176 def __set_h(self,val):
177 print "set head",val
178 c.beginUpdate()
179 try:
180 c.setHeadString(self.p,val)
181 finally:
182 c.endUpdate()
183
184 h = property( __get_h, __set_h, doc = "Node headline string")
185
186 def __get_b(self): return self.p.bodyString()
187 def __set_b(self,val):
188 print "set body",val
189 c.beginUpdate()
190 try:
191 c.setBodyString(self.p, val)
192 finally:
193 c.endUpdate()
194
195 b = property(__get_b, __set_b, doc = "Nody body string")
196
197 def __set_val(self, val):
198 self.b = format_for_leo(val)
199
200 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
201
202 def __set_l(self,val):
203 self.b = '\n'.join(val )
204 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
205 __set_l, doc = "Node value as string list")
206
207 def __iter__(self):
208 """ Iterate through nodes direct children """
209
210 return (LeoNode(p) for p in self.p.children_iter())
211
212 def __children(self):
213 d = {}
214 for child in self:
215 head = child.h
216 tup = head.split(None,1)
217 if len(tup) > 1 and tup[0] == '@k':
218 d[tup[1]] = child
219 continue
220
221 if not valid_attribute(head):
222 d[head] = child
223 continue
224 return d
225 def keys(self):
226 d = self.__children()
227 return d.keys()
228 def __getitem__(self, key):
229 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
230
231 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
232 """
233 key = str(key)
234 d = self.__children()
235 return d[key]
236 def __setitem__(self, key, val):
237 """ You can do wb.foo['My Stuff'] = 12 to create children
238
239 This will create 'My Stuff' as a child of foo (if it does not exist), and
240 do .v = 12 assignment.
241
242 Exception:
243
244 wb.foo['bar'] = 12
245
246 will create a child with headline '@k bar', because bar is a valid python name
247 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
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 43 # %store foo
44 44 # %store bar
45 45 import ipy_rehashdir
46 import ipy_signals
46
47 # does not work without subprocess module!
48 #import ipy_signals
47 49
48 50 ip.ex('import os')
49 51 ip.ex("def up(): os.chdir('..')")
50
52 ip.user_ns['LA'] = LastArgFinder()
51 53 # Nice prompt
52 54
53 55 o.prompt_in1= r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
@@ -117,6 +119,29 b' def main():'
117 119
118 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 145 # XXX You do not need to understand the next function!
121 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 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 45 import os,shlex,sys,time
46 import threading,Queue
46 47
47 48 from IPython import genutils
48 49
@@ -71,15 +72,70 b' def startjob(job):'
71 72 p.line = job
72 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 122 def jobctrl_prefilter_f(self,line):
75 123 if line.startswith('&'):
76 124 pre,fn,rest = self.split_user_input(line[1:])
77 125
78 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 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 140 def job_list(ip):
85 141 keys = ip.db.keys('tasks/*')
@@ -91,8 +147,16 b' def magic_tasks(self,line):'
91 147
92 148 A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled.
93 149 Tasks can be killed with %kill.
150
151 '%tasks clear' clears the task list (from stale tasks)
94 152 """
95 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 160 ents = job_list(ip)
97 161 if not ents:
98 162 print "No tasks running"
@@ -125,7 +189,7 b' def magic_kill(self,line):'
125 189 magic_tasks(self,line)
126 190
127 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 193 else:
130 194 # todo linux commands
131 195 shell_internal_commands = []
@@ -133,20 +197,33 b' else:'
133 197
134 198 def jobctrl_shellcmd(ip,cmd):
135 199 """ os.system replacement that stores process info to db['tasks/t1234'] """
200 cmd = cmd.strip()
136 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 203 use_shell = True
139 204 else:
140 205 use_shell = False
141 206
142 p = Popen(cmd,shell = use_shell)
143 jobentry = 'tasks/t' + str(p.pid)
144
207 jobentry = None
145 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 221 ip.db[jobentry] = (p.pid,cmd,os.getcwd(),time.time())
147 p.communicate()
222 p.communicate()
223
148 224 finally:
149 del ip.db[jobentry]
225 if jobentry:
226 del ip.db[jobentry]
150 227
151 228
152 229 def install():
@@ -158,5 +235,6 b' def install():'
158 235 ip.set_hook('shell_hook', jobctrl_shellcmd)
159 236 ip.expose_magic('kill',magic_kill)
160 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 240 install()
@@ -94,8 +94,16 b' def matchorfail(text, pos):'
94 94 match = tokenprog.match(text, pos)
95 95 if match is None:
96 96 raise ItplError(text, pos)
97
97 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 107 class Itpl:
100 108 """Class representing a string with interpolation abilities.
101 109
@@ -104,7 +112,7 b' class Itpl:'
104 112 evaluation and substitution happens in the namespace of the
105 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 116 """The single mandatory argument to this constructor is a format
109 117 string.
110 118
@@ -115,9 +115,9 b' class Magic:'
115 115
116 116 def profile_missing_notice(self, *args, **kwargs):
117 117 error("""\
118 The profile module could not be found. If you are a Debian user,
119 it has been removed from the standard Debian package because of its non-free
120 license. To use profiling, please install"python2.3-profiler" from non-free.""")
118 The profile module could not be found. It has been removed from the standard
119 python packages because of its non-free license. To use profiling, install the
120 python-profiler package from non-free.""")
121 121
122 122 def default_option(self,fn,optstr):
123 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 147 filter(inst_magic,self.__dict__.keys()) + \
148 148 filter(inst_bound_magic,self.__class__.__dict__.keys())
149 149 out = []
150 for fn in magics:
150 for fn in Set(magics):
151 151 out.append(fn.replace('magic_','',1))
152 152 out.sort()
153 153 return out
@@ -386,7 +386,10 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
386 386 return None
387 387
388 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 394 mode = ''
392 395 try:
@@ -394,6 +397,9 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
394 397 mode = 'latex'
395 398 if parameter_s.split()[0] == '-brief':
396 399 mode = 'brief'
400 if parameter_s.split()[0] == '-rest':
401 mode = 'rest'
402 rest_docs = []
397 403 except:
398 404 pass
399 405
@@ -409,14 +415,26 b' license. To use profiling, please install"python2.3-profiler" from non-free.""")'
409 415 break
410 416 if mode == 'brief':
411 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 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 433 magic_docs = ''.join(magic_docs)
419 434
435 if mode == 'rest':
436 return "".join(rest_docs)
437
420 438 if mode == 'latex':
421 439 print self.format_latex(magic_docs)
422 440 return
@@ -2612,7 +2630,7 b' Defaulting color scheme to \'NoColor\'"""'
2612 2630 os.chdir(pdir)
2613 2631 for ff in os.listdir(pdir):
2614 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 2634 if ext.lower() == '.exe':
2617 2635 ff = base
2618 2636 alias_table[base.lower()] = (0,ff)
@@ -2667,6 +2685,7 b' Defaulting color scheme to \'NoColor\'"""'
2667 2685 parameter_s = parameter_s.strip()
2668 2686 #bkms = self.shell.persist.get("bookmarks",{})
2669 2687
2688 oldcwd = os.getcwd()
2670 2689 numcd = re.match(r'(-)(\d+)$',parameter_s)
2671 2690 # jump in directory history by number
2672 2691 if numcd:
@@ -2705,7 +2724,7 b' Defaulting color scheme to \'NoColor\'"""'
2705 2724
2706 2725 # at this point ps should point to the target dir
2707 2726 if ps:
2708 try:
2727 try:
2709 2728 os.chdir(os.path.expanduser(ps))
2710 2729 if self.shell.rc.term_title:
2711 2730 #print 'set term title:',self.shell.rc.term_title # dbg
@@ -2716,8 +2735,9 b' Defaulting color scheme to \'NoColor\'"""'
2716 2735 else:
2717 2736 cwd = os.getcwd()
2718 2737 dhist = self.shell.user_ns['_dh']
2719 dhist.append(cwd)
2720 self.db['dhist'] = compress_dhist(dhist)[-100:]
2738 if oldcwd != cwd:
2739 dhist.append(cwd)
2740 self.db['dhist'] = compress_dhist(dhist)[-100:]
2721 2741
2722 2742 else:
2723 2743 os.chdir(self.shell.home_dir)
@@ -2725,8 +2745,10 b' Defaulting color scheme to \'NoColor\'"""'
2725 2745 platutils.set_term_title("IPy ~")
2726 2746 cwd = os.getcwd()
2727 2747 dhist = self.shell.user_ns['_dh']
2728 dhist.append(cwd)
2729 self.db['dhist'] = compress_dhist(dhist)[-100:]
2748
2749 if oldcwd != cwd:
2750 dhist.append(cwd)
2751 self.db['dhist'] = compress_dhist(dhist)[-100:]
2730 2752 if not 'q' in opts and self.shell.user_ns['_dh']:
2731 2753 print self.shell.user_ns['_dh'][-1]
2732 2754
@@ -3118,7 +3140,7 b' Defaulting color scheme to \'NoColor\'"""'
3118 3140 screen_lines=self.shell.rc.screen_length)
3119 3141
3120 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 3145 You must terminate the block with '--' (two minus-signs) alone on the
3124 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 3149 The block is dedented prior to execution to enable execution of method
3128 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 3153 executed block is also assigned to variable named 'pasted_block' for
3131 3154 later editing with '%edit pasted_block'.
3132 3155
3133 3156 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
3134 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 3160 Do not be alarmed by garbled output on Windows (it's a readline bug).
3138 3161 Just press enter and type -- (and press enter again) and the block
@@ -3143,6 +3166,15 b' Defaulting color scheme to \'NoColor\'"""'
3143 3166 opts,args = self.parse_options(parameter_s,'s:',mode='string')
3144 3167 par = args.strip()
3145 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 3179 from IPython import iplib
3148 3180 lines = []
@@ -3151,7 +3183,11 b' Defaulting color scheme to \'NoColor\'"""'
3151 3183 l = iplib.raw_input_original(':')
3152 3184 if l ==sentinel:
3153 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 3191 block = "\n".join(lines) + '\n'
3156 3192 #print "block:\n",block
3157 3193 if not par:
@@ -404,7 +404,13 b' class Inspector:'
404 404 # Filename where object was defined
405 405 binary_file = False
406 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 414 if fname.endswith('<string>'):
409 415 fname = 'Dynamically generated function. No source code available.'
410 416 if (fname.endswith('.so') or fname.endswith('.dll')):
@@ -432,8 +438,13 b' class Inspector:'
432 438 linecache.checkcache()
433 439 source_success = False
434 440 try:
435 source = self.format(getsource(obj,binary_file))
436 if source:
441 try:
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 448 out.write(header('Source:\n')+source.rstrip())
438 449 source_success = True
439 450 except Exception, msg:
@@ -22,9 +22,15 b" name = 'ipython'"
22 22 # because bdist_rpm does not accept dashes (an RPM) convention, and
23 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 35 description = "An enhanced interactive Python shell."
30 36
@@ -46,6 +46,13 b' from IPython.ipmaker import make_IPython'
46 46 from IPython.Magic import Magic
47 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 56 # Globals
50 57 # global flag to pass around information about Ctrl-C without exceptions
51 58 KBINT = False
@@ -358,36 +365,37 b' class MTInteractiveShell(InteractiveShell):'
358 365 InteractiveShell.__init__(self,name,usage,rc,user_ns,
359 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
365 # enough, because uses like macros cause reentrancy.
369 # A queue to hold the code to be executed.
366 370 self.code_queue = Queue.Queue()
367 371
368 372 # Stuff to do at closing time
369 self._kill = False
370 on_kill = kw.get('on_kill')
371 if on_kill is None:
372 on_kill = []
373 self._kill = None
374 on_kill = kw.get('on_kill', [])
373 375 # Check that all things to kill are callable:
374 376 for t in on_kill:
375 377 if not callable(t):
376 378 raise TypeError,'on_kill must be a list of callables'
377 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 383 def runsource(self, source, filename="<input>", symbol="single"):
380 384 """Compile and run some source in the interpreter.
381 385
382 386 Modified version of code.py's runsource(), to handle threading issues.
383 387 See the original for full docstring details."""
384
388
385 389 global KBINT
386 390
387 391 # If Ctrl-C was typed, we reset the flag and return right away
388 392 if KBINT:
389 393 KBINT = False
390 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 400 try:
393 401 code = self.compile(source, filename, symbol)
@@ -400,29 +408,40 b' class MTInteractiveShell(InteractiveShell):'
400 408 # Case 2
401 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 419 # Case 3
404 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
407 # section, so we have to acquire the lock with non-blocking semantics,
408 # else we deadlock.
409 got_lock = self.thread_ready.acquire()
410 self.code_queue.put(code)
411 if got_lock:
412 self.thread_ready.wait() # Wait until processed in timeout interval
413 self.thread_ready.release()
414
422 completed_ev, received_ev = threading.Event(), threading.Event()
423
424 self.code_queue.put((code,completed_ev, received_ev))
425 # first make sure the message was received, with timeout
426 received_ev.wait(5)
427 if not received_ev.isSet():
428 # the mainloop is dead, start executing code directly
429 print "Warning: Timeout for mainloop thread exceeded"
430 print "switching to nonthreaded mode (until mainloop wakes up again)"
431 self.worker_ident = None
432 else:
433 completed_ev.wait()
415 434 return False
416 435
417 436 def runcode(self):
418 437 """Execute a code object.
419 438
420 439 Multithreaded wrapper around IPython's runcode()."""
421
440
422 441 global CODE_RUN
423
424 # lock thread-protected stuff
425 got_lock = self.thread_ready.acquire()
442
443 # we are in worker thread, stash out the id for runsource()
444 self.worker_ident = thread.get_ident()
426 445
427 446 if self._kill:
428 447 print >>Term.cout, 'Closing threads...',
@@ -430,6 +449,9 b' class MTInteractiveShell(InteractiveShell):'
430 449 for tokill in self.on_kill:
431 450 tokill()
432 451 print >>Term.cout, 'Done.'
452 # allow kill() to return
453 self._kill.set()
454 return True
433 455
434 456 # Install sigint handler. We do it every time to ensure that if user
435 457 # code modifies it, we restore our own handling.
@@ -445,10 +467,11 b' class MTInteractiveShell(InteractiveShell):'
445 467 code_to_run = None
446 468 while 1:
447 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 471 except Queue.Empty:
450 472 break
451
473 received_ev.set()
474
452 475 # Exceptions need to be raised differently depending on which
453 476 # thread is active. This convoluted try/except is only there to
454 477 # protect against asynchronous exceptions, to ensure that a KBINT
@@ -462,28 +485,23 b' class MTInteractiveShell(InteractiveShell):'
462 485 except KeyboardInterrupt:
463 486 print "Keyboard interrupted in mainloop"
464 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 491 break
467 492 finally:
468 if got_lock:
469 CODE_RUN = False
470
471 # We're done with thread-protected variables
472 if code_to_run is not None:
473 self.thread_ready.notify()
474 self.thread_ready.release()
475
476 # We're done...
477 CODE_RUN = False
493 CODE_RUN = False
494 # allow runsource() return from wait
495 completed_ev.set()
496
497
478 498 # This MUST return true for gtk threading to work
479 499 return True
480 500
481 501 def kill(self):
482 502 """Kill the thread, returning when it has been shut down."""
483 got_lock = self.thread_ready.acquire(False)
484 self._kill = True
485 if got_lock:
486 self.thread_ready.release()
503 self._kill = threading.Event()
504 self._kill.wait()
487 505
488 506 class MatplotlibShellBase:
489 507 """Mixin class to provide the necessary modifications to regular IPython
@@ -1051,7 +1069,9 b' def _load_pylab(user_ns):'
1051 1069
1052 1070 ip = IPython.ipapi.get()
1053 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 1076 class IPShellMatplotlib(IPShell):
1057 1077 """Subclass IPShell with MatplotlibShell as the internal shell.
@@ -1144,7 +1164,7 b' def _select_shell(argv):'
1144 1164 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1145 1165 'tkthread'])
1146 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 1169 if 'tk' in special_opts:
1150 1170 USE_TK = True
@@ -72,6 +72,27 b' def main():'
72 72 #o.autoexec.append('%colors NoColor')
73 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 97 # some config helper functions you can use
77 98 def import_all(modules):
@@ -321,7 +321,7 b' class IPCompleter(Completer):'
321 321 # don't want to treat as delimiters in filename matching
322 322 # when escaped with backslash
323 323
324 protectables = ' ()[]{}'
324 protectables = ' '
325 325
326 326 if text.startswith('!'):
327 327 text = text[1:]
@@ -32,7 +32,9 b' import imp'
32 32 import sys
33 33
34 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 38 parent = determine_parent(globals)
37 39 q, tail = find_head_package(parent, name)
38 40 m = load_tail(q, tail)
@@ -34,35 +34,35 b' License: MIT Open Source license'
34 34 #Assigned in variable for "usage" printing convenience"
35 35
36 36 globsyntax = """\
37 This program allows specifying filenames with "mglob" mechanism.
38 Supported syntax in globs (wilcard matching patterns)::
39
40 *.cpp ?ellowo*
41 - obvious. Differs from normal glob in that dirs are not included.
42 Unix users might want to write this as: "*.cpp" "?ellowo*"
43 rec:/usr/share=*.txt,*.doc
44 - get all *.txt and *.doc under /usr/share,
45 recursively
46 rec:/usr/share
47 - All files under /usr/share, recursively
48 rec:*.py
49 - All .py files under current working dir, recursively
50 foo
51 - File or dir foo
52 !*.bak readme*
53 - readme*, exclude files ending with .bak
54 !.svn/ !.hg/ !*_Data/ rec:.
55 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
56 Trailing / is the key, \ does not work!
57 dir:foo
58 - the directory foo if it exists (not files in foo)
59 dir:*
60 - all directories in current folder
61 foo.py bar.* !h* rec:*.py
62 - Obvious. !h* exclusion only applies for rec:*.py.
63 foo.py is *not* included twice.
64 @filelist.txt
65 - All files listed in 'filelist.txt' file, on separate lines.
37 This program allows specifying filenames with "mglob" mechanism.
38 Supported syntax in globs (wilcard matching patterns)::
39
40 *.cpp ?ellowo*
41 - obvious. Differs from normal glob in that dirs are not included.
42 Unix users might want to write this as: "*.cpp" "?ellowo*"
43 rec:/usr/share=*.txt,*.doc
44 - get all *.txt and *.doc under /usr/share,
45 recursively
46 rec:/usr/share
47 - All files under /usr/share, recursively
48 rec:*.py
49 - All .py files under current working dir, recursively
50 foo
51 - File or dir foo
52 !*.bak readme*
53 - readme*, exclude files ending with .bak
54 !.svn/ !.hg/ !*_Data/ rec:.
55 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
56 Trailing / is the key, \ does not work!
57 dir:foo
58 - the directory foo if it exists (not files in foo)
59 dir:*
60 - all directories in current folder
61 foo.py bar.* !h* rec:*.py
62 - Obvious. !h* exclusion only applies for rec:*.py.
63 foo.py is *not* included twice.
64 @filelist.txt
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 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 37 __version__ = '2.2'
35 38 __all__ = ['path']
@@ -22,7 +22,10 b' __license__ = Release.license'
22 22 # required modules from the Python standard library
23 23 import __main__
24 24 import commands
25 import doctest
25 try:
26 import doctest
27 except ImportError:
28 pass
26 29 import os
27 30 import re
28 31 import shlex
@@ -33,6 +36,18 b' import time'
33 36 import types
34 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 51 # Other IPython utilities
37 52 import IPython
38 53 from IPython.Itpl import Itpl,itpl,printpl
@@ -1052,25 +1067,40 b' class SList(list):'
1052 1067
1053 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 1071 """ Return all strings matching 'pattern' (a regex or callable)
1057 1072
1058 1073 This is case-insensitive. If prune is true, return all items
1059 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 1079 Examples::
1062 1080
1063 1081 a.grep( lambda x: x.startswith('C') )
1064 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 1096 if isinstance(pattern, basestring):
1067 1097 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1068 1098 else:
1069 1099 pred = pattern
1070 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 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 1104 def fields(self, *fields):
1075 1105 """ Collect whitespace-separated fields from string list
1076 1106
@@ -1083,6 +1113,7 b' class SList(list):'
1083 1113 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1084 1114 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1085 1115 (note the joining by space).
1116 a.fields(-1) is ['ChangeLog', 'IPython']
1086 1117
1087 1118 IndexErrors are ignored.
1088 1119
@@ -1532,26 +1563,30 b' def page(strng,start=0,screen_lines=0,pager_cmd = None):'
1532 1563 # auto-determine screen size
1533 1564 if screen_lines <= 0:
1534 1565 if TERM=='xterm':
1535 try:
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
1566 use_curses = USE_CURSES
1543 1567 else:
1544 1568 # curses causes problems on many terminals other than xterm.
1545 use_curses = 0
1569 use_curses = False
1546 1570 if use_curses:
1547 scr = curses.initscr()
1548 screen_lines_real,screen_cols = scr.getmaxyx()
1549 curses.endwin()
1550 screen_lines += screen_lines_real
1551 #print '***Screen size:',screen_lines_real,'lines x',\
1552 #screen_cols,'columns.' # dbg
1571 # There is a bug in curses, where *sometimes* it fails to properly
1572 # initialize, and then after the endwin() call is made, the
1573 # terminal is left in an unusable state. Rather than trying to
1574 # check everytime for this (by requesting and comparing termios
1575 # flags each time), we just save the initial terminal state and
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 1588 else:
1554 screen_lines += screen_lines_def
1589 screen_lines += screen_lines_def
1555 1590
1556 1591 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1557 1592 if numlines <= screen_lines :
@@ -28,10 +28,30 b' class IPythonHistoryPanel(wx.Panel):'
28 28 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
29 29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30 30
31 self.filter_empty.SetValue(flt_empty)
32 self.filter_doc.SetValue(flt_doc)
33 self.filter_cmd.SetValue(flt_cmd)
34 self.filter_magic.SetValue(flt_magic)
31 self.options={'filter_empty':{'value':'True',
32 'checkbox':self.filter_empty,'True':True,'False':False,
33 'setfunc':lambda x:None},
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 56 sizer = wx.BoxSizer(wx.VERTICAL)
37 57
@@ -70,10 +90,54 b' class IPythonHistoryPanel(wx.Panel):'
70 90 add = False
71 91 if self.filter_magic.GetValue() == True and history_line[0] == '%':
72 92 add = False
73 if add:
74 self.text_ctrl.AppendText(history_line+'\n')
93 if add:
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 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 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 '''
4 Provides IPython WX console widget.
4 Provides IPython WX console widgets.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
@@ -26,433 +26,88 b' __license__ = "BSD"'
26 26
27 27 import wx
28 28 import wx.stc as stc
29 import wx.lib.newevent
30 29
31 30 import re
32 31 import sys
33 import os
34 32 import locale
35 import time
36 from ThreadEx import Thread
37 33 from StringIO import StringIO
38
39 34 try:
40 35 import IPython
41 36 except Exception,e:
42 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.
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()
43 An NonBlockingIPShell Thread that is WX dependent.
52 44 '''
53
54 def __init__(self,argv=[],user_ns=None,user_global_ns=None,
45 def __init__(self, parent,
46 argv=[],user_ns={},user_global_ns=None,
55 47 cin=None, cout=None, cerr=None,
56 exit_handler=None,time_loop = 0.1):
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
48 ask_exit_handler=None):
229 49
230 def updateNamespace(self, ns_dict):
231 '''
232 Add the current dictionary to the shell namespace.
50 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
51 cin, cout, cerr,
52 ask_exit_handler)
233 53
234 @param ns_dict: A dictionary of symbol-values.
235 @type ns_dict: dictionary
236 '''
237 self._IP.user_ns.update(ns_dict)
54 self.parent = parent
238 55
239 def complete(self, line):
240 '''
241 Returns an auto completed line and/or posibilities for completion.
56 self.ask_exit_callback = ask_exit_handler
57 self._IP.exit = self._askExit
242 58
243 @param line: Given line so far.
244 @type line: string
59 def addGUIShortcut(self,text,func):
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,
247 and possible further completions.
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
64 def _askExit(self):
65 wx.CallAfter(self.ask_exit_callback, ())
275 66
276 def historyBack(self):
277 '''
278 Provides one history command back.
67 def _afterExecute(self):
68 wx.CallAfter(self.parent.evtStateExecuteDone, ())
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 71 class WxConsoleView(stc.StyledTextCtrl):
422 72 '''
423 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
425 scintilla with less work.
74 We use here a scintilla frontend thus it can be reused in any GUI that
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 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 83 @type ANSI_COLORS_WHITE: dictionary
432 84
433 85 @ivar color_pat: Regex of terminal color pattern
434 86 @type color_pat: _sre.SRE_Pattern
435 87 '''
436 ANSI_STYLES_BLACK ={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
437 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
438 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
439 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
440 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
441 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
442 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
443 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
444
445 ANSI_STYLES_WHITE ={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
446 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
447 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
448 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
449 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
450 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
451 '1;34': [12,'LIGHT BLUE'], '1;35': [13,'MEDIUM VIOLET RED'],
452 '1;36': [14,'LIGHT STEEL BLUE'], '1;37': [15,'YELLOW']}
453
454 def __init__(self,parent,prompt,intro="",background_color="BLACK",pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
455 style=0):
88 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
89 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
90 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
91 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
92 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
93 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
94 '1;34': [12,'LIGHT BLUE'], '1;35':
95 [13,'MEDIUM VIOLET RED'],
96 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
97
98 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
99 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
100 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
101 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
102 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
103 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
104 '1;34': [12,'LIGHT BLUE'], '1;35':
105 [13,'MEDIUM VIOLET RED'],
106 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
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 112 Initialize console view.
458 113
@@ -464,15 +119,61 b' class WxConsoleView(stc.StyledTextCtrl):'
464 119 @param background_color: Can be BLACK or WHITE
465 120 @type background_color: string
466 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 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 132 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
474 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 177 #we define platform specific fonts
477 178 if wx.Platform == '__WXMSW__':
478 179 faces = { 'times': 'Times New Roman',
@@ -499,61 +200,64 b' class WxConsoleView(stc.StyledTextCtrl):'
499 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 203 # make some styles
525 if background_color != "BLACK":
204 if self.background_color != "BLACK":
526 205 self.background_color = "WHITE"
527 206 self.SetCaretForeground("BLACK")
528 207 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
529 208 else:
530 self.background_color = background_color
531 209 self.SetCaretForeground("WHITE")
532 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],
535 self.background_color,
536 faces['size'], faces['mono']))
212 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
213 "fore:%s,back:%s,size:%d,face:%s"
214 % (self.ANSI_STYLES['0;30'][1],
215 self.background_color,
216 faces['size'], faces['mono']))
537 217 self.StyleClearAll()
538 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FF0000,back:#0000FF,bold")
539 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
540
218 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
219 "fore:#FF0000,back:#0000FF,bold")
220 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
221 "fore:#000000,back:#FF0000,bold")
222
541 223 for style in self.ANSI_STYLES.values():
542 224 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
543 225
544 226 #######################################################################
545 227
546 self.indent = 0
547 self.prompt_count = 0
548 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
228 def setBackgroundColor(self,color):
229 self.background_color = color
230 self.buildStyles()
231
232 def getBackgroundColor(self,color):
233 return self.background_color
549 234
550 self.write(intro)
551 self.setPrompt(prompt)
552 self.showPrompt()
235 def asyncWrite(self, text):
236 '''
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)
555 #self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
556
260
557 261 def write(self, text):
558 262 '''
559 263 Write given text to buffer.
@@ -641,18 +345,6 b' class WxConsoleView(stc.StyledTextCtrl):'
641 345 return self.GetTextRange(self.getCurrentPromptStart(),
642 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 348 def moveCursorOnNewValidKey(self):
657 349 #If cursor is at wrong position put it at last line...
658 350 if self.GetCurrentPos() < self.getCurrentPromptStart():
@@ -679,33 +371,53 b' class WxConsoleView(stc.StyledTextCtrl):'
679 371 def writeHistory(self,history):
680 372 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
681 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 384 def writeCompletion(self, possibilities):
684 max_len = len(max(possibilities,key=len))
685 max_symbol =' '*max_len
686
687 #now we check how much symbol we can put on a line...
688 cursor_pos = self.getCursorPos()
689 test_buffer = max_symbol + ' '*4
690 current_lines = self.GetLineCount()
691
692 allowed_symbols = 80/len(test_buffer)
693 if allowed_symbols == 0:
694 allowed_symbols = 1
385 if self.autocomplete_mode == 'IPYTHON':
386 max_len = len(max(possibilities,key=len))
387 max_symbol =' '*max_len
388
389 #now we check how much symbol we can put on a line...
390 cursor_pos = self.getCursorPos()
391 test_buffer = max_symbol + ' '*4
392 current_lines = self.GetLineCount()
393
394 allowed_symbols = 80/len(test_buffer)
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 421 def _onKeypress(self, event, skip=True):
710 422 '''
711 423 Key press callback used for correcting behavior for console-like
@@ -720,42 +432,45 b' class WxConsoleView(stc.StyledTextCtrl):'
720 432 @return: Return True if event as been catched.
721 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:
737 if event.Modifiers == wx.MOD_NONE:
738 self.moveCursorOnNewValidKey()
739
740 self.moveCursor(self.getCursorPos()-1)
741 if self.getCursorPos() < self.getCurrentPromptStart():
436 if not self.AutoCompActive():
437 if event.GetKeyCode() == wx.WXK_HOME:
438 if event.Modifiers == wx.MOD_NONE:
439 self.moveCursorOnNewValidKey()
742 440 self.moveCursor(self.getCurrentPromptStart())
743 return True
744
745 elif event.GetKeyCode() == wx.WXK_BACK:
746 self.moveCursorOnNewValidKey()
747 if self.getCursorPos() > self.getCurrentPromptStart():
748 self.removeFromTo(self.getCursorPos()-1,self.getCursorPos())
749 return True
750
751 if skip:
752 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
441 return True
442 elif event.Modifiers == wx.MOD_SHIFT:
443 self.moveCursorOnNewValidKey()
444 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
445 return True
446 else:
447 return False
448
449 elif event.GetKeyCode() == wx.WXK_LEFT:
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 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 472 event.Skip()
756 return True
757 return False
758
473
759 474 def OnUpdateUI(self, evt):
760 475 # check for matching braces
761 476 braceAtCaret = -1
@@ -791,49 +506,90 b' class WxConsoleView(stc.StyledTextCtrl):'
791 506 #print pt
792 507 #self.Refresh(False)
793 508
794 class WxIPythonViewPanel(wx.Panel):
509 class IPShellWidget(wx.Panel):
795 510 '''
796 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
798 by YOURGUIConsoleView and make YOURGUIIPythonView derivate from whatever container you want.
799 I've choosed to derivate from a wx.Panel because it seems to be ore usefull
800 Any idea to make it more 'genric' welcomed.
512 If you want to port this to any other GUI toolkit, just replace the
513 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
514 from whatever container you want. I've choosed to derivate from a wx.Panel
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 524 Initialize.
805 525 Instanciate an IPython thread.
806 526 Instanciate a WxConsoleView.
807 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 533 self.cout = StringIO()
813 self.IP = IterableIPShell(cout=self.cout,cerr=self.cout,
814 exit_handler = exit_handler,
815 time_loop = 0.1)
816 self.IP.start()
817
534 self.add_button_handler = add_button_handler
535
536 if wx_ip_shell is not None:
537 self.IP = wx_ip_shell
538 else:
539 self.IP = WxNonBlockingIPShell(self,
540 cout = self.cout, cerr = self.cout,
541 ask_exit_handler = self.askExitCallback)
542
818 543 ### IPython wx console view instanciation ###
819 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=''
821 if intro == None:
545 #If you really wnat an empty intro just call wxIPythonViewPanel
546 #with intro=''
547 if intro is None:
822 548 welcome_text = "Welcome to WxIPython Shell.\n\n"
823 549 welcome_text+= self.IP.getBanner()
824 550 welcome_text+= "!command -> Execute command in shell\n"
825 551 welcome_text+= "TAB -> Autocompletion\n"
552 else:
553 welcome_text = intro
826 554
827 555 self.text_ctrl = WxConsoleView(self,
828 556 self.IP.getPrompt(),
829 557 intro=welcome_text,
830 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 581 ### making the layout of the panel ###
835 582 sizer = wx.BoxSizer(wx.VERTICAL)
836 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 593 self.SetAutoLayout(True)
838 594 sizer.Fit(self)
839 595 sizer.SetSizeHints(self)
@@ -841,158 +597,151 b' class WxIPythonViewPanel(wx.Panel):'
841 597 #and we focus on the widget :)
842 598 self.SetFocus()
843 599
844 ### below are the thread communication variable ###
845 # the IPython thread is managed via unidirectional communication.
846 # It's a thread slave that can't interact by itself with the GUI.
847 # When the GUI event loop is done runStateMachine() is called and the thread sate is then
848 # managed.
849
850 #Initialize the state machine #kept for information
851 #self.states = ['IDLE',
852 # 'DO_EXECUTE_LINE',
853 # 'WAIT_END_OF_EXECUTION',
854 # 'SHOW_DOC',
855 # 'SHOW_PROMPT']
856
857 self.cur_state = 'IDLE'
858 self.pager_state = 'DONE'
859 #wx.CallAfter(self.runStateMachine)
600 #widget state management (for key handling different cases)
601 self.setCurrentState('IDLE')
602 self.pager_state = 'DONE'
603 self.raw_input_current_line = 0
604
605 def askExitCallback(self, event):
606 self.askExitHandler(event)
607
608 #---------------------- IPython Thread Management ------------------------
609 def stateDoExecuteLine(self):
610 lines=self.text_ctrl.getCurrentLine()
611 self.text_ctrl.write('\n')
612 lines_to_execute = lines.replace('\t',' '*4)
613 lines_to_execute = lines_to_execute.replace('\r','')
614 self.IP.doExecute(lines_to_execute.encode('cp1252'))
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
862 (self.AskExitEvent, EVT_ASK_EXIT) = wx.lib.newevent.NewEvent()
647 def pager(self,text):
863 648
864 self.Bind(wx.EVT_IDLE, self.runStateMachine)
865 self.Bind(EVT_ASK_EXIT, exit_handler)
866
867 def __del__(self):
868 self.IP.shutdown()
869 self.IP.join()
870 WxConsoleView.__del__()
871
872 #---------------------------- IPython Thread Management ---------------------------------------
873 def runStateMachine(self,event):
874 #print >>self.sys_stdout,"state:",self.cur_state
875 self.updateStatusTracker(self.cur_state)
876
877 if self.cur_state == 'DO_EXECUTE_LINE':
878 #print >>self.sys_stdout,"command:",self.getCurrentLine()
879 self.IP.doExecute(self.text_ctrl.getCurrentLine().replace('\t',' '*4))
880 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
881 self.cur_state = 'WAIT_END_OF_EXECUTION'
882
883 if self.cur_state == 'WAIT_END_OF_EXECUTION':
884 if self.IP.isExecuteDone():
885 self.doc = self.IP.getDocText()
886 if self.IP.getAskExit():
887 evt = self.AskExitEvent()
888 wx.PostEvent(self, evt)
889 self.IP.clearAskExit()
890 if self.doc:
891 self.pager_state = 'INIT'
892 self.cur_state = 'SHOW_DOC'
649 if self.pager_state == 'INIT':
650 #print >>sys.__stdout__,"PAGER state:",self.pager_state
651 self.pager_nb_lines = len(self.pager_lines)
652 self.pager_index = 0
653 self.pager_do_remove = False
654 self.text_ctrl.write('\n')
655 self.pager_state = 'PROCESS_LINES'
656
657 if self.pager_state == 'PROCESS_LINES':
658 #print >>sys.__stdout__,"PAGER state:",self.pager_state
659 if self.pager_do_remove == True:
660 self.text_ctrl.removeCurrentLine()
661 self.pager_do_remove = False
662
663 if self.pager_nb_lines > 10:
664 #print >>sys.__stdout__,"PAGER processing 10 lines"
665 if self.pager_index > 0:
666 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
667 else:
668 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
669
670 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
671 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
672 self.pager_index += 10
673 self.pager_nb_lines -= 10
674 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
675 self.pager_do_remove = True
676 self.pager_state = 'WAITING'
677 return
893 678 else:
894 self.cur_state = 'SHOW_PROMPT'
895
896 if self.cur_state == 'SHOW_PROMPT':
897 self.text_ctrl.setPrompt(self.IP.getPrompt())
898 self.text_ctrl.setIndentation(self.IP.getIndentation())
899 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
900 rv = self.cout.getvalue()
901 if rv: rv = rv.strip('\n')
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
679 #print >>sys.__stdout__,"PAGER processing last lines"
680 if self.pager_nb_lines > 0:
681 if self.pager_index > 0:
682 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
683 else:
684 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
685
686 self.pager_index += 1
959 687 self.pager_nb_lines -= 1
960 if self.pager_nb_lines > 0:
961 for line in self.pager_lines[self.pager_index:]:
962 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
963 self.pager_nb_lines = 0
964 self.pager_state = 'DONE'
688 if self.pager_nb_lines > 0:
689 for line in self.pager_lines[self.pager_index:]:
690 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
691 self.pager_nb_lines = 0
692 self.pager_state = 'DONE'
693 self.stateShowPrompt()
965 694
966 #---------------------------- Key Handler --------------------------------------------
695 #------------------------ Key Handler ------------------------------------
967 696 def keyPress(self, event):
968 697 '''
969 698 Key press callback with plenty of shell goodness, like history,
970 699 autocompletions, etc.
971 700 '''
972
973 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 703 if self.cur_state == 'WAIT_END_OF_EXECUTION':
976 704 #we raise an exception inside the IPython thread container
977 self.IP.raise_exc(KeyboardInterrupt)
705 self.IP.ce.raise_exc(KeyboardInterrupt)
978 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 716 if event.KeyCode == wx.WXK_RETURN:
981 717 if self.cur_state == 'IDLE':
982 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 721 return
722
985 723 if self.pager_state == 'WAITING':
986 724 self.pager_state = 'PROCESS_LINES'
725 self.pager(self.doc)
987 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 734 if event.GetKeyCode() in [ord('q'),ord('Q')]:
990 735 if self.pager_state == 'WAITING':
991 736 self.pager_state = 'DONE'
737 self.text_ctrl.write('\n')
738 self.stateShowPrompt()
992 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)
995 if self.cur_state == 'IDLE':
744 if self.cur_state == 'IDLE':
996 745 if event.KeyCode == wx.WXK_UP:
997 746 history = self.IP.historyBack()
998 747 self.text_ctrl.writeHistory(history)
@@ -1008,19 +757,68 b' class WxIPythonViewPanel(wx.Panel):'
1008 757 return
1009 758 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
1010 759 if len(possibilities) > 1:
1011 cur_slice = self.text_ctrl.getCurrentLine()
1012 self.text_ctrl.write('\n')
1013 self.text_ctrl.writeCompletion(possibilities)
1014 self.text_ctrl.write('\n')
1015
1016 self.text_ctrl.showPrompt()
1017 self.text_ctrl.write(cur_slice)
1018 self.text_ctrl.changeLine(completed or cur_slice)
1019
760 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
761 cur_slice = self.text_ctrl.getCurrentLine()
762 self.text_ctrl.write('\n')
763 self.text_ctrl.writeCompletion(possibilities)
764 self.text_ctrl.write('\n')
765
766 self.text_ctrl.showPrompt()
767 self.text_ctrl.write(cur_slice)
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 774 return
1021 775 event.Skip()
1022
1023 #---------------------------- Hook Section --------------------------------------------
776
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 822 def updateHistoryTracker(self,command_line):
1025 823 '''
1026 824 Default history tracker (does nothing)
@@ -1032,6 +830,7 b' class WxIPythonViewPanel(wx.Panel):'
1032 830 Define a new history tracker
1033 831 '''
1034 832 self.updateHistoryTracker = func
833
1035 834 def updateStatusTracker(self,status):
1036 835 '''
1037 836 Default status tracker (does nothing)
@@ -1043,4 +842,36 b' class WxIPythonViewPanel(wx.Panel):'
1043 842 Define a new status tracker
1044 843 '''
1045 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
2 import inspect
3 import ctypes
4
5
6 def _async_raise(tid, exctype):
7 """raises the exception, performs cleanup if needed"""
8 if not inspect.isclass(exctype):
9 raise TypeError("Only types can be raised (not instances)")
10 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
11 if res == 0:
12 raise ValueError("invalid thread id")
13 elif res != 1:
14 # """if it returns a number greater than one, you're in trouble,
15 # and you should call it again with exc=NULL to revert the effect"""
16 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
17 raise SystemError("PyThreadState_SetAsyncExc failed")
18
19
20 class Thread(threading.Thread):
21 def _get_my_tid(self):
22 """determines this (self's) thread id"""
23 if not self.isAlive():
24 raise threading.ThreadError("the thread is not active")
25
26 # do we have it cached?
27 if hasattr(self, "_thread_id"):
28 return self._thread_id
29
30 # no, look for it in the _active dict
31 for tid, tobj in threading._active.items():
32 if tobj is self:
33 self._thread_id = tid
34 return tid
35
36 raise AssertionError("could not determine the thread's id")
37
38 def raise_exc(self, exctype):
39 """raises the given exception type in the context of this thread"""
40 _async_raise(self._get_my_tid(), exctype)
41
42 def kill(self):
43 """raises SystemExit in the context of the given thread, which should
44 cause the thread to exit silently (unless caught)"""
45 self.raise_exc(SystemExit)
1 """
2 Thread subclass that can deal with asynchronously function calls via
3 raise_exc.
4 """
5
6 import threading
7 import inspect
8 import ctypes
9
10
11 def _async_raise(tid, exctype):
12 """raises the exception, performs cleanup if needed"""
13 if not inspect.isclass(exctype):
14 raise TypeError("Only types can be raised (not instances)")
15 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
16 if res == 0:
17 raise ValueError("invalid thread id")
18 elif res != 1:
19 # """if it returns a number greater than one, you're in trouble,
20 # and you should call it again with exc=NULL to revert the effect"""
21 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
22 raise SystemError("PyThreadState_SetAsyncExc failed")
23
24
25 class ThreadEx(threading.Thread):
26 def _get_my_tid(self):
27 """determines this (self's) thread id"""
28 if not self.isAlive():
29 raise threading.ThreadError("the thread is not active")
30
31 # do we have it cached?
32 if hasattr(self, "_thread_id"):
33 return self._thread_id
34
35 # no, look for it in the _active dict
36 for tid, tobj in threading._active.items():
37 if tobj is self:
38 self._thread_id = tid
39 return tid
40
41 raise AssertionError("could not determine the thread's id")
42
43 def raise_exc(self, exctype):
44 """raises the given exception type in the context of this thread"""
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 2 # -*- coding: iso-8859-15 -*-
3 3
4 4 import wx.aui
5 import wx.py
5
6 #used for about dialog
6 7 from wx.lib.wordwrap import wordwrap
7 8
8 from ipython_view import *
9 from ipython_history import *
9 #used for ipython GUI objects
10 from IPython.gui.wx.ipython_view import IPShellWidget
11 from IPython.gui.wx.ipython_history import IPythonHistoryPanel
10 12
11 13 __version__ = 0.8
12 14 __author__ = "Laurent Dufrechou"
@@ -20,7 +22,8 b' __license__ = "BSD"'
20 22 class MyFrame(wx.Frame):
21 23 """Creating one main frame for our
22 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 27 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE):
25 28 wx.Frame.__init__(self, parent, id, title, pos, size, style)
26 29 self._mgr = wx.aui.AuiManager()
@@ -30,15 +33,18 b' class MyFrame(wx.Frame):'
30 33
31 34 #create differents panels and make them persistant
32 35 self.history_panel = IPythonHistoryPanel(self)
36
37 self.history_panel.setOptionTrackerHook(self.optionSave)
33 38
34 self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
35 background_color = "BLACK")
36
37 #self.ipython_panel = WxIPythonViewPanel(self,self.OnExitDlg,
38 # background_color = "WHITE")
39
39 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
40 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
41
40 42 self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
41 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 49 self.statusbar = self.createStatus()
44 50 self.createMenu()
@@ -48,13 +54,11 b' class MyFrame(wx.Frame):'
48 54 # main panels
49 55 self._mgr.AddPane(self.ipython_panel , wx.CENTER, "IPython Shell")
50 56 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
51
57
52 58 # now we specify some panel characteristics
53 59 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
54 60 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
55 61 self._mgr.GetPane(self.history_panel).MinSize((200,400));
56
57
58 62
59 63 # tell the manager to "commit" all the changes just made
60 64 self._mgr.Update()
@@ -66,7 +70,7 b' class MyFrame(wx.Frame):'
66 70 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
67 71 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
68 72 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
69
73
70 74 warn_text = 'Hello from IPython and wxPython.\n'
71 75 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
72 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 83 dlg.ShowModal()
80 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 120 def createMenu(self):
83 121 """local method used to create one menu bar"""
84 122
@@ -121,6 +159,7 b' class MyFrame(wx.Frame):'
121 159 states = {'IDLE':'Idle',
122 160 'DO_EXECUTE_LINE':'Send command',
123 161 'WAIT_END_OF_EXECUTION':'Running command',
162 'WAITING_USER_INPUT':'Waiting user input',
124 163 'SHOW_DOC':'Showing doc',
125 164 'SHOW_PROMPT':'Showing prompt'}
126 165 self.statusbar.SetStatusText(states[text], 0)
@@ -56,7 +56,7 b' from pprint import PrettyPrinter'
56 56 __all__ = ['editor', 'fix_error_editor', 'result_display',
57 57 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
58 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 61 pformat = PrettyPrinter().pformat
62 62
@@ -227,11 +227,17 b' def show_in_pager(self,s):'
227 227 # raising TryNext here will use the default paging functionality
228 228 raise ipapi.TryNext
229 229
230 def pre_command_hook(self,cmd):
231 """" Executed before starting to execute a command """
230 def pre_prompt_hook(self):
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 237 return None
233 238
234 def post_command_hook(self,cmd):
235 """ Executed after executing a command """
239 def pre_runcode_hook(self):
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 274 res = []
275 275 lines = script.splitlines()
276
276 277 level = 0
277 278 for l in lines:
278 stripped = l.lstrip()
279 if not l.strip():
279 lstripped = l.lstrip()
280 stripped = l.strip()
281 if not stripped:
280 282 continue
281 newlevel = len(l) - len(stripped)
282 if level > 0 and newlevel == 0:
283 newlevel = len(l) - len(lstripped)
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 294 # add empty line
284 295 res.append('')
296
285 297 res.append(l)
286 298 level = newlevel
287 299 return '\n'.join(res) + '\n'
@@ -291,7 +303,7 b' class IPApi:'
291 303 else:
292 304 script = '\n'.join(lines)
293 305 clean=cleanup_ipy_script(script)
294
306 # print "_ip.runlines() script:\n",clean #dbg
295 307 self.IP.runlines(clean)
296 308 def to_user_ns(self,vars, interactive = True):
297 309 """Inject a group of variables into the IPython user namespace.
@@ -533,7 +545,7 b' class DebugTools:'
533 545 if name in self.hotnames:
534 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 549 """ Make and start a new ipython instance.
538 550
539 551 This can be called even without having an already initialized
@@ -542,7 +554,7 b' def launch_new_instance(user_ns = None):'
542 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 558 ses.mainloop()
547 559
548 560
@@ -578,7 +590,7 b' def make_user_global_ns(ns = None):'
578 590 return ns
579 591
580 592
581 def make_session(user_ns = None):
593 def make_session(user_ns = None, shellclass = None):
582 594 """Makes, but does not launch an IPython session.
583 595
584 596 Later on you can call obj.mainloop() on the returned object.
@@ -591,6 +603,6 b' def make_session(user_ns = None):'
591 603 WARNING: This should *not* be run when a session exists already."""
592 604
593 605 import IPython.Shell
594 return IPython.Shell.start(user_ns)
595
596
606 if shellclass is None:
607 return IPython.Shell.start(user_ns)
608 return shellclass(user_ns = user_ns)
@@ -6,7 +6,6 b' Requires Python 2.3 or newer.'
6 6
7 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 54 import tempfile
56 55 import traceback
57 56 import types
57 import warnings
58 warnings.filterwarnings('ignore', r'.*sets module*')
58 59 from sets import Set
59 60 from pprint import pprint, pformat
60 61
@@ -377,7 +378,10 b' class InteractiveShell(object,Magic):'
377 378 # Get system encoding at startup time. Certain terminals (like Emacs
378 379 # under Win32 have it set to None, and we need to have a known valid
379 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 386 # dict of things NOT to alias (keywords, builtins and some magics)
383 387 no_alias = {}
@@ -698,7 +702,10 b' class InteractiveShell(object,Magic):'
698 702
699 703 # Do a proper resetting of doctest, including the necessary displayhook
700 704 # monkeypatching
701 doctest_reload()
705 try:
706 doctest_reload()
707 except ImportError:
708 warn("doctest module does not exist.")
702 709
703 710 # Set user colors (don't do it in the constructor above so that it
704 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 1273 """Reload the input history from disk file."""
1267 1274
1268 1275 if self.has_readline:
1269 self.readline.clear_history()
1270 self.readline.read_history_file(self.shell.histfile)
1276 try:
1277 self.readline.clear_history()
1278 self.readline.read_history_file(self.shell.histfile)
1279 except AttributeError:
1280 pass
1281
1271 1282
1272 1283 def history_saving_wrapper(self, func):
1273 1284 """ Wrap func for readline history saving
@@ -1744,6 +1755,7 b' want to merge them back into the new files.""" % locals()'
1744 1755 # exit_now is set by a call to %Exit or %Quit
1745 1756
1746 1757 while not self.exit_now:
1758 self.hooks.pre_prompt_hook()
1747 1759 if more:
1748 1760 try:
1749 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 2022 try:
2011 2023 code = self.compile(source,filename,symbol)
2012 except (OverflowError, SyntaxError, ValueError):
2024 except (OverflowError, SyntaxError, ValueError, TypeError):
2013 2025 # Case 1
2014 2026 self.showsyntaxerror(filename)
2015 2027 return None
@@ -2053,6 +2065,7 b' want to merge them back into the new files.""" % locals()'
2053 2065 outflag = 1 # happens in more places, so it's easier as default
2054 2066 try:
2055 2067 try:
2068 self.hooks.pre_runcode_hook()
2056 2069 # Embedded instances require separate global/local namespaces
2057 2070 # so they can see both the surrounding (local) namespace and
2058 2071 # the module-level globals when called inside another function.
@@ -58,6 +58,14 b' from IPython.iplib import InteractiveShell'
58 58 from IPython.usage import cmd_line_usage,interactive_usage
59 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 70 def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,
63 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 103 embedded=embedded,**kw)
96 104
97 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 111 IP.user_config_ns = {}
100 IP.user_ns['help'] = _Helper()
101 112
102 113
103 114 if DEVDEBUG:
@@ -176,10 +187,10 b" object? -> Details about 'object'. ?object also works, ?? prints more."
176 187
177 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 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 195 # Build the actual name list to be used by DPyGetOpt
185 196 opts_names = qw(cmdline_opts) + qw(cmdline_only)
@@ -203,7 +214,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
203 214 editor = '0',
204 215 gthread = 0,
205 216 help = 0,
206 interact = 1,
217 interact = 0,
207 218 ipythondir = ipythondir_def,
208 219 log = 0,
209 220 logfile = '',
@@ -237,6 +248,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
237 248 system_verbose = 0,
238 249 term_title = 1,
239 250 tk = 0,
251 #twisted= 0, # disabled for now
240 252 upgrade = 0,
241 253 Version = 0,
242 254 wildcards_case_sensitive = 1,
@@ -633,15 +645,17 b" object? -> Details about 'object'. ?object also works, ?? prints more."
633 645 if opts_all.profile and not profile_handled_by_legacy:
634 646 profmodname = 'ipy_profile_' + opts_all.profile
635 647 try:
636 __import__(profmodname)
648
649 force_import(profmodname)
637 650 except:
638 651 IP.InteractiveTB()
639 652 print "Error importing",profmodname,"- perhaps you should run %upgrade?"
640 653 import_fail_info(profmodname)
641 654 else:
642 import ipy_profile_none
643 try:
644 import ipy_user_conf
655 force_import('ipy_profile_none')
656 try:
657
658 force_import('ipy_user_conf')
645 659
646 660 except:
647 661 conf = opts_all.ipythondir + "/ipy_user_conf.py"
@@ -23,12 +23,17 b' __license__ = Release.license'
23 23 import sys
24 24 import os
25 25
26 ignore_termtitle = False
26 27
27 28 def _dummy_op(*a, **b):
28 29 """ A no-op function """
29 30
30 31 def _set_term_title_xterm(title):
31 32 """ Change virtual terminal title in xterm-workalikes """
33
34 if ignore_termtitle:
35 return
36
32 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 42 else:
38 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 50 return
51 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 378 def __call__(self, etype, value, elist):
379 379 Term.cout.flush()
380 Term.cerr.flush()
381 380 print >> Term.cerr, self.text(etype,value,elist)
381 Term.cerr.flush()
382 382
383 383 def text(self,etype, value, elist,context=5):
384 384 """Return a color formatted string with the traceback info."""
@@ -855,8 +855,8 b' class VerboseTB(TBTools):'
855 855 (etype, evalue, etb) = info or sys.exc_info()
856 856 self.tb = etb
857 857 Term.cout.flush()
858 Term.cerr.flush()
859 858 print >> Term.cerr, self.text(etype, evalue, etb)
859 Term.cerr.flush()
860 860
861 861 # Changed so an instance can just be called as VerboseTB_inst() and print
862 862 # out the right info on its own.
@@ -977,13 +977,13 b' class AutoFormattedTB(FormattedTB):'
977 977 if out is None:
978 978 out = Term.cerr
979 979 Term.cout.flush()
980 out.flush()
981 980 if tb_offset is not None:
982 981 tb_offset, self.tb_offset = self.tb_offset, tb_offset
983 982 print >> out, self.text(etype, evalue, etb)
984 983 self.tb_offset = tb_offset
985 984 else:
986 985 print >> out, self.text(etype, evalue, etb)
986 out.flush()
987 987 try:
988 988 self.debugger()
989 989 except KeyboardInterrupt:
@@ -9,22 +9,23 b' graft setupext'
9 9 graft IPython/UserConfig
10 10
11 11 graft doc
12 exclude doc/\#*
12 13 exclude doc/*.1
13 exclude doc/manual_base*
14 14 exclude doc/ChangeLog.*
15 exclude doc/\#*
16 exclude doc/update_magic.sh
17 15 exclude doc/update_version.sh
18 exclude doc/manual_base*
19 exclude doc/manual/WARNINGS
20 exclude doc/manual/*.aux
21 exclude doc/manual/*.log
22 exclude doc/manual/*.out
23 exclude doc/manual/*.pl
24 exclude doc/manual/*.tex
16
17 # There seems to be no way of excluding whole subdirectories, other than
18 # manually excluding all their subdirs. distutils really is horrible...
19 exclude doc/attic/*
20 exclude doc/build/doctrees/*
21 exclude doc/build/html/_sources/*
22 exclude doc/build/html/_static/*
23 exclude doc/build/html/*
24 exclude doc/build/latex/*
25 25
26 26 global-exclude *~
27 27 global-exclude *.flc
28 28 global-exclude *.pyc
29 29 global-exclude .dircopy.log
30 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 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 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 350 ipython (0.4.0-1) unstable; urgency=low
29 351
30 * New upstream release (Closes #195215)
31 * Updated Build-Depends (Closes #200021)
352 * New upstream release (Closes: #195215)
353 * Updated Build-Depends (Closes: #200021)
32 354
33 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 1 Source: ipython
2 Section: devel
2 Section: python
3 3 Priority: optional
4 Maintainer: Jack Moffitt <jack@xiph.org>
5 Build-Depends-Indep: debhelper (>> 4.1.65), dpatch, python-dev
6 Standards-Version: 3.6.1
4 Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
5 Uploaders: Norbert Tretkowski <nobse@debian.org>, Bernd Zeimetz <bernd@bzed.de>
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 12 Package: ipython
9 13 Architecture: all
10 Depends: ${python:Depends}
11 Recommends: python-numeric, python-numeric-ext
12 Description: An enhanced interactive Python shell
13 IPython is an enhanced interactive Python shell. It can be used as a
14 replacement for the standard Python shell, or it can be used as a
15 complete working environment for scientific computing (like Matlab or
16 Mathematica) when paired with the standard Python scientific and
17 numerical tools. It supports dynamic object introspections, numbered
18 input/output prompts, a macro system, session logging, session
19 restoring, complete system shell access, verbose and colored
20 traceback reports, auto-parentheses, auto-quoting, and is
21 embeddedable in other Python programs.
14 Depends: ${python:Depends}, ${misc:Depends}, python-pexpect
15 Conflicts: python2.3-ipython, python2.4-ipython, ipython-common
16 Replaces: python2.3-ipython, python2.4-ipython, ipython-common
17 Suggests: python-profiler, python-numeric, python-numeric-ext, python-matplotlib
18 Description: enhanced interactive Python shell
19 IPython can be used as a replacement for the standard Python shell,
20 or it can be used as a complete working environment for scientific
21 computing (like Matlab or Mathematica) when paired with the standard
22 Python scientific and numerical tools. It supports dynamic object
23 introspections, numbered input/output prompts, a macro system,
24 session logging, session restoring, complete system shell access,
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 4 It was downloaded from http://ipython.scipy.org/
5 5
6 6 Upstream Author: Fernando Perez <fperez@colorado.edu>,
7 Janko Hauser <jhauser@zscout.de>,
7 Janko Hauser <jhauser@ifm.uni-kiel.de>,
8 8 Nathaniel Gray <n8gray@caltech.edu>
9 9
10 10 Copyright:
11 11
12 Most IPython code is copyright (C) 2001-2004 by Fernando Perez, Janko Hauser,
13 and Nathaniel Gray. All code is licensed under a BSD-type License except as
14 explicitly mentioned below. The full IPython license is:
15
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
12 Most IPython code is copyright (C) 2001 by Fernando Perez, Janko
13 Hauser, and Nathaniel Gray. All code is licensed under the GNU Lesser
14 General Public License (LGPL) except as explicitly mentioned below.
15 Its full text is included in the file /usr/share/common-licenses/LGPL.
52 16
53 17 DPyGetOpt.py is copyright (C) 2001 by Bill Bumgarner <bbum@friday.com>
54 18 and is licensed under the MIT license, reproduced below:
@@ -1,98 +1,25 b''
1 1 #!/usr/bin/make -f
2 # Sample debian/rules that uses debhelper.
3 # GNU copyright 1997 to 1999 by Joey Hess.
4
5 # Uncomment this to turn on verbose mode.
6 #export DH_VERBOSE=1
7
8
9
10
11 CFLAGS = -Wall -g
12
13 ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
14 CFLAGS += -O0
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
2 # ipython debian/rules file
3 DEB_PYTHON_SYSTEM=pysupport
4 include /usr/share/cdbs/1/rules/debhelper.mk
5 include /usr/share/cdbs/1/class/python-distutils.mk
6 include /usr/share/cdbs/1/rules/dpatch.mk
7
8 install/ipython::
9 # remove documentation
10 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/COPYING
11 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/ChangeLog
12 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/README_Windows.txt
13 rm $(CURDIR)/debian/ipython/usr/share/doc/ipython/pycon.ico
14
62 15 # change permission on scripts
63 chmod 755 $(CURDIR)/debian/ipython/usr/share/doc/ipython/examples/example-embed.py
64 chmod 755 $(CURDIR)/debian/ipython/usr/share/doc/ipython/examples/example-gnuplot.py
65
66 binary-indep: build install
67 dh_testdir
68 dh_testroot
69 dh_installchangelogs doc/ChangeLog
70 dh_installdocs
71 # dh_installexamples
72 dh_install
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
16 chmod a-x $(CURDIR)/debian/ipython/usr/share/doc/ipython/examples/*
17
18 # removing bogus usr/IPython directory
19 rm -rf $(CURDIR)/debian/ipython/usr/IPython
20
21 binary-fixup/ipython::
22 # fix lintian warnings (see also patches/04_remove_shebang.dpatch)
23 chmod +x $(CURDIR)/debian/ipython/usr/share/python-support/ipython/IPython/upgrade_dir.py
24 chmod +x $(CURDIR)/debian/ipython/usr/share/python-support/ipython/IPython/Extensions/pickleshare.py
25 chmod +x $(CURDIR)/debian/ipython/usr/share/python-support/ipython/IPython/irunner.py
@@ -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 222 2008-02-07 Darren Dale <darren.dale@cornell.edu>
2 223
3 * IPython/Shell.py: Call QtCore.pyqtRemoveInputHook() when creating
4 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
6 partially interfere with the IPython implementation and exec_()
7 still seems to block. So we disable the PyQt implementation and
8 stick with the IPython one for now.
224 * IPython/Shell.py: Call QtCore.pyqtRemoveInputHook() when creating
225 an IPShellQt4. PyQt4-4.2.1 and later uses PyOS_InputHook to improve
226 interaction in the interpreter (like Tkinter does), but it seems to
227 partially interfere with the IPython implementation and exec_()
228 still seems to block. So we disable the PyQt implementation and
229 stick with the IPython one for now.
9 230
10 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
1 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
1 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
@@ -1,20 +1,20 b''
1 # -*- coding: utf-8 -*-
2
3 import IPython.ipapi
4 ip = IPython.ipapi.get()
5
6 def ${name}_f(self, arg):
7 r""" Short explanation
8
9 Long explanation, examples
10
11 """
12
13 # opts,args = self.parse_options(arg,'rx')
14 # if 'r' in opts: pass
15
16
17
18 ip.expose_magic("${name}",${name}_f)
19
20
1 # -*- coding: utf-8 -*-
2
3 import IPython.ipapi
4 ip = IPython.ipapi.get()
5
6 def ${name}_f(self, arg):
7 r""" Short explanation
8
9 Long explanation, examples
10
11 """
12
13 # opts,args = self.parse_options(arg,'rx')
14 # if 'r' in opts: pass
15
16
17
18 ip.expose_magic("${name}",${name}_f)
19
20
@@ -1,6 +1,6 b''
1 Windows Registry Editor Version 5.00
2
3 [HKEY_CLASSES_ROOT\Directory\shell\IPython here]
4
5 [HKEY_CLASSES_ROOT\Directory\shell\IPython here\Command]
1 Windows Registry Editor Version 5.00
2
3 [HKEY_CLASSES_ROOT\Directory\shell\IPython here]
4
5 [HKEY_CLASSES_ROOT\Directory\shell\IPython here\Command]
6 6 @="cmd.exe /C ipython.py -p sh -i -c \"%cd %1\"" No newline at end of file
@@ -36,11 +36,11 b' The following special options are ONLY valid at the beginning of the command'
36 36 line, and not later. This is because they control the initialization of
37 37 ipython itself, before the normal option-handling mechanism is active.
38 38 .TP
39 .B \-gthread, \-qthread, \-q4thread, \-wthread, \-pylab
39 .B \-gthread, \-qthread, \-q4thread, \-wthread, \-pylab, \-twisted
40 40 Only ONE of these can be given, and it can only be given as the first option
41 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
43 matplotlib library.
42 threading support for the GTK, QT3, QT4 and WXWidgets toolkits, for the
43 matplotlib library and Twisted reactor.
44 44 .br
45 45 .sp 1
46 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 56 distributions.
57 57 .br
58 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 63 If \-pylab is given, IPython loads special support for the matplotlib library
60 64 (http://matplotlib.sourceforge.net), allowing interactive usage of any of its
61 65 backends as defined in the user's .matplotlibrc file. It automatically
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
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