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