##// END OF EJS Templates
Remove unused imports
Thomas Kluyver -
Show More
@@ -1,263 +1,262 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 System command aliases.
3 System command aliases.
4
4
5 Authors:
5 Authors:
6
6
7 * Fernando Perez
7 * Fernando Perez
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License.
14 # Distributed under the terms of the BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import __builtin__
23 import __builtin__
24 import keyword
24 import keyword
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28
28
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.splitinput import split_user_input
30 from IPython.core.splitinput import split_user_input
31
31
32 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.traitlets import List, Instance
33 from IPython.utils.autoattr import auto_attr
34 from IPython.utils.warn import warn, error
33 from IPython.utils.warn import warn, error
35
34
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37 # Utilities
36 # Utilities
38 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
39
38
40 # This is used as the pattern for calls to split_user_input.
39 # This is used as the pattern for calls to split_user_input.
41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
40 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42
41
43 def default_aliases():
42 def default_aliases():
44 """Return list of shell aliases to auto-define.
43 """Return list of shell aliases to auto-define.
45 """
44 """
46 # Note: the aliases defined here should be safe to use on a kernel
45 # Note: the aliases defined here should be safe to use on a kernel
47 # regardless of what frontend it is attached to. Frontends that use a
46 # regardless of what frontend it is attached to. Frontends that use a
48 # kernel in-process can define additional aliases that will only work in
47 # kernel in-process can define additional aliases that will only work in
49 # their case. For example, things like 'less' or 'clear' that manipulate
48 # their case. For example, things like 'less' or 'clear' that manipulate
50 # the terminal should NOT be declared here, as they will only work if the
49 # the terminal should NOT be declared here, as they will only work if the
51 # kernel is running inside a true terminal, and not over the network.
50 # kernel is running inside a true terminal, and not over the network.
52
51
53 if os.name == 'posix':
52 if os.name == 'posix':
54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
53 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
54 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
56 ('cat', 'cat'),
55 ('cat', 'cat'),
57 ]
56 ]
58 # Useful set of ls aliases. The GNU and BSD options are a little
57 # Useful set of ls aliases. The GNU and BSD options are a little
59 # different, so we make aliases that provide as similar as possible
58 # different, so we make aliases that provide as similar as possible
60 # behavior in ipython, by passing the right flags for each platform
59 # behavior in ipython, by passing the right flags for each platform
61 if sys.platform.startswith('linux'):
60 if sys.platform.startswith('linux'):
62 ls_aliases = [('ls', 'ls -F --color'),
61 ls_aliases = [('ls', 'ls -F --color'),
63 # long ls
62 # long ls
64 ('ll', 'ls -F -o --color'),
63 ('ll', 'ls -F -o --color'),
65 # ls normal files only
64 # ls normal files only
66 ('lf', 'ls -F -o --color %l | grep ^-'),
65 ('lf', 'ls -F -o --color %l | grep ^-'),
67 # ls symbolic links
66 # ls symbolic links
68 ('lk', 'ls -F -o --color %l | grep ^l'),
67 ('lk', 'ls -F -o --color %l | grep ^l'),
69 # directories or links to directories,
68 # directories or links to directories,
70 ('ldir', 'ls -F -o --color %l | grep /$'),
69 ('ldir', 'ls -F -o --color %l | grep /$'),
71 # things which are executable
70 # things which are executable
72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
71 ('lx', 'ls -F -o --color %l | grep ^-..x'),
73 ]
72 ]
74 else:
73 else:
75 # BSD, OSX, etc.
74 # BSD, OSX, etc.
76 ls_aliases = [('ls', 'ls -F'),
75 ls_aliases = [('ls', 'ls -F'),
77 # long ls
76 # long ls
78 ('ll', 'ls -F -l'),
77 ('ll', 'ls -F -l'),
79 # ls normal files only
78 # ls normal files only
80 ('lf', 'ls -F -l %l | grep ^-'),
79 ('lf', 'ls -F -l %l | grep ^-'),
81 # ls symbolic links
80 # ls symbolic links
82 ('lk', 'ls -F -l %l | grep ^l'),
81 ('lk', 'ls -F -l %l | grep ^l'),
83 # directories or links to directories,
82 # directories or links to directories,
84 ('ldir', 'ls -F -l %l | grep /$'),
83 ('ldir', 'ls -F -l %l | grep /$'),
85 # things which are executable
84 # things which are executable
86 ('lx', 'ls -F -l %l | grep ^-..x'),
85 ('lx', 'ls -F -l %l | grep ^-..x'),
87 ]
86 ]
88 default_aliases = default_aliases + ls_aliases
87 default_aliases = default_aliases + ls_aliases
89 elif os.name in ['nt', 'dos']:
88 elif os.name in ['nt', 'dos']:
90 default_aliases = [('ls', 'dir /on'),
89 default_aliases = [('ls', 'dir /on'),
91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
90 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
91 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
92 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
94 ]
93 ]
95 else:
94 else:
96 default_aliases = []
95 default_aliases = []
97
96
98 return default_aliases
97 return default_aliases
99
98
100
99
101 class AliasError(Exception):
100 class AliasError(Exception):
102 pass
101 pass
103
102
104
103
105 class InvalidAliasError(AliasError):
104 class InvalidAliasError(AliasError):
106 pass
105 pass
107
106
108 #-----------------------------------------------------------------------------
107 #-----------------------------------------------------------------------------
109 # Main AliasManager class
108 # Main AliasManager class
110 #-----------------------------------------------------------------------------
109 #-----------------------------------------------------------------------------
111
110
112 class AliasManager(Configurable):
111 class AliasManager(Configurable):
113
112
114 default_aliases = List(default_aliases(), config=True)
113 default_aliases = List(default_aliases(), config=True)
115 user_aliases = List(default_value=[], config=True)
114 user_aliases = List(default_value=[], config=True)
116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
115 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
117
116
118 def __init__(self, shell=None, config=None):
117 def __init__(self, shell=None, config=None):
119 super(AliasManager, self).__init__(shell=shell, config=config)
118 super(AliasManager, self).__init__(shell=shell, config=config)
120 self.alias_table = {}
119 self.alias_table = {}
121 self.exclude_aliases()
120 self.exclude_aliases()
122 self.init_aliases()
121 self.init_aliases()
123
122
124 def __contains__(self, name):
123 def __contains__(self, name):
125 return name in self.alias_table
124 return name in self.alias_table
126
125
127 @property
126 @property
128 def aliases(self):
127 def aliases(self):
129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
128 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
130
129
131 def exclude_aliases(self):
130 def exclude_aliases(self):
132 # set of things NOT to alias (keywords, builtins and some magics)
131 # set of things NOT to alias (keywords, builtins and some magics)
133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
132 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
134 no_alias.update(set(keyword.kwlist))
133 no_alias.update(set(keyword.kwlist))
135 no_alias.update(set(__builtin__.__dict__.keys()))
134 no_alias.update(set(__builtin__.__dict__.keys()))
136 self.no_alias = no_alias
135 self.no_alias = no_alias
137
136
138 def init_aliases(self):
137 def init_aliases(self):
139 # Load default aliases
138 # Load default aliases
140 for name, cmd in self.default_aliases:
139 for name, cmd in self.default_aliases:
141 self.soft_define_alias(name, cmd)
140 self.soft_define_alias(name, cmd)
142
141
143 # Load user aliases
142 # Load user aliases
144 for name, cmd in self.user_aliases:
143 for name, cmd in self.user_aliases:
145 self.soft_define_alias(name, cmd)
144 self.soft_define_alias(name, cmd)
146
145
147 def clear_aliases(self):
146 def clear_aliases(self):
148 self.alias_table.clear()
147 self.alias_table.clear()
149
148
150 def soft_define_alias(self, name, cmd):
149 def soft_define_alias(self, name, cmd):
151 """Define an alias, but don't raise on an AliasError."""
150 """Define an alias, but don't raise on an AliasError."""
152 try:
151 try:
153 self.define_alias(name, cmd)
152 self.define_alias(name, cmd)
154 except AliasError as e:
153 except AliasError as e:
155 error("Invalid alias: %s" % e)
154 error("Invalid alias: %s" % e)
156
155
157 def define_alias(self, name, cmd):
156 def define_alias(self, name, cmd):
158 """Define a new alias after validating it.
157 """Define a new alias after validating it.
159
158
160 This will raise an :exc:`AliasError` if there are validation
159 This will raise an :exc:`AliasError` if there are validation
161 problems.
160 problems.
162 """
161 """
163 nargs = self.validate_alias(name, cmd)
162 nargs = self.validate_alias(name, cmd)
164 self.alias_table[name] = (nargs, cmd)
163 self.alias_table[name] = (nargs, cmd)
165
164
166 def undefine_alias(self, name):
165 def undefine_alias(self, name):
167 if name in self.alias_table:
166 if name in self.alias_table:
168 del self.alias_table[name]
167 del self.alias_table[name]
169
168
170 def validate_alias(self, name, cmd):
169 def validate_alias(self, name, cmd):
171 """Validate an alias and return the its number of arguments."""
170 """Validate an alias and return the its number of arguments."""
172 if name in self.no_alias:
171 if name in self.no_alias:
173 raise InvalidAliasError("The name %s can't be aliased "
172 raise InvalidAliasError("The name %s can't be aliased "
174 "because it is a keyword or builtin." % name)
173 "because it is a keyword or builtin." % name)
175 if not (isinstance(cmd, basestring)):
174 if not (isinstance(cmd, basestring)):
176 raise InvalidAliasError("An alias command must be a string, "
175 raise InvalidAliasError("An alias command must be a string, "
177 "got: %r" % cmd)
176 "got: %r" % cmd)
178 nargs = cmd.count('%s')
177 nargs = cmd.count('%s')
179 if nargs>0 and cmd.find('%l')>=0:
178 if nargs>0 and cmd.find('%l')>=0:
180 raise InvalidAliasError('The %s and %l specifiers are mutually '
179 raise InvalidAliasError('The %s and %l specifiers are mutually '
181 'exclusive in alias definitions.')
180 'exclusive in alias definitions.')
182 return nargs
181 return nargs
183
182
184 def call_alias(self, alias, rest=''):
183 def call_alias(self, alias, rest=''):
185 """Call an alias given its name and the rest of the line."""
184 """Call an alias given its name and the rest of the line."""
186 cmd = self.transform_alias(alias, rest)
185 cmd = self.transform_alias(alias, rest)
187 try:
186 try:
188 self.shell.system(cmd)
187 self.shell.system(cmd)
189 except:
188 except:
190 self.shell.showtraceback()
189 self.shell.showtraceback()
191
190
192 def transform_alias(self, alias,rest=''):
191 def transform_alias(self, alias,rest=''):
193 """Transform alias to system command string."""
192 """Transform alias to system command string."""
194 nargs, cmd = self.alias_table[alias]
193 nargs, cmd = self.alias_table[alias]
195
194
196 if ' ' in cmd and os.path.isfile(cmd):
195 if ' ' in cmd and os.path.isfile(cmd):
197 cmd = '"%s"' % cmd
196 cmd = '"%s"' % cmd
198
197
199 # Expand the %l special to be the user's input line
198 # Expand the %l special to be the user's input line
200 if cmd.find('%l') >= 0:
199 if cmd.find('%l') >= 0:
201 cmd = cmd.replace('%l', rest)
200 cmd = cmd.replace('%l', rest)
202 rest = ''
201 rest = ''
203 if nargs==0:
202 if nargs==0:
204 # Simple, argument-less aliases
203 # Simple, argument-less aliases
205 cmd = '%s %s' % (cmd, rest)
204 cmd = '%s %s' % (cmd, rest)
206 else:
205 else:
207 # Handle aliases with positional arguments
206 # Handle aliases with positional arguments
208 args = rest.split(None, nargs)
207 args = rest.split(None, nargs)
209 if len(args) < nargs:
208 if len(args) < nargs:
210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
209 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
211 (alias, nargs, len(args)))
210 (alias, nargs, len(args)))
212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
211 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
213 return cmd
212 return cmd
214
213
215 def expand_alias(self, line):
214 def expand_alias(self, line):
216 """ Expand an alias in the command line
215 """ Expand an alias in the command line
217
216
218 Returns the provided command line, possibly with the first word
217 Returns the provided command line, possibly with the first word
219 (command) translated according to alias expansion rules.
218 (command) translated according to alias expansion rules.
220
219
221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
220 [ipython]|16> _ip.expand_aliases("np myfile.txt")
222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
221 <16> 'q:/opt/np/notepad++.exe myfile.txt'
223 """
222 """
224
223
225 pre,_,fn,rest = split_user_input(line)
224 pre,_,fn,rest = split_user_input(line)
226 res = pre + self.expand_aliases(fn, rest)
225 res = pre + self.expand_aliases(fn, rest)
227 return res
226 return res
228
227
229 def expand_aliases(self, fn, rest):
228 def expand_aliases(self, fn, rest):
230 """Expand multiple levels of aliases:
229 """Expand multiple levels of aliases:
231
230
232 if:
231 if:
233
232
234 alias foo bar /tmp
233 alias foo bar /tmp
235 alias baz foo
234 alias baz foo
236
235
237 then:
236 then:
238
237
239 baz huhhahhei -> bar /tmp huhhahhei
238 baz huhhahhei -> bar /tmp huhhahhei
240 """
239 """
241 line = fn + " " + rest
240 line = fn + " " + rest
242
241
243 done = set()
242 done = set()
244 while 1:
243 while 1:
245 pre,_,fn,rest = split_user_input(line, shell_line_split)
244 pre,_,fn,rest = split_user_input(line, shell_line_split)
246 if fn in self.alias_table:
245 if fn in self.alias_table:
247 if fn in done:
246 if fn in done:
248 warn("Cyclic alias definition, repeated '%s'" % fn)
247 warn("Cyclic alias definition, repeated '%s'" % fn)
249 return ""
248 return ""
250 done.add(fn)
249 done.add(fn)
251
250
252 l2 = self.transform_alias(fn, rest)
251 l2 = self.transform_alias(fn, rest)
253 if l2 == line:
252 if l2 == line:
254 break
253 break
255 # ls -> ls -F should not recurse forever
254 # ls -> ls -F should not recurse forever
256 if l2.split(None,1)[0] == line.split(None,1)[0]:
255 if l2.split(None,1)[0] == line.split(None,1)[0]:
257 line = l2
256 line = l2
258 break
257 break
259 line=l2
258 line=l2
260 else:
259 else:
261 break
260 break
262
261
263 return line
262 return line
@@ -1,933 +1,932 b''
1 """Word completion for IPython.
1 """Word completion for IPython.
2
2
3 This module is a fork of the rlcompleter module in the Python standard
3 This module is a fork of the rlcompleter module in the Python standard
4 library. The original enhancements made to rlcompleter have been sent
4 library. The original enhancements made to rlcompleter have been sent
5 upstream and were accepted as of Python 2.3, but we need a lot more
5 upstream and were accepted as of Python 2.3, but we need a lot more
6 functionality specific to IPython, so this module will continue to live as an
6 functionality specific to IPython, so this module will continue to live as an
7 IPython-specific utility.
7 IPython-specific utility.
8
8
9 Original rlcompleter documentation:
9 Original rlcompleter documentation:
10
10
11 This requires the latest extension to the readline module (the
11 This requires the latest extension to the readline module (the
12 completes keywords, built-ins and globals in __main__; when completing
12 completes keywords, built-ins and globals in __main__; when completing
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 completes its attributes.
14 completes its attributes.
15
15
16 It's very cool to do "import string" type "string.", hit the
16 It's very cool to do "import string" type "string.", hit the
17 completion key (twice), and see the list of names defined by the
17 completion key (twice), and see the list of names defined by the
18 string module!
18 string module!
19
19
20 Tip: to use the tab key as the completion key, call
20 Tip: to use the tab key as the completion key, call
21
21
22 readline.parse_and_bind("tab: complete")
22 readline.parse_and_bind("tab: complete")
23
23
24 Notes:
24 Notes:
25
25
26 - Exceptions raised by the completer function are *ignored* (and
26 - Exceptions raised by the completer function are *ignored* (and
27 generally cause the completion to fail). This is a feature -- since
27 generally cause the completion to fail). This is a feature -- since
28 readline sets the tty device in raw (or cbreak) mode, printing a
28 readline sets the tty device in raw (or cbreak) mode, printing a
29 traceback wouldn't work well without some complicated hoopla to save,
29 traceback wouldn't work well without some complicated hoopla to save,
30 reset and restore the tty state.
30 reset and restore the tty state.
31
31
32 - The evaluation of the NAME.NAME... form may cause arbitrary
32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 application defined code to be executed if an object with a
33 application defined code to be executed if an object with a
34 __getattr__ hook is found. Since it is the responsibility of the
34 __getattr__ hook is found. Since it is the responsibility of the
35 application (or the user) to enable this feature, I consider this an
35 application (or the user) to enable this feature, I consider this an
36 acceptable risk. More complicated expressions (e.g. function calls or
36 acceptable risk. More complicated expressions (e.g. function calls or
37 indexing operations) are *not* evaluated.
37 indexing operations) are *not* evaluated.
38
38
39 - GNU readline is also used by the built-in functions input() and
39 - GNU readline is also used by the built-in functions input() and
40 raw_input(), and thus these also benefit/suffer from the completer
40 raw_input(), and thus these also benefit/suffer from the completer
41 features. Clearly an interactive application can benefit by
41 features. Clearly an interactive application can benefit by
42 specifying its own completer function and using raw_input() for all
42 specifying its own completer function and using raw_input() for all
43 its input.
43 its input.
44
44
45 - When the original stdin is not a tty device, GNU readline is never
45 - When the original stdin is not a tty device, GNU readline is never
46 used, and this module (and the readline module) are silently inactive.
46 used, and this module (and the readline module) are silently inactive.
47 """
47 """
48
48
49 #*****************************************************************************
49 #*****************************************************************************
50 #
50 #
51 # Since this file is essentially a minimally modified copy of the rlcompleter
51 # Since this file is essentially a minimally modified copy of the rlcompleter
52 # module which is part of the standard Python distribution, I assume that the
52 # module which is part of the standard Python distribution, I assume that the
53 # proper procedure is to maintain its copyright as belonging to the Python
53 # proper procedure is to maintain its copyright as belonging to the Python
54 # Software Foundation (in addition to my own, for all new code).
54 # Software Foundation (in addition to my own, for all new code).
55 #
55 #
56 # Copyright (C) 2008 IPython Development Team
56 # Copyright (C) 2008 IPython Development Team
57 # Copyright (C) 2001 Fernando Perez. <fperez@colorado.edu>
57 # Copyright (C) 2001 Fernando Perez. <fperez@colorado.edu>
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 #
59 #
60 # Distributed under the terms of the BSD License. The full license is in
60 # Distributed under the terms of the BSD License. The full license is in
61 # the file COPYING, distributed as part of this software.
61 # the file COPYING, distributed as part of this software.
62 #
62 #
63 #*****************************************************************************
63 #*****************************************************************************
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Imports
66 # Imports
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68
68
69 import __builtin__
69 import __builtin__
70 import __main__
70 import __main__
71 import glob
71 import glob
72 import inspect
72 import inspect
73 import itertools
73 import itertools
74 import keyword
74 import keyword
75 import os
75 import os
76 import re
76 import re
77 import shlex
78 import sys
77 import sys
79
78
80 from IPython.config.configurable import Configurable
79 from IPython.config.configurable import Configurable
81 from IPython.core.error import TryNext
80 from IPython.core.error import TryNext
82 from IPython.core.inputsplitter import ESC_MAGIC
81 from IPython.core.inputsplitter import ESC_MAGIC
83 from IPython.utils import generics
82 from IPython.utils import generics
84 from IPython.utils import io
83 from IPython.utils import io
85 from IPython.utils.dir2 import dir2
84 from IPython.utils.dir2 import dir2
86 from IPython.utils.process import arg_split
85 from IPython.utils.process import arg_split
87 from IPython.utils.traitlets import CBool, Enum
86 from IPython.utils.traitlets import CBool, Enum
88
87
89 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
90 # Globals
89 # Globals
91 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
92
91
93 # Public API
92 # Public API
94 __all__ = ['Completer','IPCompleter']
93 __all__ = ['Completer','IPCompleter']
95
94
96 if sys.platform == 'win32':
95 if sys.platform == 'win32':
97 PROTECTABLES = ' '
96 PROTECTABLES = ' '
98 else:
97 else:
99 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
98 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
100
99
101 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
102 # Main functions and classes
101 # Main functions and classes
103 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
104
103
105 def has_open_quotes(s):
104 def has_open_quotes(s):
106 """Return whether a string has open quotes.
105 """Return whether a string has open quotes.
107
106
108 This simply counts whether the number of quote characters of either type in
107 This simply counts whether the number of quote characters of either type in
109 the string is odd.
108 the string is odd.
110
109
111 Returns
110 Returns
112 -------
111 -------
113 If there is an open quote, the quote character is returned. Else, return
112 If there is an open quote, the quote character is returned. Else, return
114 False.
113 False.
115 """
114 """
116 # We check " first, then ', so complex cases with nested quotes will get
115 # We check " first, then ', so complex cases with nested quotes will get
117 # the " to take precedence.
116 # the " to take precedence.
118 if s.count('"') % 2:
117 if s.count('"') % 2:
119 return '"'
118 return '"'
120 elif s.count("'") % 2:
119 elif s.count("'") % 2:
121 return "'"
120 return "'"
122 else:
121 else:
123 return False
122 return False
124
123
125
124
126 def protect_filename(s):
125 def protect_filename(s):
127 """Escape a string to protect certain characters."""
126 """Escape a string to protect certain characters."""
128
127
129 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
128 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
130 for ch in s])
129 for ch in s])
131
130
132 def expand_user(path):
131 def expand_user(path):
133 """Expand '~'-style usernames in strings.
132 """Expand '~'-style usernames in strings.
134
133
135 This is similar to :func:`os.path.expanduser`, but it computes and returns
134 This is similar to :func:`os.path.expanduser`, but it computes and returns
136 extra information that will be useful if the input was being used in
135 extra information that will be useful if the input was being used in
137 computing completions, and you wish to return the completions with the
136 computing completions, and you wish to return the completions with the
138 original '~' instead of its expanded value.
137 original '~' instead of its expanded value.
139
138
140 Parameters
139 Parameters
141 ----------
140 ----------
142 path : str
141 path : str
143 String to be expanded. If no ~ is present, the output is the same as the
142 String to be expanded. If no ~ is present, the output is the same as the
144 input.
143 input.
145
144
146 Returns
145 Returns
147 -------
146 -------
148 newpath : str
147 newpath : str
149 Result of ~ expansion in the input path.
148 Result of ~ expansion in the input path.
150 tilde_expand : bool
149 tilde_expand : bool
151 Whether any expansion was performed or not.
150 Whether any expansion was performed or not.
152 tilde_val : str
151 tilde_val : str
153 The value that ~ was replaced with.
152 The value that ~ was replaced with.
154 """
153 """
155 # Default values
154 # Default values
156 tilde_expand = False
155 tilde_expand = False
157 tilde_val = ''
156 tilde_val = ''
158 newpath = path
157 newpath = path
159
158
160 if path.startswith('~'):
159 if path.startswith('~'):
161 tilde_expand = True
160 tilde_expand = True
162 rest = len(path)-1
161 rest = len(path)-1
163 newpath = os.path.expanduser(path)
162 newpath = os.path.expanduser(path)
164 if rest:
163 if rest:
165 tilde_val = newpath[:-rest]
164 tilde_val = newpath[:-rest]
166 else:
165 else:
167 tilde_val = newpath
166 tilde_val = newpath
168
167
169 return newpath, tilde_expand, tilde_val
168 return newpath, tilde_expand, tilde_val
170
169
171
170
172 def compress_user(path, tilde_expand, tilde_val):
171 def compress_user(path, tilde_expand, tilde_val):
173 """Does the opposite of expand_user, with its outputs.
172 """Does the opposite of expand_user, with its outputs.
174 """
173 """
175 if tilde_expand:
174 if tilde_expand:
176 return path.replace(tilde_val, '~')
175 return path.replace(tilde_val, '~')
177 else:
176 else:
178 return path
177 return path
179
178
180
179
181 class Bunch(object): pass
180 class Bunch(object): pass
182
181
183
182
184 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
183 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
185 GREEDY_DELIMS = ' =\r\n'
184 GREEDY_DELIMS = ' =\r\n'
186
185
187
186
188 class CompletionSplitter(object):
187 class CompletionSplitter(object):
189 """An object to split an input line in a manner similar to readline.
188 """An object to split an input line in a manner similar to readline.
190
189
191 By having our own implementation, we can expose readline-like completion in
190 By having our own implementation, we can expose readline-like completion in
192 a uniform manner to all frontends. This object only needs to be given the
191 a uniform manner to all frontends. This object only needs to be given the
193 line of text to be split and the cursor position on said line, and it
192 line of text to be split and the cursor position on said line, and it
194 returns the 'word' to be completed on at the cursor after splitting the
193 returns the 'word' to be completed on at the cursor after splitting the
195 entire line.
194 entire line.
196
195
197 What characters are used as splitting delimiters can be controlled by
196 What characters are used as splitting delimiters can be controlled by
198 setting the `delims` attribute (this is a property that internally
197 setting the `delims` attribute (this is a property that internally
199 automatically builds the necessary regular expression)"""
198 automatically builds the necessary regular expression)"""
200
199
201 # Private interface
200 # Private interface
202
201
203 # A string of delimiter characters. The default value makes sense for
202 # A string of delimiter characters. The default value makes sense for
204 # IPython's most typical usage patterns.
203 # IPython's most typical usage patterns.
205 _delims = DELIMS
204 _delims = DELIMS
206
205
207 # The expression (a normal string) to be compiled into a regular expression
206 # The expression (a normal string) to be compiled into a regular expression
208 # for actual splitting. We store it as an attribute mostly for ease of
207 # for actual splitting. We store it as an attribute mostly for ease of
209 # debugging, since this type of code can be so tricky to debug.
208 # debugging, since this type of code can be so tricky to debug.
210 _delim_expr = None
209 _delim_expr = None
211
210
212 # The regular expression that does the actual splitting
211 # The regular expression that does the actual splitting
213 _delim_re = None
212 _delim_re = None
214
213
215 def __init__(self, delims=None):
214 def __init__(self, delims=None):
216 delims = CompletionSplitter._delims if delims is None else delims
215 delims = CompletionSplitter._delims if delims is None else delims
217 self.delims = delims
216 self.delims = delims
218
217
219 @property
218 @property
220 def delims(self):
219 def delims(self):
221 """Return the string of delimiter characters."""
220 """Return the string of delimiter characters."""
222 return self._delims
221 return self._delims
223
222
224 @delims.setter
223 @delims.setter
225 def delims(self, delims):
224 def delims(self, delims):
226 """Set the delimiters for line splitting."""
225 """Set the delimiters for line splitting."""
227 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
226 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
228 self._delim_re = re.compile(expr)
227 self._delim_re = re.compile(expr)
229 self._delims = delims
228 self._delims = delims
230 self._delim_expr = expr
229 self._delim_expr = expr
231
230
232 def split_line(self, line, cursor_pos=None):
231 def split_line(self, line, cursor_pos=None):
233 """Split a line of text with a cursor at the given position.
232 """Split a line of text with a cursor at the given position.
234 """
233 """
235 l = line if cursor_pos is None else line[:cursor_pos]
234 l = line if cursor_pos is None else line[:cursor_pos]
236 return self._delim_re.split(l)[-1]
235 return self._delim_re.split(l)[-1]
237
236
238
237
239 class Completer(Configurable):
238 class Completer(Configurable):
240
239
241 greedy = CBool(False, config=True,
240 greedy = CBool(False, config=True,
242 help="""Activate greedy completion
241 help="""Activate greedy completion
243
242
244 This will enable completion on elements of lists, results of function calls, etc.,
243 This will enable completion on elements of lists, results of function calls, etc.,
245 but can be unsafe because the code is actually evaluated on TAB.
244 but can be unsafe because the code is actually evaluated on TAB.
246 """
245 """
247 )
246 )
248
247
249
248
250 def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs):
249 def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs):
251 """Create a new completer for the command line.
250 """Create a new completer for the command line.
252
251
253 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
252 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
254
253
255 If unspecified, the default namespace where completions are performed
254 If unspecified, the default namespace where completions are performed
256 is __main__ (technically, __main__.__dict__). Namespaces should be
255 is __main__ (technically, __main__.__dict__). Namespaces should be
257 given as dictionaries.
256 given as dictionaries.
258
257
259 An optional second namespace can be given. This allows the completer
258 An optional second namespace can be given. This allows the completer
260 to handle cases where both the local and global scopes need to be
259 to handle cases where both the local and global scopes need to be
261 distinguished.
260 distinguished.
262
261
263 Completer instances should be used as the completion mechanism of
262 Completer instances should be used as the completion mechanism of
264 readline via the set_completer() call:
263 readline via the set_completer() call:
265
264
266 readline.set_completer(Completer(my_namespace).complete)
265 readline.set_completer(Completer(my_namespace).complete)
267 """
266 """
268
267
269 # Don't bind to namespace quite yet, but flag whether the user wants a
268 # Don't bind to namespace quite yet, but flag whether the user wants a
270 # specific namespace or to use __main__.__dict__. This will allow us
269 # specific namespace or to use __main__.__dict__. This will allow us
271 # to bind to __main__.__dict__ at completion time, not now.
270 # to bind to __main__.__dict__ at completion time, not now.
272 if namespace is None:
271 if namespace is None:
273 self.use_main_ns = 1
272 self.use_main_ns = 1
274 else:
273 else:
275 self.use_main_ns = 0
274 self.use_main_ns = 0
276 self.namespace = namespace
275 self.namespace = namespace
277
276
278 # The global namespace, if given, can be bound directly
277 # The global namespace, if given, can be bound directly
279 if global_namespace is None:
278 if global_namespace is None:
280 self.global_namespace = {}
279 self.global_namespace = {}
281 else:
280 else:
282 self.global_namespace = global_namespace
281 self.global_namespace = global_namespace
283
282
284 super(Completer, self).__init__(config=config, **kwargs)
283 super(Completer, self).__init__(config=config, **kwargs)
285
284
286 def complete(self, text, state):
285 def complete(self, text, state):
287 """Return the next possible completion for 'text'.
286 """Return the next possible completion for 'text'.
288
287
289 This is called successively with state == 0, 1, 2, ... until it
288 This is called successively with state == 0, 1, 2, ... until it
290 returns None. The completion should begin with 'text'.
289 returns None. The completion should begin with 'text'.
291
290
292 """
291 """
293 if self.use_main_ns:
292 if self.use_main_ns:
294 self.namespace = __main__.__dict__
293 self.namespace = __main__.__dict__
295
294
296 if state == 0:
295 if state == 0:
297 if "." in text:
296 if "." in text:
298 self.matches = self.attr_matches(text)
297 self.matches = self.attr_matches(text)
299 else:
298 else:
300 self.matches = self.global_matches(text)
299 self.matches = self.global_matches(text)
301 try:
300 try:
302 return self.matches[state]
301 return self.matches[state]
303 except IndexError:
302 except IndexError:
304 return None
303 return None
305
304
306 def global_matches(self, text):
305 def global_matches(self, text):
307 """Compute matches when text is a simple name.
306 """Compute matches when text is a simple name.
308
307
309 Return a list of all keywords, built-in functions and names currently
308 Return a list of all keywords, built-in functions and names currently
310 defined in self.namespace or self.global_namespace that match.
309 defined in self.namespace or self.global_namespace that match.
311
310
312 """
311 """
313 #print 'Completer->global_matches, txt=%r' % text # dbg
312 #print 'Completer->global_matches, txt=%r' % text # dbg
314 matches = []
313 matches = []
315 match_append = matches.append
314 match_append = matches.append
316 n = len(text)
315 n = len(text)
317 for lst in [keyword.kwlist,
316 for lst in [keyword.kwlist,
318 __builtin__.__dict__.keys(),
317 __builtin__.__dict__.keys(),
319 self.namespace.keys(),
318 self.namespace.keys(),
320 self.global_namespace.keys()]:
319 self.global_namespace.keys()]:
321 for word in lst:
320 for word in lst:
322 if word[:n] == text and word != "__builtins__":
321 if word[:n] == text and word != "__builtins__":
323 match_append(word)
322 match_append(word)
324 return matches
323 return matches
325
324
326 def attr_matches(self, text):
325 def attr_matches(self, text):
327 """Compute matches when text contains a dot.
326 """Compute matches when text contains a dot.
328
327
329 Assuming the text is of the form NAME.NAME....[NAME], and is
328 Assuming the text is of the form NAME.NAME....[NAME], and is
330 evaluatable in self.namespace or self.global_namespace, it will be
329 evaluatable in self.namespace or self.global_namespace, it will be
331 evaluated and its attributes (as revealed by dir()) are used as
330 evaluated and its attributes (as revealed by dir()) are used as
332 possible completions. (For class instances, class members are are
331 possible completions. (For class instances, class members are are
333 also considered.)
332 also considered.)
334
333
335 WARNING: this can still invoke arbitrary C code, if an object
334 WARNING: this can still invoke arbitrary C code, if an object
336 with a __getattr__ hook is evaluated.
335 with a __getattr__ hook is evaluated.
337
336
338 """
337 """
339
338
340 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
339 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
341 # Another option, seems to work great. Catches things like ''.<tab>
340 # Another option, seems to work great. Catches things like ''.<tab>
342 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
341 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
343
342
344 if m:
343 if m:
345 expr, attr = m.group(1, 3)
344 expr, attr = m.group(1, 3)
346 elif self.greedy:
345 elif self.greedy:
347 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
346 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
348 if not m2:
347 if not m2:
349 return []
348 return []
350 expr, attr = m2.group(1,2)
349 expr, attr = m2.group(1,2)
351 else:
350 else:
352 return []
351 return []
353
352
354 try:
353 try:
355 obj = eval(expr, self.namespace)
354 obj = eval(expr, self.namespace)
356 except:
355 except:
357 try:
356 try:
358 obj = eval(expr, self.global_namespace)
357 obj = eval(expr, self.global_namespace)
359 except:
358 except:
360 return []
359 return []
361
360
362 if self.limit_to__all__ and hasattr(obj, '__all__'):
361 if self.limit_to__all__ and hasattr(obj, '__all__'):
363 words = get__all__entries(obj)
362 words = get__all__entries(obj)
364 else:
363 else:
365 words = dir2(obj)
364 words = dir2(obj)
366
365
367 try:
366 try:
368 words = generics.complete_object(obj, words)
367 words = generics.complete_object(obj, words)
369 except TryNext:
368 except TryNext:
370 pass
369 pass
371 except Exception:
370 except Exception:
372 # Silence errors from completion function
371 # Silence errors from completion function
373 #raise # dbg
372 #raise # dbg
374 pass
373 pass
375 # Build match list to return
374 # Build match list to return
376 n = len(attr)
375 n = len(attr)
377 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
376 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
378 return res
377 return res
379
378
380
379
381 def get__all__entries(obj):
380 def get__all__entries(obj):
382 """returns the strings in the __all__ attribute"""
381 """returns the strings in the __all__ attribute"""
383 try:
382 try:
384 words = getattr(obj, '__all__')
383 words = getattr(obj, '__all__')
385 except:
384 except:
386 return []
385 return []
387
386
388 return [w for w in words if isinstance(w, basestring)]
387 return [w for w in words if isinstance(w, basestring)]
389
388
390
389
391 class IPCompleter(Completer):
390 class IPCompleter(Completer):
392 """Extension of the completer class with IPython-specific features"""
391 """Extension of the completer class with IPython-specific features"""
393
392
394 def _greedy_changed(self, name, old, new):
393 def _greedy_changed(self, name, old, new):
395 """update the splitter and readline delims when greedy is changed"""
394 """update the splitter and readline delims when greedy is changed"""
396 if new:
395 if new:
397 self.splitter.delims = GREEDY_DELIMS
396 self.splitter.delims = GREEDY_DELIMS
398 else:
397 else:
399 self.splitter.delims = DELIMS
398 self.splitter.delims = DELIMS
400
399
401 if self.readline:
400 if self.readline:
402 self.readline.set_completer_delims(self.splitter.delims)
401 self.readline.set_completer_delims(self.splitter.delims)
403
402
404 merge_completions = CBool(True, config=True,
403 merge_completions = CBool(True, config=True,
405 help="""Whether to merge completion results into a single list
404 help="""Whether to merge completion results into a single list
406
405
407 If False, only the completion results from the first non-empty
406 If False, only the completion results from the first non-empty
408 completer will be returned.
407 completer will be returned.
409 """
408 """
410 )
409 )
411 omit__names = Enum((0,1,2), default_value=2, config=True,
410 omit__names = Enum((0,1,2), default_value=2, config=True,
412 help="""Instruct the completer to omit private method names
411 help="""Instruct the completer to omit private method names
413
412
414 Specifically, when completing on ``object.<tab>``.
413 Specifically, when completing on ``object.<tab>``.
415
414
416 When 2 [default]: all names that start with '_' will be excluded.
415 When 2 [default]: all names that start with '_' will be excluded.
417
416
418 When 1: all 'magic' names (``__foo__``) will be excluded.
417 When 1: all 'magic' names (``__foo__``) will be excluded.
419
418
420 When 0: nothing will be excluded.
419 When 0: nothing will be excluded.
421 """
420 """
422 )
421 )
423 limit_to__all__ = CBool(default_value=False, config=True,
422 limit_to__all__ = CBool(default_value=False, config=True,
424 help="""Instruct the completer to use __all__ for the completion
423 help="""Instruct the completer to use __all__ for the completion
425
424
426 Specifically, when completing on ``object.<tab>``.
425 Specifically, when completing on ``object.<tab>``.
427
426
428 When True: only those names in obj.__all__ will be included.
427 When True: only those names in obj.__all__ will be included.
429
428
430 When False [default]: the __all__ attribute is ignored
429 When False [default]: the __all__ attribute is ignored
431 """
430 """
432 )
431 )
433
432
434 def __init__(self, shell=None, namespace=None, global_namespace=None,
433 def __init__(self, shell=None, namespace=None, global_namespace=None,
435 alias_table=None, use_readline=True,
434 alias_table=None, use_readline=True,
436 config=None, **kwargs):
435 config=None, **kwargs):
437 """IPCompleter() -> completer
436 """IPCompleter() -> completer
438
437
439 Return a completer object suitable for use by the readline library
438 Return a completer object suitable for use by the readline library
440 via readline.set_completer().
439 via readline.set_completer().
441
440
442 Inputs:
441 Inputs:
443
442
444 - shell: a pointer to the ipython shell itself. This is needed
443 - shell: a pointer to the ipython shell itself. This is needed
445 because this completer knows about magic functions, and those can
444 because this completer knows about magic functions, and those can
446 only be accessed via the ipython instance.
445 only be accessed via the ipython instance.
447
446
448 - namespace: an optional dict where completions are performed.
447 - namespace: an optional dict where completions are performed.
449
448
450 - global_namespace: secondary optional dict for completions, to
449 - global_namespace: secondary optional dict for completions, to
451 handle cases (such as IPython embedded inside functions) where
450 handle cases (such as IPython embedded inside functions) where
452 both Python scopes are visible.
451 both Python scopes are visible.
453
452
454 - If alias_table is supplied, it should be a dictionary of aliases
453 - If alias_table is supplied, it should be a dictionary of aliases
455 to complete.
454 to complete.
456
455
457 use_readline : bool, optional
456 use_readline : bool, optional
458 If true, use the readline library. This completer can still function
457 If true, use the readline library. This completer can still function
459 without readline, though in that case callers must provide some extra
458 without readline, though in that case callers must provide some extra
460 information on each call about the current line."""
459 information on each call about the current line."""
461
460
462 self.magic_escape = ESC_MAGIC
461 self.magic_escape = ESC_MAGIC
463 self.splitter = CompletionSplitter()
462 self.splitter = CompletionSplitter()
464
463
465 # Readline configuration, only used by the rlcompleter method.
464 # Readline configuration, only used by the rlcompleter method.
466 if use_readline:
465 if use_readline:
467 # We store the right version of readline so that later code
466 # We store the right version of readline so that later code
468 import IPython.utils.rlineimpl as readline
467 import IPython.utils.rlineimpl as readline
469 self.readline = readline
468 self.readline = readline
470 else:
469 else:
471 self.readline = None
470 self.readline = None
472
471
473 # _greedy_changed() depends on splitter and readline being defined:
472 # _greedy_changed() depends on splitter and readline being defined:
474 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
473 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
475 config=config, **kwargs)
474 config=config, **kwargs)
476
475
477 # List where completion matches will be stored
476 # List where completion matches will be stored
478 self.matches = []
477 self.matches = []
479 self.shell = shell
478 self.shell = shell
480 if alias_table is None:
479 if alias_table is None:
481 alias_table = {}
480 alias_table = {}
482 self.alias_table = alias_table
481 self.alias_table = alias_table
483 # Regexp to split filenames with spaces in them
482 # Regexp to split filenames with spaces in them
484 self.space_name_re = re.compile(r'([^\\] )')
483 self.space_name_re = re.compile(r'([^\\] )')
485 # Hold a local ref. to glob.glob for speed
484 # Hold a local ref. to glob.glob for speed
486 self.glob = glob.glob
485 self.glob = glob.glob
487
486
488 # Determine if we are running on 'dumb' terminals, like (X)Emacs
487 # Determine if we are running on 'dumb' terminals, like (X)Emacs
489 # buffers, to avoid completion problems.
488 # buffers, to avoid completion problems.
490 term = os.environ.get('TERM','xterm')
489 term = os.environ.get('TERM','xterm')
491 self.dumb_terminal = term in ['dumb','emacs']
490 self.dumb_terminal = term in ['dumb','emacs']
492
491
493 # Special handling of backslashes needed in win32 platforms
492 # Special handling of backslashes needed in win32 platforms
494 if sys.platform == "win32":
493 if sys.platform == "win32":
495 self.clean_glob = self._clean_glob_win32
494 self.clean_glob = self._clean_glob_win32
496 else:
495 else:
497 self.clean_glob = self._clean_glob
496 self.clean_glob = self._clean_glob
498
497
499 # All active matcher routines for completion
498 # All active matcher routines for completion
500 self.matchers = [self.python_matches,
499 self.matchers = [self.python_matches,
501 self.file_matches,
500 self.file_matches,
502 self.magic_matches,
501 self.magic_matches,
503 self.alias_matches,
502 self.alias_matches,
504 self.python_func_kw_matches,
503 self.python_func_kw_matches,
505 ]
504 ]
506
505
507 def all_completions(self, text):
506 def all_completions(self, text):
508 """
507 """
509 Wrapper around the complete method for the benefit of emacs
508 Wrapper around the complete method for the benefit of emacs
510 and pydb.
509 and pydb.
511 """
510 """
512 return self.complete(text)[1]
511 return self.complete(text)[1]
513
512
514 def _clean_glob(self,text):
513 def _clean_glob(self,text):
515 return self.glob("%s*" % text)
514 return self.glob("%s*" % text)
516
515
517 def _clean_glob_win32(self,text):
516 def _clean_glob_win32(self,text):
518 return [f.replace("\\","/")
517 return [f.replace("\\","/")
519 for f in self.glob("%s*" % text)]
518 for f in self.glob("%s*" % text)]
520
519
521 def file_matches(self, text):
520 def file_matches(self, text):
522 """Match filenames, expanding ~USER type strings.
521 """Match filenames, expanding ~USER type strings.
523
522
524 Most of the seemingly convoluted logic in this completer is an
523 Most of the seemingly convoluted logic in this completer is an
525 attempt to handle filenames with spaces in them. And yet it's not
524 attempt to handle filenames with spaces in them. And yet it's not
526 quite perfect, because Python's readline doesn't expose all of the
525 quite perfect, because Python's readline doesn't expose all of the
527 GNU readline details needed for this to be done correctly.
526 GNU readline details needed for this to be done correctly.
528
527
529 For a filename with a space in it, the printed completions will be
528 For a filename with a space in it, the printed completions will be
530 only the parts after what's already been typed (instead of the
529 only the parts after what's already been typed (instead of the
531 full completions, as is normally done). I don't think with the
530 full completions, as is normally done). I don't think with the
532 current (as of Python 2.3) Python readline it's possible to do
531 current (as of Python 2.3) Python readline it's possible to do
533 better."""
532 better."""
534
533
535 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
534 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
536
535
537 # chars that require escaping with backslash - i.e. chars
536 # chars that require escaping with backslash - i.e. chars
538 # that readline treats incorrectly as delimiters, but we
537 # that readline treats incorrectly as delimiters, but we
539 # don't want to treat as delimiters in filename matching
538 # don't want to treat as delimiters in filename matching
540 # when escaped with backslash
539 # when escaped with backslash
541 if text.startswith('!'):
540 if text.startswith('!'):
542 text = text[1:]
541 text = text[1:]
543 text_prefix = '!'
542 text_prefix = '!'
544 else:
543 else:
545 text_prefix = ''
544 text_prefix = ''
546
545
547 text_until_cursor = self.text_until_cursor
546 text_until_cursor = self.text_until_cursor
548 # track strings with open quotes
547 # track strings with open quotes
549 open_quotes = has_open_quotes(text_until_cursor)
548 open_quotes = has_open_quotes(text_until_cursor)
550
549
551 if '(' in text_until_cursor or '[' in text_until_cursor:
550 if '(' in text_until_cursor or '[' in text_until_cursor:
552 lsplit = text
551 lsplit = text
553 else:
552 else:
554 try:
553 try:
555 # arg_split ~ shlex.split, but with unicode bugs fixed by us
554 # arg_split ~ shlex.split, but with unicode bugs fixed by us
556 lsplit = arg_split(text_until_cursor)[-1]
555 lsplit = arg_split(text_until_cursor)[-1]
557 except ValueError:
556 except ValueError:
558 # typically an unmatched ", or backslash without escaped char.
557 # typically an unmatched ", or backslash without escaped char.
559 if open_quotes:
558 if open_quotes:
560 lsplit = text_until_cursor.split(open_quotes)[-1]
559 lsplit = text_until_cursor.split(open_quotes)[-1]
561 else:
560 else:
562 return []
561 return []
563 except IndexError:
562 except IndexError:
564 # tab pressed on empty line
563 # tab pressed on empty line
565 lsplit = ""
564 lsplit = ""
566
565
567 if not open_quotes and lsplit != protect_filename(lsplit):
566 if not open_quotes and lsplit != protect_filename(lsplit):
568 # if protectables are found, do matching on the whole escaped name
567 # if protectables are found, do matching on the whole escaped name
569 has_protectables = True
568 has_protectables = True
570 text0,text = text,lsplit
569 text0,text = text,lsplit
571 else:
570 else:
572 has_protectables = False
571 has_protectables = False
573 text = os.path.expanduser(text)
572 text = os.path.expanduser(text)
574
573
575 if text == "":
574 if text == "":
576 return [text_prefix + protect_filename(f) for f in self.glob("*")]
575 return [text_prefix + protect_filename(f) for f in self.glob("*")]
577
576
578 # Compute the matches from the filesystem
577 # Compute the matches from the filesystem
579 m0 = self.clean_glob(text.replace('\\',''))
578 m0 = self.clean_glob(text.replace('\\',''))
580
579
581 if has_protectables:
580 if has_protectables:
582 # If we had protectables, we need to revert our changes to the
581 # If we had protectables, we need to revert our changes to the
583 # beginning of filename so that we don't double-write the part
582 # beginning of filename so that we don't double-write the part
584 # of the filename we have so far
583 # of the filename we have so far
585 len_lsplit = len(lsplit)
584 len_lsplit = len(lsplit)
586 matches = [text_prefix + text0 +
585 matches = [text_prefix + text0 +
587 protect_filename(f[len_lsplit:]) for f in m0]
586 protect_filename(f[len_lsplit:]) for f in m0]
588 else:
587 else:
589 if open_quotes:
588 if open_quotes:
590 # if we have a string with an open quote, we don't need to
589 # if we have a string with an open quote, we don't need to
591 # protect the names at all (and we _shouldn't_, as it
590 # protect the names at all (and we _shouldn't_, as it
592 # would cause bugs when the filesystem call is made).
591 # would cause bugs when the filesystem call is made).
593 matches = m0
592 matches = m0
594 else:
593 else:
595 matches = [text_prefix +
594 matches = [text_prefix +
596 protect_filename(f) for f in m0]
595 protect_filename(f) for f in m0]
597
596
598 #io.rprint('mm', matches) # dbg
597 #io.rprint('mm', matches) # dbg
599
598
600 # Mark directories in input list by appending '/' to their names.
599 # Mark directories in input list by appending '/' to their names.
601 matches = [x+'/' if os.path.isdir(x) else x for x in matches]
600 matches = [x+'/' if os.path.isdir(x) else x for x in matches]
602 return matches
601 return matches
603
602
604 def magic_matches(self, text):
603 def magic_matches(self, text):
605 """Match magics"""
604 """Match magics"""
606 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
605 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
607 # Get all shell magics now rather than statically, so magics loaded at
606 # Get all shell magics now rather than statically, so magics loaded at
608 # runtime show up too.
607 # runtime show up too.
609 lsm = self.shell.magics_manager.lsmagic()
608 lsm = self.shell.magics_manager.lsmagic()
610 line_magics = lsm['line']
609 line_magics = lsm['line']
611 cell_magics = lsm['cell']
610 cell_magics = lsm['cell']
612 pre = self.magic_escape
611 pre = self.magic_escape
613 pre2 = pre+pre
612 pre2 = pre+pre
614
613
615 # Completion logic:
614 # Completion logic:
616 # - user gives %%: only do cell magics
615 # - user gives %%: only do cell magics
617 # - user gives %: do both line and cell magics
616 # - user gives %: do both line and cell magics
618 # - no prefix: do both
617 # - no prefix: do both
619 # In other words, line magics are skipped if the user gives %% explicitly
618 # In other words, line magics are skipped if the user gives %% explicitly
620 bare_text = text.lstrip(pre)
619 bare_text = text.lstrip(pre)
621 comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)]
620 comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)]
622 if not text.startswith(pre2):
621 if not text.startswith(pre2):
623 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
622 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
624 return comp
623 return comp
625
624
626 def alias_matches(self, text):
625 def alias_matches(self, text):
627 """Match internal system aliases"""
626 """Match internal system aliases"""
628 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
627 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
629
628
630 # if we are not in the first 'item', alias matching
629 # if we are not in the first 'item', alias matching
631 # doesn't make sense - unless we are starting with 'sudo' command.
630 # doesn't make sense - unless we are starting with 'sudo' command.
632 main_text = self.text_until_cursor.lstrip()
631 main_text = self.text_until_cursor.lstrip()
633 if ' ' in main_text and not main_text.startswith('sudo'):
632 if ' ' in main_text and not main_text.startswith('sudo'):
634 return []
633 return []
635 text = os.path.expanduser(text)
634 text = os.path.expanduser(text)
636 aliases = self.alias_table.keys()
635 aliases = self.alias_table.keys()
637 if text == '':
636 if text == '':
638 return aliases
637 return aliases
639 else:
638 else:
640 return [a for a in aliases if a.startswith(text)]
639 return [a for a in aliases if a.startswith(text)]
641
640
642 def python_matches(self,text):
641 def python_matches(self,text):
643 """Match attributes or global python names"""
642 """Match attributes or global python names"""
644
643
645 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
644 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
646 if "." in text:
645 if "." in text:
647 try:
646 try:
648 matches = self.attr_matches(text)
647 matches = self.attr_matches(text)
649 if text.endswith('.') and self.omit__names:
648 if text.endswith('.') and self.omit__names:
650 if self.omit__names == 1:
649 if self.omit__names == 1:
651 # true if txt is _not_ a __ name, false otherwise:
650 # true if txt is _not_ a __ name, false otherwise:
652 no__name = (lambda txt:
651 no__name = (lambda txt:
653 re.match(r'.*\.__.*?__',txt) is None)
652 re.match(r'.*\.__.*?__',txt) is None)
654 else:
653 else:
655 # true if txt is _not_ a _ name, false otherwise:
654 # true if txt is _not_ a _ name, false otherwise:
656 no__name = (lambda txt:
655 no__name = (lambda txt:
657 re.match(r'.*\._.*?',txt) is None)
656 re.match(r'.*\._.*?',txt) is None)
658 matches = filter(no__name, matches)
657 matches = filter(no__name, matches)
659 except NameError:
658 except NameError:
660 # catches <undefined attributes>.<tab>
659 # catches <undefined attributes>.<tab>
661 matches = []
660 matches = []
662 else:
661 else:
663 matches = self.global_matches(text)
662 matches = self.global_matches(text)
664
663
665 return matches
664 return matches
666
665
667 def _default_arguments(self, obj):
666 def _default_arguments(self, obj):
668 """Return the list of default arguments of obj if it is callable,
667 """Return the list of default arguments of obj if it is callable,
669 or empty list otherwise."""
668 or empty list otherwise."""
670
669
671 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
670 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
672 # for classes, check for __init__,__new__
671 # for classes, check for __init__,__new__
673 if inspect.isclass(obj):
672 if inspect.isclass(obj):
674 obj = (getattr(obj,'__init__',None) or
673 obj = (getattr(obj,'__init__',None) or
675 getattr(obj,'__new__',None))
674 getattr(obj,'__new__',None))
676 # for all others, check if they are __call__able
675 # for all others, check if they are __call__able
677 elif hasattr(obj, '__call__'):
676 elif hasattr(obj, '__call__'):
678 obj = obj.__call__
677 obj = obj.__call__
679 # XXX: is there a way to handle the builtins ?
678 # XXX: is there a way to handle the builtins ?
680 try:
679 try:
681 args,_,_1,defaults = inspect.getargspec(obj)
680 args,_,_1,defaults = inspect.getargspec(obj)
682 if defaults:
681 if defaults:
683 return args[-len(defaults):]
682 return args[-len(defaults):]
684 except TypeError: pass
683 except TypeError: pass
685 return []
684 return []
686
685
687 def python_func_kw_matches(self,text):
686 def python_func_kw_matches(self,text):
688 """Match named parameters (kwargs) of the last open function"""
687 """Match named parameters (kwargs) of the last open function"""
689
688
690 if "." in text: # a parameter cannot be dotted
689 if "." in text: # a parameter cannot be dotted
691 return []
690 return []
692 try: regexp = self.__funcParamsRegex
691 try: regexp = self.__funcParamsRegex
693 except AttributeError:
692 except AttributeError:
694 regexp = self.__funcParamsRegex = re.compile(r'''
693 regexp = self.__funcParamsRegex = re.compile(r'''
695 '.*?(?<!\\)' | # single quoted strings or
694 '.*?(?<!\\)' | # single quoted strings or
696 ".*?(?<!\\)" | # double quoted strings or
695 ".*?(?<!\\)" | # double quoted strings or
697 \w+ | # identifier
696 \w+ | # identifier
698 \S # other characters
697 \S # other characters
699 ''', re.VERBOSE | re.DOTALL)
698 ''', re.VERBOSE | re.DOTALL)
700 # 1. find the nearest identifier that comes before an unclosed
699 # 1. find the nearest identifier that comes before an unclosed
701 # parenthesis before the cursor
700 # parenthesis before the cursor
702 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
701 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
703 tokens = regexp.findall(self.text_until_cursor)
702 tokens = regexp.findall(self.text_until_cursor)
704 tokens.reverse()
703 tokens.reverse()
705 iterTokens = iter(tokens); openPar = 0
704 iterTokens = iter(tokens); openPar = 0
706 for token in iterTokens:
705 for token in iterTokens:
707 if token == ')':
706 if token == ')':
708 openPar -= 1
707 openPar -= 1
709 elif token == '(':
708 elif token == '(':
710 openPar += 1
709 openPar += 1
711 if openPar > 0:
710 if openPar > 0:
712 # found the last unclosed parenthesis
711 # found the last unclosed parenthesis
713 break
712 break
714 else:
713 else:
715 return []
714 return []
716 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
715 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
717 ids = []
716 ids = []
718 isId = re.compile(r'\w+$').match
717 isId = re.compile(r'\w+$').match
719 while True:
718 while True:
720 try:
719 try:
721 ids.append(next(iterTokens))
720 ids.append(next(iterTokens))
722 if not isId(ids[-1]):
721 if not isId(ids[-1]):
723 ids.pop(); break
722 ids.pop(); break
724 if not next(iterTokens) == '.':
723 if not next(iterTokens) == '.':
725 break
724 break
726 except StopIteration:
725 except StopIteration:
727 break
726 break
728 # lookup the candidate callable matches either using global_matches
727 # lookup the candidate callable matches either using global_matches
729 # or attr_matches for dotted names
728 # or attr_matches for dotted names
730 if len(ids) == 1:
729 if len(ids) == 1:
731 callableMatches = self.global_matches(ids[0])
730 callableMatches = self.global_matches(ids[0])
732 else:
731 else:
733 callableMatches = self.attr_matches('.'.join(ids[::-1]))
732 callableMatches = self.attr_matches('.'.join(ids[::-1]))
734 argMatches = []
733 argMatches = []
735 for callableMatch in callableMatches:
734 for callableMatch in callableMatches:
736 try:
735 try:
737 namedArgs = self._default_arguments(eval(callableMatch,
736 namedArgs = self._default_arguments(eval(callableMatch,
738 self.namespace))
737 self.namespace))
739 except:
738 except:
740 continue
739 continue
741 for namedArg in namedArgs:
740 for namedArg in namedArgs:
742 if namedArg.startswith(text):
741 if namedArg.startswith(text):
743 argMatches.append("%s=" %namedArg)
742 argMatches.append("%s=" %namedArg)
744 return argMatches
743 return argMatches
745
744
746 def dispatch_custom_completer(self, text):
745 def dispatch_custom_completer(self, text):
747 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
746 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
748 line = self.line_buffer
747 line = self.line_buffer
749 if not line.strip():
748 if not line.strip():
750 return None
749 return None
751
750
752 # Create a little structure to pass all the relevant information about
751 # Create a little structure to pass all the relevant information about
753 # the current completion to any custom completer.
752 # the current completion to any custom completer.
754 event = Bunch()
753 event = Bunch()
755 event.line = line
754 event.line = line
756 event.symbol = text
755 event.symbol = text
757 cmd = line.split(None,1)[0]
756 cmd = line.split(None,1)[0]
758 event.command = cmd
757 event.command = cmd
759 event.text_until_cursor = self.text_until_cursor
758 event.text_until_cursor = self.text_until_cursor
760
759
761 #print "\ncustom:{%s]\n" % event # dbg
760 #print "\ncustom:{%s]\n" % event # dbg
762
761
763 # for foo etc, try also to find completer for %foo
762 # for foo etc, try also to find completer for %foo
764 if not cmd.startswith(self.magic_escape):
763 if not cmd.startswith(self.magic_escape):
765 try_magic = self.custom_completers.s_matches(
764 try_magic = self.custom_completers.s_matches(
766 self.magic_escape + cmd)
765 self.magic_escape + cmd)
767 else:
766 else:
768 try_magic = []
767 try_magic = []
769
768
770 for c in itertools.chain(self.custom_completers.s_matches(cmd),
769 for c in itertools.chain(self.custom_completers.s_matches(cmd),
771 try_magic,
770 try_magic,
772 self.custom_completers.flat_matches(self.text_until_cursor)):
771 self.custom_completers.flat_matches(self.text_until_cursor)):
773 #print "try",c # dbg
772 #print "try",c # dbg
774 try:
773 try:
775 res = c(event)
774 res = c(event)
776 if res:
775 if res:
777 # first, try case sensitive match
776 # first, try case sensitive match
778 withcase = [r for r in res if r.startswith(text)]
777 withcase = [r for r in res if r.startswith(text)]
779 if withcase:
778 if withcase:
780 return withcase
779 return withcase
781 # if none, then case insensitive ones are ok too
780 # if none, then case insensitive ones are ok too
782 text_low = text.lower()
781 text_low = text.lower()
783 return [r for r in res if r.lower().startswith(text_low)]
782 return [r for r in res if r.lower().startswith(text_low)]
784 except TryNext:
783 except TryNext:
785 pass
784 pass
786
785
787 return None
786 return None
788
787
789 def complete(self, text=None, line_buffer=None, cursor_pos=None):
788 def complete(self, text=None, line_buffer=None, cursor_pos=None):
790 """Find completions for the given text and line context.
789 """Find completions for the given text and line context.
791
790
792 This is called successively with state == 0, 1, 2, ... until it
791 This is called successively with state == 0, 1, 2, ... until it
793 returns None. The completion should begin with 'text'.
792 returns None. The completion should begin with 'text'.
794
793
795 Note that both the text and the line_buffer are optional, but at least
794 Note that both the text and the line_buffer are optional, but at least
796 one of them must be given.
795 one of them must be given.
797
796
798 Parameters
797 Parameters
799 ----------
798 ----------
800 text : string, optional
799 text : string, optional
801 Text to perform the completion on. If not given, the line buffer
800 Text to perform the completion on. If not given, the line buffer
802 is split using the instance's CompletionSplitter object.
801 is split using the instance's CompletionSplitter object.
803
802
804 line_buffer : string, optional
803 line_buffer : string, optional
805 If not given, the completer attempts to obtain the current line
804 If not given, the completer attempts to obtain the current line
806 buffer via readline. This keyword allows clients which are
805 buffer via readline. This keyword allows clients which are
807 requesting for text completions in non-readline contexts to inform
806 requesting for text completions in non-readline contexts to inform
808 the completer of the entire text.
807 the completer of the entire text.
809
808
810 cursor_pos : int, optional
809 cursor_pos : int, optional
811 Index of the cursor in the full line buffer. Should be provided by
810 Index of the cursor in the full line buffer. Should be provided by
812 remote frontends where kernel has no access to frontend state.
811 remote frontends where kernel has no access to frontend state.
813
812
814 Returns
813 Returns
815 -------
814 -------
816 text : str
815 text : str
817 Text that was actually used in the completion.
816 Text that was actually used in the completion.
818
817
819 matches : list
818 matches : list
820 A list of completion matches.
819 A list of completion matches.
821 """
820 """
822 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
821 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
823
822
824 # if the cursor position isn't given, the only sane assumption we can
823 # if the cursor position isn't given, the only sane assumption we can
825 # make is that it's at the end of the line (the common case)
824 # make is that it's at the end of the line (the common case)
826 if cursor_pos is None:
825 if cursor_pos is None:
827 cursor_pos = len(line_buffer) if text is None else len(text)
826 cursor_pos = len(line_buffer) if text is None else len(text)
828
827
829 # if text is either None or an empty string, rely on the line buffer
828 # if text is either None or an empty string, rely on the line buffer
830 if not text:
829 if not text:
831 text = self.splitter.split_line(line_buffer, cursor_pos)
830 text = self.splitter.split_line(line_buffer, cursor_pos)
832
831
833 # If no line buffer is given, assume the input text is all there was
832 # If no line buffer is given, assume the input text is all there was
834 if line_buffer is None:
833 if line_buffer is None:
835 line_buffer = text
834 line_buffer = text
836
835
837 self.line_buffer = line_buffer
836 self.line_buffer = line_buffer
838 self.text_until_cursor = self.line_buffer[:cursor_pos]
837 self.text_until_cursor = self.line_buffer[:cursor_pos]
839 #io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
838 #io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
840
839
841 # Start with a clean slate of completions
840 # Start with a clean slate of completions
842 self.matches[:] = []
841 self.matches[:] = []
843 custom_res = self.dispatch_custom_completer(text)
842 custom_res = self.dispatch_custom_completer(text)
844 if custom_res is not None:
843 if custom_res is not None:
845 # did custom completers produce something?
844 # did custom completers produce something?
846 self.matches = custom_res
845 self.matches = custom_res
847 else:
846 else:
848 # Extend the list of completions with the results of each
847 # Extend the list of completions with the results of each
849 # matcher, so we return results to the user from all
848 # matcher, so we return results to the user from all
850 # namespaces.
849 # namespaces.
851 if self.merge_completions:
850 if self.merge_completions:
852 self.matches = []
851 self.matches = []
853 for matcher in self.matchers:
852 for matcher in self.matchers:
854 try:
853 try:
855 self.matches.extend(matcher(text))
854 self.matches.extend(matcher(text))
856 except:
855 except:
857 # Show the ugly traceback if the matcher causes an
856 # Show the ugly traceback if the matcher causes an
858 # exception, but do NOT crash the kernel!
857 # exception, but do NOT crash the kernel!
859 sys.excepthook(*sys.exc_info())
858 sys.excepthook(*sys.exc_info())
860 else:
859 else:
861 for matcher in self.matchers:
860 for matcher in self.matchers:
862 self.matches = matcher(text)
861 self.matches = matcher(text)
863 if self.matches:
862 if self.matches:
864 break
863 break
865 # FIXME: we should extend our api to return a dict with completions for
864 # FIXME: we should extend our api to return a dict with completions for
866 # different types of objects. The rlcomplete() method could then
865 # different types of objects. The rlcomplete() method could then
867 # simply collapse the dict into a list for readline, but we'd have
866 # simply collapse the dict into a list for readline, but we'd have
868 # richer completion semantics in other evironments.
867 # richer completion semantics in other evironments.
869 self.matches = sorted(set(self.matches))
868 self.matches = sorted(set(self.matches))
870 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
869 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
871 return text, self.matches
870 return text, self.matches
872
871
873 def rlcomplete(self, text, state):
872 def rlcomplete(self, text, state):
874 """Return the state-th possible completion for 'text'.
873 """Return the state-th possible completion for 'text'.
875
874
876 This is called successively with state == 0, 1, 2, ... until it
875 This is called successively with state == 0, 1, 2, ... until it
877 returns None. The completion should begin with 'text'.
876 returns None. The completion should begin with 'text'.
878
877
879 Parameters
878 Parameters
880 ----------
879 ----------
881 text : string
880 text : string
882 Text to perform the completion on.
881 Text to perform the completion on.
883
882
884 state : int
883 state : int
885 Counter used by readline.
884 Counter used by readline.
886 """
885 """
887 if state==0:
886 if state==0:
888
887
889 self.line_buffer = line_buffer = self.readline.get_line_buffer()
888 self.line_buffer = line_buffer = self.readline.get_line_buffer()
890 cursor_pos = self.readline.get_endidx()
889 cursor_pos = self.readline.get_endidx()
891
890
892 #io.rprint("\nRLCOMPLETE: %r %r %r" %
891 #io.rprint("\nRLCOMPLETE: %r %r %r" %
893 # (text, line_buffer, cursor_pos) ) # dbg
892 # (text, line_buffer, cursor_pos) ) # dbg
894
893
895 # if there is only a tab on a line with only whitespace, instead of
894 # if there is only a tab on a line with only whitespace, instead of
896 # the mostly useless 'do you want to see all million completions'
895 # the mostly useless 'do you want to see all million completions'
897 # message, just do the right thing and give the user his tab!
896 # message, just do the right thing and give the user his tab!
898 # Incidentally, this enables pasting of tabbed text from an editor
897 # Incidentally, this enables pasting of tabbed text from an editor
899 # (as long as autoindent is off).
898 # (as long as autoindent is off).
900
899
901 # It should be noted that at least pyreadline still shows file
900 # It should be noted that at least pyreadline still shows file
902 # completions - is there a way around it?
901 # completions - is there a way around it?
903
902
904 # don't apply this on 'dumb' terminals, such as emacs buffers, so
903 # don't apply this on 'dumb' terminals, such as emacs buffers, so
905 # we don't interfere with their own tab-completion mechanism.
904 # we don't interfere with their own tab-completion mechanism.
906 if not (self.dumb_terminal or line_buffer.strip()):
905 if not (self.dumb_terminal or line_buffer.strip()):
907 self.readline.insert_text('\t')
906 self.readline.insert_text('\t')
908 sys.stdout.flush()
907 sys.stdout.flush()
909 return None
908 return None
910
909
911 # Note: debugging exceptions that may occur in completion is very
910 # Note: debugging exceptions that may occur in completion is very
912 # tricky, because readline unconditionally silences them. So if
911 # tricky, because readline unconditionally silences them. So if
913 # during development you suspect a bug in the completion code, turn
912 # during development you suspect a bug in the completion code, turn
914 # this flag on temporarily by uncommenting the second form (don't
913 # this flag on temporarily by uncommenting the second form (don't
915 # flip the value in the first line, as the '# dbg' marker can be
914 # flip the value in the first line, as the '# dbg' marker can be
916 # automatically detected and is used elsewhere).
915 # automatically detected and is used elsewhere).
917 DEBUG = False
916 DEBUG = False
918 #DEBUG = True # dbg
917 #DEBUG = True # dbg
919 if DEBUG:
918 if DEBUG:
920 try:
919 try:
921 self.complete(text, line_buffer, cursor_pos)
920 self.complete(text, line_buffer, cursor_pos)
922 except:
921 except:
923 import traceback; traceback.print_exc()
922 import traceback; traceback.print_exc()
924 else:
923 else:
925 # The normal production version is here
924 # The normal production version is here
926
925
927 # This method computes the self.matches array
926 # This method computes the self.matches array
928 self.complete(text, line_buffer, cursor_pos)
927 self.complete(text, line_buffer, cursor_pos)
929
928
930 try:
929 try:
931 return self.matches[state]
930 return self.matches[state]
932 except IndexError:
931 except IndexError:
933 return None
932 return None
@@ -1,333 +1,332 b''
1 """Implementations for various useful completers.
1 """Implementations for various useful completers.
2
2
3 These are all loaded by default by IPython.
3 These are all loaded by default by IPython.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2010-2011 The IPython Development Team.
6 # Copyright (C) 2010-2011 The IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the BSD License.
8 # Distributed under the terms of the BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib imports
18 # Stdlib imports
19 import glob
19 import glob
20 import imp
20 import imp
21 import inspect
21 import inspect
22 import os
22 import os
23 import re
23 import re
24 import sys
24 import sys
25
25
26 # Third-party imports
26 # Third-party imports
27 from time import time
27 from time import time
28 from zipimport import zipimporter
28 from zipimport import zipimporter
29
29
30 # Our own imports
30 # Our own imports
31 from IPython.core.completer import expand_user, compress_user
31 from IPython.core.completer import expand_user, compress_user
32 from IPython.core.error import TryNext
32 from IPython.core.error import TryNext
33 from IPython.utils import py3compat
34 from IPython.utils._process_common import arg_split
33 from IPython.utils._process_common import arg_split
35
34
36 # FIXME: this should be pulled in with the right call via the component system
35 # FIXME: this should be pulled in with the right call via the component system
37 from IPython.core.ipapi import get as get_ipython
36 from IPython.core.ipapi import get as get_ipython
38
37
39 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
40 # Globals and constants
39 # Globals and constants
41 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
42
41
43 # Time in seconds after which the rootmodules will be stored permanently in the
42 # Time in seconds after which the rootmodules will be stored permanently in the
44 # ipython ip.db database (kept in the user's .ipython dir).
43 # ipython ip.db database (kept in the user's .ipython dir).
45 TIMEOUT_STORAGE = 2
44 TIMEOUT_STORAGE = 2
46
45
47 # Time in seconds after which we give up
46 # Time in seconds after which we give up
48 TIMEOUT_GIVEUP = 20
47 TIMEOUT_GIVEUP = 20
49
48
50 # Regular expression for the python import statement
49 # Regular expression for the python import statement
51 import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
50 import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
52 r'(?P<package>[/\\]__init__)?'
51 r'(?P<package>[/\\]__init__)?'
53 r'(?P<suffix>%s)$' %
52 r'(?P<suffix>%s)$' %
54 r'|'.join(re.escape(s[0]) for s in imp.get_suffixes()))
53 r'|'.join(re.escape(s[0]) for s in imp.get_suffixes()))
55
54
56 # RE for the ipython %run command (python + ipython scripts)
55 # RE for the ipython %run command (python + ipython scripts)
57 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
56 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
58
57
59 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
60 # Local utilities
59 # Local utilities
61 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
62
61
63 def module_list(path):
62 def module_list(path):
64 """
63 """
65 Return the list containing the names of the modules available in the given
64 Return the list containing the names of the modules available in the given
66 folder.
65 folder.
67 """
66 """
68 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
67 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
69 if path == '':
68 if path == '':
70 path = '.'
69 path = '.'
71
70
72 # A few local constants to be used in loops below
71 # A few local constants to be used in loops below
73 pjoin = os.path.join
72 pjoin = os.path.join
74
73
75 if os.path.isdir(path):
74 if os.path.isdir(path):
76 # Build a list of all files in the directory and all files
75 # Build a list of all files in the directory and all files
77 # in its subdirectories. For performance reasons, do not
76 # in its subdirectories. For performance reasons, do not
78 # recurse more than one level into subdirectories.
77 # recurse more than one level into subdirectories.
79 files = []
78 files = []
80 for root, dirs, nondirs in os.walk(path):
79 for root, dirs, nondirs in os.walk(path):
81 subdir = root[len(path)+1:]
80 subdir = root[len(path)+1:]
82 if subdir:
81 if subdir:
83 files.extend(pjoin(subdir, f) for f in nondirs)
82 files.extend(pjoin(subdir, f) for f in nondirs)
84 dirs[:] = [] # Do not recurse into additional subdirectories.
83 dirs[:] = [] # Do not recurse into additional subdirectories.
85 else:
84 else:
86 files.extend(nondirs)
85 files.extend(nondirs)
87
86
88 else:
87 else:
89 try:
88 try:
90 files = list(zipimporter(path)._files.keys())
89 files = list(zipimporter(path)._files.keys())
91 except:
90 except:
92 files = []
91 files = []
93
92
94 # Build a list of modules which match the import_re regex.
93 # Build a list of modules which match the import_re regex.
95 modules = []
94 modules = []
96 for f in files:
95 for f in files:
97 m = import_re.match(f)
96 m = import_re.match(f)
98 if m:
97 if m:
99 modules.append(m.group('name'))
98 modules.append(m.group('name'))
100 return list(set(modules))
99 return list(set(modules))
101
100
102 def get_root_modules():
101 def get_root_modules():
103 """
102 """
104 Returns a list containing the names of all the modules available in the
103 Returns a list containing the names of all the modules available in the
105 folders of the pythonpath.
104 folders of the pythonpath.
106 """
105 """
107 ip = get_ipython()
106 ip = get_ipython()
108
107
109 if 'rootmodules' in ip.db:
108 if 'rootmodules' in ip.db:
110 return ip.db['rootmodules']
109 return ip.db['rootmodules']
111
110
112 t = time()
111 t = time()
113 store = False
112 store = False
114 modules = list(sys.builtin_module_names)
113 modules = list(sys.builtin_module_names)
115 for path in sys.path:
114 for path in sys.path:
116 modules += module_list(path)
115 modules += module_list(path)
117 if time() - t >= TIMEOUT_STORAGE and not store:
116 if time() - t >= TIMEOUT_STORAGE and not store:
118 store = True
117 store = True
119 print("\nCaching the list of root modules, please wait!")
118 print("\nCaching the list of root modules, please wait!")
120 print("(This will only be done once - type '%rehashx' to "
119 print("(This will only be done once - type '%rehashx' to "
121 "reset cache!)\n")
120 "reset cache!)\n")
122 sys.stdout.flush()
121 sys.stdout.flush()
123 if time() - t > TIMEOUT_GIVEUP:
122 if time() - t > TIMEOUT_GIVEUP:
124 print("This is taking too long, we give up.\n")
123 print("This is taking too long, we give up.\n")
125 ip.db['rootmodules'] = []
124 ip.db['rootmodules'] = []
126 return []
125 return []
127
126
128 modules = set(modules)
127 modules = set(modules)
129 if '__init__' in modules:
128 if '__init__' in modules:
130 modules.remove('__init__')
129 modules.remove('__init__')
131 modules = list(modules)
130 modules = list(modules)
132 if store:
131 if store:
133 ip.db['rootmodules'] = modules
132 ip.db['rootmodules'] = modules
134 return modules
133 return modules
135
134
136
135
137 def is_importable(module, attr, only_modules):
136 def is_importable(module, attr, only_modules):
138 if only_modules:
137 if only_modules:
139 return inspect.ismodule(getattr(module, attr))
138 return inspect.ismodule(getattr(module, attr))
140 else:
139 else:
141 return not(attr[:2] == '__' and attr[-2:] == '__')
140 return not(attr[:2] == '__' and attr[-2:] == '__')
142
141
143
142
144 def try_import(mod, only_modules=False):
143 def try_import(mod, only_modules=False):
145 try:
144 try:
146 m = __import__(mod)
145 m = __import__(mod)
147 except:
146 except:
148 return []
147 return []
149 mods = mod.split('.')
148 mods = mod.split('.')
150 for module in mods[1:]:
149 for module in mods[1:]:
151 m = getattr(m, module)
150 m = getattr(m, module)
152
151
153 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
152 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
154
153
155 completions = []
154 completions = []
156 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
155 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
157 completions.extend( [attr for attr in dir(m) if
156 completions.extend( [attr for attr in dir(m) if
158 is_importable(m, attr, only_modules)])
157 is_importable(m, attr, only_modules)])
159
158
160 completions.extend(getattr(m, '__all__', []))
159 completions.extend(getattr(m, '__all__', []))
161 if m_is_init:
160 if m_is_init:
162 completions.extend(module_list(os.path.dirname(m.__file__)))
161 completions.extend(module_list(os.path.dirname(m.__file__)))
163 completions = set(completions)
162 completions = set(completions)
164 if '__init__' in completions:
163 if '__init__' in completions:
165 completions.remove('__init__')
164 completions.remove('__init__')
166 return list(completions)
165 return list(completions)
167
166
168
167
169 #-----------------------------------------------------------------------------
168 #-----------------------------------------------------------------------------
170 # Completion-related functions.
169 # Completion-related functions.
171 #-----------------------------------------------------------------------------
170 #-----------------------------------------------------------------------------
172
171
173 def quick_completer(cmd, completions):
172 def quick_completer(cmd, completions):
174 """ Easily create a trivial completer for a command.
173 """ Easily create a trivial completer for a command.
175
174
176 Takes either a list of completions, or all completions in string (that will
175 Takes either a list of completions, or all completions in string (that will
177 be split on whitespace).
176 be split on whitespace).
178
177
179 Example::
178 Example::
180
179
181 [d:\ipython]|1> import ipy_completers
180 [d:\ipython]|1> import ipy_completers
182 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
181 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
183 [d:\ipython]|3> foo b<TAB>
182 [d:\ipython]|3> foo b<TAB>
184 bar baz
183 bar baz
185 [d:\ipython]|3> foo ba
184 [d:\ipython]|3> foo ba
186 """
185 """
187
186
188 if isinstance(completions, basestring):
187 if isinstance(completions, basestring):
189 completions = completions.split()
188 completions = completions.split()
190
189
191 def do_complete(self, event):
190 def do_complete(self, event):
192 return completions
191 return completions
193
192
194 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
193 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
195
194
196 def module_completion(line):
195 def module_completion(line):
197 """
196 """
198 Returns a list containing the completion possibilities for an import line.
197 Returns a list containing the completion possibilities for an import line.
199
198
200 The line looks like this :
199 The line looks like this :
201 'import xml.d'
200 'import xml.d'
202 'from xml.dom import'
201 'from xml.dom import'
203 """
202 """
204
203
205 words = line.split(' ')
204 words = line.split(' ')
206 nwords = len(words)
205 nwords = len(words)
207
206
208 # from whatever <tab> -> 'import '
207 # from whatever <tab> -> 'import '
209 if nwords == 3 and words[0] == 'from':
208 if nwords == 3 and words[0] == 'from':
210 return ['import ']
209 return ['import ']
211
210
212 # 'from xy<tab>' or 'import xy<tab>'
211 # 'from xy<tab>' or 'import xy<tab>'
213 if nwords < 3 and (words[0] in ['import','from']) :
212 if nwords < 3 and (words[0] in ['import','from']) :
214 if nwords == 1:
213 if nwords == 1:
215 return get_root_modules()
214 return get_root_modules()
216 mod = words[1].split('.')
215 mod = words[1].split('.')
217 if len(mod) < 2:
216 if len(mod) < 2:
218 return get_root_modules()
217 return get_root_modules()
219 completion_list = try_import('.'.join(mod[:-1]), True)
218 completion_list = try_import('.'.join(mod[:-1]), True)
220 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
219 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
221
220
222 # 'from xyz import abc<tab>'
221 # 'from xyz import abc<tab>'
223 if nwords >= 3 and words[0] == 'from':
222 if nwords >= 3 and words[0] == 'from':
224 mod = words[1]
223 mod = words[1]
225 return try_import(mod)
224 return try_import(mod)
226
225
227 #-----------------------------------------------------------------------------
226 #-----------------------------------------------------------------------------
228 # Completers
227 # Completers
229 #-----------------------------------------------------------------------------
228 #-----------------------------------------------------------------------------
230 # These all have the func(self, event) signature to be used as custom
229 # These all have the func(self, event) signature to be used as custom
231 # completers
230 # completers
232
231
233 def module_completer(self,event):
232 def module_completer(self,event):
234 """Give completions after user has typed 'import ...' or 'from ...'"""
233 """Give completions after user has typed 'import ...' or 'from ...'"""
235
234
236 # This works in all versions of python. While 2.5 has
235 # This works in all versions of python. While 2.5 has
237 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
236 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
238 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
237 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
239 # of possibly problematic side effects.
238 # of possibly problematic side effects.
240 # This search the folders in the sys.path for available modules.
239 # This search the folders in the sys.path for available modules.
241
240
242 return module_completion(event.line)
241 return module_completion(event.line)
243
242
244 # FIXME: there's a lot of logic common to the run, cd and builtin file
243 # FIXME: there's a lot of logic common to the run, cd and builtin file
245 # completers, that is currently reimplemented in each.
244 # completers, that is currently reimplemented in each.
246
245
247 def magic_run_completer(self, event):
246 def magic_run_completer(self, event):
248 """Complete files that end in .py or .ipy for the %run command.
247 """Complete files that end in .py or .ipy for the %run command.
249 """
248 """
250 comps = arg_split(event.line, strict=False)
249 comps = arg_split(event.line, strict=False)
251 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
250 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
252
251
253 #print("\nev=", event) # dbg
252 #print("\nev=", event) # dbg
254 #print("rp=", relpath) # dbg
253 #print("rp=", relpath) # dbg
255 #print('comps=', comps) # dbg
254 #print('comps=', comps) # dbg
256
255
257 lglob = glob.glob
256 lglob = glob.glob
258 isdir = os.path.isdir
257 isdir = os.path.isdir
259 relpath, tilde_expand, tilde_val = expand_user(relpath)
258 relpath, tilde_expand, tilde_val = expand_user(relpath)
260
259
261 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
260 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
262
261
263 # Find if the user has already typed the first filename, after which we
262 # Find if the user has already typed the first filename, after which we
264 # should complete on all files, since after the first one other files may
263 # should complete on all files, since after the first one other files may
265 # be arguments to the input script.
264 # be arguments to the input script.
266
265
267 if filter(magic_run_re.match, comps):
266 if filter(magic_run_re.match, comps):
268 pys = [f.replace('\\','/') for f in lglob('*')]
267 pys = [f.replace('\\','/') for f in lglob('*')]
269 else:
268 else:
270 pys = [f.replace('\\','/')
269 pys = [f.replace('\\','/')
271 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
270 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
272 lglob(relpath + '*.pyw')]
271 lglob(relpath + '*.pyw')]
273 #print('run comp:', dirs+pys) # dbg
272 #print('run comp:', dirs+pys) # dbg
274 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
273 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
275
274
276
275
277 def cd_completer(self, event):
276 def cd_completer(self, event):
278 """Completer function for cd, which only returns directories."""
277 """Completer function for cd, which only returns directories."""
279 ip = get_ipython()
278 ip = get_ipython()
280 relpath = event.symbol
279 relpath = event.symbol
281
280
282 #print(event) # dbg
281 #print(event) # dbg
283 if event.line.endswith('-b') or ' -b ' in event.line:
282 if event.line.endswith('-b') or ' -b ' in event.line:
284 # return only bookmark completions
283 # return only bookmark completions
285 bkms = self.db.get('bookmarks', None)
284 bkms = self.db.get('bookmarks', None)
286 if bkms:
285 if bkms:
287 return bkms.keys()
286 return bkms.keys()
288 else:
287 else:
289 return []
288 return []
290
289
291 if event.symbol == '-':
290 if event.symbol == '-':
292 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
291 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
293 # jump in directory history by number
292 # jump in directory history by number
294 fmt = '-%0' + width_dh +'d [%s]'
293 fmt = '-%0' + width_dh +'d [%s]'
295 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
294 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
296 if len(ents) > 1:
295 if len(ents) > 1:
297 return ents
296 return ents
298 return []
297 return []
299
298
300 if event.symbol.startswith('--'):
299 if event.symbol.startswith('--'):
301 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
300 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
302
301
303 # Expand ~ in path and normalize directory separators.
302 # Expand ~ in path and normalize directory separators.
304 relpath, tilde_expand, tilde_val = expand_user(relpath)
303 relpath, tilde_expand, tilde_val = expand_user(relpath)
305 relpath = relpath.replace('\\','/')
304 relpath = relpath.replace('\\','/')
306
305
307 found = []
306 found = []
308 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
307 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
309 if os.path.isdir(f)]:
308 if os.path.isdir(f)]:
310 if ' ' in d:
309 if ' ' in d:
311 # we don't want to deal with any of that, complex code
310 # we don't want to deal with any of that, complex code
312 # for this is elsewhere
311 # for this is elsewhere
313 raise TryNext
312 raise TryNext
314
313
315 found.append(d)
314 found.append(d)
316
315
317 if not found:
316 if not found:
318 if os.path.isdir(relpath):
317 if os.path.isdir(relpath):
319 return [compress_user(relpath, tilde_expand, tilde_val)]
318 return [compress_user(relpath, tilde_expand, tilde_val)]
320
319
321 # if no completions so far, try bookmarks
320 # if no completions so far, try bookmarks
322 bks = self.db.get('bookmarks',{}).iterkeys()
321 bks = self.db.get('bookmarks',{}).iterkeys()
323 bkmatches = [s for s in bks if s.startswith(event.symbol)]
322 bkmatches = [s for s in bks if s.startswith(event.symbol)]
324 if bkmatches:
323 if bkmatches:
325 return bkmatches
324 return bkmatches
326
325
327 raise TryNext
326 raise TryNext
328
327
329 return [compress_user(p, tilde_expand, tilde_val) for p in found]
328 return [compress_user(p, tilde_expand, tilde_val) for p in found]
330
329
331 def reset_completer(self, event):
330 def reset_completer(self, event):
332 "A completer for %reset magic"
331 "A completer for %reset magic"
333 return '-f -s in out array dhist'.split()
332 return '-f -s in out array dhist'.split()
@@ -1,566 +1,566 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 the command line completion of other programs which include this isn't
6 the command line completion of other programs which include this isn't
7 damaged.
7 damaged.
8
8
9 In the future, this class will be expanded with improvements over the standard
9 In the future, this class will be expanded with improvements over the standard
10 pdb.
10 pdb.
11
11
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 changes. Licensing should therefore be under the standard Python terms. For
13 changes. Licensing should therefore be under the standard Python terms. For
14 details on the PSF (Python Software Foundation) standard license, see:
14 details on the PSF (Python Software Foundation) standard license, see:
15
15
16 http://www.python.org/2.2.3/license.html"""
16 http://www.python.org/2.2.3/license.html"""
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 #
19 #
20 # This file is licensed under the PSF license.
20 # This file is licensed under the PSF license.
21 #
21 #
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 #
24 #
25 #
25 #
26 #*****************************************************************************
26 #*****************************************************************************
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 import bdb
29 import bdb
30 import functools
30 import functools
31 import linecache
31 import linecache
32 import sys
32 import sys
33
33
34 from IPython.utils import PyColorize, ulinecache
34 from IPython.utils import PyColorize, ulinecache
35 from IPython.core import ipapi
35 from IPython.core import ipapi
36 from IPython.utils import coloransi, io, openpy, py3compat
36 from IPython.utils import coloransi, io, py3compat
37 from IPython.core.excolors import exception_colors
37 from IPython.core.excolors import exception_colors
38
38
39 # See if we can use pydb.
39 # See if we can use pydb.
40 has_pydb = False
40 has_pydb = False
41 prompt = 'ipdb> '
41 prompt = 'ipdb> '
42 #We have to check this directly from sys.argv, config struct not yet available
42 #We have to check this directly from sys.argv, config struct not yet available
43 if '--pydb' in sys.argv:
43 if '--pydb' in sys.argv:
44 try:
44 try:
45 import pydb
45 import pydb
46 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
46 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
47 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
47 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
48 # better protect against it.
48 # better protect against it.
49 has_pydb = True
49 has_pydb = True
50 except ImportError:
50 except ImportError:
51 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
51 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
52
52
53 if has_pydb:
53 if has_pydb:
54 from pydb import Pdb as OldPdb
54 from pydb import Pdb as OldPdb
55 #print "Using pydb for %run -d and post-mortem" #dbg
55 #print "Using pydb for %run -d and post-mortem" #dbg
56 prompt = 'ipydb> '
56 prompt = 'ipydb> '
57 else:
57 else:
58 from pdb import Pdb as OldPdb
58 from pdb import Pdb as OldPdb
59
59
60 # Allow the set_trace code to operate outside of an ipython instance, even if
60 # Allow the set_trace code to operate outside of an ipython instance, even if
61 # it does so with some limitations. The rest of this support is implemented in
61 # it does so with some limitations. The rest of this support is implemented in
62 # the Tracer constructor.
62 # the Tracer constructor.
63 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
63 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
64 """Exception hook which handles `BdbQuit` exceptions.
64 """Exception hook which handles `BdbQuit` exceptions.
65
65
66 All other exceptions are processed using the `excepthook`
66 All other exceptions are processed using the `excepthook`
67 parameter.
67 parameter.
68 """
68 """
69 if et==bdb.BdbQuit:
69 if et==bdb.BdbQuit:
70 print('Exiting Debugger.')
70 print('Exiting Debugger.')
71 elif excepthook is not None:
71 elif excepthook is not None:
72 excepthook(et, ev, tb)
72 excepthook(et, ev, tb)
73 else:
73 else:
74 # Backwards compatibility. Raise deprecation warning?
74 # Backwards compatibility. Raise deprecation warning?
75 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
75 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
76
76
77 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
77 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
78 print('Exiting Debugger.')
78 print('Exiting Debugger.')
79
79
80
80
81 class Tracer(object):
81 class Tracer(object):
82 """Class for local debugging, similar to pdb.set_trace.
82 """Class for local debugging, similar to pdb.set_trace.
83
83
84 Instances of this class, when called, behave like pdb.set_trace, but
84 Instances of this class, when called, behave like pdb.set_trace, but
85 providing IPython's enhanced capabilities.
85 providing IPython's enhanced capabilities.
86
86
87 This is implemented as a class which must be initialized in your own code
87 This is implemented as a class which must be initialized in your own code
88 and not as a standalone function because we need to detect at runtime
88 and not as a standalone function because we need to detect at runtime
89 whether IPython is already active or not. That detection is done in the
89 whether IPython is already active or not. That detection is done in the
90 constructor, ensuring that this code plays nicely with a running IPython,
90 constructor, ensuring that this code plays nicely with a running IPython,
91 while functioning acceptably (though with limitations) if outside of it.
91 while functioning acceptably (though with limitations) if outside of it.
92 """
92 """
93
93
94 def __init__(self,colors=None):
94 def __init__(self,colors=None):
95 """Create a local debugger instance.
95 """Create a local debugger instance.
96
96
97 :Parameters:
97 :Parameters:
98
98
99 - `colors` (None): a string containing the name of the color scheme to
99 - `colors` (None): a string containing the name of the color scheme to
100 use, it must be one of IPython's valid color schemes. If not given, the
100 use, it must be one of IPython's valid color schemes. If not given, the
101 function will default to the current IPython scheme when running inside
101 function will default to the current IPython scheme when running inside
102 IPython, and to 'NoColor' otherwise.
102 IPython, and to 'NoColor' otherwise.
103
103
104 Usage example:
104 Usage example:
105
105
106 from IPython.core.debugger import Tracer; debug_here = Tracer()
106 from IPython.core.debugger import Tracer; debug_here = Tracer()
107
107
108 ... later in your code
108 ... later in your code
109 debug_here() # -> will open up the debugger at that point.
109 debug_here() # -> will open up the debugger at that point.
110
110
111 Once the debugger activates, you can use all of its regular commands to
111 Once the debugger activates, you can use all of its regular commands to
112 step through code, set breakpoints, etc. See the pdb documentation
112 step through code, set breakpoints, etc. See the pdb documentation
113 from the Python standard library for usage details.
113 from the Python standard library for usage details.
114 """
114 """
115
115
116 try:
116 try:
117 ip = get_ipython()
117 ip = get_ipython()
118 except NameError:
118 except NameError:
119 # Outside of ipython, we set our own exception hook manually
119 # Outside of ipython, we set our own exception hook manually
120 sys.excepthook = functools.partial(BdbQuit_excepthook,
120 sys.excepthook = functools.partial(BdbQuit_excepthook,
121 excepthook=sys.excepthook)
121 excepthook=sys.excepthook)
122 def_colors = 'NoColor'
122 def_colors = 'NoColor'
123 try:
123 try:
124 # Limited tab completion support
124 # Limited tab completion support
125 import readline
125 import readline
126 readline.parse_and_bind('tab: complete')
126 readline.parse_and_bind('tab: complete')
127 except ImportError:
127 except ImportError:
128 pass
128 pass
129 else:
129 else:
130 # In ipython, we use its custom exception handler mechanism
130 # In ipython, we use its custom exception handler mechanism
131 def_colors = ip.colors
131 def_colors = ip.colors
132 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
132 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
133
133
134 if colors is None:
134 if colors is None:
135 colors = def_colors
135 colors = def_colors
136
136
137 # The stdlib debugger internally uses a modified repr from the `repr`
137 # The stdlib debugger internally uses a modified repr from the `repr`
138 # module, that limits the length of printed strings to a hardcoded
138 # module, that limits the length of printed strings to a hardcoded
139 # limit of 30 characters. That much trimming is too aggressive, let's
139 # limit of 30 characters. That much trimming is too aggressive, let's
140 # at least raise that limit to 80 chars, which should be enough for
140 # at least raise that limit to 80 chars, which should be enough for
141 # most interactive uses.
141 # most interactive uses.
142 try:
142 try:
143 from repr import aRepr
143 from repr import aRepr
144 aRepr.maxstring = 80
144 aRepr.maxstring = 80
145 except:
145 except:
146 # This is only a user-facing convenience, so any error we encounter
146 # This is only a user-facing convenience, so any error we encounter
147 # here can be warned about but can be otherwise ignored. These
147 # here can be warned about but can be otherwise ignored. These
148 # printouts will tell us about problems if this API changes
148 # printouts will tell us about problems if this API changes
149 import traceback
149 import traceback
150 traceback.print_exc()
150 traceback.print_exc()
151
151
152 self.debugger = Pdb(colors)
152 self.debugger = Pdb(colors)
153
153
154 def __call__(self):
154 def __call__(self):
155 """Starts an interactive debugger at the point where called.
155 """Starts an interactive debugger at the point where called.
156
156
157 This is similar to the pdb.set_trace() function from the std lib, but
157 This is similar to the pdb.set_trace() function from the std lib, but
158 using IPython's enhanced debugger."""
158 using IPython's enhanced debugger."""
159
159
160 self.debugger.set_trace(sys._getframe().f_back)
160 self.debugger.set_trace(sys._getframe().f_back)
161
161
162
162
163 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
163 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
164 """Make new_fn have old_fn's doc string. This is particularly useful
164 """Make new_fn have old_fn's doc string. This is particularly useful
165 for the ``do_...`` commands that hook into the help system.
165 for the ``do_...`` commands that hook into the help system.
166 Adapted from from a comp.lang.python posting
166 Adapted from from a comp.lang.python posting
167 by Duncan Booth."""
167 by Duncan Booth."""
168 def wrapper(*args, **kw):
168 def wrapper(*args, **kw):
169 return new_fn(*args, **kw)
169 return new_fn(*args, **kw)
170 if old_fn.__doc__:
170 if old_fn.__doc__:
171 wrapper.__doc__ = old_fn.__doc__ + additional_text
171 wrapper.__doc__ = old_fn.__doc__ + additional_text
172 return wrapper
172 return wrapper
173
173
174
174
175 def _file_lines(fname):
175 def _file_lines(fname):
176 """Return the contents of a named file as a list of lines.
176 """Return the contents of a named file as a list of lines.
177
177
178 This function never raises an IOError exception: if the file can't be
178 This function never raises an IOError exception: if the file can't be
179 read, it simply returns an empty list."""
179 read, it simply returns an empty list."""
180
180
181 try:
181 try:
182 outfile = open(fname)
182 outfile = open(fname)
183 except IOError:
183 except IOError:
184 return []
184 return []
185 else:
185 else:
186 out = outfile.readlines()
186 out = outfile.readlines()
187 outfile.close()
187 outfile.close()
188 return out
188 return out
189
189
190
190
191 class Pdb(OldPdb):
191 class Pdb(OldPdb):
192 """Modified Pdb class, does not load readline."""
192 """Modified Pdb class, does not load readline."""
193
193
194 def __init__(self,color_scheme='NoColor',completekey=None,
194 def __init__(self,color_scheme='NoColor',completekey=None,
195 stdin=None, stdout=None):
195 stdin=None, stdout=None):
196
196
197 # Parent constructor:
197 # Parent constructor:
198 if has_pydb and completekey is None:
198 if has_pydb and completekey is None:
199 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
199 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
200 else:
200 else:
201 OldPdb.__init__(self,completekey,stdin,stdout)
201 OldPdb.__init__(self,completekey,stdin,stdout)
202
202
203 self.prompt = prompt # The default prompt is '(Pdb)'
203 self.prompt = prompt # The default prompt is '(Pdb)'
204
204
205 # IPython changes...
205 # IPython changes...
206 self.is_pydb = has_pydb
206 self.is_pydb = has_pydb
207
207
208 self.shell = ipapi.get()
208 self.shell = ipapi.get()
209
209
210 if self.is_pydb:
210 if self.is_pydb:
211
211
212 # interactiveshell.py's ipalias seems to want pdb's checkline
212 # interactiveshell.py's ipalias seems to want pdb's checkline
213 # which located in pydb.fn
213 # which located in pydb.fn
214 import pydb.fns
214 import pydb.fns
215 self.checkline = lambda filename, lineno: \
215 self.checkline = lambda filename, lineno: \
216 pydb.fns.checkline(self, filename, lineno)
216 pydb.fns.checkline(self, filename, lineno)
217
217
218 self.curframe = None
218 self.curframe = None
219 self.do_restart = self.new_do_restart
219 self.do_restart = self.new_do_restart
220
220
221 self.old_all_completions = self.shell.Completer.all_completions
221 self.old_all_completions = self.shell.Completer.all_completions
222 self.shell.Completer.all_completions=self.all_completions
222 self.shell.Completer.all_completions=self.all_completions
223
223
224 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
224 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
225 OldPdb.do_list)
225 OldPdb.do_list)
226 self.do_l = self.do_list
226 self.do_l = self.do_list
227 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
227 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
228 OldPdb.do_frame)
228 OldPdb.do_frame)
229
229
230 self.aliases = {}
230 self.aliases = {}
231
231
232 # Create color table: we copy the default one from the traceback
232 # Create color table: we copy the default one from the traceback
233 # module and add a few attributes needed for debugging
233 # module and add a few attributes needed for debugging
234 self.color_scheme_table = exception_colors()
234 self.color_scheme_table = exception_colors()
235
235
236 # shorthands
236 # shorthands
237 C = coloransi.TermColors
237 C = coloransi.TermColors
238 cst = self.color_scheme_table
238 cst = self.color_scheme_table
239
239
240 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
240 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
241 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
241 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
242
242
243 cst['Linux'].colors.breakpoint_enabled = C.LightRed
243 cst['Linux'].colors.breakpoint_enabled = C.LightRed
244 cst['Linux'].colors.breakpoint_disabled = C.Red
244 cst['Linux'].colors.breakpoint_disabled = C.Red
245
245
246 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
246 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
247 cst['LightBG'].colors.breakpoint_disabled = C.Red
247 cst['LightBG'].colors.breakpoint_disabled = C.Red
248
248
249 self.set_colors(color_scheme)
249 self.set_colors(color_scheme)
250
250
251 # Add a python parser so we can syntax highlight source while
251 # Add a python parser so we can syntax highlight source while
252 # debugging.
252 # debugging.
253 self.parser = PyColorize.Parser()
253 self.parser = PyColorize.Parser()
254
254
255 def set_colors(self, scheme):
255 def set_colors(self, scheme):
256 """Shorthand access to the color table scheme selector method."""
256 """Shorthand access to the color table scheme selector method."""
257 self.color_scheme_table.set_active_scheme(scheme)
257 self.color_scheme_table.set_active_scheme(scheme)
258
258
259 def interaction(self, frame, traceback):
259 def interaction(self, frame, traceback):
260 self.shell.set_completer_frame(frame)
260 self.shell.set_completer_frame(frame)
261 OldPdb.interaction(self, frame, traceback)
261 OldPdb.interaction(self, frame, traceback)
262
262
263 def new_do_up(self, arg):
263 def new_do_up(self, arg):
264 OldPdb.do_up(self, arg)
264 OldPdb.do_up(self, arg)
265 self.shell.set_completer_frame(self.curframe)
265 self.shell.set_completer_frame(self.curframe)
266 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
266 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
267
267
268 def new_do_down(self, arg):
268 def new_do_down(self, arg):
269 OldPdb.do_down(self, arg)
269 OldPdb.do_down(self, arg)
270 self.shell.set_completer_frame(self.curframe)
270 self.shell.set_completer_frame(self.curframe)
271
271
272 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
272 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
273
273
274 def new_do_frame(self, arg):
274 def new_do_frame(self, arg):
275 OldPdb.do_frame(self, arg)
275 OldPdb.do_frame(self, arg)
276 self.shell.set_completer_frame(self.curframe)
276 self.shell.set_completer_frame(self.curframe)
277
277
278 def new_do_quit(self, arg):
278 def new_do_quit(self, arg):
279
279
280 if hasattr(self, 'old_all_completions'):
280 if hasattr(self, 'old_all_completions'):
281 self.shell.Completer.all_completions=self.old_all_completions
281 self.shell.Completer.all_completions=self.old_all_completions
282
282
283
283
284 return OldPdb.do_quit(self, arg)
284 return OldPdb.do_quit(self, arg)
285
285
286 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
286 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
287
287
288 def new_do_restart(self, arg):
288 def new_do_restart(self, arg):
289 """Restart command. In the context of ipython this is exactly the same
289 """Restart command. In the context of ipython this is exactly the same
290 thing as 'quit'."""
290 thing as 'quit'."""
291 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
291 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
292 return self.do_quit(arg)
292 return self.do_quit(arg)
293
293
294 def postloop(self):
294 def postloop(self):
295 self.shell.set_completer_frame(None)
295 self.shell.set_completer_frame(None)
296
296
297 def print_stack_trace(self):
297 def print_stack_trace(self):
298 try:
298 try:
299 for frame_lineno in self.stack:
299 for frame_lineno in self.stack:
300 self.print_stack_entry(frame_lineno, context = 5)
300 self.print_stack_entry(frame_lineno, context = 5)
301 except KeyboardInterrupt:
301 except KeyboardInterrupt:
302 pass
302 pass
303
303
304 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
304 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
305 context = 3):
305 context = 3):
306 #frame, lineno = frame_lineno
306 #frame, lineno = frame_lineno
307 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
307 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
308
308
309 # vds: >>
309 # vds: >>
310 frame, lineno = frame_lineno
310 frame, lineno = frame_lineno
311 filename = frame.f_code.co_filename
311 filename = frame.f_code.co_filename
312 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
312 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
313 # vds: <<
313 # vds: <<
314
314
315 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
315 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
316 import repr
316 import repr
317
317
318 ret = []
318 ret = []
319
319
320 Colors = self.color_scheme_table.active_colors
320 Colors = self.color_scheme_table.active_colors
321 ColorsNormal = Colors.Normal
321 ColorsNormal = Colors.Normal
322 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
322 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
323 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
323 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
324 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
324 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
325 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
325 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
326 ColorsNormal)
326 ColorsNormal)
327
327
328 frame, lineno = frame_lineno
328 frame, lineno = frame_lineno
329
329
330 return_value = ''
330 return_value = ''
331 if '__return__' in frame.f_locals:
331 if '__return__' in frame.f_locals:
332 rv = frame.f_locals['__return__']
332 rv = frame.f_locals['__return__']
333 #return_value += '->'
333 #return_value += '->'
334 return_value += repr.repr(rv) + '\n'
334 return_value += repr.repr(rv) + '\n'
335 ret.append(return_value)
335 ret.append(return_value)
336
336
337 #s = filename + '(' + `lineno` + ')'
337 #s = filename + '(' + `lineno` + ')'
338 filename = self.canonic(frame.f_code.co_filename)
338 filename = self.canonic(frame.f_code.co_filename)
339 link = tpl_link % py3compat.cast_unicode(filename)
339 link = tpl_link % py3compat.cast_unicode(filename)
340
340
341 if frame.f_code.co_name:
341 if frame.f_code.co_name:
342 func = frame.f_code.co_name
342 func = frame.f_code.co_name
343 else:
343 else:
344 func = "<lambda>"
344 func = "<lambda>"
345
345
346 call = ''
346 call = ''
347 if func != '?':
347 if func != '?':
348 if '__args__' in frame.f_locals:
348 if '__args__' in frame.f_locals:
349 args = repr.repr(frame.f_locals['__args__'])
349 args = repr.repr(frame.f_locals['__args__'])
350 else:
350 else:
351 args = '()'
351 args = '()'
352 call = tpl_call % (func, args)
352 call = tpl_call % (func, args)
353
353
354 # The level info should be generated in the same format pdb uses, to
354 # The level info should be generated in the same format pdb uses, to
355 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
355 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
356 if frame is self.curframe:
356 if frame is self.curframe:
357 ret.append('> ')
357 ret.append('> ')
358 else:
358 else:
359 ret.append(' ')
359 ret.append(' ')
360 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
360 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
361
361
362 start = lineno - 1 - context//2
362 start = lineno - 1 - context//2
363 lines = ulinecache.getlines(filename)
363 lines = ulinecache.getlines(filename)
364 start = min(start, len(lines) - context)
364 start = min(start, len(lines) - context)
365 start = max(start, 0)
365 start = max(start, 0)
366 lines = lines[start : start + context]
366 lines = lines[start : start + context]
367
367
368 for i,line in enumerate(lines):
368 for i,line in enumerate(lines):
369 show_arrow = (start + 1 + i == lineno)
369 show_arrow = (start + 1 + i == lineno)
370 linetpl = (frame is self.curframe or show_arrow) \
370 linetpl = (frame is self.curframe or show_arrow) \
371 and tpl_line_em \
371 and tpl_line_em \
372 or tpl_line
372 or tpl_line
373 ret.append(self.__format_line(linetpl, filename,
373 ret.append(self.__format_line(linetpl, filename,
374 start + 1 + i, line,
374 start + 1 + i, line,
375 arrow = show_arrow) )
375 arrow = show_arrow) )
376 return ''.join(ret)
376 return ''.join(ret)
377
377
378 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
378 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
379 bp_mark = ""
379 bp_mark = ""
380 bp_mark_color = ""
380 bp_mark_color = ""
381
381
382 scheme = self.color_scheme_table.active_scheme_name
382 scheme = self.color_scheme_table.active_scheme_name
383 new_line, err = self.parser.format2(line, 'str', scheme)
383 new_line, err = self.parser.format2(line, 'str', scheme)
384 if not err: line = new_line
384 if not err: line = new_line
385
385
386 bp = None
386 bp = None
387 if lineno in self.get_file_breaks(filename):
387 if lineno in self.get_file_breaks(filename):
388 bps = self.get_breaks(filename, lineno)
388 bps = self.get_breaks(filename, lineno)
389 bp = bps[-1]
389 bp = bps[-1]
390
390
391 if bp:
391 if bp:
392 Colors = self.color_scheme_table.active_colors
392 Colors = self.color_scheme_table.active_colors
393 bp_mark = str(bp.number)
393 bp_mark = str(bp.number)
394 bp_mark_color = Colors.breakpoint_enabled
394 bp_mark_color = Colors.breakpoint_enabled
395 if not bp.enabled:
395 if not bp.enabled:
396 bp_mark_color = Colors.breakpoint_disabled
396 bp_mark_color = Colors.breakpoint_disabled
397
397
398 numbers_width = 7
398 numbers_width = 7
399 if arrow:
399 if arrow:
400 # This is the line with the error
400 # This is the line with the error
401 pad = numbers_width - len(str(lineno)) - len(bp_mark)
401 pad = numbers_width - len(str(lineno)) - len(bp_mark)
402 if pad >= 3:
402 if pad >= 3:
403 marker = '-'*(pad-3) + '-> '
403 marker = '-'*(pad-3) + '-> '
404 elif pad == 2:
404 elif pad == 2:
405 marker = '> '
405 marker = '> '
406 elif pad == 1:
406 elif pad == 1:
407 marker = '>'
407 marker = '>'
408 else:
408 else:
409 marker = ''
409 marker = ''
410 num = '%s%s' % (marker, str(lineno))
410 num = '%s%s' % (marker, str(lineno))
411 line = tpl_line % (bp_mark_color + bp_mark, num, line)
411 line = tpl_line % (bp_mark_color + bp_mark, num, line)
412 else:
412 else:
413 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
413 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
414 line = tpl_line % (bp_mark_color + bp_mark, num, line)
414 line = tpl_line % (bp_mark_color + bp_mark, num, line)
415
415
416 return line
416 return line
417
417
418 def list_command_pydb(self, arg):
418 def list_command_pydb(self, arg):
419 """List command to use if we have a newer pydb installed"""
419 """List command to use if we have a newer pydb installed"""
420 filename, first, last = OldPdb.parse_list_cmd(self, arg)
420 filename, first, last = OldPdb.parse_list_cmd(self, arg)
421 if filename is not None:
421 if filename is not None:
422 self.print_list_lines(filename, first, last)
422 self.print_list_lines(filename, first, last)
423
423
424 def print_list_lines(self, filename, first, last):
424 def print_list_lines(self, filename, first, last):
425 """The printing (as opposed to the parsing part of a 'list'
425 """The printing (as opposed to the parsing part of a 'list'
426 command."""
426 command."""
427 try:
427 try:
428 Colors = self.color_scheme_table.active_colors
428 Colors = self.color_scheme_table.active_colors
429 ColorsNormal = Colors.Normal
429 ColorsNormal = Colors.Normal
430 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
430 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
431 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
431 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
432 src = []
432 src = []
433 if filename == "<string>" and hasattr(self, "_exec_filename"):
433 if filename == "<string>" and hasattr(self, "_exec_filename"):
434 filename = self._exec_filename
434 filename = self._exec_filename
435
435
436 for lineno in range(first, last+1):
436 for lineno in range(first, last+1):
437 line = ulinecache.getline(filename, lineno)
437 line = ulinecache.getline(filename, lineno)
438 if not line:
438 if not line:
439 break
439 break
440
440
441 if lineno == self.curframe.f_lineno:
441 if lineno == self.curframe.f_lineno:
442 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
442 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
443 else:
443 else:
444 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
444 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
445
445
446 src.append(line)
446 src.append(line)
447 self.lineno = lineno
447 self.lineno = lineno
448
448
449 print(''.join(src), file=io.stdout)
449 print(''.join(src), file=io.stdout)
450
450
451 except KeyboardInterrupt:
451 except KeyboardInterrupt:
452 pass
452 pass
453
453
454 def do_list(self, arg):
454 def do_list(self, arg):
455 self.lastcmd = 'list'
455 self.lastcmd = 'list'
456 last = None
456 last = None
457 if arg:
457 if arg:
458 try:
458 try:
459 x = eval(arg, {}, {})
459 x = eval(arg, {}, {})
460 if type(x) == type(()):
460 if type(x) == type(()):
461 first, last = x
461 first, last = x
462 first = int(first)
462 first = int(first)
463 last = int(last)
463 last = int(last)
464 if last < first:
464 if last < first:
465 # Assume it's a count
465 # Assume it's a count
466 last = first + last
466 last = first + last
467 else:
467 else:
468 first = max(1, int(x) - 5)
468 first = max(1, int(x) - 5)
469 except:
469 except:
470 print('*** Error in argument:', repr(arg))
470 print('*** Error in argument:', repr(arg))
471 return
471 return
472 elif self.lineno is None:
472 elif self.lineno is None:
473 first = max(1, self.curframe.f_lineno - 5)
473 first = max(1, self.curframe.f_lineno - 5)
474 else:
474 else:
475 first = self.lineno + 1
475 first = self.lineno + 1
476 if last is None:
476 if last is None:
477 last = first + 10
477 last = first + 10
478 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
478 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
479
479
480 # vds: >>
480 # vds: >>
481 lineno = first
481 lineno = first
482 filename = self.curframe.f_code.co_filename
482 filename = self.curframe.f_code.co_filename
483 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
483 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
484 # vds: <<
484 # vds: <<
485
485
486 do_l = do_list
486 do_l = do_list
487
487
488 def do_pdef(self, arg):
488 def do_pdef(self, arg):
489 """Print the call signature for any callable object.
489 """Print the call signature for any callable object.
490
490
491 The debugger interface to %pdef"""
491 The debugger interface to %pdef"""
492 namespaces = [('Locals', self.curframe.f_locals),
492 namespaces = [('Locals', self.curframe.f_locals),
493 ('Globals', self.curframe.f_globals)]
493 ('Globals', self.curframe.f_globals)]
494 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
494 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
495
495
496 def do_pdoc(self, arg):
496 def do_pdoc(self, arg):
497 """Print the docstring for an object.
497 """Print the docstring for an object.
498
498
499 The debugger interface to %pdoc."""
499 The debugger interface to %pdoc."""
500 namespaces = [('Locals', self.curframe.f_locals),
500 namespaces = [('Locals', self.curframe.f_locals),
501 ('Globals', self.curframe.f_globals)]
501 ('Globals', self.curframe.f_globals)]
502 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
502 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
503
503
504 def do_pfile(self, arg):
504 def do_pfile(self, arg):
505 """Print (or run through pager) the file where an object is defined.
505 """Print (or run through pager) the file where an object is defined.
506
506
507 The debugger interface to %pfile.
507 The debugger interface to %pfile.
508 """
508 """
509 namespaces = [('Locals', self.curframe.f_locals),
509 namespaces = [('Locals', self.curframe.f_locals),
510 ('Globals', self.curframe.f_globals)]
510 ('Globals', self.curframe.f_globals)]
511 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
511 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
512
512
513 def do_pinfo(self, arg):
513 def do_pinfo(self, arg):
514 """Provide detailed information about an object.
514 """Provide detailed information about an object.
515
515
516 The debugger interface to %pinfo, i.e., obj?."""
516 The debugger interface to %pinfo, i.e., obj?."""
517 namespaces = [('Locals', self.curframe.f_locals),
517 namespaces = [('Locals', self.curframe.f_locals),
518 ('Globals', self.curframe.f_globals)]
518 ('Globals', self.curframe.f_globals)]
519 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
519 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
520
520
521 def do_pinfo2(self, arg):
521 def do_pinfo2(self, arg):
522 """Provide extra detailed information about an object.
522 """Provide extra detailed information about an object.
523
523
524 The debugger interface to %pinfo2, i.e., obj??."""
524 The debugger interface to %pinfo2, i.e., obj??."""
525 namespaces = [('Locals', self.curframe.f_locals),
525 namespaces = [('Locals', self.curframe.f_locals),
526 ('Globals', self.curframe.f_globals)]
526 ('Globals', self.curframe.f_globals)]
527 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
527 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
528
528
529 def do_psource(self, arg):
529 def do_psource(self, arg):
530 """Print (or run through pager) the source code for an object."""
530 """Print (or run through pager) the source code for an object."""
531 namespaces = [('Locals', self.curframe.f_locals),
531 namespaces = [('Locals', self.curframe.f_locals),
532 ('Globals', self.curframe.f_globals)]
532 ('Globals', self.curframe.f_globals)]
533 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
533 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
534
534
535 def checkline(self, filename, lineno):
535 def checkline(self, filename, lineno):
536 """Check whether specified line seems to be executable.
536 """Check whether specified line seems to be executable.
537
537
538 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
538 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
539 line or EOF). Warning: testing is not comprehensive.
539 line or EOF). Warning: testing is not comprehensive.
540 """
540 """
541 #######################################################################
541 #######################################################################
542 # XXX Hack! Use python-2.5 compatible code for this call, because with
542 # XXX Hack! Use python-2.5 compatible code for this call, because with
543 # all of our changes, we've drifted from the pdb api in 2.6. For now,
543 # all of our changes, we've drifted from the pdb api in 2.6. For now,
544 # changing:
544 # changing:
545 #
545 #
546 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
546 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
547 # to:
547 # to:
548 #
548 #
549 line = linecache.getline(filename, lineno)
549 line = linecache.getline(filename, lineno)
550 #
550 #
551 # does the trick. But in reality, we need to fix this by reconciling
551 # does the trick. But in reality, we need to fix this by reconciling
552 # our updates with the new Pdb APIs in Python 2.6.
552 # our updates with the new Pdb APIs in Python 2.6.
553 #
553 #
554 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
554 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
555 #######################################################################
555 #######################################################################
556
556
557 if not line:
557 if not line:
558 print('End of file', file=self.stdout)
558 print('End of file', file=self.stdout)
559 return 0
559 return 0
560 line = line.strip()
560 line = line.strip()
561 # Don't allow setting breakpoint at a blank line
561 # Don't allow setting breakpoint at a blank line
562 if (not line or (line[0] == '#') or
562 if (not line or (line[0] == '#') or
563 (line[:3] == '"""') or line[:3] == "'''"):
563 (line[:3] == '"""') or line[:3] == "'''"):
564 print('*** Blank or comment', file=self.stdout)
564 print('*** Blank or comment', file=self.stdout)
565 return 0
565 return 0
566 return lineno
566 return lineno
@@ -1,275 +1,275 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Displayhook for IPython.
2 """Displayhook for IPython.
3
3
4 This defines a callable class that IPython uses for `sys.displayhook`.
4 This defines a callable class that IPython uses for `sys.displayhook`.
5
5
6 Authors:
6 Authors:
7
7
8 * Fernando Perez
8 * Fernando Perez
9 * Brian Granger
9 * Brian Granger
10 * Robert Kern
10 * Robert Kern
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 from __future__ import print_function
24 from __future__ import print_function
25
25
26 import __builtin__
26 import __builtin__
27
27
28 import sys
28 import sys
29
29
30
30
31 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
32 from IPython.utils import io
32 from IPython.utils import io
33 from IPython.utils.traitlets import Instance, List
33 from IPython.utils.traitlets import Instance
34 from IPython.utils.warn import warn
34 from IPython.utils.warn import warn
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Main displayhook class
37 # Main displayhook class
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # TODO: Move the various attributes (cache_size, [others now moved]). Some
40 # TODO: Move the various attributes (cache_size, [others now moved]). Some
41 # of these are also attributes of InteractiveShell. They should be on ONE object
41 # of these are also attributes of InteractiveShell. They should be on ONE object
42 # only and the other objects should ask that one object for their values.
42 # only and the other objects should ask that one object for their values.
43
43
44 class DisplayHook(Configurable):
44 class DisplayHook(Configurable):
45 """The custom IPython displayhook to replace sys.displayhook.
45 """The custom IPython displayhook to replace sys.displayhook.
46
46
47 This class does many things, but the basic idea is that it is a callable
47 This class does many things, but the basic idea is that it is a callable
48 that gets called anytime user code returns a value.
48 that gets called anytime user code returns a value.
49 """
49 """
50
50
51 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
51 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
52
52
53 def __init__(self, shell=None, cache_size=1000, config=None):
53 def __init__(self, shell=None, cache_size=1000, config=None):
54 super(DisplayHook, self).__init__(shell=shell, config=config)
54 super(DisplayHook, self).__init__(shell=shell, config=config)
55
55
56 cache_size_min = 3
56 cache_size_min = 3
57 if cache_size <= 0:
57 if cache_size <= 0:
58 self.do_full_cache = 0
58 self.do_full_cache = 0
59 cache_size = 0
59 cache_size = 0
60 elif cache_size < cache_size_min:
60 elif cache_size < cache_size_min:
61 self.do_full_cache = 0
61 self.do_full_cache = 0
62 cache_size = 0
62 cache_size = 0
63 warn('caching was disabled (min value for cache size is %s).' %
63 warn('caching was disabled (min value for cache size is %s).' %
64 cache_size_min,level=3)
64 cache_size_min,level=3)
65 else:
65 else:
66 self.do_full_cache = 1
66 self.do_full_cache = 1
67
67
68 self.cache_size = cache_size
68 self.cache_size = cache_size
69
69
70 # we need a reference to the user-level namespace
70 # we need a reference to the user-level namespace
71 self.shell = shell
71 self.shell = shell
72
72
73 self._,self.__,self.___ = '','',''
73 self._,self.__,self.___ = '','',''
74
74
75 # these are deliberately global:
75 # these are deliberately global:
76 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
76 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
77 self.shell.user_ns.update(to_user_ns)
77 self.shell.user_ns.update(to_user_ns)
78
78
79 @property
79 @property
80 def prompt_count(self):
80 def prompt_count(self):
81 return self.shell.execution_count
81 return self.shell.execution_count
82
82
83 #-------------------------------------------------------------------------
83 #-------------------------------------------------------------------------
84 # Methods used in __call__. Override these methods to modify the behavior
84 # Methods used in __call__. Override these methods to modify the behavior
85 # of the displayhook.
85 # of the displayhook.
86 #-------------------------------------------------------------------------
86 #-------------------------------------------------------------------------
87
87
88 def check_for_underscore(self):
88 def check_for_underscore(self):
89 """Check if the user has set the '_' variable by hand."""
89 """Check if the user has set the '_' variable by hand."""
90 # If something injected a '_' variable in __builtin__, delete
90 # If something injected a '_' variable in __builtin__, delete
91 # ipython's automatic one so we don't clobber that. gettext() in
91 # ipython's automatic one so we don't clobber that. gettext() in
92 # particular uses _, so we need to stay away from it.
92 # particular uses _, so we need to stay away from it.
93 if '_' in __builtin__.__dict__:
93 if '_' in __builtin__.__dict__:
94 try:
94 try:
95 del self.shell.user_ns['_']
95 del self.shell.user_ns['_']
96 except KeyError:
96 except KeyError:
97 pass
97 pass
98
98
99 def quiet(self):
99 def quiet(self):
100 """Should we silence the display hook because of ';'?"""
100 """Should we silence the display hook because of ';'?"""
101 # do not print output if input ends in ';'
101 # do not print output if input ends in ';'
102 try:
102 try:
103 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
103 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
104 if cell.rstrip().endswith(';'):
104 if cell.rstrip().endswith(';'):
105 return True
105 return True
106 except IndexError:
106 except IndexError:
107 # some uses of ipshellembed may fail here
107 # some uses of ipshellembed may fail here
108 pass
108 pass
109 return False
109 return False
110
110
111 def start_displayhook(self):
111 def start_displayhook(self):
112 """Start the displayhook, initializing resources."""
112 """Start the displayhook, initializing resources."""
113 pass
113 pass
114
114
115 def write_output_prompt(self):
115 def write_output_prompt(self):
116 """Write the output prompt.
116 """Write the output prompt.
117
117
118 The default implementation simply writes the prompt to
118 The default implementation simply writes the prompt to
119 ``io.stdout``.
119 ``io.stdout``.
120 """
120 """
121 # Use write, not print which adds an extra space.
121 # Use write, not print which adds an extra space.
122 io.stdout.write(self.shell.separate_out)
122 io.stdout.write(self.shell.separate_out)
123 outprompt = self.shell.prompt_manager.render('out')
123 outprompt = self.shell.prompt_manager.render('out')
124 if self.do_full_cache:
124 if self.do_full_cache:
125 io.stdout.write(outprompt)
125 io.stdout.write(outprompt)
126
126
127 def compute_format_data(self, result):
127 def compute_format_data(self, result):
128 """Compute format data of the object to be displayed.
128 """Compute format data of the object to be displayed.
129
129
130 The format data is a generalization of the :func:`repr` of an object.
130 The format data is a generalization of the :func:`repr` of an object.
131 In the default implementation the format data is a :class:`dict` of
131 In the default implementation the format data is a :class:`dict` of
132 key value pair where the keys are valid MIME types and the values
132 key value pair where the keys are valid MIME types and the values
133 are JSON'able data structure containing the raw data for that MIME
133 are JSON'able data structure containing the raw data for that MIME
134 type. It is up to frontends to determine pick a MIME to to use and
134 type. It is up to frontends to determine pick a MIME to to use and
135 display that data in an appropriate manner.
135 display that data in an appropriate manner.
136
136
137 This method only computes the format data for the object and should
137 This method only computes the format data for the object and should
138 NOT actually print or write that to a stream.
138 NOT actually print or write that to a stream.
139
139
140 Parameters
140 Parameters
141 ----------
141 ----------
142 result : object
142 result : object
143 The Python object passed to the display hook, whose format will be
143 The Python object passed to the display hook, whose format will be
144 computed.
144 computed.
145
145
146 Returns
146 Returns
147 -------
147 -------
148 format_data : dict
148 format_data : dict
149 A :class:`dict` whose keys are valid MIME types and values are
149 A :class:`dict` whose keys are valid MIME types and values are
150 JSON'able raw data for that MIME type. It is recommended that
150 JSON'able raw data for that MIME type. It is recommended that
151 all return values of this should always include the "text/plain"
151 all return values of this should always include the "text/plain"
152 MIME type representation of the object.
152 MIME type representation of the object.
153 """
153 """
154 return self.shell.display_formatter.format(result)
154 return self.shell.display_formatter.format(result)
155
155
156 def write_format_data(self, format_dict):
156 def write_format_data(self, format_dict):
157 """Write the format data dict to the frontend.
157 """Write the format data dict to the frontend.
158
158
159 This default version of this method simply writes the plain text
159 This default version of this method simply writes the plain text
160 representation of the object to ``io.stdout``. Subclasses should
160 representation of the object to ``io.stdout``. Subclasses should
161 override this method to send the entire `format_dict` to the
161 override this method to send the entire `format_dict` to the
162 frontends.
162 frontends.
163
163
164 Parameters
164 Parameters
165 ----------
165 ----------
166 format_dict : dict
166 format_dict : dict
167 The format dict for the object passed to `sys.displayhook`.
167 The format dict for the object passed to `sys.displayhook`.
168 """
168 """
169 # We want to print because we want to always make sure we have a
169 # We want to print because we want to always make sure we have a
170 # newline, even if all the prompt separators are ''. This is the
170 # newline, even if all the prompt separators are ''. This is the
171 # standard IPython behavior.
171 # standard IPython behavior.
172 result_repr = format_dict['text/plain']
172 result_repr = format_dict['text/plain']
173 if '\n' in result_repr:
173 if '\n' in result_repr:
174 # So that multi-line strings line up with the left column of
174 # So that multi-line strings line up with the left column of
175 # the screen, instead of having the output prompt mess up
175 # the screen, instead of having the output prompt mess up
176 # their first line.
176 # their first line.
177 # We use the prompt template instead of the expanded prompt
177 # We use the prompt template instead of the expanded prompt
178 # because the expansion may add ANSI escapes that will interfere
178 # because the expansion may add ANSI escapes that will interfere
179 # with our ability to determine whether or not we should add
179 # with our ability to determine whether or not we should add
180 # a newline.
180 # a newline.
181 prompt_template = self.shell.prompt_manager.out_template
181 prompt_template = self.shell.prompt_manager.out_template
182 if prompt_template and not prompt_template.endswith('\n'):
182 if prompt_template and not prompt_template.endswith('\n'):
183 # But avoid extraneous empty lines.
183 # But avoid extraneous empty lines.
184 result_repr = '\n' + result_repr
184 result_repr = '\n' + result_repr
185
185
186 print(result_repr, file=io.stdout)
186 print(result_repr, file=io.stdout)
187
187
188 def update_user_ns(self, result):
188 def update_user_ns(self, result):
189 """Update user_ns with various things like _, __, _1, etc."""
189 """Update user_ns with various things like _, __, _1, etc."""
190
190
191 # Avoid recursive reference when displaying _oh/Out
191 # Avoid recursive reference when displaying _oh/Out
192 if result is not self.shell.user_ns['_oh']:
192 if result is not self.shell.user_ns['_oh']:
193 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
193 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
194 warn('Output cache limit (currently '+
194 warn('Output cache limit (currently '+
195 repr(self.cache_size)+' entries) hit.\n'
195 repr(self.cache_size)+' entries) hit.\n'
196 'Flushing cache and resetting history counter...\n'
196 'Flushing cache and resetting history counter...\n'
197 'The only history variables available will be _,__,___ and _1\n'
197 'The only history variables available will be _,__,___ and _1\n'
198 'with the current result.')
198 'with the current result.')
199
199
200 self.flush()
200 self.flush()
201 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
201 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
202 # we cause buggy behavior for things like gettext).
202 # we cause buggy behavior for things like gettext).
203
203
204 if '_' not in __builtin__.__dict__:
204 if '_' not in __builtin__.__dict__:
205 self.___ = self.__
205 self.___ = self.__
206 self.__ = self._
206 self.__ = self._
207 self._ = result
207 self._ = result
208 self.shell.push({'_':self._,
208 self.shell.push({'_':self._,
209 '__':self.__,
209 '__':self.__,
210 '___':self.___}, interactive=False)
210 '___':self.___}, interactive=False)
211
211
212 # hackish access to top-level namespace to create _1,_2... dynamically
212 # hackish access to top-level namespace to create _1,_2... dynamically
213 to_main = {}
213 to_main = {}
214 if self.do_full_cache:
214 if self.do_full_cache:
215 new_result = '_'+repr(self.prompt_count)
215 new_result = '_'+repr(self.prompt_count)
216 to_main[new_result] = result
216 to_main[new_result] = result
217 self.shell.push(to_main, interactive=False)
217 self.shell.push(to_main, interactive=False)
218 self.shell.user_ns['_oh'][self.prompt_count] = result
218 self.shell.user_ns['_oh'][self.prompt_count] = result
219
219
220 def log_output(self, format_dict):
220 def log_output(self, format_dict):
221 """Log the output."""
221 """Log the output."""
222 if self.shell.logger.log_output:
222 if self.shell.logger.log_output:
223 self.shell.logger.log_write(format_dict['text/plain'], 'output')
223 self.shell.logger.log_write(format_dict['text/plain'], 'output')
224 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
224 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
225 format_dict['text/plain']
225 format_dict['text/plain']
226
226
227 def finish_displayhook(self):
227 def finish_displayhook(self):
228 """Finish up all displayhook activities."""
228 """Finish up all displayhook activities."""
229 io.stdout.write(self.shell.separate_out2)
229 io.stdout.write(self.shell.separate_out2)
230 io.stdout.flush()
230 io.stdout.flush()
231
231
232 def __call__(self, result=None):
232 def __call__(self, result=None):
233 """Printing with history cache management.
233 """Printing with history cache management.
234
234
235 This is invoked everytime the interpreter needs to print, and is
235 This is invoked everytime the interpreter needs to print, and is
236 activated by setting the variable sys.displayhook to it.
236 activated by setting the variable sys.displayhook to it.
237 """
237 """
238 self.check_for_underscore()
238 self.check_for_underscore()
239 if result is not None and not self.quiet():
239 if result is not None and not self.quiet():
240 self.start_displayhook()
240 self.start_displayhook()
241 self.write_output_prompt()
241 self.write_output_prompt()
242 format_dict = self.compute_format_data(result)
242 format_dict = self.compute_format_data(result)
243 self.write_format_data(format_dict)
243 self.write_format_data(format_dict)
244 self.update_user_ns(result)
244 self.update_user_ns(result)
245 self.log_output(format_dict)
245 self.log_output(format_dict)
246 self.finish_displayhook()
246 self.finish_displayhook()
247
247
248 def flush(self):
248 def flush(self):
249 if not self.do_full_cache:
249 if not self.do_full_cache:
250 raise ValueError("You shouldn't have reached the cache flush "
250 raise ValueError("You shouldn't have reached the cache flush "
251 "if full caching is not enabled!")
251 "if full caching is not enabled!")
252 # delete auto-generated vars from global namespace
252 # delete auto-generated vars from global namespace
253
253
254 for n in range(1,self.prompt_count + 1):
254 for n in range(1,self.prompt_count + 1):
255 key = '_'+repr(n)
255 key = '_'+repr(n)
256 try:
256 try:
257 del self.shell.user_ns[key]
257 del self.shell.user_ns[key]
258 except: pass
258 except: pass
259 # In some embedded circumstances, the user_ns doesn't have the
259 # In some embedded circumstances, the user_ns doesn't have the
260 # '_oh' key set up.
260 # '_oh' key set up.
261 oh = self.shell.user_ns.get('_oh', None)
261 oh = self.shell.user_ns.get('_oh', None)
262 if oh is not None:
262 if oh is not None:
263 oh.clear()
263 oh.clear()
264
264
265 # Release our own references to objects:
265 # Release our own references to objects:
266 self._, self.__, self.___ = '', '', ''
266 self._, self.__, self.___ = '', '', ''
267
267
268 if '_' not in __builtin__.__dict__:
268 if '_' not in __builtin__.__dict__:
269 self.shell.user_ns.update({'_':None,'__':None, '___':None})
269 self.shell.user_ns.update({'_':None,'__':None, '___':None})
270 import gc
270 import gc
271 # TODO: Is this really needed?
271 # TODO: Is this really needed?
272 # IronPython blocks here forever
272 # IronPython blocks here forever
273 if sys.platform != "cli":
273 if sys.platform != "cli":
274 gc.collect()
274 gc.collect()
275
275
@@ -1,60 +1,59 b''
1 """Support for interactive macros in IPython"""
1 """Support for interactive macros in IPython"""
2
2
3 #*****************************************************************************
3 #*****************************************************************************
4 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
4 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #*****************************************************************************
8 #*****************************************************************************
9
9
10 import re
10 import re
11 import sys
12
11
13 from IPython.utils import py3compat
12 from IPython.utils import py3compat
14 from IPython.utils.encoding import DEFAULT_ENCODING
13 from IPython.utils.encoding import DEFAULT_ENCODING
15
14
16 coding_declaration = re.compile(r"#\s*coding[:=]\s*([-\w.]+)")
15 coding_declaration = re.compile(r"#\s*coding[:=]\s*([-\w.]+)")
17
16
18 class Macro(object):
17 class Macro(object):
19 """Simple class to store the value of macros as strings.
18 """Simple class to store the value of macros as strings.
20
19
21 Macro is just a callable that executes a string of IPython
20 Macro is just a callable that executes a string of IPython
22 input when called.
21 input when called.
23
22
24 Args to macro are available in _margv list if you need them.
23 Args to macro are available in _margv list if you need them.
25 """
24 """
26
25
27 def __init__(self,code):
26 def __init__(self,code):
28 """store the macro value, as a single string which can be executed"""
27 """store the macro value, as a single string which can be executed"""
29 lines = []
28 lines = []
30 enc = None
29 enc = None
31 for line in code.splitlines():
30 for line in code.splitlines():
32 coding_match = coding_declaration.match(line)
31 coding_match = coding_declaration.match(line)
33 if coding_match:
32 if coding_match:
34 enc = coding_match.group(1)
33 enc = coding_match.group(1)
35 else:
34 else:
36 lines.append(line)
35 lines.append(line)
37 code = "\n".join(lines)
36 code = "\n".join(lines)
38 if isinstance(code, bytes):
37 if isinstance(code, bytes):
39 code = code.decode(enc or DEFAULT_ENCODING)
38 code = code.decode(enc or DEFAULT_ENCODING)
40 self.value = code + '\n'
39 self.value = code + '\n'
41
40
42 def __str__(self):
41 def __str__(self):
43 return py3compat.unicode_to_str(self.value)
42 return py3compat.unicode_to_str(self.value)
44
43
45 def __unicode__(self):
44 def __unicode__(self):
46 return self.value
45 return self.value
47
46
48 def __repr__(self):
47 def __repr__(self):
49 return 'IPython.macro.Macro(%s)' % repr(self.value)
48 return 'IPython.macro.Macro(%s)' % repr(self.value)
50
49
51 def __getstate__(self):
50 def __getstate__(self):
52 """ needed for safe pickling via %store """
51 """ needed for safe pickling via %store """
53 return {'value': self.value}
52 return {'value': self.value}
54
53
55 def __add__(self, other):
54 def __add__(self, other):
56 if isinstance(other, Macro):
55 if isinstance(other, Macro):
57 return Macro(self.value + other.value)
56 return Macro(self.value + other.value)
58 elif isinstance(other, basestring):
57 elif isinstance(other, basestring):
59 return Macro(self.value + other)
58 return Macro(self.value + other)
60 raise TypeError
59 raise TypeError
@@ -1,683 +1,683 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 The IPython Development Team
9
9
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Stdlib
17 # Stdlib
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21 import types
21 import types
22 from getopt import getopt, GetoptError
22 from getopt import getopt, GetoptError
23
23
24 # Our own
24 # Our own
25 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
26 from IPython.core import oinspect
26 from IPython.core import oinspect
27 from IPython.core.error import UsageError
27 from IPython.core.error import UsageError
28 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
28 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
29 from IPython.external.decorator import decorator
29 from IPython.external.decorator import decorator
30 from IPython.utils.ipstruct import Struct
30 from IPython.utils.ipstruct import Struct
31 from IPython.utils.process import arg_split
31 from IPython.utils.process import arg_split
32 from IPython.utils.text import dedent
32 from IPython.utils.text import dedent
33 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
33 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
34 from IPython.utils.warn import error, warn
34 from IPython.utils.warn import error
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals
37 # Globals
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # A dict we'll use for each class that has magics, used as temporary storage to
40 # A dict we'll use for each class that has magics, used as temporary storage to
41 # pass information between the @line/cell_magic method decorators and the
41 # pass information between the @line/cell_magic method decorators and the
42 # @magics_class class decorator, because the method decorators have no
42 # @magics_class class decorator, because the method decorators have no
43 # access to the class when they run. See for more details:
43 # access to the class when they run. See for more details:
44 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
44 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
45
45
46 magics = dict(line={}, cell={})
46 magics = dict(line={}, cell={})
47
47
48 magic_kinds = ('line', 'cell')
48 magic_kinds = ('line', 'cell')
49 magic_spec = ('line', 'cell', 'line_cell')
49 magic_spec = ('line', 'cell', 'line_cell')
50 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
50 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Utility classes and functions
53 # Utility classes and functions
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class Bunch: pass
56 class Bunch: pass
57
57
58
58
59 def on_off(tag):
59 def on_off(tag):
60 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
60 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
61 return ['OFF','ON'][tag]
61 return ['OFF','ON'][tag]
62
62
63
63
64 def compress_dhist(dh):
64 def compress_dhist(dh):
65 """Compress a directory history into a new one with at most 20 entries.
65 """Compress a directory history into a new one with at most 20 entries.
66
66
67 Return a new list made from the first and last 10 elements of dhist after
67 Return a new list made from the first and last 10 elements of dhist after
68 removal of duplicates.
68 removal of duplicates.
69 """
69 """
70 head, tail = dh[:-10], dh[-10:]
70 head, tail = dh[:-10], dh[-10:]
71
71
72 newhead = []
72 newhead = []
73 done = set()
73 done = set()
74 for h in head:
74 for h in head:
75 if h in done:
75 if h in done:
76 continue
76 continue
77 newhead.append(h)
77 newhead.append(h)
78 done.add(h)
78 done.add(h)
79
79
80 return newhead + tail
80 return newhead + tail
81
81
82
82
83 def needs_local_scope(func):
83 def needs_local_scope(func):
84 """Decorator to mark magic functions which need to local scope to run."""
84 """Decorator to mark magic functions which need to local scope to run."""
85 func.needs_local_scope = True
85 func.needs_local_scope = True
86 return func
86 return func
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Class and method decorators for registering magics
89 # Class and method decorators for registering magics
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92 def magics_class(cls):
92 def magics_class(cls):
93 """Class decorator for all subclasses of the main Magics class.
93 """Class decorator for all subclasses of the main Magics class.
94
94
95 Any class that subclasses Magics *must* also apply this decorator, to
95 Any class that subclasses Magics *must* also apply this decorator, to
96 ensure that all the methods that have been decorated as line/cell magics
96 ensure that all the methods that have been decorated as line/cell magics
97 get correctly registered in the class instance. This is necessary because
97 get correctly registered in the class instance. This is necessary because
98 when method decorators run, the class does not exist yet, so they
98 when method decorators run, the class does not exist yet, so they
99 temporarily store their information into a module global. Application of
99 temporarily store their information into a module global. Application of
100 this class decorator copies that global data to the class instance and
100 this class decorator copies that global data to the class instance and
101 clears the global.
101 clears the global.
102
102
103 Obviously, this mechanism is not thread-safe, which means that the
103 Obviously, this mechanism is not thread-safe, which means that the
104 *creation* of subclasses of Magic should only be done in a single-thread
104 *creation* of subclasses of Magic should only be done in a single-thread
105 context. Instantiation of the classes has no restrictions. Given that
105 context. Instantiation of the classes has no restrictions. Given that
106 these classes are typically created at IPython startup time and before user
106 these classes are typically created at IPython startup time and before user
107 application code becomes active, in practice this should not pose any
107 application code becomes active, in practice this should not pose any
108 problems.
108 problems.
109 """
109 """
110 cls.registered = True
110 cls.registered = True
111 cls.magics = dict(line = magics['line'],
111 cls.magics = dict(line = magics['line'],
112 cell = magics['cell'])
112 cell = magics['cell'])
113 magics['line'] = {}
113 magics['line'] = {}
114 magics['cell'] = {}
114 magics['cell'] = {}
115 return cls
115 return cls
116
116
117
117
118 def record_magic(dct, magic_kind, magic_name, func):
118 def record_magic(dct, magic_kind, magic_name, func):
119 """Utility function to store a function as a magic of a specific kind.
119 """Utility function to store a function as a magic of a specific kind.
120
120
121 Parameters
121 Parameters
122 ----------
122 ----------
123 dct : dict
123 dct : dict
124 A dictionary with 'line' and 'cell' subdicts.
124 A dictionary with 'line' and 'cell' subdicts.
125
125
126 magic_kind : str
126 magic_kind : str
127 Kind of magic to be stored.
127 Kind of magic to be stored.
128
128
129 magic_name : str
129 magic_name : str
130 Key to store the magic as.
130 Key to store the magic as.
131
131
132 func : function
132 func : function
133 Callable object to store.
133 Callable object to store.
134 """
134 """
135 if magic_kind == 'line_cell':
135 if magic_kind == 'line_cell':
136 dct['line'][magic_name] = dct['cell'][magic_name] = func
136 dct['line'][magic_name] = dct['cell'][magic_name] = func
137 else:
137 else:
138 dct[magic_kind][magic_name] = func
138 dct[magic_kind][magic_name] = func
139
139
140
140
141 def validate_type(magic_kind):
141 def validate_type(magic_kind):
142 """Ensure that the given magic_kind is valid.
142 """Ensure that the given magic_kind is valid.
143
143
144 Check that the given magic_kind is one of the accepted spec types (stored
144 Check that the given magic_kind is one of the accepted spec types (stored
145 in the global `magic_spec`), raise ValueError otherwise.
145 in the global `magic_spec`), raise ValueError otherwise.
146 """
146 """
147 if magic_kind not in magic_spec:
147 if magic_kind not in magic_spec:
148 raise ValueError('magic_kind must be one of %s, %s given' %
148 raise ValueError('magic_kind must be one of %s, %s given' %
149 magic_kinds, magic_kind)
149 magic_kinds, magic_kind)
150
150
151
151
152 # The docstrings for the decorator below will be fairly similar for the two
152 # The docstrings for the decorator below will be fairly similar for the two
153 # types (method and function), so we generate them here once and reuse the
153 # types (method and function), so we generate them here once and reuse the
154 # templates below.
154 # templates below.
155 _docstring_template = \
155 _docstring_template = \
156 """Decorate the given {0} as {1} magic.
156 """Decorate the given {0} as {1} magic.
157
157
158 The decorator can be used with or without arguments, as follows.
158 The decorator can be used with or without arguments, as follows.
159
159
160 i) without arguments: it will create a {1} magic named as the {0} being
160 i) without arguments: it will create a {1} magic named as the {0} being
161 decorated::
161 decorated::
162
162
163 @deco
163 @deco
164 def foo(...)
164 def foo(...)
165
165
166 will create a {1} magic named `foo`.
166 will create a {1} magic named `foo`.
167
167
168 ii) with one string argument: which will be used as the actual name of the
168 ii) with one string argument: which will be used as the actual name of the
169 resulting magic::
169 resulting magic::
170
170
171 @deco('bar')
171 @deco('bar')
172 def foo(...)
172 def foo(...)
173
173
174 will create a {1} magic named `bar`.
174 will create a {1} magic named `bar`.
175 """
175 """
176
176
177 # These two are decorator factories. While they are conceptually very similar,
177 # These two are decorator factories. While they are conceptually very similar,
178 # there are enough differences in the details that it's simpler to have them
178 # there are enough differences in the details that it's simpler to have them
179 # written as completely standalone functions rather than trying to share code
179 # written as completely standalone functions rather than trying to share code
180 # and make a single one with convoluted logic.
180 # and make a single one with convoluted logic.
181
181
182 def _method_magic_marker(magic_kind):
182 def _method_magic_marker(magic_kind):
183 """Decorator factory for methods in Magics subclasses.
183 """Decorator factory for methods in Magics subclasses.
184 """
184 """
185
185
186 validate_type(magic_kind)
186 validate_type(magic_kind)
187
187
188 # This is a closure to capture the magic_kind. We could also use a class,
188 # This is a closure to capture the magic_kind. We could also use a class,
189 # but it's overkill for just that one bit of state.
189 # but it's overkill for just that one bit of state.
190 def magic_deco(arg):
190 def magic_deco(arg):
191 call = lambda f, *a, **k: f(*a, **k)
191 call = lambda f, *a, **k: f(*a, **k)
192
192
193 if callable(arg):
193 if callable(arg):
194 # "Naked" decorator call (just @foo, no args)
194 # "Naked" decorator call (just @foo, no args)
195 func = arg
195 func = arg
196 name = func.func_name
196 name = func.func_name
197 retval = decorator(call, func)
197 retval = decorator(call, func)
198 record_magic(magics, magic_kind, name, name)
198 record_magic(magics, magic_kind, name, name)
199 elif isinstance(arg, basestring):
199 elif isinstance(arg, basestring):
200 # Decorator called with arguments (@foo('bar'))
200 # Decorator called with arguments (@foo('bar'))
201 name = arg
201 name = arg
202 def mark(func, *a, **kw):
202 def mark(func, *a, **kw):
203 record_magic(magics, magic_kind, name, func.func_name)
203 record_magic(magics, magic_kind, name, func.func_name)
204 return decorator(call, func)
204 return decorator(call, func)
205 retval = mark
205 retval = mark
206 else:
206 else:
207 raise TypeError("Decorator can only be called with "
207 raise TypeError("Decorator can only be called with "
208 "string or function")
208 "string or function")
209 return retval
209 return retval
210
210
211 # Ensure the resulting decorator has a usable docstring
211 # Ensure the resulting decorator has a usable docstring
212 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
212 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
213 return magic_deco
213 return magic_deco
214
214
215
215
216 def _function_magic_marker(magic_kind):
216 def _function_magic_marker(magic_kind):
217 """Decorator factory for standalone functions.
217 """Decorator factory for standalone functions.
218 """
218 """
219 validate_type(magic_kind)
219 validate_type(magic_kind)
220
220
221 # This is a closure to capture the magic_kind. We could also use a class,
221 # This is a closure to capture the magic_kind. We could also use a class,
222 # but it's overkill for just that one bit of state.
222 # but it's overkill for just that one bit of state.
223 def magic_deco(arg):
223 def magic_deco(arg):
224 call = lambda f, *a, **k: f(*a, **k)
224 call = lambda f, *a, **k: f(*a, **k)
225
225
226 # Find get_ipython() in the caller's namespace
226 # Find get_ipython() in the caller's namespace
227 caller = sys._getframe(1)
227 caller = sys._getframe(1)
228 for ns in ['f_locals', 'f_globals', 'f_builtins']:
228 for ns in ['f_locals', 'f_globals', 'f_builtins']:
229 get_ipython = getattr(caller, ns).get('get_ipython')
229 get_ipython = getattr(caller, ns).get('get_ipython')
230 if get_ipython is not None:
230 if get_ipython is not None:
231 break
231 break
232 else:
232 else:
233 raise NameError('Decorator can only run in context where '
233 raise NameError('Decorator can only run in context where '
234 '`get_ipython` exists')
234 '`get_ipython` exists')
235
235
236 ip = get_ipython()
236 ip = get_ipython()
237
237
238 if callable(arg):
238 if callable(arg):
239 # "Naked" decorator call (just @foo, no args)
239 # "Naked" decorator call (just @foo, no args)
240 func = arg
240 func = arg
241 name = func.func_name
241 name = func.func_name
242 ip.register_magic_function(func, magic_kind, name)
242 ip.register_magic_function(func, magic_kind, name)
243 retval = decorator(call, func)
243 retval = decorator(call, func)
244 elif isinstance(arg, basestring):
244 elif isinstance(arg, basestring):
245 # Decorator called with arguments (@foo('bar'))
245 # Decorator called with arguments (@foo('bar'))
246 name = arg
246 name = arg
247 def mark(func, *a, **kw):
247 def mark(func, *a, **kw):
248 ip.register_magic_function(func, magic_kind, name)
248 ip.register_magic_function(func, magic_kind, name)
249 return decorator(call, func)
249 return decorator(call, func)
250 retval = mark
250 retval = mark
251 else:
251 else:
252 raise TypeError("Decorator can only be called with "
252 raise TypeError("Decorator can only be called with "
253 "string or function")
253 "string or function")
254 return retval
254 return retval
255
255
256 # Ensure the resulting decorator has a usable docstring
256 # Ensure the resulting decorator has a usable docstring
257 ds = _docstring_template.format('function', magic_kind)
257 ds = _docstring_template.format('function', magic_kind)
258
258
259 ds += dedent("""
259 ds += dedent("""
260 Note: this decorator can only be used in a context where IPython is already
260 Note: this decorator can only be used in a context where IPython is already
261 active, so that the `get_ipython()` call succeeds. You can therefore use
261 active, so that the `get_ipython()` call succeeds. You can therefore use
262 it in your startup files loaded after IPython initializes, but *not* in the
262 it in your startup files loaded after IPython initializes, but *not* in the
263 IPython configuration file itself, which is executed before IPython is
263 IPython configuration file itself, which is executed before IPython is
264 fully up and running. Any file located in the `startup` subdirectory of
264 fully up and running. Any file located in the `startup` subdirectory of
265 your configuration profile will be OK in this sense.
265 your configuration profile will be OK in this sense.
266 """)
266 """)
267
267
268 magic_deco.__doc__ = ds
268 magic_deco.__doc__ = ds
269 return magic_deco
269 return magic_deco
270
270
271
271
272 # Create the actual decorators for public use
272 # Create the actual decorators for public use
273
273
274 # These three are used to decorate methods in class definitions
274 # These three are used to decorate methods in class definitions
275 line_magic = _method_magic_marker('line')
275 line_magic = _method_magic_marker('line')
276 cell_magic = _method_magic_marker('cell')
276 cell_magic = _method_magic_marker('cell')
277 line_cell_magic = _method_magic_marker('line_cell')
277 line_cell_magic = _method_magic_marker('line_cell')
278
278
279 # These three decorate standalone functions and perform the decoration
279 # These three decorate standalone functions and perform the decoration
280 # immediately. They can only run where get_ipython() works
280 # immediately. They can only run where get_ipython() works
281 register_line_magic = _function_magic_marker('line')
281 register_line_magic = _function_magic_marker('line')
282 register_cell_magic = _function_magic_marker('cell')
282 register_cell_magic = _function_magic_marker('cell')
283 register_line_cell_magic = _function_magic_marker('line_cell')
283 register_line_cell_magic = _function_magic_marker('line_cell')
284
284
285 #-----------------------------------------------------------------------------
285 #-----------------------------------------------------------------------------
286 # Core Magic classes
286 # Core Magic classes
287 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
288
288
289 class MagicsManager(Configurable):
289 class MagicsManager(Configurable):
290 """Object that handles all magic-related functionality for IPython.
290 """Object that handles all magic-related functionality for IPython.
291 """
291 """
292 # Non-configurable class attributes
292 # Non-configurable class attributes
293
293
294 # A two-level dict, first keyed by magic type, then by magic function, and
294 # A two-level dict, first keyed by magic type, then by magic function, and
295 # holding the actual callable object as value. This is the dict used for
295 # holding the actual callable object as value. This is the dict used for
296 # magic function dispatch
296 # magic function dispatch
297 magics = Dict
297 magics = Dict
298
298
299 # A registry of the original objects that we've been given holding magics.
299 # A registry of the original objects that we've been given holding magics.
300 registry = Dict
300 registry = Dict
301
301
302 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
302 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
303
303
304 auto_magic = Bool(True, config=True, help=
304 auto_magic = Bool(True, config=True, help=
305 "Automatically call line magics without requiring explicit % prefix")
305 "Automatically call line magics without requiring explicit % prefix")
306
306
307 _auto_status = [
307 _auto_status = [
308 'Automagic is OFF, % prefix IS needed for line magics.',
308 'Automagic is OFF, % prefix IS needed for line magics.',
309 'Automagic is ON, % prefix IS NOT needed for line magics.']
309 'Automagic is ON, % prefix IS NOT needed for line magics.']
310
310
311 user_magics = Instance('IPython.core.magics.UserMagics')
311 user_magics = Instance('IPython.core.magics.UserMagics')
312
312
313 def __init__(self, shell=None, config=None, user_magics=None, **traits):
313 def __init__(self, shell=None, config=None, user_magics=None, **traits):
314
314
315 super(MagicsManager, self).__init__(shell=shell, config=config,
315 super(MagicsManager, self).__init__(shell=shell, config=config,
316 user_magics=user_magics, **traits)
316 user_magics=user_magics, **traits)
317 self.magics = dict(line={}, cell={})
317 self.magics = dict(line={}, cell={})
318 # Let's add the user_magics to the registry for uniformity, so *all*
318 # Let's add the user_magics to the registry for uniformity, so *all*
319 # registered magic containers can be found there.
319 # registered magic containers can be found there.
320 self.registry[user_magics.__class__.__name__] = user_magics
320 self.registry[user_magics.__class__.__name__] = user_magics
321
321
322 def auto_status(self):
322 def auto_status(self):
323 """Return descriptive string with automagic status."""
323 """Return descriptive string with automagic status."""
324 return self._auto_status[self.auto_magic]
324 return self._auto_status[self.auto_magic]
325
325
326 def lsmagic_info(self):
326 def lsmagic_info(self):
327 magic_list = []
327 magic_list = []
328 for m_type in self.magics :
328 for m_type in self.magics :
329 for m_name,mgc in self.magics[m_type].items():
329 for m_name,mgc in self.magics[m_type].items():
330 try :
330 try :
331 magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__})
331 magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__})
332 except AttributeError :
332 except AttributeError :
333 magic_list.append({'name':m_name,'type':m_type,'class':'Other'})
333 magic_list.append({'name':m_name,'type':m_type,'class':'Other'})
334 return magic_list
334 return magic_list
335
335
336 def lsmagic(self):
336 def lsmagic(self):
337 """Return a dict of currently available magic functions.
337 """Return a dict of currently available magic functions.
338
338
339 The return dict has the keys 'line' and 'cell', corresponding to the
339 The return dict has the keys 'line' and 'cell', corresponding to the
340 two types of magics we support. Each value is a list of names.
340 two types of magics we support. Each value is a list of names.
341 """
341 """
342 return self.magics
342 return self.magics
343
343
344 def lsmagic_docs(self, brief=False, missing=''):
344 def lsmagic_docs(self, brief=False, missing=''):
345 """Return dict of documentation of magic functions.
345 """Return dict of documentation of magic functions.
346
346
347 The return dict has the keys 'line' and 'cell', corresponding to the
347 The return dict has the keys 'line' and 'cell', corresponding to the
348 two types of magics we support. Each value is a dict keyed by magic
348 two types of magics we support. Each value is a dict keyed by magic
349 name whose value is the function docstring. If a docstring is
349 name whose value is the function docstring. If a docstring is
350 unavailable, the value of `missing` is used instead.
350 unavailable, the value of `missing` is used instead.
351
351
352 If brief is True, only the first line of each docstring will be returned.
352 If brief is True, only the first line of each docstring will be returned.
353 """
353 """
354 docs = {}
354 docs = {}
355 for m_type in self.magics:
355 for m_type in self.magics:
356 m_docs = {}
356 m_docs = {}
357 for m_name, m_func in self.magics[m_type].iteritems():
357 for m_name, m_func in self.magics[m_type].iteritems():
358 if m_func.__doc__:
358 if m_func.__doc__:
359 if brief:
359 if brief:
360 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
360 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
361 else:
361 else:
362 m_docs[m_name] = m_func.__doc__.rstrip()
362 m_docs[m_name] = m_func.__doc__.rstrip()
363 else:
363 else:
364 m_docs[m_name] = missing
364 m_docs[m_name] = missing
365 docs[m_type] = m_docs
365 docs[m_type] = m_docs
366 return docs
366 return docs
367
367
368 def register(self, *magic_objects):
368 def register(self, *magic_objects):
369 """Register one or more instances of Magics.
369 """Register one or more instances of Magics.
370
370
371 Take one or more classes or instances of classes that subclass the main
371 Take one or more classes or instances of classes that subclass the main
372 `core.Magic` class, and register them with IPython to use the magic
372 `core.Magic` class, and register them with IPython to use the magic
373 functions they provide. The registration process will then ensure that
373 functions they provide. The registration process will then ensure that
374 any methods that have decorated to provide line and/or cell magics will
374 any methods that have decorated to provide line and/or cell magics will
375 be recognized with the `%x`/`%%x` syntax as a line/cell magic
375 be recognized with the `%x`/`%%x` syntax as a line/cell magic
376 respectively.
376 respectively.
377
377
378 If classes are given, they will be instantiated with the default
378 If classes are given, they will be instantiated with the default
379 constructor. If your classes need a custom constructor, you should
379 constructor. If your classes need a custom constructor, you should
380 instanitate them first and pass the instance.
380 instanitate them first and pass the instance.
381
381
382 The provided arguments can be an arbitrary mix of classes and instances.
382 The provided arguments can be an arbitrary mix of classes and instances.
383
383
384 Parameters
384 Parameters
385 ----------
385 ----------
386 magic_objects : one or more classes or instances
386 magic_objects : one or more classes or instances
387 """
387 """
388 # Start by validating them to ensure they have all had their magic
388 # Start by validating them to ensure they have all had their magic
389 # methods registered at the instance level
389 # methods registered at the instance level
390 for m in magic_objects:
390 for m in magic_objects:
391 if not m.registered:
391 if not m.registered:
392 raise ValueError("Class of magics %r was constructed without "
392 raise ValueError("Class of magics %r was constructed without "
393 "the @register_magics class decorator")
393 "the @register_magics class decorator")
394 if type(m) in (type, MetaHasTraits):
394 if type(m) in (type, MetaHasTraits):
395 # If we're given an uninstantiated class
395 # If we're given an uninstantiated class
396 m = m(shell=self.shell)
396 m = m(shell=self.shell)
397
397
398 # Now that we have an instance, we can register it and update the
398 # Now that we have an instance, we can register it and update the
399 # table of callables
399 # table of callables
400 self.registry[m.__class__.__name__] = m
400 self.registry[m.__class__.__name__] = m
401 for mtype in magic_kinds:
401 for mtype in magic_kinds:
402 self.magics[mtype].update(m.magics[mtype])
402 self.magics[mtype].update(m.magics[mtype])
403
403
404 def register_function(self, func, magic_kind='line', magic_name=None):
404 def register_function(self, func, magic_kind='line', magic_name=None):
405 """Expose a standalone function as magic function for IPython.
405 """Expose a standalone function as magic function for IPython.
406
406
407 This will create an IPython magic (line, cell or both) from a
407 This will create an IPython magic (line, cell or both) from a
408 standalone function. The functions should have the following
408 standalone function. The functions should have the following
409 signatures:
409 signatures:
410
410
411 * For line magics: `def f(line)`
411 * For line magics: `def f(line)`
412 * For cell magics: `def f(line, cell)`
412 * For cell magics: `def f(line, cell)`
413 * For a function that does both: `def f(line, cell=None)`
413 * For a function that does both: `def f(line, cell=None)`
414
414
415 In the latter case, the function will be called with `cell==None` when
415 In the latter case, the function will be called with `cell==None` when
416 invoked as `%f`, and with cell as a string when invoked as `%%f`.
416 invoked as `%f`, and with cell as a string when invoked as `%%f`.
417
417
418 Parameters
418 Parameters
419 ----------
419 ----------
420 func : callable
420 func : callable
421 Function to be registered as a magic.
421 Function to be registered as a magic.
422
422
423 magic_kind : str
423 magic_kind : str
424 Kind of magic, one of 'line', 'cell' or 'line_cell'
424 Kind of magic, one of 'line', 'cell' or 'line_cell'
425
425
426 magic_name : optional str
426 magic_name : optional str
427 If given, the name the magic will have in the IPython namespace. By
427 If given, the name the magic will have in the IPython namespace. By
428 default, the name of the function itself is used.
428 default, the name of the function itself is used.
429 """
429 """
430
430
431 # Create the new method in the user_magics and register it in the
431 # Create the new method in the user_magics and register it in the
432 # global table
432 # global table
433 validate_type(magic_kind)
433 validate_type(magic_kind)
434 magic_name = func.func_name if magic_name is None else magic_name
434 magic_name = func.func_name if magic_name is None else magic_name
435 setattr(self.user_magics, magic_name, func)
435 setattr(self.user_magics, magic_name, func)
436 record_magic(self.magics, magic_kind, magic_name, func)
436 record_magic(self.magics, magic_kind, magic_name, func)
437
437
438 def define_magic(self, name, func):
438 def define_magic(self, name, func):
439 """[Deprecated] Expose own function as magic function for IPython.
439 """[Deprecated] Expose own function as magic function for IPython.
440
440
441 Example::
441 Example::
442
442
443 def foo_impl(self, parameter_s=''):
443 def foo_impl(self, parameter_s=''):
444 'My very own magic!. (Use docstrings, IPython reads them).'
444 'My very own magic!. (Use docstrings, IPython reads them).'
445 print 'Magic function. Passed parameter is between < >:'
445 print 'Magic function. Passed parameter is between < >:'
446 print '<%s>' % parameter_s
446 print '<%s>' % parameter_s
447 print 'The self object is:', self
447 print 'The self object is:', self
448
448
449 ip.define_magic('foo',foo_impl)
449 ip.define_magic('foo',foo_impl)
450 """
450 """
451 meth = types.MethodType(func, self.user_magics)
451 meth = types.MethodType(func, self.user_magics)
452 setattr(self.user_magics, name, meth)
452 setattr(self.user_magics, name, meth)
453 record_magic(self.magics, 'line', name, meth)
453 record_magic(self.magics, 'line', name, meth)
454
454
455 def register_alias(self, alias_name, magic_name, magic_kind='line'):
455 def register_alias(self, alias_name, magic_name, magic_kind='line'):
456 """Register an alias to a magic function.
456 """Register an alias to a magic function.
457
457
458 The alias is an instance of :class:`MagicAlias`, which holds the
458 The alias is an instance of :class:`MagicAlias`, which holds the
459 name and kind of the magic it should call. Binding is done at
459 name and kind of the magic it should call. Binding is done at
460 call time, so if the underlying magic function is changed the alias
460 call time, so if the underlying magic function is changed the alias
461 will call the new function.
461 will call the new function.
462
462
463 Parameters
463 Parameters
464 ----------
464 ----------
465 alias_name : str
465 alias_name : str
466 The name of the magic to be registered.
466 The name of the magic to be registered.
467
467
468 magic_name : str
468 magic_name : str
469 The name of an existing magic.
469 The name of an existing magic.
470
470
471 magic_kind : str
471 magic_kind : str
472 Kind of magic, one of 'line' or 'cell'
472 Kind of magic, one of 'line' or 'cell'
473 """
473 """
474
474
475 # `validate_type` is too permissive, as it allows 'line_cell'
475 # `validate_type` is too permissive, as it allows 'line_cell'
476 # which we do not handle.
476 # which we do not handle.
477 if magic_kind not in magic_kinds:
477 if magic_kind not in magic_kinds:
478 raise ValueError('magic_kind must be one of %s, %s given' %
478 raise ValueError('magic_kind must be one of %s, %s given' %
479 magic_kinds, magic_kind)
479 magic_kinds, magic_kind)
480
480
481 alias = MagicAlias(self.shell, magic_name, magic_kind)
481 alias = MagicAlias(self.shell, magic_name, magic_kind)
482 setattr(self.user_magics, alias_name, alias)
482 setattr(self.user_magics, alias_name, alias)
483 record_magic(self.magics, magic_kind, alias_name, alias)
483 record_magic(self.magics, magic_kind, alias_name, alias)
484
484
485 # Key base class that provides the central functionality for magics.
485 # Key base class that provides the central functionality for magics.
486
486
487 class Magics(object):
487 class Magics(object):
488 """Base class for implementing magic functions.
488 """Base class for implementing magic functions.
489
489
490 Shell functions which can be reached as %function_name. All magic
490 Shell functions which can be reached as %function_name. All magic
491 functions should accept a string, which they can parse for their own
491 functions should accept a string, which they can parse for their own
492 needs. This can make some functions easier to type, eg `%cd ../`
492 needs. This can make some functions easier to type, eg `%cd ../`
493 vs. `%cd("../")`
493 vs. `%cd("../")`
494
494
495 Classes providing magic functions need to subclass this class, and they
495 Classes providing magic functions need to subclass this class, and they
496 MUST:
496 MUST:
497
497
498 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
498 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
499 individual methods as magic functions, AND
499 individual methods as magic functions, AND
500
500
501 - Use the class decorator `@magics_class` to ensure that the magic
501 - Use the class decorator `@magics_class` to ensure that the magic
502 methods are properly registered at the instance level upon instance
502 methods are properly registered at the instance level upon instance
503 initialization.
503 initialization.
504
504
505 See :mod:`magic_functions` for examples of actual implementation classes.
505 See :mod:`magic_functions` for examples of actual implementation classes.
506 """
506 """
507 # Dict holding all command-line options for each magic.
507 # Dict holding all command-line options for each magic.
508 options_table = None
508 options_table = None
509 # Dict for the mapping of magic names to methods, set by class decorator
509 # Dict for the mapping of magic names to methods, set by class decorator
510 magics = None
510 magics = None
511 # Flag to check that the class decorator was properly applied
511 # Flag to check that the class decorator was properly applied
512 registered = False
512 registered = False
513 # Instance of IPython shell
513 # Instance of IPython shell
514 shell = None
514 shell = None
515
515
516 def __init__(self, shell):
516 def __init__(self, shell):
517 if not(self.__class__.registered):
517 if not(self.__class__.registered):
518 raise ValueError('Magics subclass without registration - '
518 raise ValueError('Magics subclass without registration - '
519 'did you forget to apply @magics_class?')
519 'did you forget to apply @magics_class?')
520 self.shell = shell
520 self.shell = shell
521 self.options_table = {}
521 self.options_table = {}
522 # The method decorators are run when the instance doesn't exist yet, so
522 # The method decorators are run when the instance doesn't exist yet, so
523 # they can only record the names of the methods they are supposed to
523 # they can only record the names of the methods they are supposed to
524 # grab. Only now, that the instance exists, can we create the proper
524 # grab. Only now, that the instance exists, can we create the proper
525 # mapping to bound methods. So we read the info off the original names
525 # mapping to bound methods. So we read the info off the original names
526 # table and replace each method name by the actual bound method.
526 # table and replace each method name by the actual bound method.
527 # But we mustn't clobber the *class* mapping, in case of multiple instances.
527 # But we mustn't clobber the *class* mapping, in case of multiple instances.
528 class_magics = self.magics
528 class_magics = self.magics
529 self.magics = {}
529 self.magics = {}
530 for mtype in magic_kinds:
530 for mtype in magic_kinds:
531 tab = self.magics[mtype] = {}
531 tab = self.magics[mtype] = {}
532 cls_tab = class_magics[mtype]
532 cls_tab = class_magics[mtype]
533 for magic_name, meth_name in cls_tab.iteritems():
533 for magic_name, meth_name in cls_tab.iteritems():
534 if isinstance(meth_name, basestring):
534 if isinstance(meth_name, basestring):
535 # it's a method name, grab it
535 # it's a method name, grab it
536 tab[magic_name] = getattr(self, meth_name)
536 tab[magic_name] = getattr(self, meth_name)
537 else:
537 else:
538 # it's the real thing
538 # it's the real thing
539 tab[magic_name] = meth_name
539 tab[magic_name] = meth_name
540
540
541 def arg_err(self,func):
541 def arg_err(self,func):
542 """Print docstring if incorrect arguments were passed"""
542 """Print docstring if incorrect arguments were passed"""
543 print 'Error in arguments:'
543 print 'Error in arguments:'
544 print oinspect.getdoc(func)
544 print oinspect.getdoc(func)
545
545
546 def format_latex(self, strng):
546 def format_latex(self, strng):
547 """Format a string for latex inclusion."""
547 """Format a string for latex inclusion."""
548
548
549 # Characters that need to be escaped for latex:
549 # Characters that need to be escaped for latex:
550 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
550 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
551 # Magic command names as headers:
551 # Magic command names as headers:
552 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
552 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
553 re.MULTILINE)
553 re.MULTILINE)
554 # Magic commands
554 # Magic commands
555 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
555 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
556 re.MULTILINE)
556 re.MULTILINE)
557 # Paragraph continue
557 # Paragraph continue
558 par_re = re.compile(r'\\$',re.MULTILINE)
558 par_re = re.compile(r'\\$',re.MULTILINE)
559
559
560 # The "\n" symbol
560 # The "\n" symbol
561 newline_re = re.compile(r'\\n')
561 newline_re = re.compile(r'\\n')
562
562
563 # Now build the string for output:
563 # Now build the string for output:
564 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
564 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
565 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
565 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
566 strng)
566 strng)
567 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
567 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
568 strng = par_re.sub(r'\\\\',strng)
568 strng = par_re.sub(r'\\\\',strng)
569 strng = escape_re.sub(r'\\\1',strng)
569 strng = escape_re.sub(r'\\\1',strng)
570 strng = newline_re.sub(r'\\textbackslash{}n',strng)
570 strng = newline_re.sub(r'\\textbackslash{}n',strng)
571 return strng
571 return strng
572
572
573 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
573 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
574 """Parse options passed to an argument string.
574 """Parse options passed to an argument string.
575
575
576 The interface is similar to that of getopt(), but it returns back a
576 The interface is similar to that of getopt(), but it returns back a
577 Struct with the options as keys and the stripped argument string still
577 Struct with the options as keys and the stripped argument string still
578 as a string.
578 as a string.
579
579
580 arg_str is quoted as a true sys.argv vector by using shlex.split.
580 arg_str is quoted as a true sys.argv vector by using shlex.split.
581 This allows us to easily expand variables, glob files, quote
581 This allows us to easily expand variables, glob files, quote
582 arguments, etc.
582 arguments, etc.
583
583
584 Options:
584 Options:
585 -mode: default 'string'. If given as 'list', the argument string is
585 -mode: default 'string'. If given as 'list', the argument string is
586 returned as a list (split on whitespace) instead of a string.
586 returned as a list (split on whitespace) instead of a string.
587
587
588 -list_all: put all option values in lists. Normally only options
588 -list_all: put all option values in lists. Normally only options
589 appearing more than once are put in a list.
589 appearing more than once are put in a list.
590
590
591 -posix (True): whether to split the input line in POSIX mode or not,
591 -posix (True): whether to split the input line in POSIX mode or not,
592 as per the conventions outlined in the shlex module from the
592 as per the conventions outlined in the shlex module from the
593 standard library."""
593 standard library."""
594
594
595 # inject default options at the beginning of the input line
595 # inject default options at the beginning of the input line
596 caller = sys._getframe(1).f_code.co_name
596 caller = sys._getframe(1).f_code.co_name
597 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
597 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
598
598
599 mode = kw.get('mode','string')
599 mode = kw.get('mode','string')
600 if mode not in ['string','list']:
600 if mode not in ['string','list']:
601 raise ValueError('incorrect mode given: %s' % mode)
601 raise ValueError('incorrect mode given: %s' % mode)
602 # Get options
602 # Get options
603 list_all = kw.get('list_all',0)
603 list_all = kw.get('list_all',0)
604 posix = kw.get('posix', os.name == 'posix')
604 posix = kw.get('posix', os.name == 'posix')
605 strict = kw.get('strict', True)
605 strict = kw.get('strict', True)
606
606
607 # Check if we have more than one argument to warrant extra processing:
607 # Check if we have more than one argument to warrant extra processing:
608 odict = {} # Dictionary with options
608 odict = {} # Dictionary with options
609 args = arg_str.split()
609 args = arg_str.split()
610 if len(args) >= 1:
610 if len(args) >= 1:
611 # If the list of inputs only has 0 or 1 thing in it, there's no
611 # If the list of inputs only has 0 or 1 thing in it, there's no
612 # need to look for options
612 # need to look for options
613 argv = arg_split(arg_str, posix, strict)
613 argv = arg_split(arg_str, posix, strict)
614 # Do regular option processing
614 # Do regular option processing
615 try:
615 try:
616 opts,args = getopt(argv, opt_str, long_opts)
616 opts,args = getopt(argv, opt_str, long_opts)
617 except GetoptError as e:
617 except GetoptError as e:
618 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
618 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
619 " ".join(long_opts)))
619 " ".join(long_opts)))
620 for o,a in opts:
620 for o,a in opts:
621 if o.startswith('--'):
621 if o.startswith('--'):
622 o = o[2:]
622 o = o[2:]
623 else:
623 else:
624 o = o[1:]
624 o = o[1:]
625 try:
625 try:
626 odict[o].append(a)
626 odict[o].append(a)
627 except AttributeError:
627 except AttributeError:
628 odict[o] = [odict[o],a]
628 odict[o] = [odict[o],a]
629 except KeyError:
629 except KeyError:
630 if list_all:
630 if list_all:
631 odict[o] = [a]
631 odict[o] = [a]
632 else:
632 else:
633 odict[o] = a
633 odict[o] = a
634
634
635 # Prepare opts,args for return
635 # Prepare opts,args for return
636 opts = Struct(odict)
636 opts = Struct(odict)
637 if mode == 'string':
637 if mode == 'string':
638 args = ' '.join(args)
638 args = ' '.join(args)
639
639
640 return opts,args
640 return opts,args
641
641
642 def default_option(self, fn, optstr):
642 def default_option(self, fn, optstr):
643 """Make an entry in the options_table for fn, with value optstr"""
643 """Make an entry in the options_table for fn, with value optstr"""
644
644
645 if fn not in self.lsmagic():
645 if fn not in self.lsmagic():
646 error("%s is not a magic function" % fn)
646 error("%s is not a magic function" % fn)
647 self.options_table[fn] = optstr
647 self.options_table[fn] = optstr
648
648
649 class MagicAlias(object):
649 class MagicAlias(object):
650 """An alias to another magic function.
650 """An alias to another magic function.
651
651
652 An alias is determined by its magic name and magic kind. Lookup
652 An alias is determined by its magic name and magic kind. Lookup
653 is done at call time, so if the underlying magic changes the alias
653 is done at call time, so if the underlying magic changes the alias
654 will call the new function.
654 will call the new function.
655
655
656 Use the :meth:`MagicsManager.register_alias` method or the
656 Use the :meth:`MagicsManager.register_alias` method or the
657 `%alias_magic` magic function to create and register a new alias.
657 `%alias_magic` magic function to create and register a new alias.
658 """
658 """
659 def __init__(self, shell, magic_name, magic_kind):
659 def __init__(self, shell, magic_name, magic_kind):
660 self.shell = shell
660 self.shell = shell
661 self.magic_name = magic_name
661 self.magic_name = magic_name
662 self.magic_kind = magic_kind
662 self.magic_kind = magic_kind
663
663
664 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
664 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
665 self.__doc__ = "Alias for `%s`." % self.pretty_target
665 self.__doc__ = "Alias for `%s`." % self.pretty_target
666
666
667 self._in_call = False
667 self._in_call = False
668
668
669 def __call__(self, *args, **kwargs):
669 def __call__(self, *args, **kwargs):
670 """Call the magic alias."""
670 """Call the magic alias."""
671 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
671 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
672 if fn is None:
672 if fn is None:
673 raise UsageError("Magic `%s` not found." % self.pretty_target)
673 raise UsageError("Magic `%s` not found." % self.pretty_target)
674
674
675 # Protect against infinite recursion.
675 # Protect against infinite recursion.
676 if self._in_call:
676 if self._in_call:
677 raise UsageError("Infinite recursion detected; "
677 raise UsageError("Infinite recursion detected; "
678 "magic aliases cannot call themselves.")
678 "magic aliases cannot call themselves.")
679 self._in_call = True
679 self._in_call = True
680 try:
680 try:
681 return fn(*args, **kwargs)
681 return fn(*args, **kwargs)
682 finally:
682 finally:
683 self._in_call = False
683 self._in_call = False
@@ -1,559 +1,558 b''
1 """Implementation of code management magic functions.
1 """Implementation of code management magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import inspect
16 import inspect
17 import io
17 import io
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21
21
22 # Our own packages
22 # Our own packages
23 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
23 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
24 from IPython.core.macro import Macro
24 from IPython.core.macro import Macro
25 from IPython.core.magic import Magics, magics_class, line_magic
25 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.oinspect import find_file, find_source_lines
26 from IPython.core.oinspect import find_file, find_source_lines
27 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.utils import openpy
29 from IPython.utils import py3compat
28 from IPython.utils import py3compat
30 from IPython.utils.contexts import preserve_keys
29 from IPython.utils.contexts import preserve_keys
31 from IPython.utils.io import file_read
30 from IPython.utils.io import file_read
32 from IPython.utils.path import get_py_filename, unquote_filename
31 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.warn import warn
32 from IPython.utils.warn import warn
34
33
35 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
36 # Magic implementation classes
35 # Magic implementation classes
37 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
38
37
39 # Used for exception handling in magic_edit
38 # Used for exception handling in magic_edit
40 class MacroToEdit(ValueError): pass
39 class MacroToEdit(ValueError): pass
41
40
42 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
41 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
43
42
44 class InteractivelyDefined(Exception):
43 class InteractivelyDefined(Exception):
45 """Exception for interactively defined variable in magic_edit"""
44 """Exception for interactively defined variable in magic_edit"""
46 def __init__(self, index):
45 def __init__(self, index):
47 self.index = index
46 self.index = index
48
47
49
48
50 @magics_class
49 @magics_class
51 class CodeMagics(Magics):
50 class CodeMagics(Magics):
52 """Magics related to code management (loading, saving, editing, ...)."""
51 """Magics related to code management (loading, saving, editing, ...)."""
53
52
54 @line_magic
53 @line_magic
55 def save(self, parameter_s=''):
54 def save(self, parameter_s=''):
56 """Save a set of lines or a macro to a given filename.
55 """Save a set of lines or a macro to a given filename.
57
56
58 Usage:\\
57 Usage:\\
59 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
58 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
60
59
61 Options:
60 Options:
62
61
63 -r: use 'raw' input. By default, the 'processed' history is used,
62 -r: use 'raw' input. By default, the 'processed' history is used,
64 so that magics are loaded in their transformed version to valid
63 so that magics are loaded in their transformed version to valid
65 Python. If this option is given, the raw input as typed as the
64 Python. If this option is given, the raw input as typed as the
66 command line is used instead.
65 command line is used instead.
67
66
68 -f: force overwrite. If file exists, %save will prompt for overwrite
67 -f: force overwrite. If file exists, %save will prompt for overwrite
69 unless -f is given.
68 unless -f is given.
70
69
71 -a: append to the file instead of overwriting it.
70 -a: append to the file instead of overwriting it.
72
71
73 This function uses the same syntax as %history for input ranges,
72 This function uses the same syntax as %history for input ranges,
74 then saves the lines to the filename you specify.
73 then saves the lines to the filename you specify.
75
74
76 It adds a '.py' extension to the file if you don't do so yourself, and
75 It adds a '.py' extension to the file if you don't do so yourself, and
77 it asks for confirmation before overwriting existing files.
76 it asks for confirmation before overwriting existing files.
78
77
79 If `-r` option is used, the default extension is `.ipy`.
78 If `-r` option is used, the default extension is `.ipy`.
80 """
79 """
81
80
82 opts,args = self.parse_options(parameter_s,'fra',mode='list')
81 opts,args = self.parse_options(parameter_s,'fra',mode='list')
83 if not args:
82 if not args:
84 raise UsageError('Missing filename.')
83 raise UsageError('Missing filename.')
85 raw = 'r' in opts
84 raw = 'r' in opts
86 force = 'f' in opts
85 force = 'f' in opts
87 append = 'a' in opts
86 append = 'a' in opts
88 mode = 'a' if append else 'w'
87 mode = 'a' if append else 'w'
89 ext = u'.ipy' if raw else u'.py'
88 ext = u'.ipy' if raw else u'.py'
90 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
89 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
91 if not fname.endswith((u'.py',u'.ipy')):
90 if not fname.endswith((u'.py',u'.ipy')):
92 fname += ext
91 fname += ext
93 file_exists = os.path.isfile(fname)
92 file_exists = os.path.isfile(fname)
94 if file_exists and not force and not append:
93 if file_exists and not force and not append:
95 try:
94 try:
96 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
95 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
97 except StdinNotImplementedError:
96 except StdinNotImplementedError:
98 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
97 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
99 return
98 return
100 if not overwrite :
99 if not overwrite :
101 print 'Operation cancelled.'
100 print 'Operation cancelled.'
102 return
101 return
103 try:
102 try:
104 cmds = self.shell.find_user_code(codefrom,raw)
103 cmds = self.shell.find_user_code(codefrom,raw)
105 except (TypeError, ValueError) as e:
104 except (TypeError, ValueError) as e:
106 print e.args[0]
105 print e.args[0]
107 return
106 return
108 out = py3compat.cast_unicode(cmds)
107 out = py3compat.cast_unicode(cmds)
109 with io.open(fname, mode, encoding="utf-8") as f:
108 with io.open(fname, mode, encoding="utf-8") as f:
110 if not file_exists or not append:
109 if not file_exists or not append:
111 f.write(u"# coding: utf-8\n")
110 f.write(u"# coding: utf-8\n")
112 f.write(out)
111 f.write(out)
113 # make sure we end on a newline
112 # make sure we end on a newline
114 if not out.endswith(u'\n'):
113 if not out.endswith(u'\n'):
115 f.write(u'\n')
114 f.write(u'\n')
116 print 'The following commands were written to file `%s`:' % fname
115 print 'The following commands were written to file `%s`:' % fname
117 print cmds
116 print cmds
118
117
119 @line_magic
118 @line_magic
120 def pastebin(self, parameter_s=''):
119 def pastebin(self, parameter_s=''):
121 """Upload code to Github's Gist paste bin, returning the URL.
120 """Upload code to Github's Gist paste bin, returning the URL.
122
121
123 Usage:\\
122 Usage:\\
124 %pastebin [-d "Custom description"] 1-7
123 %pastebin [-d "Custom description"] 1-7
125
124
126 The argument can be an input history range, a filename, or the name of a
125 The argument can be an input history range, a filename, or the name of a
127 string or macro.
126 string or macro.
128
127
129 Options:
128 Options:
130
129
131 -d: Pass a custom description for the gist. The default will say
130 -d: Pass a custom description for the gist. The default will say
132 "Pasted from IPython".
131 "Pasted from IPython".
133 """
132 """
134 opts, args = self.parse_options(parameter_s, 'd:')
133 opts, args = self.parse_options(parameter_s, 'd:')
135
134
136 try:
135 try:
137 code = self.shell.find_user_code(args)
136 code = self.shell.find_user_code(args)
138 except (ValueError, TypeError) as e:
137 except (ValueError, TypeError) as e:
139 print e.args[0]
138 print e.args[0]
140 return
139 return
141
140
142 from urllib2 import urlopen # Deferred import
141 from urllib2 import urlopen # Deferred import
143 import json
142 import json
144 post_data = json.dumps({
143 post_data = json.dumps({
145 "description": opts.get('d', "Pasted from IPython"),
144 "description": opts.get('d', "Pasted from IPython"),
146 "public": True,
145 "public": True,
147 "files": {
146 "files": {
148 "file1.py": {
147 "file1.py": {
149 "content": code
148 "content": code
150 }
149 }
151 }
150 }
152 }).encode('utf-8')
151 }).encode('utf-8')
153
152
154 response = urlopen("https://api.github.com/gists", post_data)
153 response = urlopen("https://api.github.com/gists", post_data)
155 response_data = json.loads(response.read().decode('utf-8'))
154 response_data = json.loads(response.read().decode('utf-8'))
156 return response_data['html_url']
155 return response_data['html_url']
157
156
158 @line_magic
157 @line_magic
159 def loadpy(self, arg_s):
158 def loadpy(self, arg_s):
160 """Alias of `%load`
159 """Alias of `%load`
161
160
162 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
161 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
163 extension. So it has been renamed simply into %load. You can look at
162 extension. So it has been renamed simply into %load. You can look at
164 `%load`'s docstring for more info.
163 `%load`'s docstring for more info.
165 """
164 """
166 self.load(arg_s)
165 self.load(arg_s)
167
166
168 @line_magic
167 @line_magic
169 def load(self, arg_s):
168 def load(self, arg_s):
170 """Load code into the current frontend.
169 """Load code into the current frontend.
171
170
172 Usage:\\
171 Usage:\\
173 %load [options] source
172 %load [options] source
174
173
175 where source can be a filename, URL, input history range or macro
174 where source can be a filename, URL, input history range or macro
176
175
177 Options:
176 Options:
178 --------
177 --------
179 -y : Don't ask confirmation for loading source above 200 000 characters.
178 -y : Don't ask confirmation for loading source above 200 000 characters.
180
179
181 This magic command can either take a local filename, a URL, an history
180 This magic command can either take a local filename, a URL, an history
182 range (see %history) or a macro as argument, it will prompt for
181 range (see %history) or a macro as argument, it will prompt for
183 confirmation before loading source with more than 200 000 characters, unless
182 confirmation before loading source with more than 200 000 characters, unless
184 -y flag is passed or if the frontend does not support raw_input::
183 -y flag is passed or if the frontend does not support raw_input::
185
184
186 %load myscript.py
185 %load myscript.py
187 %load 7-27
186 %load 7-27
188 %load myMacro
187 %load myMacro
189 %load http://www.example.com/myscript.py
188 %load http://www.example.com/myscript.py
190 """
189 """
191 opts,args = self.parse_options(arg_s,'y')
190 opts,args = self.parse_options(arg_s,'y')
192 if not args:
191 if not args:
193 raise UsageError('Missing filename, URL, input history range, '
192 raise UsageError('Missing filename, URL, input history range, '
194 'or macro.')
193 'or macro.')
195
194
196 contents = self.shell.find_user_code(args)
195 contents = self.shell.find_user_code(args)
197 l = len(contents)
196 l = len(contents)
198
197
199 # 200 000 is ~ 2500 full 80 caracter lines
198 # 200 000 is ~ 2500 full 80 caracter lines
200 # so in average, more than 5000 lines
199 # so in average, more than 5000 lines
201 if l > 200000 and 'y' not in opts:
200 if l > 200000 and 'y' not in opts:
202 try:
201 try:
203 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
202 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
204 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
203 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
205 except StdinNotImplementedError:
204 except StdinNotImplementedError:
206 #asume yes if raw input not implemented
205 #asume yes if raw input not implemented
207 ans = True
206 ans = True
208
207
209 if ans is False :
208 if ans is False :
210 print 'Operation cancelled.'
209 print 'Operation cancelled.'
211 return
210 return
212
211
213 self.shell.set_next_input(contents)
212 self.shell.set_next_input(contents)
214
213
215 @staticmethod
214 @staticmethod
216 def _find_edit_target(shell, args, opts, last_call):
215 def _find_edit_target(shell, args, opts, last_call):
217 """Utility method used by magic_edit to find what to edit."""
216 """Utility method used by magic_edit to find what to edit."""
218
217
219 def make_filename(arg):
218 def make_filename(arg):
220 "Make a filename from the given args"
219 "Make a filename from the given args"
221 arg = unquote_filename(arg)
220 arg = unquote_filename(arg)
222 try:
221 try:
223 filename = get_py_filename(arg)
222 filename = get_py_filename(arg)
224 except IOError:
223 except IOError:
225 # If it ends with .py but doesn't already exist, assume we want
224 # If it ends with .py but doesn't already exist, assume we want
226 # a new file.
225 # a new file.
227 if arg.endswith('.py'):
226 if arg.endswith('.py'):
228 filename = arg
227 filename = arg
229 else:
228 else:
230 filename = None
229 filename = None
231 return filename
230 return filename
232
231
233 # Set a few locals from the options for convenience:
232 # Set a few locals from the options for convenience:
234 opts_prev = 'p' in opts
233 opts_prev = 'p' in opts
235 opts_raw = 'r' in opts
234 opts_raw = 'r' in opts
236
235
237 # custom exceptions
236 # custom exceptions
238 class DataIsObject(Exception): pass
237 class DataIsObject(Exception): pass
239
238
240 # Default line number value
239 # Default line number value
241 lineno = opts.get('n',None)
240 lineno = opts.get('n',None)
242
241
243 if opts_prev:
242 if opts_prev:
244 args = '_%s' % last_call[0]
243 args = '_%s' % last_call[0]
245 if args not in shell.user_ns:
244 if args not in shell.user_ns:
246 args = last_call[1]
245 args = last_call[1]
247
246
248 # by default this is done with temp files, except when the given
247 # by default this is done with temp files, except when the given
249 # arg is a filename
248 # arg is a filename
250 use_temp = True
249 use_temp = True
251
250
252 data = ''
251 data = ''
253
252
254 # First, see if the arguments should be a filename.
253 # First, see if the arguments should be a filename.
255 filename = make_filename(args)
254 filename = make_filename(args)
256 if filename:
255 if filename:
257 use_temp = False
256 use_temp = False
258 elif args:
257 elif args:
259 # Mode where user specifies ranges of lines, like in %macro.
258 # Mode where user specifies ranges of lines, like in %macro.
260 data = shell.extract_input_lines(args, opts_raw)
259 data = shell.extract_input_lines(args, opts_raw)
261 if not data:
260 if not data:
262 try:
261 try:
263 # Load the parameter given as a variable. If not a string,
262 # Load the parameter given as a variable. If not a string,
264 # process it as an object instead (below)
263 # process it as an object instead (below)
265
264
266 #print '*** args',args,'type',type(args) # dbg
265 #print '*** args',args,'type',type(args) # dbg
267 data = eval(args, shell.user_ns)
266 data = eval(args, shell.user_ns)
268 if not isinstance(data, basestring):
267 if not isinstance(data, basestring):
269 raise DataIsObject
268 raise DataIsObject
270
269
271 except (NameError,SyntaxError):
270 except (NameError,SyntaxError):
272 # given argument is not a variable, try as a filename
271 # given argument is not a variable, try as a filename
273 filename = make_filename(args)
272 filename = make_filename(args)
274 if filename is None:
273 if filename is None:
275 warn("Argument given (%s) can't be found as a variable "
274 warn("Argument given (%s) can't be found as a variable "
276 "or as a filename." % args)
275 "or as a filename." % args)
277 return (None, None, None)
276 return (None, None, None)
278 use_temp = False
277 use_temp = False
279
278
280 except DataIsObject:
279 except DataIsObject:
281 # macros have a special edit function
280 # macros have a special edit function
282 if isinstance(data, Macro):
281 if isinstance(data, Macro):
283 raise MacroToEdit(data)
282 raise MacroToEdit(data)
284
283
285 # For objects, try to edit the file where they are defined
284 # For objects, try to edit the file where they are defined
286 filename = find_file(data)
285 filename = find_file(data)
287 if filename:
286 if filename:
288 if 'fakemodule' in filename.lower() and \
287 if 'fakemodule' in filename.lower() and \
289 inspect.isclass(data):
288 inspect.isclass(data):
290 # class created by %edit? Try to find source
289 # class created by %edit? Try to find source
291 # by looking for method definitions instead, the
290 # by looking for method definitions instead, the
292 # __module__ in those classes is FakeModule.
291 # __module__ in those classes is FakeModule.
293 attrs = [getattr(data, aname) for aname in dir(data)]
292 attrs = [getattr(data, aname) for aname in dir(data)]
294 for attr in attrs:
293 for attr in attrs:
295 if not inspect.ismethod(attr):
294 if not inspect.ismethod(attr):
296 continue
295 continue
297 filename = find_file(attr)
296 filename = find_file(attr)
298 if filename and \
297 if filename and \
299 'fakemodule' not in filename.lower():
298 'fakemodule' not in filename.lower():
300 # change the attribute to be the edit
299 # change the attribute to be the edit
301 # target instead
300 # target instead
302 data = attr
301 data = attr
303 break
302 break
304
303
305 m = ipython_input_pat.match(os.path.basename(filename))
304 m = ipython_input_pat.match(os.path.basename(filename))
306 if m:
305 if m:
307 raise InteractivelyDefined(int(m.groups()[0]))
306 raise InteractivelyDefined(int(m.groups()[0]))
308
307
309 datafile = 1
308 datafile = 1
310 if filename is None:
309 if filename is None:
311 filename = make_filename(args)
310 filename = make_filename(args)
312 datafile = 1
311 datafile = 1
313 if filename is not None:
312 if filename is not None:
314 # only warn about this if we get a real name
313 # only warn about this if we get a real name
315 warn('Could not find file where `%s` is defined.\n'
314 warn('Could not find file where `%s` is defined.\n'
316 'Opening a file named `%s`' % (args, filename))
315 'Opening a file named `%s`' % (args, filename))
317 # Now, make sure we can actually read the source (if it was
316 # Now, make sure we can actually read the source (if it was
318 # in a temp file it's gone by now).
317 # in a temp file it's gone by now).
319 if datafile:
318 if datafile:
320 if lineno is None:
319 if lineno is None:
321 lineno = find_source_lines(data)
320 lineno = find_source_lines(data)
322 if lineno is None:
321 if lineno is None:
323 filename = make_filename(args)
322 filename = make_filename(args)
324 if filename is None:
323 if filename is None:
325 warn('The file where `%s` was defined '
324 warn('The file where `%s` was defined '
326 'cannot be read or found.' % data)
325 'cannot be read or found.' % data)
327 return (None, None, None)
326 return (None, None, None)
328 use_temp = False
327 use_temp = False
329
328
330 if use_temp:
329 if use_temp:
331 filename = shell.mktempfile(data)
330 filename = shell.mktempfile(data)
332 print 'IPython will make a temporary file named:',filename
331 print 'IPython will make a temporary file named:',filename
333
332
334 # use last_call to remember the state of the previous call, but don't
333 # use last_call to remember the state of the previous call, but don't
335 # let it be clobbered by successive '-p' calls.
334 # let it be clobbered by successive '-p' calls.
336 try:
335 try:
337 last_call[0] = shell.displayhook.prompt_count
336 last_call[0] = shell.displayhook.prompt_count
338 if not opts_prev:
337 if not opts_prev:
339 last_call[1] = args
338 last_call[1] = args
340 except:
339 except:
341 pass
340 pass
342
341
343
342
344 return filename, lineno, use_temp
343 return filename, lineno, use_temp
345
344
346 def _edit_macro(self,mname,macro):
345 def _edit_macro(self,mname,macro):
347 """open an editor with the macro data in a file"""
346 """open an editor with the macro data in a file"""
348 filename = self.shell.mktempfile(macro.value)
347 filename = self.shell.mktempfile(macro.value)
349 self.shell.hooks.editor(filename)
348 self.shell.hooks.editor(filename)
350
349
351 # and make a new macro object, to replace the old one
350 # and make a new macro object, to replace the old one
352 mfile = open(filename)
351 mfile = open(filename)
353 mvalue = mfile.read()
352 mvalue = mfile.read()
354 mfile.close()
353 mfile.close()
355 self.shell.user_ns[mname] = Macro(mvalue)
354 self.shell.user_ns[mname] = Macro(mvalue)
356
355
357 @skip_doctest
356 @skip_doctest
358 @line_magic
357 @line_magic
359 def edit(self, parameter_s='',last_call=['','']):
358 def edit(self, parameter_s='',last_call=['','']):
360 """Bring up an editor and execute the resulting code.
359 """Bring up an editor and execute the resulting code.
361
360
362 Usage:
361 Usage:
363 %edit [options] [args]
362 %edit [options] [args]
364
363
365 %edit runs IPython's editor hook. The default version of this hook is
364 %edit runs IPython's editor hook. The default version of this hook is
366 set to call the editor specified by your $EDITOR environment variable.
365 set to call the editor specified by your $EDITOR environment variable.
367 If this isn't found, it will default to vi under Linux/Unix and to
366 If this isn't found, it will default to vi under Linux/Unix and to
368 notepad under Windows. See the end of this docstring for how to change
367 notepad under Windows. See the end of this docstring for how to change
369 the editor hook.
368 the editor hook.
370
369
371 You can also set the value of this editor via the
370 You can also set the value of this editor via the
372 ``TerminalInteractiveShell.editor`` option in your configuration file.
371 ``TerminalInteractiveShell.editor`` option in your configuration file.
373 This is useful if you wish to use a different editor from your typical
372 This is useful if you wish to use a different editor from your typical
374 default with IPython (and for Windows users who typically don't set
373 default with IPython (and for Windows users who typically don't set
375 environment variables).
374 environment variables).
376
375
377 This command allows you to conveniently edit multi-line code right in
376 This command allows you to conveniently edit multi-line code right in
378 your IPython session.
377 your IPython session.
379
378
380 If called without arguments, %edit opens up an empty editor with a
379 If called without arguments, %edit opens up an empty editor with a
381 temporary file and will execute the contents of this file when you
380 temporary file and will execute the contents of this file when you
382 close it (don't forget to save it!).
381 close it (don't forget to save it!).
383
382
384
383
385 Options:
384 Options:
386
385
387 -n <number>: open the editor at a specified line number. By default,
386 -n <number>: open the editor at a specified line number. By default,
388 the IPython editor hook uses the unix syntax 'editor +N filename', but
387 the IPython editor hook uses the unix syntax 'editor +N filename', but
389 you can configure this by providing your own modified hook if your
388 you can configure this by providing your own modified hook if your
390 favorite editor supports line-number specifications with a different
389 favorite editor supports line-number specifications with a different
391 syntax.
390 syntax.
392
391
393 -p: this will call the editor with the same data as the previous time
392 -p: this will call the editor with the same data as the previous time
394 it was used, regardless of how long ago (in your current session) it
393 it was used, regardless of how long ago (in your current session) it
395 was.
394 was.
396
395
397 -r: use 'raw' input. This option only applies to input taken from the
396 -r: use 'raw' input. This option only applies to input taken from the
398 user's history. By default, the 'processed' history is used, so that
397 user's history. By default, the 'processed' history is used, so that
399 magics are loaded in their transformed version to valid Python. If
398 magics are loaded in their transformed version to valid Python. If
400 this option is given, the raw input as typed as the command line is
399 this option is given, the raw input as typed as the command line is
401 used instead. When you exit the editor, it will be executed by
400 used instead. When you exit the editor, it will be executed by
402 IPython's own processor.
401 IPython's own processor.
403
402
404 -x: do not execute the edited code immediately upon exit. This is
403 -x: do not execute the edited code immediately upon exit. This is
405 mainly useful if you are editing programs which need to be called with
404 mainly useful if you are editing programs which need to be called with
406 command line arguments, which you can then do using %run.
405 command line arguments, which you can then do using %run.
407
406
408
407
409 Arguments:
408 Arguments:
410
409
411 If arguments are given, the following possibilities exist:
410 If arguments are given, the following possibilities exist:
412
411
413 - If the argument is a filename, IPython will load that into the
412 - If the argument is a filename, IPython will load that into the
414 editor. It will execute its contents with execfile() when you exit,
413 editor. It will execute its contents with execfile() when you exit,
415 loading any code in the file into your interactive namespace.
414 loading any code in the file into your interactive namespace.
416
415
417 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
416 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
418 The syntax is the same as in the %history magic.
417 The syntax is the same as in the %history magic.
419
418
420 - If the argument is a string variable, its contents are loaded
419 - If the argument is a string variable, its contents are loaded
421 into the editor. You can thus edit any string which contains
420 into the editor. You can thus edit any string which contains
422 python code (including the result of previous edits).
421 python code (including the result of previous edits).
423
422
424 - If the argument is the name of an object (other than a string),
423 - If the argument is the name of an object (other than a string),
425 IPython will try to locate the file where it was defined and open the
424 IPython will try to locate the file where it was defined and open the
426 editor at the point where it is defined. You can use `%edit function`
425 editor at the point where it is defined. You can use `%edit function`
427 to load an editor exactly at the point where 'function' is defined,
426 to load an editor exactly at the point where 'function' is defined,
428 edit it and have the file be executed automatically.
427 edit it and have the file be executed automatically.
429
428
430 - If the object is a macro (see %macro for details), this opens up your
429 - If the object is a macro (see %macro for details), this opens up your
431 specified editor with a temporary file containing the macro's data.
430 specified editor with a temporary file containing the macro's data.
432 Upon exit, the macro is reloaded with the contents of the file.
431 Upon exit, the macro is reloaded with the contents of the file.
433
432
434 Note: opening at an exact line is only supported under Unix, and some
433 Note: opening at an exact line is only supported under Unix, and some
435 editors (like kedit and gedit up to Gnome 2.8) do not understand the
434 editors (like kedit and gedit up to Gnome 2.8) do not understand the
436 '+NUMBER' parameter necessary for this feature. Good editors like
435 '+NUMBER' parameter necessary for this feature. Good editors like
437 (X)Emacs, vi, jed, pico and joe all do.
436 (X)Emacs, vi, jed, pico and joe all do.
438
437
439 After executing your code, %edit will return as output the code you
438 After executing your code, %edit will return as output the code you
440 typed in the editor (except when it was an existing file). This way
439 typed in the editor (except when it was an existing file). This way
441 you can reload the code in further invocations of %edit as a variable,
440 you can reload the code in further invocations of %edit as a variable,
442 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
441 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
443 the output.
442 the output.
444
443
445 Note that %edit is also available through the alias %ed.
444 Note that %edit is also available through the alias %ed.
446
445
447 This is an example of creating a simple function inside the editor and
446 This is an example of creating a simple function inside the editor and
448 then modifying it. First, start up the editor::
447 then modifying it. First, start up the editor::
449
448
450 In [1]: edit
449 In [1]: edit
451 Editing... done. Executing edited code...
450 Editing... done. Executing edited code...
452 Out[1]: 'def foo():\\n print "foo() was defined in an editing
451 Out[1]: 'def foo():\\n print "foo() was defined in an editing
453 session"\\n'
452 session"\\n'
454
453
455 We can then call the function foo()::
454 We can then call the function foo()::
456
455
457 In [2]: foo()
456 In [2]: foo()
458 foo() was defined in an editing session
457 foo() was defined in an editing session
459
458
460 Now we edit foo. IPython automatically loads the editor with the
459 Now we edit foo. IPython automatically loads the editor with the
461 (temporary) file where foo() was previously defined::
460 (temporary) file where foo() was previously defined::
462
461
463 In [3]: edit foo
462 In [3]: edit foo
464 Editing... done. Executing edited code...
463 Editing... done. Executing edited code...
465
464
466 And if we call foo() again we get the modified version::
465 And if we call foo() again we get the modified version::
467
466
468 In [4]: foo()
467 In [4]: foo()
469 foo() has now been changed!
468 foo() has now been changed!
470
469
471 Here is an example of how to edit a code snippet successive
470 Here is an example of how to edit a code snippet successive
472 times. First we call the editor::
471 times. First we call the editor::
473
472
474 In [5]: edit
473 In [5]: edit
475 Editing... done. Executing edited code...
474 Editing... done. Executing edited code...
476 hello
475 hello
477 Out[5]: "print 'hello'\\n"
476 Out[5]: "print 'hello'\\n"
478
477
479 Now we call it again with the previous output (stored in _)::
478 Now we call it again with the previous output (stored in _)::
480
479
481 In [6]: edit _
480 In [6]: edit _
482 Editing... done. Executing edited code...
481 Editing... done. Executing edited code...
483 hello world
482 hello world
484 Out[6]: "print 'hello world'\\n"
483 Out[6]: "print 'hello world'\\n"
485
484
486 Now we call it with the output #8 (stored in _8, also as Out[8])::
485 Now we call it with the output #8 (stored in _8, also as Out[8])::
487
486
488 In [7]: edit _8
487 In [7]: edit _8
489 Editing... done. Executing edited code...
488 Editing... done. Executing edited code...
490 hello again
489 hello again
491 Out[7]: "print 'hello again'\\n"
490 Out[7]: "print 'hello again'\\n"
492
491
493
492
494 Changing the default editor hook:
493 Changing the default editor hook:
495
494
496 If you wish to write your own editor hook, you can put it in a
495 If you wish to write your own editor hook, you can put it in a
497 configuration file which you load at startup time. The default hook
496 configuration file which you load at startup time. The default hook
498 is defined in the IPython.core.hooks module, and you can use that as a
497 is defined in the IPython.core.hooks module, and you can use that as a
499 starting example for further modifications. That file also has
498 starting example for further modifications. That file also has
500 general instructions on how to set a new hook for use once you've
499 general instructions on how to set a new hook for use once you've
501 defined it."""
500 defined it."""
502 opts,args = self.parse_options(parameter_s,'prxn:')
501 opts,args = self.parse_options(parameter_s,'prxn:')
503
502
504 try:
503 try:
505 filename, lineno, is_temp = self._find_edit_target(self.shell,
504 filename, lineno, is_temp = self._find_edit_target(self.shell,
506 args, opts, last_call)
505 args, opts, last_call)
507 except MacroToEdit as e:
506 except MacroToEdit as e:
508 self._edit_macro(args, e.args[0])
507 self._edit_macro(args, e.args[0])
509 return
508 return
510 except InteractivelyDefined as e:
509 except InteractivelyDefined as e:
511 print "Editing In[%i]" % e.index
510 print "Editing In[%i]" % e.index
512 args = str(e.index)
511 args = str(e.index)
513 filename, lineno, is_temp = self._find_edit_target(self.shell,
512 filename, lineno, is_temp = self._find_edit_target(self.shell,
514 args, opts, last_call)
513 args, opts, last_call)
515 if filename is None:
514 if filename is None:
516 # nothing was found, warnings have already been issued,
515 # nothing was found, warnings have already been issued,
517 # just give up.
516 # just give up.
518 return
517 return
519
518
520 # do actual editing here
519 # do actual editing here
521 print 'Editing...',
520 print 'Editing...',
522 sys.stdout.flush()
521 sys.stdout.flush()
523 try:
522 try:
524 # Quote filenames that may have spaces in them
523 # Quote filenames that may have spaces in them
525 if ' ' in filename:
524 if ' ' in filename:
526 filename = "'%s'" % filename
525 filename = "'%s'" % filename
527 self.shell.hooks.editor(filename,lineno)
526 self.shell.hooks.editor(filename,lineno)
528 except TryNext:
527 except TryNext:
529 warn('Could not open editor')
528 warn('Could not open editor')
530 return
529 return
531
530
532 # XXX TODO: should this be generalized for all string vars?
531 # XXX TODO: should this be generalized for all string vars?
533 # For now, this is special-cased to blocks created by cpaste
532 # For now, this is special-cased to blocks created by cpaste
534 if args.strip() == 'pasted_block':
533 if args.strip() == 'pasted_block':
535 self.shell.user_ns['pasted_block'] = file_read(filename)
534 self.shell.user_ns['pasted_block'] = file_read(filename)
536
535
537 if 'x' in opts: # -x prevents actual execution
536 if 'x' in opts: # -x prevents actual execution
538 print
537 print
539 else:
538 else:
540 print 'done. Executing edited code...'
539 print 'done. Executing edited code...'
541 with preserve_keys(self.shell.user_ns, '__file__'):
540 with preserve_keys(self.shell.user_ns, '__file__'):
542 if not is_temp:
541 if not is_temp:
543 self.shell.user_ns['__file__'] = filename
542 self.shell.user_ns['__file__'] = filename
544 if 'r' in opts: # Untranslated IPython code
543 if 'r' in opts: # Untranslated IPython code
545 self.shell.run_cell(file_read(filename),
544 self.shell.run_cell(file_read(filename),
546 store_history=False)
545 store_history=False)
547 else:
546 else:
548 self.shell.safe_execfile(filename, self.shell.user_ns,
547 self.shell.safe_execfile(filename, self.shell.user_ns,
549 self.shell.user_ns)
548 self.shell.user_ns)
550
549
551 if is_temp:
550 if is_temp:
552 try:
551 try:
553 return open(filename).read()
552 return open(filename).read()
554 except IOError as msg:
553 except IOError as msg:
555 if msg.filename == filename:
554 if msg.filename == filename:
556 warn('File not found. Did you forget to save?')
555 warn('File not found. Did you forget to save?')
557 return
556 return
558 else:
557 else:
559 self.shell.showtraceback()
558 self.shell.showtraceback()
@@ -1,47 +1,47 b''
1 """Simple magics for display formats"""
1 """Simple magics for display formats"""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2012 The IPython Development Team.
3 # Copyright (c) 2012 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 # Our own packages
14 # Our own packages
15 from IPython.core.display import display, Javascript, Latex, SVG
15 from IPython.core.display import display, Javascript, Latex, SVG
16 from IPython.core.magic import (
16 from IPython.core.magic import (
17 Magics, magics_class, line_magic, cell_magic
17 Magics, magics_class, cell_magic
18 )
18 )
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Magic implementation classes
21 # Magic implementation classes
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24
24
25 @magics_class
25 @magics_class
26 class DisplayMagics(Magics):
26 class DisplayMagics(Magics):
27 """Magics for displaying various output types with literals
27 """Magics for displaying various output types with literals
28
28
29 Defines javascript/latex cell magics for writing blocks in those languages,
29 Defines javascript/latex cell magics for writing blocks in those languages,
30 to be rendered in the frontend.
30 to be rendered in the frontend.
31 """
31 """
32
32
33 @cell_magic
33 @cell_magic
34 def javascript(self, line, cell):
34 def javascript(self, line, cell):
35 """Run the cell block of Javascript code"""
35 """Run the cell block of Javascript code"""
36 display(Javascript(cell))
36 display(Javascript(cell))
37
37
38
38
39 @cell_magic
39 @cell_magic
40 def latex(self, line, cell):
40 def latex(self, line, cell):
41 """Render the cell as a block of latex"""
41 """Render the cell as a block of latex"""
42 display(Latex(cell))
42 display(Latex(cell))
43
43
44 @cell_magic
44 @cell_magic
45 def svg(self, line, cell):
45 def svg(self, line, cell):
46 """Render the cell as an SVG literal"""
46 """Render the cell as an SVG literal"""
47 display(SVG(cell))
47 display(SVG(cell))
@@ -1,319 +1,318 b''
1 """Implementation of magic functions related to History.
1 """Implementation of magic functions related to History.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012, IPython Development Team.
4 # Copyright (c) 2012, IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib
16 # Stdlib
17 import os
17 import os
18 from io import open as io_open
18 from io import open as io_open
19 from IPython.external.argparse import Action
20
19
21 # Our own packages
20 # Our own packages
22 from IPython.core.error import StdinNotImplementedError
21 from IPython.core.error import StdinNotImplementedError
23 from IPython.core.magic import Magics, magics_class, line_magic
22 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.core.magic_arguments import (argument, magic_arguments,
23 from IPython.core.magic_arguments import (argument, magic_arguments,
25 parse_argstring)
24 parse_argstring)
26 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.utils import io
26 from IPython.utils import io
28
27
29 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
30 # Magics class implementation
29 # Magics class implementation
31 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
32
31
33
32
34 _unspecified = object()
33 _unspecified = object()
35
34
36
35
37 @magics_class
36 @magics_class
38 class HistoryMagics(Magics):
37 class HistoryMagics(Magics):
39
38
40 @magic_arguments()
39 @magic_arguments()
41 @argument(
40 @argument(
42 '-n', dest='print_nums', action='store_true', default=False,
41 '-n', dest='print_nums', action='store_true', default=False,
43 help="""
42 help="""
44 print line numbers for each input.
43 print line numbers for each input.
45 This feature is only available if numbered prompts are in use.
44 This feature is only available if numbered prompts are in use.
46 """)
45 """)
47 @argument(
46 @argument(
48 '-o', dest='get_output', action='store_true', default=False,
47 '-o', dest='get_output', action='store_true', default=False,
49 help="also print outputs for each input.")
48 help="also print outputs for each input.")
50 @argument(
49 @argument(
51 '-p', dest='pyprompts', action='store_true', default=False,
50 '-p', dest='pyprompts', action='store_true', default=False,
52 help="""
51 help="""
53 print classic '>>>' python prompts before each input.
52 print classic '>>>' python prompts before each input.
54 This is useful for making documentation, and in conjunction
53 This is useful for making documentation, and in conjunction
55 with -o, for producing doctest-ready output.
54 with -o, for producing doctest-ready output.
56 """)
55 """)
57 @argument(
56 @argument(
58 '-t', dest='raw', action='store_false', default=True,
57 '-t', dest='raw', action='store_false', default=True,
59 help="""
58 help="""
60 print the 'translated' history, as IPython understands it.
59 print the 'translated' history, as IPython understands it.
61 IPython filters your input and converts it all into valid Python
60 IPython filters your input and converts it all into valid Python
62 source before executing it (things like magics or aliases are turned
61 source before executing it (things like magics or aliases are turned
63 into function calls, for example). With this option, you'll see the
62 into function calls, for example). With this option, you'll see the
64 native history instead of the user-entered version: '%%cd /' will be
63 native history instead of the user-entered version: '%%cd /' will be
65 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
64 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
66 """)
65 """)
67 @argument(
66 @argument(
68 '-f', dest='filename',
67 '-f', dest='filename',
69 help="""
68 help="""
70 FILENAME: instead of printing the output to the screen, redirect
69 FILENAME: instead of printing the output to the screen, redirect
71 it to the given file. The file is always overwritten, though *when
70 it to the given file. The file is always overwritten, though *when
72 it can*, IPython asks for confirmation first. In particular, running
71 it can*, IPython asks for confirmation first. In particular, running
73 the command 'history -f FILENAME' from the IPython Notebook
72 the command 'history -f FILENAME' from the IPython Notebook
74 interface will replace FILENAME even if it already exists *without*
73 interface will replace FILENAME even if it already exists *without*
75 confirmation.
74 confirmation.
76 """)
75 """)
77 @argument(
76 @argument(
78 '-g', dest='pattern', nargs='*', default=None,
77 '-g', dest='pattern', nargs='*', default=None,
79 help="""
78 help="""
80 treat the arg as a glob pattern to search for in (full) history.
79 treat the arg as a glob pattern to search for in (full) history.
81 This includes the saved history (almost all commands ever written).
80 This includes the saved history (almost all commands ever written).
82 The pattern may contain '?' to match one unknown character and '*'
81 The pattern may contain '?' to match one unknown character and '*'
83 to match any number of unknown characters. Use '%%hist -g' to show
82 to match any number of unknown characters. Use '%%hist -g' to show
84 full saved history (may be very long).
83 full saved history (may be very long).
85 """)
84 """)
86 @argument(
85 @argument(
87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
86 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
88 help="""
87 help="""
89 get the last n lines from all sessions. Specify n as a single
88 get the last n lines from all sessions. Specify n as a single
90 arg, or the default is the last 10 lines.
89 arg, or the default is the last 10 lines.
91 """)
90 """)
92 @argument(
91 @argument(
93 '-u', dest='unique', action='store_true',
92 '-u', dest='unique', action='store_true',
94 help="""
93 help="""
95 when searching history using `-g`, show only unique history.
94 when searching history using `-g`, show only unique history.
96 """)
95 """)
97 @argument('range', nargs='*')
96 @argument('range', nargs='*')
98 @skip_doctest
97 @skip_doctest
99 @line_magic
98 @line_magic
100 def history(self, parameter_s = ''):
99 def history(self, parameter_s = ''):
101 """Print input history (_i<n> variables), with most recent last.
100 """Print input history (_i<n> variables), with most recent last.
102
101
103 By default, input history is printed without line numbers so it can be
102 By default, input history is printed without line numbers so it can be
104 directly pasted into an editor. Use -n to show them.
103 directly pasted into an editor. Use -n to show them.
105
104
106 By default, all input history from the current session is displayed.
105 By default, all input history from the current session is displayed.
107 Ranges of history can be indicated using the syntax:
106 Ranges of history can be indicated using the syntax:
108
107
109 ``4``
108 ``4``
110 Line 4, current session
109 Line 4, current session
111 ``4-6``
110 ``4-6``
112 Lines 4-6, current session
111 Lines 4-6, current session
113 ``243/1-5``
112 ``243/1-5``
114 Lines 1-5, session 243
113 Lines 1-5, session 243
115 ``~2/7``
114 ``~2/7``
116 Line 7, session 2 before current
115 Line 7, session 2 before current
117 ``~8/1-~6/5``
116 ``~8/1-~6/5``
118 From the first line of 8 sessions ago, to the fifth line of 6
117 From the first line of 8 sessions ago, to the fifth line of 6
119 sessions ago.
118 sessions ago.
120
119
121 Multiple ranges can be entered, separated by spaces
120 Multiple ranges can be entered, separated by spaces
122
121
123 The same syntax is used by %macro, %save, %edit, %rerun
122 The same syntax is used by %macro, %save, %edit, %rerun
124
123
125 Examples
124 Examples
126 --------
125 --------
127 ::
126 ::
128
127
129 In [6]: %history -n 4-6
128 In [6]: %history -n 4-6
130 4:a = 12
129 4:a = 12
131 5:print a**2
130 5:print a**2
132 6:%history -n 4-6
131 6:%history -n 4-6
133
132
134 """
133 """
135
134
136 args = parse_argstring(self.history, parameter_s)
135 args = parse_argstring(self.history, parameter_s)
137
136
138 # For brevity
137 # For brevity
139 history_manager = self.shell.history_manager
138 history_manager = self.shell.history_manager
140
139
141 def _format_lineno(session, line):
140 def _format_lineno(session, line):
142 """Helper function to format line numbers properly."""
141 """Helper function to format line numbers properly."""
143 if session in (0, history_manager.session_number):
142 if session in (0, history_manager.session_number):
144 return str(line)
143 return str(line)
145 return "%s/%s" % (session, line)
144 return "%s/%s" % (session, line)
146
145
147 # Check if output to specific file was requested.
146 # Check if output to specific file was requested.
148 outfname = args.filename
147 outfname = args.filename
149 if not outfname:
148 if not outfname:
150 outfile = io.stdout # default
149 outfile = io.stdout # default
151 # We don't want to close stdout at the end!
150 # We don't want to close stdout at the end!
152 close_at_end = False
151 close_at_end = False
153 else:
152 else:
154 if os.path.exists(outfname):
153 if os.path.exists(outfname):
155 try:
154 try:
156 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
155 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
157 except StdinNotImplementedError:
156 except StdinNotImplementedError:
158 ans = True
157 ans = True
159 if not ans:
158 if not ans:
160 print('Aborting.')
159 print('Aborting.')
161 return
160 return
162 print("Overwriting file.")
161 print("Overwriting file.")
163 outfile = io_open(outfname, 'w', encoding='utf-8')
162 outfile = io_open(outfname, 'w', encoding='utf-8')
164 close_at_end = True
163 close_at_end = True
165
164
166 print_nums = args.print_nums
165 print_nums = args.print_nums
167 get_output = args.get_output
166 get_output = args.get_output
168 pyprompts = args.pyprompts
167 pyprompts = args.pyprompts
169 raw = args.raw
168 raw = args.raw
170
169
171 pattern = None
170 pattern = None
172 limit = None if args.limit is _unspecified else args.limit
171 limit = None if args.limit is _unspecified else args.limit
173
172
174 if args.pattern is not None:
173 if args.pattern is not None:
175 if args.pattern:
174 if args.pattern:
176 pattern = "*" + " ".join(args.pattern) + "*"
175 pattern = "*" + " ".join(args.pattern) + "*"
177 else:
176 else:
178 pattern = "*"
177 pattern = "*"
179 hist = history_manager.search(pattern, raw=raw, output=get_output,
178 hist = history_manager.search(pattern, raw=raw, output=get_output,
180 n=limit, unique=args.unique)
179 n=limit, unique=args.unique)
181 print_nums = True
180 print_nums = True
182 elif args.limit is not _unspecified:
181 elif args.limit is not _unspecified:
183 n = 10 if limit is None else limit
182 n = 10 if limit is None else limit
184 hist = history_manager.get_tail(n, raw=raw, output=get_output)
183 hist = history_manager.get_tail(n, raw=raw, output=get_output)
185 else:
184 else:
186 if args.range: # Get history by ranges
185 if args.range: # Get history by ranges
187 hist = history_manager.get_range_by_str(" ".join(args.range),
186 hist = history_manager.get_range_by_str(" ".join(args.range),
188 raw, get_output)
187 raw, get_output)
189 else: # Just get history for the current session
188 else: # Just get history for the current session
190 hist = history_manager.get_range(raw=raw, output=get_output)
189 hist = history_manager.get_range(raw=raw, output=get_output)
191
190
192 # We could be displaying the entire history, so let's not try to pull
191 # We could be displaying the entire history, so let's not try to pull
193 # it into a list in memory. Anything that needs more space will just
192 # it into a list in memory. Anything that needs more space will just
194 # misalign.
193 # misalign.
195 width = 4
194 width = 4
196
195
197 for session, lineno, inline in hist:
196 for session, lineno, inline in hist:
198 # Print user history with tabs expanded to 4 spaces. The GUI
197 # Print user history with tabs expanded to 4 spaces. The GUI
199 # clients use hard tabs for easier usability in auto-indented code,
198 # clients use hard tabs for easier usability in auto-indented code,
200 # but we want to produce PEP-8 compliant history for safe pasting
199 # but we want to produce PEP-8 compliant history for safe pasting
201 # into an editor.
200 # into an editor.
202 if get_output:
201 if get_output:
203 inline, output = inline
202 inline, output = inline
204 inline = inline.expandtabs(4).rstrip()
203 inline = inline.expandtabs(4).rstrip()
205
204
206 multiline = "\n" in inline
205 multiline = "\n" in inline
207 line_sep = '\n' if multiline else ' '
206 line_sep = '\n' if multiline else ' '
208 if print_nums:
207 if print_nums:
209 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
208 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
210 line_sep), file=outfile, end=u'')
209 line_sep), file=outfile, end=u'')
211 if pyprompts:
210 if pyprompts:
212 print(u">>> ", end=u"", file=outfile)
211 print(u">>> ", end=u"", file=outfile)
213 if multiline:
212 if multiline:
214 inline = "\n... ".join(inline.splitlines()) + "\n..."
213 inline = "\n... ".join(inline.splitlines()) + "\n..."
215 print(inline, file=outfile)
214 print(inline, file=outfile)
216 if get_output and output:
215 if get_output and output:
217 print(output, file=outfile)
216 print(output, file=outfile)
218
217
219 if close_at_end:
218 if close_at_end:
220 outfile.close()
219 outfile.close()
221
220
222 @line_magic
221 @line_magic
223 def recall(self, arg):
222 def recall(self, arg):
224 r"""Repeat a command, or get command to input line for editing.
223 r"""Repeat a command, or get command to input line for editing.
225
224
226 %recall and %rep are equivalent.
225 %recall and %rep are equivalent.
227
226
228 - %recall (no arguments):
227 - %recall (no arguments):
229
228
230 Place a string version of last computation result (stored in the
229 Place a string version of last computation result (stored in the
231 special '_' variable) to the next input prompt. Allows you to create
230 special '_' variable) to the next input prompt. Allows you to create
232 elaborate command lines without using copy-paste::
231 elaborate command lines without using copy-paste::
233
232
234 In[1]: l = ["hei", "vaan"]
233 In[1]: l = ["hei", "vaan"]
235 In[2]: "".join(l)
234 In[2]: "".join(l)
236 Out[2]: heivaan
235 Out[2]: heivaan
237 In[3]: %recall
236 In[3]: %recall
238 In[4]: heivaan_ <== cursor blinking
237 In[4]: heivaan_ <== cursor blinking
239
238
240 %recall 45
239 %recall 45
241
240
242 Place history line 45 on the next input prompt. Use %hist to find
241 Place history line 45 on the next input prompt. Use %hist to find
243 out the number.
242 out the number.
244
243
245 %recall 1-4
244 %recall 1-4
246
245
247 Combine the specified lines into one cell, and place it on the next
246 Combine the specified lines into one cell, and place it on the next
248 input prompt. See %history for the slice syntax.
247 input prompt. See %history for the slice syntax.
249
248
250 %recall foo+bar
249 %recall foo+bar
251
250
252 If foo+bar can be evaluated in the user namespace, the result is
251 If foo+bar can be evaluated in the user namespace, the result is
253 placed at the next input prompt. Otherwise, the history is searched
252 placed at the next input prompt. Otherwise, the history is searched
254 for lines which contain that substring, and the most recent one is
253 for lines which contain that substring, and the most recent one is
255 placed at the next input prompt.
254 placed at the next input prompt.
256 """
255 """
257 if not arg: # Last output
256 if not arg: # Last output
258 self.shell.set_next_input(str(self.shell.user_ns["_"]))
257 self.shell.set_next_input(str(self.shell.user_ns["_"]))
259 return
258 return
260 # Get history range
259 # Get history range
261 histlines = self.shell.history_manager.get_range_by_str(arg)
260 histlines = self.shell.history_manager.get_range_by_str(arg)
262 cmd = "\n".join(x[2] for x in histlines)
261 cmd = "\n".join(x[2] for x in histlines)
263 if cmd:
262 if cmd:
264 self.shell.set_next_input(cmd.rstrip())
263 self.shell.set_next_input(cmd.rstrip())
265 return
264 return
266
265
267 try: # Variable in user namespace
266 try: # Variable in user namespace
268 cmd = str(eval(arg, self.shell.user_ns))
267 cmd = str(eval(arg, self.shell.user_ns))
269 except Exception: # Search for term in history
268 except Exception: # Search for term in history
270 histlines = self.shell.history_manager.search("*"+arg+"*")
269 histlines = self.shell.history_manager.search("*"+arg+"*")
271 for h in reversed([x[2] for x in histlines]):
270 for h in reversed([x[2] for x in histlines]):
272 if 'recall' in h or 'rep' in h:
271 if 'recall' in h or 'rep' in h:
273 continue
272 continue
274 self.shell.set_next_input(h.rstrip())
273 self.shell.set_next_input(h.rstrip())
275 return
274 return
276 else:
275 else:
277 self.shell.set_next_input(cmd.rstrip())
276 self.shell.set_next_input(cmd.rstrip())
278 print("Couldn't evaluate or find in history:", arg)
277 print("Couldn't evaluate or find in history:", arg)
279
278
280 @line_magic
279 @line_magic
281 def rerun(self, parameter_s=''):
280 def rerun(self, parameter_s=''):
282 """Re-run previous input
281 """Re-run previous input
283
282
284 By default, you can specify ranges of input history to be repeated
283 By default, you can specify ranges of input history to be repeated
285 (as with %history). With no arguments, it will repeat the last line.
284 (as with %history). With no arguments, it will repeat the last line.
286
285
287 Options:
286 Options:
288
287
289 -l <n> : Repeat the last n lines of input, not including the
288 -l <n> : Repeat the last n lines of input, not including the
290 current command.
289 current command.
291
290
292 -g foo : Repeat the most recent line which contains foo
291 -g foo : Repeat the most recent line which contains foo
293 """
292 """
294 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
293 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
295 if "l" in opts: # Last n lines
294 if "l" in opts: # Last n lines
296 n = int(opts['l'])
295 n = int(opts['l'])
297 hist = self.shell.history_manager.get_tail(n)
296 hist = self.shell.history_manager.get_tail(n)
298 elif "g" in opts: # Search
297 elif "g" in opts: # Search
299 p = "*"+opts['g']+"*"
298 p = "*"+opts['g']+"*"
300 hist = list(self.shell.history_manager.search(p))
299 hist = list(self.shell.history_manager.search(p))
301 for l in reversed(hist):
300 for l in reversed(hist):
302 if "rerun" not in l[2]:
301 if "rerun" not in l[2]:
303 hist = [l] # The last match which isn't a %rerun
302 hist = [l] # The last match which isn't a %rerun
304 break
303 break
305 else:
304 else:
306 hist = [] # No matches except %rerun
305 hist = [] # No matches except %rerun
307 elif args: # Specify history ranges
306 elif args: # Specify history ranges
308 hist = self.shell.history_manager.get_range_by_str(args)
307 hist = self.shell.history_manager.get_range_by_str(args)
309 else: # Last line
308 else: # Last line
310 hist = self.shell.history_manager.get_tail(1)
309 hist = self.shell.history_manager.get_tail(1)
311 hist = [x[2] for x in hist]
310 hist = [x[2] for x in hist]
312 if not hist:
311 if not hist:
313 print("No lines in history match specification")
312 print("No lines in history match specification")
314 return
313 return
315 histlines = "\n".join(hist)
314 histlines = "\n".join(hist)
316 print("=== Executing: ===")
315 print("=== Executing: ===")
317 print(histlines)
316 print(histlines)
318 print("=== Output: ===")
317 print("=== Output: ===")
319 self.shell.run_cell("\n".join(hist), store_history=False)
318 self.shell.run_cell("\n".join(hist), store_history=False)
@@ -1,725 +1,725 b''
1 """Implementation of magic functions for interaction with the OS.
1 """Implementation of magic functions for interaction with the OS.
2
2
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 builtin.
4 builtin.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2012 The IPython Development Team.
7 # Copyright (c) 2012 The IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Stdlib
18 # Stdlib
19 import io
19 import io
20 import os
20 import os
21 import re
21 import re
22 import sys
22 import sys
23 from pprint import pformat
23 from pprint import pformat
24
24
25 # Our own packages
25 # Our own packages
26 from IPython.core import magic_arguments
26 from IPython.core import magic_arguments
27 from IPython.core import oinspect
27 from IPython.core import oinspect
28 from IPython.core import page
28 from IPython.core import page
29 from IPython.core.error import UsageError, StdinNotImplementedError
29 from IPython.core.error import UsageError
30 from IPython.core.magic import (
30 from IPython.core.magic import (
31 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
31 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
32 )
32 )
33 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils.io import file_read, nlprint
34 from IPython.utils.io import nlprint
35 from IPython.utils.openpy import source_to_unicode
35 from IPython.utils.openpy import source_to_unicode
36 from IPython.utils.path import get_py_filename, unquote_filename
36 from IPython.utils.path import unquote_filename
37 from IPython.utils.process import abbrev_cwd
37 from IPython.utils.process import abbrev_cwd
38 from IPython.utils.terminal import set_term_title
38 from IPython.utils.terminal import set_term_title
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Magic implementation classes
40 # Magic implementation classes
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 @magics_class
42 @magics_class
43 class OSMagics(Magics):
43 class OSMagics(Magics):
44 """Magics to interact with the underlying OS (shell-type functionality).
44 """Magics to interact with the underlying OS (shell-type functionality).
45 """
45 """
46
46
47 @skip_doctest
47 @skip_doctest
48 @line_magic
48 @line_magic
49 def alias(self, parameter_s=''):
49 def alias(self, parameter_s=''):
50 """Define an alias for a system command.
50 """Define an alias for a system command.
51
51
52 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
52 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
53
53
54 Then, typing 'alias_name params' will execute the system command 'cmd
54 Then, typing 'alias_name params' will execute the system command 'cmd
55 params' (from your underlying operating system).
55 params' (from your underlying operating system).
56
56
57 Aliases have lower precedence than magic functions and Python normal
57 Aliases have lower precedence than magic functions and Python normal
58 variables, so if 'foo' is both a Python variable and an alias, the
58 variables, so if 'foo' is both a Python variable and an alias, the
59 alias can not be executed until 'del foo' removes the Python variable.
59 alias can not be executed until 'del foo' removes the Python variable.
60
60
61 You can use the %l specifier in an alias definition to represent the
61 You can use the %l specifier in an alias definition to represent the
62 whole line when the alias is called. For example::
62 whole line when the alias is called. For example::
63
63
64 In [2]: alias bracket echo "Input in brackets: <%l>"
64 In [2]: alias bracket echo "Input in brackets: <%l>"
65 In [3]: bracket hello world
65 In [3]: bracket hello world
66 Input in brackets: <hello world>
66 Input in brackets: <hello world>
67
67
68 You can also define aliases with parameters using %s specifiers (one
68 You can also define aliases with parameters using %s specifiers (one
69 per parameter)::
69 per parameter)::
70
70
71 In [1]: alias parts echo first %s second %s
71 In [1]: alias parts echo first %s second %s
72 In [2]: %parts A B
72 In [2]: %parts A B
73 first A second B
73 first A second B
74 In [3]: %parts A
74 In [3]: %parts A
75 Incorrect number of arguments: 2 expected.
75 Incorrect number of arguments: 2 expected.
76 parts is an alias to: 'echo first %s second %s'
76 parts is an alias to: 'echo first %s second %s'
77
77
78 Note that %l and %s are mutually exclusive. You can only use one or
78 Note that %l and %s are mutually exclusive. You can only use one or
79 the other in your aliases.
79 the other in your aliases.
80
80
81 Aliases expand Python variables just like system calls using ! or !!
81 Aliases expand Python variables just like system calls using ! or !!
82 do: all expressions prefixed with '$' get expanded. For details of
82 do: all expressions prefixed with '$' get expanded. For details of
83 the semantic rules, see PEP-215:
83 the semantic rules, see PEP-215:
84 http://www.python.org/peps/pep-0215.html. This is the library used by
84 http://www.python.org/peps/pep-0215.html. This is the library used by
85 IPython for variable expansion. If you want to access a true shell
85 IPython for variable expansion. If you want to access a true shell
86 variable, an extra $ is necessary to prevent its expansion by
86 variable, an extra $ is necessary to prevent its expansion by
87 IPython::
87 IPython::
88
88
89 In [6]: alias show echo
89 In [6]: alias show echo
90 In [7]: PATH='A Python string'
90 In [7]: PATH='A Python string'
91 In [8]: show $PATH
91 In [8]: show $PATH
92 A Python string
92 A Python string
93 In [9]: show $$PATH
93 In [9]: show $$PATH
94 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
94 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
95
95
96 You can use the alias facility to acess all of $PATH. See the %rehash
96 You can use the alias facility to acess all of $PATH. See the %rehash
97 and %rehashx functions, which automatically create aliases for the
97 and %rehashx functions, which automatically create aliases for the
98 contents of your $PATH.
98 contents of your $PATH.
99
99
100 If called with no parameters, %alias prints the current alias table."""
100 If called with no parameters, %alias prints the current alias table."""
101
101
102 par = parameter_s.strip()
102 par = parameter_s.strip()
103 if not par:
103 if not par:
104 aliases = sorted(self.shell.alias_manager.aliases)
104 aliases = sorted(self.shell.alias_manager.aliases)
105 # stored = self.shell.db.get('stored_aliases', {} )
105 # stored = self.shell.db.get('stored_aliases', {} )
106 # for k, v in stored:
106 # for k, v in stored:
107 # atab.append(k, v[0])
107 # atab.append(k, v[0])
108
108
109 print "Total number of aliases:", len(aliases)
109 print "Total number of aliases:", len(aliases)
110 sys.stdout.flush()
110 sys.stdout.flush()
111 return aliases
111 return aliases
112
112
113 # Now try to define a new one
113 # Now try to define a new one
114 try:
114 try:
115 alias,cmd = par.split(None, 1)
115 alias,cmd = par.split(None, 1)
116 except:
116 except:
117 print oinspect.getdoc(self.alias)
117 print oinspect.getdoc(self.alias)
118 else:
118 else:
119 self.shell.alias_manager.soft_define_alias(alias, cmd)
119 self.shell.alias_manager.soft_define_alias(alias, cmd)
120 # end magic_alias
120 # end magic_alias
121
121
122 @line_magic
122 @line_magic
123 def unalias(self, parameter_s=''):
123 def unalias(self, parameter_s=''):
124 """Remove an alias"""
124 """Remove an alias"""
125
125
126 aname = parameter_s.strip()
126 aname = parameter_s.strip()
127 self.shell.alias_manager.undefine_alias(aname)
127 self.shell.alias_manager.undefine_alias(aname)
128 stored = self.shell.db.get('stored_aliases', {} )
128 stored = self.shell.db.get('stored_aliases', {} )
129 if aname in stored:
129 if aname in stored:
130 print "Removing %stored alias",aname
130 print "Removing %stored alias",aname
131 del stored[aname]
131 del stored[aname]
132 self.shell.db['stored_aliases'] = stored
132 self.shell.db['stored_aliases'] = stored
133
133
134 @line_magic
134 @line_magic
135 def rehashx(self, parameter_s=''):
135 def rehashx(self, parameter_s=''):
136 """Update the alias table with all executable files in $PATH.
136 """Update the alias table with all executable files in $PATH.
137
137
138 This version explicitly checks that every entry in $PATH is a file
138 This version explicitly checks that every entry in $PATH is a file
139 with execute access (os.X_OK), so it is much slower than %rehash.
139 with execute access (os.X_OK), so it is much slower than %rehash.
140
140
141 Under Windows, it checks executability as a match against a
141 Under Windows, it checks executability as a match against a
142 '|'-separated string of extensions, stored in the IPython config
142 '|'-separated string of extensions, stored in the IPython config
143 variable win_exec_ext. This defaults to 'exe|com|bat'.
143 variable win_exec_ext. This defaults to 'exe|com|bat'.
144
144
145 This function also resets the root module cache of module completer,
145 This function also resets the root module cache of module completer,
146 used on slow filesystems.
146 used on slow filesystems.
147 """
147 """
148 from IPython.core.alias import InvalidAliasError
148 from IPython.core.alias import InvalidAliasError
149
149
150 # for the benefit of module completer in ipy_completers.py
150 # for the benefit of module completer in ipy_completers.py
151 del self.shell.db['rootmodules']
151 del self.shell.db['rootmodules']
152
152
153 path = [os.path.abspath(os.path.expanduser(p)) for p in
153 path = [os.path.abspath(os.path.expanduser(p)) for p in
154 os.environ.get('PATH','').split(os.pathsep)]
154 os.environ.get('PATH','').split(os.pathsep)]
155 path = filter(os.path.isdir,path)
155 path = filter(os.path.isdir,path)
156
156
157 syscmdlist = []
157 syscmdlist = []
158 # Now define isexec in a cross platform manner.
158 # Now define isexec in a cross platform manner.
159 if os.name == 'posix':
159 if os.name == 'posix':
160 isexec = lambda fname:os.path.isfile(fname) and \
160 isexec = lambda fname:os.path.isfile(fname) and \
161 os.access(fname,os.X_OK)
161 os.access(fname,os.X_OK)
162 else:
162 else:
163 try:
163 try:
164 winext = os.environ['pathext'].replace(';','|').replace('.','')
164 winext = os.environ['pathext'].replace(';','|').replace('.','')
165 except KeyError:
165 except KeyError:
166 winext = 'exe|com|bat|py'
166 winext = 'exe|com|bat|py'
167 if 'py' not in winext:
167 if 'py' not in winext:
168 winext += '|py'
168 winext += '|py'
169 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
169 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
170 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
170 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
171 savedir = os.getcwdu()
171 savedir = os.getcwdu()
172
172
173 # Now walk the paths looking for executables to alias.
173 # Now walk the paths looking for executables to alias.
174 try:
174 try:
175 # write the whole loop for posix/Windows so we don't have an if in
175 # write the whole loop for posix/Windows so we don't have an if in
176 # the innermost part
176 # the innermost part
177 if os.name == 'posix':
177 if os.name == 'posix':
178 for pdir in path:
178 for pdir in path:
179 os.chdir(pdir)
179 os.chdir(pdir)
180 for ff in os.listdir(pdir):
180 for ff in os.listdir(pdir):
181 if isexec(ff):
181 if isexec(ff):
182 try:
182 try:
183 # Removes dots from the name since ipython
183 # Removes dots from the name since ipython
184 # will assume names with dots to be python.
184 # will assume names with dots to be python.
185 self.shell.alias_manager.define_alias(
185 self.shell.alias_manager.define_alias(
186 ff.replace('.',''), ff)
186 ff.replace('.',''), ff)
187 except InvalidAliasError:
187 except InvalidAliasError:
188 pass
188 pass
189 else:
189 else:
190 syscmdlist.append(ff)
190 syscmdlist.append(ff)
191 else:
191 else:
192 no_alias = self.shell.alias_manager.no_alias
192 no_alias = self.shell.alias_manager.no_alias
193 for pdir in path:
193 for pdir in path:
194 os.chdir(pdir)
194 os.chdir(pdir)
195 for ff in os.listdir(pdir):
195 for ff in os.listdir(pdir):
196 base, ext = os.path.splitext(ff)
196 base, ext = os.path.splitext(ff)
197 if isexec(ff) and base.lower() not in no_alias:
197 if isexec(ff) and base.lower() not in no_alias:
198 if ext.lower() == '.exe':
198 if ext.lower() == '.exe':
199 ff = base
199 ff = base
200 try:
200 try:
201 # Removes dots from the name since ipython
201 # Removes dots from the name since ipython
202 # will assume names with dots to be python.
202 # will assume names with dots to be python.
203 self.shell.alias_manager.define_alias(
203 self.shell.alias_manager.define_alias(
204 base.lower().replace('.',''), ff)
204 base.lower().replace('.',''), ff)
205 except InvalidAliasError:
205 except InvalidAliasError:
206 pass
206 pass
207 syscmdlist.append(ff)
207 syscmdlist.append(ff)
208 self.shell.db['syscmdlist'] = syscmdlist
208 self.shell.db['syscmdlist'] = syscmdlist
209 finally:
209 finally:
210 os.chdir(savedir)
210 os.chdir(savedir)
211
211
212 @skip_doctest
212 @skip_doctest
213 @line_magic
213 @line_magic
214 def pwd(self, parameter_s=''):
214 def pwd(self, parameter_s=''):
215 """Return the current working directory path.
215 """Return the current working directory path.
216
216
217 Examples
217 Examples
218 --------
218 --------
219 ::
219 ::
220
220
221 In [9]: pwd
221 In [9]: pwd
222 Out[9]: '/home/tsuser/sprint/ipython'
222 Out[9]: '/home/tsuser/sprint/ipython'
223 """
223 """
224 return os.getcwdu()
224 return os.getcwdu()
225
225
226 @skip_doctest
226 @skip_doctest
227 @line_magic
227 @line_magic
228 def cd(self, parameter_s=''):
228 def cd(self, parameter_s=''):
229 """Change the current working directory.
229 """Change the current working directory.
230
230
231 This command automatically maintains an internal list of directories
231 This command automatically maintains an internal list of directories
232 you visit during your IPython session, in the variable _dh. The
232 you visit during your IPython session, in the variable _dh. The
233 command %dhist shows this history nicely formatted. You can also
233 command %dhist shows this history nicely formatted. You can also
234 do 'cd -<tab>' to see directory history conveniently.
234 do 'cd -<tab>' to see directory history conveniently.
235
235
236 Usage:
236 Usage:
237
237
238 cd 'dir': changes to directory 'dir'.
238 cd 'dir': changes to directory 'dir'.
239
239
240 cd -: changes to the last visited directory.
240 cd -: changes to the last visited directory.
241
241
242 cd -<n>: changes to the n-th directory in the directory history.
242 cd -<n>: changes to the n-th directory in the directory history.
243
243
244 cd --foo: change to directory that matches 'foo' in history
244 cd --foo: change to directory that matches 'foo' in history
245
245
246 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
246 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
247 (note: cd <bookmark_name> is enough if there is no
247 (note: cd <bookmark_name> is enough if there is no
248 directory <bookmark_name>, but a bookmark with the name exists.)
248 directory <bookmark_name>, but a bookmark with the name exists.)
249 'cd -b <tab>' allows you to tab-complete bookmark names.
249 'cd -b <tab>' allows you to tab-complete bookmark names.
250
250
251 Options:
251 Options:
252
252
253 -q: quiet. Do not print the working directory after the cd command is
253 -q: quiet. Do not print the working directory after the cd command is
254 executed. By default IPython's cd command does print this directory,
254 executed. By default IPython's cd command does print this directory,
255 since the default prompts do not display path information.
255 since the default prompts do not display path information.
256
256
257 Note that !cd doesn't work for this purpose because the shell where
257 Note that !cd doesn't work for this purpose because the shell where
258 !command runs is immediately discarded after executing 'command'.
258 !command runs is immediately discarded after executing 'command'.
259
259
260 Examples
260 Examples
261 --------
261 --------
262 ::
262 ::
263
263
264 In [10]: cd parent/child
264 In [10]: cd parent/child
265 /home/tsuser/parent/child
265 /home/tsuser/parent/child
266 """
266 """
267
267
268 oldcwd = os.getcwdu()
268 oldcwd = os.getcwdu()
269 numcd = re.match(r'(-)(\d+)$',parameter_s)
269 numcd = re.match(r'(-)(\d+)$',parameter_s)
270 # jump in directory history by number
270 # jump in directory history by number
271 if numcd:
271 if numcd:
272 nn = int(numcd.group(2))
272 nn = int(numcd.group(2))
273 try:
273 try:
274 ps = self.shell.user_ns['_dh'][nn]
274 ps = self.shell.user_ns['_dh'][nn]
275 except IndexError:
275 except IndexError:
276 print 'The requested directory does not exist in history.'
276 print 'The requested directory does not exist in history.'
277 return
277 return
278 else:
278 else:
279 opts = {}
279 opts = {}
280 elif parameter_s.startswith('--'):
280 elif parameter_s.startswith('--'):
281 ps = None
281 ps = None
282 fallback = None
282 fallback = None
283 pat = parameter_s[2:]
283 pat = parameter_s[2:]
284 dh = self.shell.user_ns['_dh']
284 dh = self.shell.user_ns['_dh']
285 # first search only by basename (last component)
285 # first search only by basename (last component)
286 for ent in reversed(dh):
286 for ent in reversed(dh):
287 if pat in os.path.basename(ent) and os.path.isdir(ent):
287 if pat in os.path.basename(ent) and os.path.isdir(ent):
288 ps = ent
288 ps = ent
289 break
289 break
290
290
291 if fallback is None and pat in ent and os.path.isdir(ent):
291 if fallback is None and pat in ent and os.path.isdir(ent):
292 fallback = ent
292 fallback = ent
293
293
294 # if we have no last part match, pick the first full path match
294 # if we have no last part match, pick the first full path match
295 if ps is None:
295 if ps is None:
296 ps = fallback
296 ps = fallback
297
297
298 if ps is None:
298 if ps is None:
299 print "No matching entry in directory history"
299 print "No matching entry in directory history"
300 return
300 return
301 else:
301 else:
302 opts = {}
302 opts = {}
303
303
304
304
305 else:
305 else:
306 #turn all non-space-escaping backslashes to slashes,
306 #turn all non-space-escaping backslashes to slashes,
307 # for c:\windows\directory\names\
307 # for c:\windows\directory\names\
308 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
308 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
309 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
309 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
310 # jump to previous
310 # jump to previous
311 if ps == '-':
311 if ps == '-':
312 try:
312 try:
313 ps = self.shell.user_ns['_dh'][-2]
313 ps = self.shell.user_ns['_dh'][-2]
314 except IndexError:
314 except IndexError:
315 raise UsageError('%cd -: No previous directory to change to.')
315 raise UsageError('%cd -: No previous directory to change to.')
316 # jump to bookmark if needed
316 # jump to bookmark if needed
317 else:
317 else:
318 if not os.path.isdir(ps) or 'b' in opts:
318 if not os.path.isdir(ps) or 'b' in opts:
319 bkms = self.shell.db.get('bookmarks', {})
319 bkms = self.shell.db.get('bookmarks', {})
320
320
321 if ps in bkms:
321 if ps in bkms:
322 target = bkms[ps]
322 target = bkms[ps]
323 print '(bookmark:%s) -> %s' % (ps, target)
323 print '(bookmark:%s) -> %s' % (ps, target)
324 ps = target
324 ps = target
325 else:
325 else:
326 if 'b' in opts:
326 if 'b' in opts:
327 raise UsageError("Bookmark '%s' not found. "
327 raise UsageError("Bookmark '%s' not found. "
328 "Use '%%bookmark -l' to see your bookmarks." % ps)
328 "Use '%%bookmark -l' to see your bookmarks." % ps)
329
329
330 # strip extra quotes on Windows, because os.chdir doesn't like them
330 # strip extra quotes on Windows, because os.chdir doesn't like them
331 ps = unquote_filename(ps)
331 ps = unquote_filename(ps)
332 # at this point ps should point to the target dir
332 # at this point ps should point to the target dir
333 if ps:
333 if ps:
334 try:
334 try:
335 os.chdir(os.path.expanduser(ps))
335 os.chdir(os.path.expanduser(ps))
336 if hasattr(self.shell, 'term_title') and self.shell.term_title:
336 if hasattr(self.shell, 'term_title') and self.shell.term_title:
337 set_term_title('IPython: ' + abbrev_cwd())
337 set_term_title('IPython: ' + abbrev_cwd())
338 except OSError:
338 except OSError:
339 print sys.exc_info()[1]
339 print sys.exc_info()[1]
340 else:
340 else:
341 cwd = os.getcwdu()
341 cwd = os.getcwdu()
342 dhist = self.shell.user_ns['_dh']
342 dhist = self.shell.user_ns['_dh']
343 if oldcwd != cwd:
343 if oldcwd != cwd:
344 dhist.append(cwd)
344 dhist.append(cwd)
345 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
345 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
346
346
347 else:
347 else:
348 os.chdir(self.shell.home_dir)
348 os.chdir(self.shell.home_dir)
349 if hasattr(self.shell, 'term_title') and self.shell.term_title:
349 if hasattr(self.shell, 'term_title') and self.shell.term_title:
350 set_term_title('IPython: ' + '~')
350 set_term_title('IPython: ' + '~')
351 cwd = os.getcwdu()
351 cwd = os.getcwdu()
352 dhist = self.shell.user_ns['_dh']
352 dhist = self.shell.user_ns['_dh']
353
353
354 if oldcwd != cwd:
354 if oldcwd != cwd:
355 dhist.append(cwd)
355 dhist.append(cwd)
356 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
356 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
357 if not 'q' in opts and self.shell.user_ns['_dh']:
357 if not 'q' in opts and self.shell.user_ns['_dh']:
358 print self.shell.user_ns['_dh'][-1]
358 print self.shell.user_ns['_dh'][-1]
359
359
360
360
361 @line_magic
361 @line_magic
362 def env(self, parameter_s=''):
362 def env(self, parameter_s=''):
363 """List environment variables."""
363 """List environment variables."""
364
364
365 return dict(os.environ)
365 return dict(os.environ)
366
366
367 @line_magic
367 @line_magic
368 def pushd(self, parameter_s=''):
368 def pushd(self, parameter_s=''):
369 """Place the current dir on stack and change directory.
369 """Place the current dir on stack and change directory.
370
370
371 Usage:\\
371 Usage:\\
372 %pushd ['dirname']
372 %pushd ['dirname']
373 """
373 """
374
374
375 dir_s = self.shell.dir_stack
375 dir_s = self.shell.dir_stack
376 tgt = os.path.expanduser(unquote_filename(parameter_s))
376 tgt = os.path.expanduser(unquote_filename(parameter_s))
377 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
377 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
378 if tgt:
378 if tgt:
379 self.cd(parameter_s)
379 self.cd(parameter_s)
380 dir_s.insert(0,cwd)
380 dir_s.insert(0,cwd)
381 return self.shell.magic('dirs')
381 return self.shell.magic('dirs')
382
382
383 @line_magic
383 @line_magic
384 def popd(self, parameter_s=''):
384 def popd(self, parameter_s=''):
385 """Change to directory popped off the top of the stack.
385 """Change to directory popped off the top of the stack.
386 """
386 """
387 if not self.shell.dir_stack:
387 if not self.shell.dir_stack:
388 raise UsageError("%popd on empty stack")
388 raise UsageError("%popd on empty stack")
389 top = self.shell.dir_stack.pop(0)
389 top = self.shell.dir_stack.pop(0)
390 self.cd(top)
390 self.cd(top)
391 print "popd ->",top
391 print "popd ->",top
392
392
393 @line_magic
393 @line_magic
394 def dirs(self, parameter_s=''):
394 def dirs(self, parameter_s=''):
395 """Return the current directory stack."""
395 """Return the current directory stack."""
396
396
397 return self.shell.dir_stack
397 return self.shell.dir_stack
398
398
399 @line_magic
399 @line_magic
400 def dhist(self, parameter_s=''):
400 def dhist(self, parameter_s=''):
401 """Print your history of visited directories.
401 """Print your history of visited directories.
402
402
403 %dhist -> print full history\\
403 %dhist -> print full history\\
404 %dhist n -> print last n entries only\\
404 %dhist n -> print last n entries only\\
405 %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\
405 %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\
406
406
407 This history is automatically maintained by the %cd command, and
407 This history is automatically maintained by the %cd command, and
408 always available as the global list variable _dh. You can use %cd -<n>
408 always available as the global list variable _dh. You can use %cd -<n>
409 to go to directory number <n>.
409 to go to directory number <n>.
410
410
411 Note that most of time, you should view directory history by entering
411 Note that most of time, you should view directory history by entering
412 cd -<TAB>.
412 cd -<TAB>.
413
413
414 """
414 """
415
415
416 dh = self.shell.user_ns['_dh']
416 dh = self.shell.user_ns['_dh']
417 if parameter_s:
417 if parameter_s:
418 try:
418 try:
419 args = map(int,parameter_s.split())
419 args = map(int,parameter_s.split())
420 except:
420 except:
421 self.arg_err(self.dhist)
421 self.arg_err(self.dhist)
422 return
422 return
423 if len(args) == 1:
423 if len(args) == 1:
424 ini,fin = max(len(dh)-(args[0]),0),len(dh)
424 ini,fin = max(len(dh)-(args[0]),0),len(dh)
425 elif len(args) == 2:
425 elif len(args) == 2:
426 ini,fin = args
426 ini,fin = args
427 else:
427 else:
428 self.arg_err(self.dhist)
428 self.arg_err(self.dhist)
429 return
429 return
430 else:
430 else:
431 ini,fin = 0,len(dh)
431 ini,fin = 0,len(dh)
432 nlprint(dh,
432 nlprint(dh,
433 header = 'Directory history (kept in _dh)',
433 header = 'Directory history (kept in _dh)',
434 start=ini,stop=fin)
434 start=ini,stop=fin)
435
435
436 @skip_doctest
436 @skip_doctest
437 @line_magic
437 @line_magic
438 def sc(self, parameter_s=''):
438 def sc(self, parameter_s=''):
439 """Shell capture - run shell command and capture output (DEPRECATED use !).
439 """Shell capture - run shell command and capture output (DEPRECATED use !).
440
440
441 DEPRECATED. Suboptimal, retained for backwards compatibility.
441 DEPRECATED. Suboptimal, retained for backwards compatibility.
442
442
443 You should use the form 'var = !command' instead. Example:
443 You should use the form 'var = !command' instead. Example:
444
444
445 "%sc -l myfiles = ls ~" should now be written as
445 "%sc -l myfiles = ls ~" should now be written as
446
446
447 "myfiles = !ls ~"
447 "myfiles = !ls ~"
448
448
449 myfiles.s, myfiles.l and myfiles.n still apply as documented
449 myfiles.s, myfiles.l and myfiles.n still apply as documented
450 below.
450 below.
451
451
452 --
452 --
453 %sc [options] varname=command
453 %sc [options] varname=command
454
454
455 IPython will run the given command using commands.getoutput(), and
455 IPython will run the given command using commands.getoutput(), and
456 will then update the user's interactive namespace with a variable
456 will then update the user's interactive namespace with a variable
457 called varname, containing the value of the call. Your command can
457 called varname, containing the value of the call. Your command can
458 contain shell wildcards, pipes, etc.
458 contain shell wildcards, pipes, etc.
459
459
460 The '=' sign in the syntax is mandatory, and the variable name you
460 The '=' sign in the syntax is mandatory, and the variable name you
461 supply must follow Python's standard conventions for valid names.
461 supply must follow Python's standard conventions for valid names.
462
462
463 (A special format without variable name exists for internal use)
463 (A special format without variable name exists for internal use)
464
464
465 Options:
465 Options:
466
466
467 -l: list output. Split the output on newlines into a list before
467 -l: list output. Split the output on newlines into a list before
468 assigning it to the given variable. By default the output is stored
468 assigning it to the given variable. By default the output is stored
469 as a single string.
469 as a single string.
470
470
471 -v: verbose. Print the contents of the variable.
471 -v: verbose. Print the contents of the variable.
472
472
473 In most cases you should not need to split as a list, because the
473 In most cases you should not need to split as a list, because the
474 returned value is a special type of string which can automatically
474 returned value is a special type of string which can automatically
475 provide its contents either as a list (split on newlines) or as a
475 provide its contents either as a list (split on newlines) or as a
476 space-separated string. These are convenient, respectively, either
476 space-separated string. These are convenient, respectively, either
477 for sequential processing or to be passed to a shell command.
477 for sequential processing or to be passed to a shell command.
478
478
479 For example::
479 For example::
480
480
481 # Capture into variable a
481 # Capture into variable a
482 In [1]: sc a=ls *py
482 In [1]: sc a=ls *py
483
483
484 # a is a string with embedded newlines
484 # a is a string with embedded newlines
485 In [2]: a
485 In [2]: a
486 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
486 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
487
487
488 # which can be seen as a list:
488 # which can be seen as a list:
489 In [3]: a.l
489 In [3]: a.l
490 Out[3]: ['setup.py', 'win32_manual_post_install.py']
490 Out[3]: ['setup.py', 'win32_manual_post_install.py']
491
491
492 # or as a whitespace-separated string:
492 # or as a whitespace-separated string:
493 In [4]: a.s
493 In [4]: a.s
494 Out[4]: 'setup.py win32_manual_post_install.py'
494 Out[4]: 'setup.py win32_manual_post_install.py'
495
495
496 # a.s is useful to pass as a single command line:
496 # a.s is useful to pass as a single command line:
497 In [5]: !wc -l $a.s
497 In [5]: !wc -l $a.s
498 146 setup.py
498 146 setup.py
499 130 win32_manual_post_install.py
499 130 win32_manual_post_install.py
500 276 total
500 276 total
501
501
502 # while the list form is useful to loop over:
502 # while the list form is useful to loop over:
503 In [6]: for f in a.l:
503 In [6]: for f in a.l:
504 ...: !wc -l $f
504 ...: !wc -l $f
505 ...:
505 ...:
506 146 setup.py
506 146 setup.py
507 130 win32_manual_post_install.py
507 130 win32_manual_post_install.py
508
508
509 Similarly, the lists returned by the -l option are also special, in
509 Similarly, the lists returned by the -l option are also special, in
510 the sense that you can equally invoke the .s attribute on them to
510 the sense that you can equally invoke the .s attribute on them to
511 automatically get a whitespace-separated string from their contents::
511 automatically get a whitespace-separated string from their contents::
512
512
513 In [7]: sc -l b=ls *py
513 In [7]: sc -l b=ls *py
514
514
515 In [8]: b
515 In [8]: b
516 Out[8]: ['setup.py', 'win32_manual_post_install.py']
516 Out[8]: ['setup.py', 'win32_manual_post_install.py']
517
517
518 In [9]: b.s
518 In [9]: b.s
519 Out[9]: 'setup.py win32_manual_post_install.py'
519 Out[9]: 'setup.py win32_manual_post_install.py'
520
520
521 In summary, both the lists and strings used for output capture have
521 In summary, both the lists and strings used for output capture have
522 the following special attributes::
522 the following special attributes::
523
523
524 .l (or .list) : value as list.
524 .l (or .list) : value as list.
525 .n (or .nlstr): value as newline-separated string.
525 .n (or .nlstr): value as newline-separated string.
526 .s (or .spstr): value as space-separated string.
526 .s (or .spstr): value as space-separated string.
527 """
527 """
528
528
529 opts,args = self.parse_options(parameter_s, 'lv')
529 opts,args = self.parse_options(parameter_s, 'lv')
530 # Try to get a variable name and command to run
530 # Try to get a variable name and command to run
531 try:
531 try:
532 # the variable name must be obtained from the parse_options
532 # the variable name must be obtained from the parse_options
533 # output, which uses shlex.split to strip options out.
533 # output, which uses shlex.split to strip options out.
534 var,_ = args.split('=', 1)
534 var,_ = args.split('=', 1)
535 var = var.strip()
535 var = var.strip()
536 # But the command has to be extracted from the original input
536 # But the command has to be extracted from the original input
537 # parameter_s, not on what parse_options returns, to avoid the
537 # parameter_s, not on what parse_options returns, to avoid the
538 # quote stripping which shlex.split performs on it.
538 # quote stripping which shlex.split performs on it.
539 _,cmd = parameter_s.split('=', 1)
539 _,cmd = parameter_s.split('=', 1)
540 except ValueError:
540 except ValueError:
541 var,cmd = '',''
541 var,cmd = '',''
542 # If all looks ok, proceed
542 # If all looks ok, proceed
543 split = 'l' in opts
543 split = 'l' in opts
544 out = self.shell.getoutput(cmd, split=split)
544 out = self.shell.getoutput(cmd, split=split)
545 if 'v' in opts:
545 if 'v' in opts:
546 print '%s ==\n%s' % (var, pformat(out))
546 print '%s ==\n%s' % (var, pformat(out))
547 if var:
547 if var:
548 self.shell.user_ns.update({var:out})
548 self.shell.user_ns.update({var:out})
549 else:
549 else:
550 return out
550 return out
551
551
552 @line_cell_magic
552 @line_cell_magic
553 def sx(self, line='', cell=None):
553 def sx(self, line='', cell=None):
554 """Shell execute - run shell command and capture output (!! is short-hand).
554 """Shell execute - run shell command and capture output (!! is short-hand).
555
555
556 %sx command
556 %sx command
557
557
558 IPython will run the given command using commands.getoutput(), and
558 IPython will run the given command using commands.getoutput(), and
559 return the result formatted as a list (split on '\\n'). Since the
559 return the result formatted as a list (split on '\\n'). Since the
560 output is _returned_, it will be stored in ipython's regular output
560 output is _returned_, it will be stored in ipython's regular output
561 cache Out[N] and in the '_N' automatic variables.
561 cache Out[N] and in the '_N' automatic variables.
562
562
563 Notes:
563 Notes:
564
564
565 1) If an input line begins with '!!', then %sx is automatically
565 1) If an input line begins with '!!', then %sx is automatically
566 invoked. That is, while::
566 invoked. That is, while::
567
567
568 !ls
568 !ls
569
569
570 causes ipython to simply issue system('ls'), typing::
570 causes ipython to simply issue system('ls'), typing::
571
571
572 !!ls
572 !!ls
573
573
574 is a shorthand equivalent to::
574 is a shorthand equivalent to::
575
575
576 %sx ls
576 %sx ls
577
577
578 2) %sx differs from %sc in that %sx automatically splits into a list,
578 2) %sx differs from %sc in that %sx automatically splits into a list,
579 like '%sc -l'. The reason for this is to make it as easy as possible
579 like '%sc -l'. The reason for this is to make it as easy as possible
580 to process line-oriented shell output via further python commands.
580 to process line-oriented shell output via further python commands.
581 %sc is meant to provide much finer control, but requires more
581 %sc is meant to provide much finer control, but requires more
582 typing.
582 typing.
583
583
584 3) Just like %sc -l, this is a list with special attributes:
584 3) Just like %sc -l, this is a list with special attributes:
585 ::
585 ::
586
586
587 .l (or .list) : value as list.
587 .l (or .list) : value as list.
588 .n (or .nlstr): value as newline-separated string.
588 .n (or .nlstr): value as newline-separated string.
589 .s (or .spstr): value as whitespace-separated string.
589 .s (or .spstr): value as whitespace-separated string.
590
590
591 This is very useful when trying to use such lists as arguments to
591 This is very useful when trying to use such lists as arguments to
592 system commands."""
592 system commands."""
593
593
594 if cell is None:
594 if cell is None:
595 # line magic
595 # line magic
596 return self.shell.getoutput(line)
596 return self.shell.getoutput(line)
597 else:
597 else:
598 opts,args = self.parse_options(line, '', 'out=')
598 opts,args = self.parse_options(line, '', 'out=')
599 output = self.shell.getoutput(cell)
599 output = self.shell.getoutput(cell)
600 out_name = opts.get('out', opts.get('o'))
600 out_name = opts.get('out', opts.get('o'))
601 if out_name:
601 if out_name:
602 self.shell.user_ns[out_name] = output
602 self.shell.user_ns[out_name] = output
603 else:
603 else:
604 return output
604 return output
605
605
606 system = line_cell_magic('system')(sx)
606 system = line_cell_magic('system')(sx)
607 bang = cell_magic('!')(sx)
607 bang = cell_magic('!')(sx)
608
608
609 @line_magic
609 @line_magic
610 def bookmark(self, parameter_s=''):
610 def bookmark(self, parameter_s=''):
611 """Manage IPython's bookmark system.
611 """Manage IPython's bookmark system.
612
612
613 %bookmark <name> - set bookmark to current dir
613 %bookmark <name> - set bookmark to current dir
614 %bookmark <name> <dir> - set bookmark to <dir>
614 %bookmark <name> <dir> - set bookmark to <dir>
615 %bookmark -l - list all bookmarks
615 %bookmark -l - list all bookmarks
616 %bookmark -d <name> - remove bookmark
616 %bookmark -d <name> - remove bookmark
617 %bookmark -r - remove all bookmarks
617 %bookmark -r - remove all bookmarks
618
618
619 You can later on access a bookmarked folder with::
619 You can later on access a bookmarked folder with::
620
620
621 %cd -b <name>
621 %cd -b <name>
622
622
623 or simply '%cd <name>' if there is no directory called <name> AND
623 or simply '%cd <name>' if there is no directory called <name> AND
624 there is such a bookmark defined.
624 there is such a bookmark defined.
625
625
626 Your bookmarks persist through IPython sessions, but they are
626 Your bookmarks persist through IPython sessions, but they are
627 associated with each profile."""
627 associated with each profile."""
628
628
629 opts,args = self.parse_options(parameter_s,'drl',mode='list')
629 opts,args = self.parse_options(parameter_s,'drl',mode='list')
630 if len(args) > 2:
630 if len(args) > 2:
631 raise UsageError("%bookmark: too many arguments")
631 raise UsageError("%bookmark: too many arguments")
632
632
633 bkms = self.shell.db.get('bookmarks',{})
633 bkms = self.shell.db.get('bookmarks',{})
634
634
635 if 'd' in opts:
635 if 'd' in opts:
636 try:
636 try:
637 todel = args[0]
637 todel = args[0]
638 except IndexError:
638 except IndexError:
639 raise UsageError(
639 raise UsageError(
640 "%bookmark -d: must provide a bookmark to delete")
640 "%bookmark -d: must provide a bookmark to delete")
641 else:
641 else:
642 try:
642 try:
643 del bkms[todel]
643 del bkms[todel]
644 except KeyError:
644 except KeyError:
645 raise UsageError(
645 raise UsageError(
646 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
646 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
647
647
648 elif 'r' in opts:
648 elif 'r' in opts:
649 bkms = {}
649 bkms = {}
650 elif 'l' in opts:
650 elif 'l' in opts:
651 bks = bkms.keys()
651 bks = bkms.keys()
652 bks.sort()
652 bks.sort()
653 if bks:
653 if bks:
654 size = max(map(len, bks))
654 size = max(map(len, bks))
655 else:
655 else:
656 size = 0
656 size = 0
657 fmt = '%-'+str(size)+'s -> %s'
657 fmt = '%-'+str(size)+'s -> %s'
658 print 'Current bookmarks:'
658 print 'Current bookmarks:'
659 for bk in bks:
659 for bk in bks:
660 print fmt % (bk, bkms[bk])
660 print fmt % (bk, bkms[bk])
661 else:
661 else:
662 if not args:
662 if not args:
663 raise UsageError("%bookmark: You must specify the bookmark name")
663 raise UsageError("%bookmark: You must specify the bookmark name")
664 elif len(args)==1:
664 elif len(args)==1:
665 bkms[args[0]] = os.getcwdu()
665 bkms[args[0]] = os.getcwdu()
666 elif len(args)==2:
666 elif len(args)==2:
667 bkms[args[0]] = args[1]
667 bkms[args[0]] = args[1]
668 self.shell.db['bookmarks'] = bkms
668 self.shell.db['bookmarks'] = bkms
669
669
670 @line_magic
670 @line_magic
671 def pycat(self, parameter_s=''):
671 def pycat(self, parameter_s=''):
672 """Show a syntax-highlighted file through a pager.
672 """Show a syntax-highlighted file through a pager.
673
673
674 This magic is similar to the cat utility, but it will assume the file
674 This magic is similar to the cat utility, but it will assume the file
675 to be Python source and will show it with syntax highlighting.
675 to be Python source and will show it with syntax highlighting.
676
676
677 This magic command can either take a local filename, an url,
677 This magic command can either take a local filename, an url,
678 an history range (see %history) or a macro as argument ::
678 an history range (see %history) or a macro as argument ::
679
679
680 %pycat myscript.py
680 %pycat myscript.py
681 %pycat 7-27
681 %pycat 7-27
682 %pycat myMacro
682 %pycat myMacro
683 %pycat http://www.example.com/myscript.py
683 %pycat http://www.example.com/myscript.py
684 """
684 """
685 if not parameter_s:
685 if not parameter_s:
686 raise UsageError('Missing filename, URL, input history range, '
686 raise UsageError('Missing filename, URL, input history range, '
687 'or macro.')
687 'or macro.')
688
688
689 try :
689 try :
690 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
690 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
691 except (ValueError, IOError):
691 except (ValueError, IOError):
692 print "Error: no such file, variable, URL, history range or macro"
692 print "Error: no such file, variable, URL, history range or macro"
693 return
693 return
694
694
695 page.page(self.shell.pycolorize(source_to_unicode(cont)))
695 page.page(self.shell.pycolorize(source_to_unicode(cont)))
696
696
697 @magic_arguments.magic_arguments()
697 @magic_arguments.magic_arguments()
698 @magic_arguments.argument(
698 @magic_arguments.argument(
699 '-a', '--amend', action='store_true', default=False,
699 '-a', '--amend', action='store_true', default=False,
700 help='Open file for amending if it exists'
700 help='Open file for amending if it exists'
701 )
701 )
702 @magic_arguments.argument(
702 @magic_arguments.argument(
703 'filename', type=unicode,
703 'filename', type=unicode,
704 help='file to write'
704 help='file to write'
705 )
705 )
706 @cell_magic
706 @cell_magic
707 def file(self, line, cell):
707 def file(self, line, cell):
708 """Write the contents of the cell to a file.
708 """Write the contents of the cell to a file.
709
709
710 For frontends that do not support stdin (Notebook), -f is implied.
710 For frontends that do not support stdin (Notebook), -f is implied.
711 """
711 """
712 args = magic_arguments.parse_argstring(self.file, line)
712 args = magic_arguments.parse_argstring(self.file, line)
713 filename = unquote_filename(args.filename)
713 filename = unquote_filename(args.filename)
714
714
715 if os.path.exists(filename):
715 if os.path.exists(filename):
716 if args.amend:
716 if args.amend:
717 print "Amending to %s" % filename
717 print "Amending to %s" % filename
718 else:
718 else:
719 print "Overwriting %s" % filename
719 print "Overwriting %s" % filename
720 else:
720 else:
721 print "Writing %s" % filename
721 print "Writing %s" % filename
722
722
723 mode = 'a' if args.amend else 'w'
723 mode = 'a' if args.amend else 'w'
724 with io.open(filename, mode, encoding='utf-8') as f:
724 with io.open(filename, mode, encoding='utf-8') as f:
725 f.write(cell)
725 f.write(cell)
@@ -1,283 +1,280 b''
1 """Magic functions for running cells in various scripts."""
1 """Magic functions for running cells in various scripts."""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2012 The IPython Development Team.
3 # Copyright (c) 2012 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 # Stdlib
14 # Stdlib
15 import errno
15 import errno
16 import os
16 import os
17 import re
18 import sys
17 import sys
19 import signal
18 import signal
20 import time
19 import time
21 from subprocess import Popen, PIPE
20 from subprocess import Popen, PIPE
22 import atexit
21 import atexit
23
22
24 # Our own packages
23 # Our own packages
25 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
26 from IPython.core import magic_arguments
25 from IPython.core import magic_arguments
27 from IPython.core.error import UsageError
28 from IPython.core.magic import (
26 from IPython.core.magic import (
29 Magics, magics_class, line_magic, cell_magic
27 Magics, magics_class, line_magic, cell_magic
30 )
28 )
31 from IPython.lib.backgroundjobs import BackgroundJobManager
29 from IPython.lib.backgroundjobs import BackgroundJobManager
32 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.utils import py3compat
30 from IPython.utils import py3compat
34 from IPython.utils.process import arg_split
31 from IPython.utils.process import arg_split
35 from IPython.utils.traitlets import List, Dict
32 from IPython.utils.traitlets import List, Dict
36
33
37 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
38 # Magic implementation classes
35 # Magic implementation classes
39 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
40
37
41 def script_args(f):
38 def script_args(f):
42 """single decorator for adding script args"""
39 """single decorator for adding script args"""
43 args = [
40 args = [
44 magic_arguments.argument(
41 magic_arguments.argument(
45 '--out', type=str,
42 '--out', type=str,
46 help="""The variable in which to store stdout from the script.
43 help="""The variable in which to store stdout from the script.
47 If the script is backgrounded, this will be the stdout *pipe*,
44 If the script is backgrounded, this will be the stdout *pipe*,
48 instead of the stderr text itself.
45 instead of the stderr text itself.
49 """
46 """
50 ),
47 ),
51 magic_arguments.argument(
48 magic_arguments.argument(
52 '--err', type=str,
49 '--err', type=str,
53 help="""The variable in which to store stderr from the script.
50 help="""The variable in which to store stderr from the script.
54 If the script is backgrounded, this will be the stderr *pipe*,
51 If the script is backgrounded, this will be the stderr *pipe*,
55 instead of the stderr text itself.
52 instead of the stderr text itself.
56 """
53 """
57 ),
54 ),
58 magic_arguments.argument(
55 magic_arguments.argument(
59 '--bg', action="store_true",
56 '--bg', action="store_true",
60 help="""Whether to run the script in the background.
57 help="""Whether to run the script in the background.
61 If given, the only way to see the output of the command is
58 If given, the only way to see the output of the command is
62 with --out/err.
59 with --out/err.
63 """
60 """
64 ),
61 ),
65 magic_arguments.argument(
62 magic_arguments.argument(
66 '--proc', type=str,
63 '--proc', type=str,
67 help="""The variable in which to store Popen instance.
64 help="""The variable in which to store Popen instance.
68 This is used only when --bg option is given.
65 This is used only when --bg option is given.
69 """
66 """
70 ),
67 ),
71 ]
68 ]
72 for arg in args:
69 for arg in args:
73 f = arg(f)
70 f = arg(f)
74 return f
71 return f
75
72
76 @magics_class
73 @magics_class
77 class ScriptMagics(Magics, Configurable):
74 class ScriptMagics(Magics, Configurable):
78 """Magics for talking to scripts
75 """Magics for talking to scripts
79
76
80 This defines a base `%%script` cell magic for running a cell
77 This defines a base `%%script` cell magic for running a cell
81 with a program in a subprocess, and registers a few top-level
78 with a program in a subprocess, and registers a few top-level
82 magics that call %%script with common interpreters.
79 magics that call %%script with common interpreters.
83 """
80 """
84 script_magics = List(config=True,
81 script_magics = List(config=True,
85 help="""Extra script cell magics to define
82 help="""Extra script cell magics to define
86
83
87 This generates simple wrappers of `%%script foo` as `%%foo`.
84 This generates simple wrappers of `%%script foo` as `%%foo`.
88
85
89 If you want to add script magics that aren't on your path,
86 If you want to add script magics that aren't on your path,
90 specify them in script_paths
87 specify them in script_paths
91 """,
88 """,
92 )
89 )
93 def _script_magics_default(self):
90 def _script_magics_default(self):
94 """default to a common list of programs"""
91 """default to a common list of programs"""
95
92
96 defaults = [
93 defaults = [
97 'sh',
94 'sh',
98 'bash',
95 'bash',
99 'perl',
96 'perl',
100 'ruby',
97 'ruby',
101 'python',
98 'python',
102 'python3',
99 'python3',
103 'pypy',
100 'pypy',
104 ]
101 ]
105 if os.name == 'nt':
102 if os.name == 'nt':
106 defaults.extend([
103 defaults.extend([
107 'cmd',
104 'cmd',
108 'powershell',
105 'powershell',
109 ])
106 ])
110
107
111 return defaults
108 return defaults
112
109
113 script_paths = Dict(config=True,
110 script_paths = Dict(config=True,
114 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
111 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
115
112
116 Only necessary for items in script_magics where the default path will not
113 Only necessary for items in script_magics where the default path will not
117 find the right interpreter.
114 find the right interpreter.
118 """
115 """
119 )
116 )
120
117
121 def __init__(self, shell=None):
118 def __init__(self, shell=None):
122 Configurable.__init__(self, config=shell.config)
119 Configurable.__init__(self, config=shell.config)
123 self._generate_script_magics()
120 self._generate_script_magics()
124 Magics.__init__(self, shell=shell)
121 Magics.__init__(self, shell=shell)
125 self.job_manager = BackgroundJobManager()
122 self.job_manager = BackgroundJobManager()
126 self.bg_processes = []
123 self.bg_processes = []
127 atexit.register(self.kill_bg_processes)
124 atexit.register(self.kill_bg_processes)
128
125
129 def __del__(self):
126 def __del__(self):
130 self.kill_bg_processes()
127 self.kill_bg_processes()
131
128
132 def _generate_script_magics(self):
129 def _generate_script_magics(self):
133 cell_magics = self.magics['cell']
130 cell_magics = self.magics['cell']
134 for name in self.script_magics:
131 for name in self.script_magics:
135 cell_magics[name] = self._make_script_magic(name)
132 cell_magics[name] = self._make_script_magic(name)
136
133
137 def _make_script_magic(self, name):
134 def _make_script_magic(self, name):
138 """make a named magic, that calls %%script with a particular program"""
135 """make a named magic, that calls %%script with a particular program"""
139 # expand to explicit path if necessary:
136 # expand to explicit path if necessary:
140 script = self.script_paths.get(name, name)
137 script = self.script_paths.get(name, name)
141
138
142 @magic_arguments.magic_arguments()
139 @magic_arguments.magic_arguments()
143 @script_args
140 @script_args
144 def named_script_magic(line, cell):
141 def named_script_magic(line, cell):
145 # if line, add it as cl-flags
142 # if line, add it as cl-flags
146 if line:
143 if line:
147 line = "%s %s" % (script, line)
144 line = "%s %s" % (script, line)
148 else:
145 else:
149 line = script
146 line = script
150 return self.shebang(line, cell)
147 return self.shebang(line, cell)
151
148
152 # write a basic docstring:
149 # write a basic docstring:
153 named_script_magic.__doc__ = \
150 named_script_magic.__doc__ = \
154 """%%{name} script magic
151 """%%{name} script magic
155
152
156 Run cells with {script} in a subprocess.
153 Run cells with {script} in a subprocess.
157
154
158 This is a shortcut for `%%script {script}`
155 This is a shortcut for `%%script {script}`
159 """.format(**locals())
156 """.format(**locals())
160
157
161 return named_script_magic
158 return named_script_magic
162
159
163 @magic_arguments.magic_arguments()
160 @magic_arguments.magic_arguments()
164 @script_args
161 @script_args
165 @cell_magic("script")
162 @cell_magic("script")
166 def shebang(self, line, cell):
163 def shebang(self, line, cell):
167 """Run a cell via a shell command
164 """Run a cell via a shell command
168
165
169 The `%%script` line is like the #! line of script,
166 The `%%script` line is like the #! line of script,
170 specifying a program (bash, perl, ruby, etc.) with which to run.
167 specifying a program (bash, perl, ruby, etc.) with which to run.
171
168
172 The rest of the cell is run by that program.
169 The rest of the cell is run by that program.
173
170
174 Examples
171 Examples
175 --------
172 --------
176 ::
173 ::
177
174
178 In [1]: %%script bash
175 In [1]: %%script bash
179 ...: for i in 1 2 3; do
176 ...: for i in 1 2 3; do
180 ...: echo $i
177 ...: echo $i
181 ...: done
178 ...: done
182 1
179 1
183 2
180 2
184 3
181 3
185 """
182 """
186 argv = arg_split(line, posix = not sys.platform.startswith('win'))
183 argv = arg_split(line, posix = not sys.platform.startswith('win'))
187 args, cmd = self.shebang.parser.parse_known_args(argv)
184 args, cmd = self.shebang.parser.parse_known_args(argv)
188
185
189 try:
186 try:
190 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
187 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
191 except OSError as e:
188 except OSError as e:
192 if e.errno == errno.ENOENT:
189 if e.errno == errno.ENOENT:
193 print "Couldn't find program: %r" % cmd[0]
190 print "Couldn't find program: %r" % cmd[0]
194 return
191 return
195 else:
192 else:
196 raise
193 raise
197
194
198 cell = cell.encode('utf8', 'replace')
195 cell = cell.encode('utf8', 'replace')
199 if args.bg:
196 if args.bg:
200 self.bg_processes.append(p)
197 self.bg_processes.append(p)
201 self._gc_bg_processes()
198 self._gc_bg_processes()
202 if args.out:
199 if args.out:
203 self.shell.user_ns[args.out] = p.stdout
200 self.shell.user_ns[args.out] = p.stdout
204 if args.err:
201 if args.err:
205 self.shell.user_ns[args.err] = p.stderr
202 self.shell.user_ns[args.err] = p.stderr
206 self.job_manager.new(self._run_script, p, cell, daemon=True)
203 self.job_manager.new(self._run_script, p, cell, daemon=True)
207 if args.proc:
204 if args.proc:
208 self.shell.user_ns[args.proc] = p
205 self.shell.user_ns[args.proc] = p
209 return
206 return
210
207
211 try:
208 try:
212 out, err = p.communicate(cell)
209 out, err = p.communicate(cell)
213 except KeyboardInterrupt:
210 except KeyboardInterrupt:
214 try:
211 try:
215 p.send_signal(signal.SIGINT)
212 p.send_signal(signal.SIGINT)
216 time.sleep(0.1)
213 time.sleep(0.1)
217 if p.poll() is not None:
214 if p.poll() is not None:
218 print "Process is interrupted."
215 print "Process is interrupted."
219 return
216 return
220 p.terminate()
217 p.terminate()
221 time.sleep(0.1)
218 time.sleep(0.1)
222 if p.poll() is not None:
219 if p.poll() is not None:
223 print "Process is terminated."
220 print "Process is terminated."
224 return
221 return
225 p.kill()
222 p.kill()
226 print "Process is killed."
223 print "Process is killed."
227 except OSError:
224 except OSError:
228 pass
225 pass
229 except Exception as e:
226 except Exception as e:
230 print "Error while terminating subprocess (pid=%i): %s" \
227 print "Error while terminating subprocess (pid=%i): %s" \
231 % (p.pid, e)
228 % (p.pid, e)
232 return
229 return
233 out = py3compat.bytes_to_str(out)
230 out = py3compat.bytes_to_str(out)
234 err = py3compat.bytes_to_str(err)
231 err = py3compat.bytes_to_str(err)
235 if args.out:
232 if args.out:
236 self.shell.user_ns[args.out] = out
233 self.shell.user_ns[args.out] = out
237 else:
234 else:
238 sys.stdout.write(out)
235 sys.stdout.write(out)
239 sys.stdout.flush()
236 sys.stdout.flush()
240 if args.err:
237 if args.err:
241 self.shell.user_ns[args.err] = err
238 self.shell.user_ns[args.err] = err
242 else:
239 else:
243 sys.stderr.write(err)
240 sys.stderr.write(err)
244 sys.stderr.flush()
241 sys.stderr.flush()
245
242
246 def _run_script(self, p, cell):
243 def _run_script(self, p, cell):
247 """callback for running the script in the background"""
244 """callback for running the script in the background"""
248 p.stdin.write(cell)
245 p.stdin.write(cell)
249 p.stdin.close()
246 p.stdin.close()
250 p.wait()
247 p.wait()
251
248
252 @line_magic("killbgscripts")
249 @line_magic("killbgscripts")
253 def killbgscripts(self, _nouse_=''):
250 def killbgscripts(self, _nouse_=''):
254 """Kill all BG processes started by %%script and its family."""
251 """Kill all BG processes started by %%script and its family."""
255 self.kill_bg_processes()
252 self.kill_bg_processes()
256 print "All background processes were killed."
253 print "All background processes were killed."
257
254
258 def kill_bg_processes(self):
255 def kill_bg_processes(self):
259 """Kill all BG processes which are still running."""
256 """Kill all BG processes which are still running."""
260 for p in self.bg_processes:
257 for p in self.bg_processes:
261 if p.poll() is None:
258 if p.poll() is None:
262 try:
259 try:
263 p.send_signal(signal.SIGINT)
260 p.send_signal(signal.SIGINT)
264 except:
261 except:
265 pass
262 pass
266 time.sleep(0.1)
263 time.sleep(0.1)
267 for p in self.bg_processes:
264 for p in self.bg_processes:
268 if p.poll() is None:
265 if p.poll() is None:
269 try:
266 try:
270 p.terminate()
267 p.terminate()
271 except:
268 except:
272 pass
269 pass
273 time.sleep(0.1)
270 time.sleep(0.1)
274 for p in self.bg_processes:
271 for p in self.bg_processes:
275 if p.poll() is None:
272 if p.poll() is None:
276 try:
273 try:
277 p.kill()
274 p.kill()
278 except:
275 except:
279 pass
276 pass
280 self._gc_bg_processes()
277 self._gc_bg_processes()
281
278
282 def _gc_bg_processes(self):
279 def _gc_bg_processes(self):
283 self.bg_processes = [p for p in self.bg_processes if p.poll() is None]
280 self.bg_processes = [p for p in self.bg_processes if p.poll() is None]
@@ -1,349 +1,348 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9
9
10 Notes
10 Notes
11 -----
11 -----
12
12
13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
14 rid of that dependency, we could move it there.
14 rid of that dependency, we could move it there.
15 -----
15 -----
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Copyright (C) 2008-2011 The IPython Development Team
19 # Copyright (C) 2008-2011 The IPython Development Team
20 #
20 #
21 # Distributed under the terms of the BSD License. The full license is in
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Imports
26 # Imports
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 from __future__ import print_function
28 from __future__ import print_function
29
29
30 import os
30 import os
31 import re
31 import re
32 import subprocess
33 import sys
32 import sys
34 import tempfile
33 import tempfile
35
34
36 from io import UnsupportedOperation
35 from io import UnsupportedOperation
37
36
38 from IPython.core import ipapi
37 from IPython.core import ipapi
39 from IPython.core.error import TryNext
38 from IPython.core.error import TryNext
40 from IPython.utils.data import chop
39 from IPython.utils.data import chop
41 from IPython.utils import io
40 from IPython.utils import io
42 from IPython.utils.process import system
41 from IPython.utils.process import system
43 from IPython.utils.terminal import get_terminal_size
42 from IPython.utils.terminal import get_terminal_size
44 from IPython.utils import py3compat
43 from IPython.utils import py3compat
45
44
46
45
47 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
48 # Classes and functions
47 # Classes and functions
49 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
50
49
51 esc_re = re.compile(r"(\x1b[^m]+m)")
50 esc_re = re.compile(r"(\x1b[^m]+m)")
52
51
53 def page_dumb(strng, start=0, screen_lines=25):
52 def page_dumb(strng, start=0, screen_lines=25):
54 """Very dumb 'pager' in Python, for when nothing else works.
53 """Very dumb 'pager' in Python, for when nothing else works.
55
54
56 Only moves forward, same interface as page(), except for pager_cmd and
55 Only moves forward, same interface as page(), except for pager_cmd and
57 mode."""
56 mode."""
58
57
59 out_ln = strng.splitlines()[start:]
58 out_ln = strng.splitlines()[start:]
60 screens = chop(out_ln,screen_lines-1)
59 screens = chop(out_ln,screen_lines-1)
61 if len(screens) == 1:
60 if len(screens) == 1:
62 print(os.linesep.join(screens[0]), file=io.stdout)
61 print(os.linesep.join(screens[0]), file=io.stdout)
63 else:
62 else:
64 last_escape = ""
63 last_escape = ""
65 for scr in screens[0:-1]:
64 for scr in screens[0:-1]:
66 hunk = os.linesep.join(scr)
65 hunk = os.linesep.join(scr)
67 print(last_escape + hunk, file=io.stdout)
66 print(last_escape + hunk, file=io.stdout)
68 if not page_more():
67 if not page_more():
69 return
68 return
70 esc_list = esc_re.findall(hunk)
69 esc_list = esc_re.findall(hunk)
71 if len(esc_list) > 0:
70 if len(esc_list) > 0:
72 last_escape = esc_list[-1]
71 last_escape = esc_list[-1]
73 print(last_escape + os.linesep.join(screens[-1]), file=io.stdout)
72 print(last_escape + os.linesep.join(screens[-1]), file=io.stdout)
74
73
75 def _detect_screen_size(screen_lines_def):
74 def _detect_screen_size(screen_lines_def):
76 """Attempt to work out the number of lines on the screen.
75 """Attempt to work out the number of lines on the screen.
77
76
78 This is called by page(). It can raise an error (e.g. when run in the
77 This is called by page(). It can raise an error (e.g. when run in the
79 test suite), so it's separated out so it can easily be called in a try block.
78 test suite), so it's separated out so it can easily be called in a try block.
80 """
79 """
81 TERM = os.environ.get('TERM',None)
80 TERM = os.environ.get('TERM',None)
82 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
81 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
83 # curses causes problems on many terminals other than xterm, and
82 # curses causes problems on many terminals other than xterm, and
84 # some termios calls lock up on Sun OS5.
83 # some termios calls lock up on Sun OS5.
85 return screen_lines_def
84 return screen_lines_def
86
85
87 try:
86 try:
88 import termios
87 import termios
89 import curses
88 import curses
90 except ImportError:
89 except ImportError:
91 return screen_lines_def
90 return screen_lines_def
92
91
93 # There is a bug in curses, where *sometimes* it fails to properly
92 # There is a bug in curses, where *sometimes* it fails to properly
94 # initialize, and then after the endwin() call is made, the
93 # initialize, and then after the endwin() call is made, the
95 # terminal is left in an unusable state. Rather than trying to
94 # terminal is left in an unusable state. Rather than trying to
96 # check everytime for this (by requesting and comparing termios
95 # check everytime for this (by requesting and comparing termios
97 # flags each time), we just save the initial terminal state and
96 # flags each time), we just save the initial terminal state and
98 # unconditionally reset it every time. It's cheaper than making
97 # unconditionally reset it every time. It's cheaper than making
99 # the checks.
98 # the checks.
100 term_flags = termios.tcgetattr(sys.stdout)
99 term_flags = termios.tcgetattr(sys.stdout)
101
100
102 # Curses modifies the stdout buffer size by default, which messes
101 # Curses modifies the stdout buffer size by default, which messes
103 # up Python's normal stdout buffering. This would manifest itself
102 # up Python's normal stdout buffering. This would manifest itself
104 # to IPython users as delayed printing on stdout after having used
103 # to IPython users as delayed printing on stdout after having used
105 # the pager.
104 # the pager.
106 #
105 #
107 # We can prevent this by manually setting the NCURSES_NO_SETBUF
106 # We can prevent this by manually setting the NCURSES_NO_SETBUF
108 # environment variable. For more details, see:
107 # environment variable. For more details, see:
109 # http://bugs.python.org/issue10144
108 # http://bugs.python.org/issue10144
110 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
109 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
111 os.environ['NCURSES_NO_SETBUF'] = ''
110 os.environ['NCURSES_NO_SETBUF'] = ''
112
111
113 # Proceed with curses initialization
112 # Proceed with curses initialization
114 try:
113 try:
115 scr = curses.initscr()
114 scr = curses.initscr()
116 except AttributeError:
115 except AttributeError:
117 # Curses on Solaris may not be complete, so we can't use it there
116 # Curses on Solaris may not be complete, so we can't use it there
118 return screen_lines_def
117 return screen_lines_def
119
118
120 screen_lines_real,screen_cols = scr.getmaxyx()
119 screen_lines_real,screen_cols = scr.getmaxyx()
121 curses.endwin()
120 curses.endwin()
122
121
123 # Restore environment
122 # Restore environment
124 if NCURSES_NO_SETBUF is None:
123 if NCURSES_NO_SETBUF is None:
125 del os.environ['NCURSES_NO_SETBUF']
124 del os.environ['NCURSES_NO_SETBUF']
126 else:
125 else:
127 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
126 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
128
127
129 # Restore terminal state in case endwin() didn't.
128 # Restore terminal state in case endwin() didn't.
130 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
129 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
131 # Now we have what we needed: the screen size in rows/columns
130 # Now we have what we needed: the screen size in rows/columns
132 return screen_lines_real
131 return screen_lines_real
133 #print '***Screen size:',screen_lines_real,'lines x',\
132 #print '***Screen size:',screen_lines_real,'lines x',\
134 #screen_cols,'columns.' # dbg
133 #screen_cols,'columns.' # dbg
135
134
136 def page(strng, start=0, screen_lines=0, pager_cmd=None):
135 def page(strng, start=0, screen_lines=0, pager_cmd=None):
137 """Print a string, piping through a pager after a certain length.
136 """Print a string, piping through a pager after a certain length.
138
137
139 The screen_lines parameter specifies the number of *usable* lines of your
138 The screen_lines parameter specifies the number of *usable* lines of your
140 terminal screen (total lines minus lines you need to reserve to show other
139 terminal screen (total lines minus lines you need to reserve to show other
141 information).
140 information).
142
141
143 If you set screen_lines to a number <=0, page() will try to auto-determine
142 If you set screen_lines to a number <=0, page() will try to auto-determine
144 your screen size and will only use up to (screen_size+screen_lines) for
143 your screen size and will only use up to (screen_size+screen_lines) for
145 printing, paging after that. That is, if you want auto-detection but need
144 printing, paging after that. That is, if you want auto-detection but need
146 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
145 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
147 auto-detection without any lines reserved simply use screen_lines = 0.
146 auto-detection without any lines reserved simply use screen_lines = 0.
148
147
149 If a string won't fit in the allowed lines, it is sent through the
148 If a string won't fit in the allowed lines, it is sent through the
150 specified pager command. If none given, look for PAGER in the environment,
149 specified pager command. If none given, look for PAGER in the environment,
151 and ultimately default to less.
150 and ultimately default to less.
152
151
153 If no system pager works, the string is sent through a 'dumb pager'
152 If no system pager works, the string is sent through a 'dumb pager'
154 written in python, very simplistic.
153 written in python, very simplistic.
155 """
154 """
156
155
157 # Some routines may auto-compute start offsets incorrectly and pass a
156 # Some routines may auto-compute start offsets incorrectly and pass a
158 # negative value. Offset to 0 for robustness.
157 # negative value. Offset to 0 for robustness.
159 start = max(0, start)
158 start = max(0, start)
160
159
161 # first, try the hook
160 # first, try the hook
162 ip = ipapi.get()
161 ip = ipapi.get()
163 if ip:
162 if ip:
164 try:
163 try:
165 ip.hooks.show_in_pager(strng)
164 ip.hooks.show_in_pager(strng)
166 return
165 return
167 except TryNext:
166 except TryNext:
168 pass
167 pass
169
168
170 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
169 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
171 TERM = os.environ.get('TERM','dumb')
170 TERM = os.environ.get('TERM','dumb')
172 if TERM in ['dumb','emacs'] and os.name != 'nt':
171 if TERM in ['dumb','emacs'] and os.name != 'nt':
173 print(strng)
172 print(strng)
174 return
173 return
175 # chop off the topmost part of the string we don't want to see
174 # chop off the topmost part of the string we don't want to see
176 str_lines = strng.splitlines()[start:]
175 str_lines = strng.splitlines()[start:]
177 str_toprint = os.linesep.join(str_lines)
176 str_toprint = os.linesep.join(str_lines)
178 num_newlines = len(str_lines)
177 num_newlines = len(str_lines)
179 len_str = len(str_toprint)
178 len_str = len(str_toprint)
180
179
181 # Dumb heuristics to guesstimate number of on-screen lines the string
180 # Dumb heuristics to guesstimate number of on-screen lines the string
182 # takes. Very basic, but good enough for docstrings in reasonable
181 # takes. Very basic, but good enough for docstrings in reasonable
183 # terminals. If someone later feels like refining it, it's not hard.
182 # terminals. If someone later feels like refining it, it's not hard.
184 numlines = max(num_newlines,int(len_str/80)+1)
183 numlines = max(num_newlines,int(len_str/80)+1)
185
184
186 screen_lines_def = get_terminal_size()[1]
185 screen_lines_def = get_terminal_size()[1]
187
186
188 # auto-determine screen size
187 # auto-determine screen size
189 if screen_lines <= 0:
188 if screen_lines <= 0:
190 try:
189 try:
191 screen_lines += _detect_screen_size(screen_lines_def)
190 screen_lines += _detect_screen_size(screen_lines_def)
192 except (TypeError, UnsupportedOperation):
191 except (TypeError, UnsupportedOperation):
193 print(str_toprint, file=io.stdout)
192 print(str_toprint, file=io.stdout)
194 return
193 return
195
194
196 #print 'numlines',numlines,'screenlines',screen_lines # dbg
195 #print 'numlines',numlines,'screenlines',screen_lines # dbg
197 if numlines <= screen_lines :
196 if numlines <= screen_lines :
198 #print '*** normal print' # dbg
197 #print '*** normal print' # dbg
199 print(str_toprint, file=io.stdout)
198 print(str_toprint, file=io.stdout)
200 else:
199 else:
201 # Try to open pager and default to internal one if that fails.
200 # Try to open pager and default to internal one if that fails.
202 # All failure modes are tagged as 'retval=1', to match the return
201 # All failure modes are tagged as 'retval=1', to match the return
203 # value of a failed system command. If any intermediate attempt
202 # value of a failed system command. If any intermediate attempt
204 # sets retval to 1, at the end we resort to our own page_dumb() pager.
203 # sets retval to 1, at the end we resort to our own page_dumb() pager.
205 pager_cmd = get_pager_cmd(pager_cmd)
204 pager_cmd = get_pager_cmd(pager_cmd)
206 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
205 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
207 if os.name == 'nt':
206 if os.name == 'nt':
208 if pager_cmd.startswith('type'):
207 if pager_cmd.startswith('type'):
209 # The default WinXP 'type' command is failing on complex strings.
208 # The default WinXP 'type' command is failing on complex strings.
210 retval = 1
209 retval = 1
211 else:
210 else:
212 tmpname = tempfile.mktemp('.txt')
211 tmpname = tempfile.mktemp('.txt')
213 tmpfile = open(tmpname,'wt')
212 tmpfile = open(tmpname,'wt')
214 tmpfile.write(strng)
213 tmpfile.write(strng)
215 tmpfile.close()
214 tmpfile.close()
216 cmd = "%s < %s" % (pager_cmd,tmpname)
215 cmd = "%s < %s" % (pager_cmd,tmpname)
217 if os.system(cmd):
216 if os.system(cmd):
218 retval = 1
217 retval = 1
219 else:
218 else:
220 retval = None
219 retval = None
221 os.remove(tmpname)
220 os.remove(tmpname)
222 else:
221 else:
223 try:
222 try:
224 retval = None
223 retval = None
225 # if I use popen4, things hang. No idea why.
224 # if I use popen4, things hang. No idea why.
226 #pager,shell_out = os.popen4(pager_cmd)
225 #pager,shell_out = os.popen4(pager_cmd)
227 pager = os.popen(pager_cmd, 'w')
226 pager = os.popen(pager_cmd, 'w')
228 try:
227 try:
229 pager_encoding = pager.encoding or sys.stdout.encoding
228 pager_encoding = pager.encoding or sys.stdout.encoding
230 pager.write(py3compat.cast_bytes_py2(
229 pager.write(py3compat.cast_bytes_py2(
231 strng, encoding=pager_encoding))
230 strng, encoding=pager_encoding))
232 finally:
231 finally:
233 retval = pager.close()
232 retval = pager.close()
234 except IOError as msg: # broken pipe when user quits
233 except IOError as msg: # broken pipe when user quits
235 if msg.args == (32, 'Broken pipe'):
234 if msg.args == (32, 'Broken pipe'):
236 retval = None
235 retval = None
237 else:
236 else:
238 retval = 1
237 retval = 1
239 except OSError:
238 except OSError:
240 # Other strange problems, sometimes seen in Win2k/cygwin
239 # Other strange problems, sometimes seen in Win2k/cygwin
241 retval = 1
240 retval = 1
242 if retval is not None:
241 if retval is not None:
243 page_dumb(strng,screen_lines=screen_lines)
242 page_dumb(strng,screen_lines=screen_lines)
244
243
245
244
246 def page_file(fname, start=0, pager_cmd=None):
245 def page_file(fname, start=0, pager_cmd=None):
247 """Page a file, using an optional pager command and starting line.
246 """Page a file, using an optional pager command and starting line.
248 """
247 """
249
248
250 pager_cmd = get_pager_cmd(pager_cmd)
249 pager_cmd = get_pager_cmd(pager_cmd)
251 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
250 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
252
251
253 try:
252 try:
254 if os.environ['TERM'] in ['emacs','dumb']:
253 if os.environ['TERM'] in ['emacs','dumb']:
255 raise EnvironmentError
254 raise EnvironmentError
256 system(pager_cmd + ' ' + fname)
255 system(pager_cmd + ' ' + fname)
257 except:
256 except:
258 try:
257 try:
259 if start > 0:
258 if start > 0:
260 start -= 1
259 start -= 1
261 page(open(fname).read(),start)
260 page(open(fname).read(),start)
262 except:
261 except:
263 print('Unable to show file',repr(fname))
262 print('Unable to show file',repr(fname))
264
263
265
264
266 def get_pager_cmd(pager_cmd=None):
265 def get_pager_cmd(pager_cmd=None):
267 """Return a pager command.
266 """Return a pager command.
268
267
269 Makes some attempts at finding an OS-correct one.
268 Makes some attempts at finding an OS-correct one.
270 """
269 """
271 if os.name == 'posix':
270 if os.name == 'posix':
272 default_pager_cmd = 'less -r' # -r for color control sequences
271 default_pager_cmd = 'less -r' # -r for color control sequences
273 elif os.name in ['nt','dos']:
272 elif os.name in ['nt','dos']:
274 default_pager_cmd = 'type'
273 default_pager_cmd = 'type'
275
274
276 if pager_cmd is None:
275 if pager_cmd is None:
277 try:
276 try:
278 pager_cmd = os.environ['PAGER']
277 pager_cmd = os.environ['PAGER']
279 except:
278 except:
280 pager_cmd = default_pager_cmd
279 pager_cmd = default_pager_cmd
281 return pager_cmd
280 return pager_cmd
282
281
283
282
284 def get_pager_start(pager, start):
283 def get_pager_start(pager, start):
285 """Return the string for paging files with an offset.
284 """Return the string for paging files with an offset.
286
285
287 This is the '+N' argument which less and more (under Unix) accept.
286 This is the '+N' argument which less and more (under Unix) accept.
288 """
287 """
289
288
290 if pager in ['less','more']:
289 if pager in ['less','more']:
291 if start:
290 if start:
292 start_string = '+' + str(start)
291 start_string = '+' + str(start)
293 else:
292 else:
294 start_string = ''
293 start_string = ''
295 else:
294 else:
296 start_string = ''
295 start_string = ''
297 return start_string
296 return start_string
298
297
299
298
300 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
299 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
301 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
300 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
302 import msvcrt
301 import msvcrt
303 def page_more():
302 def page_more():
304 """ Smart pausing between pages
303 """ Smart pausing between pages
305
304
306 @return: True if need print more lines, False if quit
305 @return: True if need print more lines, False if quit
307 """
306 """
308 io.stdout.write('---Return to continue, q to quit--- ')
307 io.stdout.write('---Return to continue, q to quit--- ')
309 ans = msvcrt.getch()
308 ans = msvcrt.getch()
310 if ans in ("q", "Q"):
309 if ans in ("q", "Q"):
311 result = False
310 result = False
312 else:
311 else:
313 result = True
312 result = True
314 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
313 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
315 return result
314 return result
316 else:
315 else:
317 def page_more():
316 def page_more():
318 ans = raw_input('---Return to continue, q to quit--- ')
317 ans = raw_input('---Return to continue, q to quit--- ')
319 if ans.lower().startswith('q'):
318 if ans.lower().startswith('q'):
320 return False
319 return False
321 else:
320 else:
322 return True
321 return True
323
322
324
323
325 def snip_print(str,width = 75,print_full = 0,header = ''):
324 def snip_print(str,width = 75,print_full = 0,header = ''):
326 """Print a string snipping the midsection to fit in width.
325 """Print a string snipping the midsection to fit in width.
327
326
328 print_full: mode control:
327 print_full: mode control:
329 - 0: only snip long strings
328 - 0: only snip long strings
330 - 1: send to page() directly.
329 - 1: send to page() directly.
331 - 2: snip long strings and ask for full length viewing with page()
330 - 2: snip long strings and ask for full length viewing with page()
332 Return 1 if snipping was necessary, 0 otherwise."""
331 Return 1 if snipping was necessary, 0 otherwise."""
333
332
334 if print_full == 1:
333 if print_full == 1:
335 page(header+str)
334 page(header+str)
336 return 0
335 return 0
337
336
338 print(header, end=' ')
337 print(header, end=' ')
339 if len(str) < width:
338 if len(str) < width:
340 print(str)
339 print(str)
341 snip = 0
340 snip = 0
342 else:
341 else:
343 whalf = int((width -5)/2)
342 whalf = int((width -5)/2)
344 print(str[:whalf] + ' <...> ' + str[-whalf:])
343 print(str[:whalf] + ' <...> ' + str[-whalf:])
345 snip = 1
344 snip = 1
346 if snip and print_full == 2:
345 if snip and print_full == 2:
347 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
346 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
348 page(str)
347 page(str)
349 return snip
348 return snip
@@ -1,754 +1,749 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Prefiltering components.
3 Prefiltering components.
4
4
5 Prefilters transform user input before it is exec'd by Python. These
5 Prefilters transform user input before it is exec'd by Python. These
6 transforms are used to implement additional syntax such as !ls and %magic.
6 transforms are used to implement additional syntax such as !ls and %magic.
7
7
8 Authors:
8 Authors:
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Dan Milstein
12 * Dan Milstein
13 * Ville Vainio
13 * Ville Vainio
14 """
14 """
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008-2011 The IPython Development Team
17 # Copyright (C) 2008-2011 The IPython Development Team
18 #
18 #
19 # Distributed under the terms of the BSD License. The full license is in
19 # Distributed under the terms of the BSD License. The full license is in
20 # the file COPYING, distributed as part of this software.
20 # the file COPYING, distributed as part of this software.
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Imports
24 # Imports
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 import __builtin__
28 import codeop
29 import re
27 import re
30
28
31 from IPython.core.alias import AliasManager
32 from IPython.core.autocall import IPyAutocall
29 from IPython.core.autocall import IPyAutocall
33 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
34 from IPython.core.inputsplitter import (
31 from IPython.core.inputsplitter import (
35 ESC_SHELL,
32 ESC_SHELL,
36 ESC_SH_CAP,
33 ESC_SH_CAP,
37 ESC_HELP,
34 ESC_HELP,
38 ESC_MAGIC,
35 ESC_MAGIC,
39 ESC_MAGIC2,
36 ESC_MAGIC2,
40 ESC_QUOTE,
37 ESC_QUOTE,
41 ESC_QUOTE2,
38 ESC_QUOTE2,
42 ESC_PAREN,
39 ESC_PAREN,
43 )
40 )
44 from IPython.core.macro import Macro
41 from IPython.core.macro import Macro
45 from IPython.core.splitinput import split_user_input, LineInfo
42 from IPython.core.splitinput import LineInfo
46 from IPython.core import page
47
43
48 from IPython.utils.traitlets import (
44 from IPython.utils.traitlets import (
49 List, Integer, Any, Unicode, CBool, Bool, Instance, CRegExp
45 List, Integer, Unicode, CBool, Bool, Instance, CRegExp
50 )
46 )
51 from IPython.utils.autoattr import auto_attr
52
47
53 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
54 # Global utilities, errors and constants
49 # Global utilities, errors and constants
55 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
56
51
57
52
58 class PrefilterError(Exception):
53 class PrefilterError(Exception):
59 pass
54 pass
60
55
61
56
62 # RegExp to identify potential function names
57 # RegExp to identify potential function names
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
58 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
64
59
65 # RegExp to exclude strings with this start from autocalling. In
60 # RegExp to exclude strings with this start from autocalling. In
66 # particular, all binary operators should be excluded, so that if foo is
61 # particular, all binary operators should be excluded, so that if foo is
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
62 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
63 # characters '!=()' don't need to be checked for, as the checkPythonChars
69 # routine explicitely does so, to catch direct calls and rebindings of
64 # routine explicitely does so, to catch direct calls and rebindings of
70 # existing names.
65 # existing names.
71
66
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
67 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
73 # it affects the rest of the group in square brackets.
68 # it affects the rest of the group in square brackets.
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
69 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
75 r'|^is |^not |^in |^and |^or ')
70 r'|^is |^not |^in |^and |^or ')
76
71
77 # try to catch also methods for stuff in lists/tuples/dicts: off
72 # try to catch also methods for stuff in lists/tuples/dicts: off
78 # (experimental). For this to work, the line_split regexp would need
73 # (experimental). For this to work, the line_split regexp would need
79 # to be modified so it wouldn't break things at '['. That line is
74 # to be modified so it wouldn't break things at '['. That line is
80 # nasty enough that I shouldn't change it until I can test it _well_.
75 # nasty enough that I shouldn't change it until I can test it _well_.
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
76 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
82
77
83
78
84 # Handler Check Utilities
79 # Handler Check Utilities
85 def is_shadowed(identifier, ip):
80 def is_shadowed(identifier, ip):
86 """Is the given identifier defined in one of the namespaces which shadow
81 """Is the given identifier defined in one of the namespaces which shadow
87 the alias and magic namespaces? Note that an identifier is different
82 the alias and magic namespaces? Note that an identifier is different
88 than ifun, because it can not contain a '.' character."""
83 than ifun, because it can not contain a '.' character."""
89 # This is much safer than calling ofind, which can change state
84 # This is much safer than calling ofind, which can change state
90 return (identifier in ip.user_ns \
85 return (identifier in ip.user_ns \
91 or identifier in ip.user_global_ns \
86 or identifier in ip.user_global_ns \
92 or identifier in ip.ns_table['builtin'])
87 or identifier in ip.ns_table['builtin'])
93
88
94
89
95 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
96 # Main Prefilter manager
91 # Main Prefilter manager
97 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
98
93
99
94
100 class PrefilterManager(Configurable):
95 class PrefilterManager(Configurable):
101 """Main prefilter component.
96 """Main prefilter component.
102
97
103 The IPython prefilter is run on all user input before it is run. The
98 The IPython prefilter is run on all user input before it is run. The
104 prefilter consumes lines of input and produces transformed lines of
99 prefilter consumes lines of input and produces transformed lines of
105 input.
100 input.
106
101
107 The iplementation consists of two phases:
102 The iplementation consists of two phases:
108
103
109 1. Transformers
104 1. Transformers
110 2. Checkers and handlers
105 2. Checkers and handlers
111
106
112 Over time, we plan on deprecating the checkers and handlers and doing
107 Over time, we plan on deprecating the checkers and handlers and doing
113 everything in the transformers.
108 everything in the transformers.
114
109
115 The transformers are instances of :class:`PrefilterTransformer` and have
110 The transformers are instances of :class:`PrefilterTransformer` and have
116 a single method :meth:`transform` that takes a line and returns a
111 a single method :meth:`transform` that takes a line and returns a
117 transformed line. The transformation can be accomplished using any
112 transformed line. The transformation can be accomplished using any
118 tool, but our current ones use regular expressions for speed.
113 tool, but our current ones use regular expressions for speed.
119
114
120 After all the transformers have been run, the line is fed to the checkers,
115 After all the transformers have been run, the line is fed to the checkers,
121 which are instances of :class:`PrefilterChecker`. The line is passed to
116 which are instances of :class:`PrefilterChecker`. The line is passed to
122 the :meth:`check` method, which either returns `None` or a
117 the :meth:`check` method, which either returns `None` or a
123 :class:`PrefilterHandler` instance. If `None` is returned, the other
118 :class:`PrefilterHandler` instance. If `None` is returned, the other
124 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
119 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
125 the line is passed to the :meth:`handle` method of the returned
120 the line is passed to the :meth:`handle` method of the returned
126 handler and no further checkers are tried.
121 handler and no further checkers are tried.
127
122
128 Both transformers and checkers have a `priority` attribute, that determines
123 Both transformers and checkers have a `priority` attribute, that determines
129 the order in which they are called. Smaller priorities are tried first.
124 the order in which they are called. Smaller priorities are tried first.
130
125
131 Both transformers and checkers also have `enabled` attribute, which is
126 Both transformers and checkers also have `enabled` attribute, which is
132 a boolean that determines if the instance is used.
127 a boolean that determines if the instance is used.
133
128
134 Users or developers can change the priority or enabled attribute of
129 Users or developers can change the priority or enabled attribute of
135 transformers or checkers, but they must call the :meth:`sort_checkers`
130 transformers or checkers, but they must call the :meth:`sort_checkers`
136 or :meth:`sort_transformers` method after changing the priority.
131 or :meth:`sort_transformers` method after changing the priority.
137 """
132 """
138
133
139 multi_line_specials = CBool(True, config=True)
134 multi_line_specials = CBool(True, config=True)
140 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
135 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
141
136
142 def __init__(self, shell=None, config=None):
137 def __init__(self, shell=None, config=None):
143 super(PrefilterManager, self).__init__(shell=shell, config=config)
138 super(PrefilterManager, self).__init__(shell=shell, config=config)
144 self.shell = shell
139 self.shell = shell
145 self.init_transformers()
140 self.init_transformers()
146 self.init_handlers()
141 self.init_handlers()
147 self.init_checkers()
142 self.init_checkers()
148
143
149 #-------------------------------------------------------------------------
144 #-------------------------------------------------------------------------
150 # API for managing transformers
145 # API for managing transformers
151 #-------------------------------------------------------------------------
146 #-------------------------------------------------------------------------
152
147
153 def init_transformers(self):
148 def init_transformers(self):
154 """Create the default transformers."""
149 """Create the default transformers."""
155 self._transformers = []
150 self._transformers = []
156 for transformer_cls in _default_transformers:
151 for transformer_cls in _default_transformers:
157 transformer_cls(
152 transformer_cls(
158 shell=self.shell, prefilter_manager=self, config=self.config
153 shell=self.shell, prefilter_manager=self, config=self.config
159 )
154 )
160
155
161 def sort_transformers(self):
156 def sort_transformers(self):
162 """Sort the transformers by priority.
157 """Sort the transformers by priority.
163
158
164 This must be called after the priority of a transformer is changed.
159 This must be called after the priority of a transformer is changed.
165 The :meth:`register_transformer` method calls this automatically.
160 The :meth:`register_transformer` method calls this automatically.
166 """
161 """
167 self._transformers.sort(key=lambda x: x.priority)
162 self._transformers.sort(key=lambda x: x.priority)
168
163
169 @property
164 @property
170 def transformers(self):
165 def transformers(self):
171 """Return a list of checkers, sorted by priority."""
166 """Return a list of checkers, sorted by priority."""
172 return self._transformers
167 return self._transformers
173
168
174 def register_transformer(self, transformer):
169 def register_transformer(self, transformer):
175 """Register a transformer instance."""
170 """Register a transformer instance."""
176 if transformer not in self._transformers:
171 if transformer not in self._transformers:
177 self._transformers.append(transformer)
172 self._transformers.append(transformer)
178 self.sort_transformers()
173 self.sort_transformers()
179
174
180 def unregister_transformer(self, transformer):
175 def unregister_transformer(self, transformer):
181 """Unregister a transformer instance."""
176 """Unregister a transformer instance."""
182 if transformer in self._transformers:
177 if transformer in self._transformers:
183 self._transformers.remove(transformer)
178 self._transformers.remove(transformer)
184
179
185 #-------------------------------------------------------------------------
180 #-------------------------------------------------------------------------
186 # API for managing checkers
181 # API for managing checkers
187 #-------------------------------------------------------------------------
182 #-------------------------------------------------------------------------
188
183
189 def init_checkers(self):
184 def init_checkers(self):
190 """Create the default checkers."""
185 """Create the default checkers."""
191 self._checkers = []
186 self._checkers = []
192 for checker in _default_checkers:
187 for checker in _default_checkers:
193 checker(
188 checker(
194 shell=self.shell, prefilter_manager=self, config=self.config
189 shell=self.shell, prefilter_manager=self, config=self.config
195 )
190 )
196
191
197 def sort_checkers(self):
192 def sort_checkers(self):
198 """Sort the checkers by priority.
193 """Sort the checkers by priority.
199
194
200 This must be called after the priority of a checker is changed.
195 This must be called after the priority of a checker is changed.
201 The :meth:`register_checker` method calls this automatically.
196 The :meth:`register_checker` method calls this automatically.
202 """
197 """
203 self._checkers.sort(key=lambda x: x.priority)
198 self._checkers.sort(key=lambda x: x.priority)
204
199
205 @property
200 @property
206 def checkers(self):
201 def checkers(self):
207 """Return a list of checkers, sorted by priority."""
202 """Return a list of checkers, sorted by priority."""
208 return self._checkers
203 return self._checkers
209
204
210 def register_checker(self, checker):
205 def register_checker(self, checker):
211 """Register a checker instance."""
206 """Register a checker instance."""
212 if checker not in self._checkers:
207 if checker not in self._checkers:
213 self._checkers.append(checker)
208 self._checkers.append(checker)
214 self.sort_checkers()
209 self.sort_checkers()
215
210
216 def unregister_checker(self, checker):
211 def unregister_checker(self, checker):
217 """Unregister a checker instance."""
212 """Unregister a checker instance."""
218 if checker in self._checkers:
213 if checker in self._checkers:
219 self._checkers.remove(checker)
214 self._checkers.remove(checker)
220
215
221 #-------------------------------------------------------------------------
216 #-------------------------------------------------------------------------
222 # API for managing checkers
217 # API for managing checkers
223 #-------------------------------------------------------------------------
218 #-------------------------------------------------------------------------
224
219
225 def init_handlers(self):
220 def init_handlers(self):
226 """Create the default handlers."""
221 """Create the default handlers."""
227 self._handlers = {}
222 self._handlers = {}
228 self._esc_handlers = {}
223 self._esc_handlers = {}
229 for handler in _default_handlers:
224 for handler in _default_handlers:
230 handler(
225 handler(
231 shell=self.shell, prefilter_manager=self, config=self.config
226 shell=self.shell, prefilter_manager=self, config=self.config
232 )
227 )
233
228
234 @property
229 @property
235 def handlers(self):
230 def handlers(self):
236 """Return a dict of all the handlers."""
231 """Return a dict of all the handlers."""
237 return self._handlers
232 return self._handlers
238
233
239 def register_handler(self, name, handler, esc_strings):
234 def register_handler(self, name, handler, esc_strings):
240 """Register a handler instance by name with esc_strings."""
235 """Register a handler instance by name with esc_strings."""
241 self._handlers[name] = handler
236 self._handlers[name] = handler
242 for esc_str in esc_strings:
237 for esc_str in esc_strings:
243 self._esc_handlers[esc_str] = handler
238 self._esc_handlers[esc_str] = handler
244
239
245 def unregister_handler(self, name, handler, esc_strings):
240 def unregister_handler(self, name, handler, esc_strings):
246 """Unregister a handler instance by name with esc_strings."""
241 """Unregister a handler instance by name with esc_strings."""
247 try:
242 try:
248 del self._handlers[name]
243 del self._handlers[name]
249 except KeyError:
244 except KeyError:
250 pass
245 pass
251 for esc_str in esc_strings:
246 for esc_str in esc_strings:
252 h = self._esc_handlers.get(esc_str)
247 h = self._esc_handlers.get(esc_str)
253 if h is handler:
248 if h is handler:
254 del self._esc_handlers[esc_str]
249 del self._esc_handlers[esc_str]
255
250
256 def get_handler_by_name(self, name):
251 def get_handler_by_name(self, name):
257 """Get a handler by its name."""
252 """Get a handler by its name."""
258 return self._handlers.get(name)
253 return self._handlers.get(name)
259
254
260 def get_handler_by_esc(self, esc_str):
255 def get_handler_by_esc(self, esc_str):
261 """Get a handler by its escape string."""
256 """Get a handler by its escape string."""
262 return self._esc_handlers.get(esc_str)
257 return self._esc_handlers.get(esc_str)
263
258
264 #-------------------------------------------------------------------------
259 #-------------------------------------------------------------------------
265 # Main prefiltering API
260 # Main prefiltering API
266 #-------------------------------------------------------------------------
261 #-------------------------------------------------------------------------
267
262
268 def prefilter_line_info(self, line_info):
263 def prefilter_line_info(self, line_info):
269 """Prefilter a line that has been converted to a LineInfo object.
264 """Prefilter a line that has been converted to a LineInfo object.
270
265
271 This implements the checker/handler part of the prefilter pipe.
266 This implements the checker/handler part of the prefilter pipe.
272 """
267 """
273 # print "prefilter_line_info: ", line_info
268 # print "prefilter_line_info: ", line_info
274 handler = self.find_handler(line_info)
269 handler = self.find_handler(line_info)
275 return handler.handle(line_info)
270 return handler.handle(line_info)
276
271
277 def find_handler(self, line_info):
272 def find_handler(self, line_info):
278 """Find a handler for the line_info by trying checkers."""
273 """Find a handler for the line_info by trying checkers."""
279 for checker in self.checkers:
274 for checker in self.checkers:
280 if checker.enabled:
275 if checker.enabled:
281 handler = checker.check(line_info)
276 handler = checker.check(line_info)
282 if handler:
277 if handler:
283 return handler
278 return handler
284 return self.get_handler_by_name('normal')
279 return self.get_handler_by_name('normal')
285
280
286 def transform_line(self, line, continue_prompt):
281 def transform_line(self, line, continue_prompt):
287 """Calls the enabled transformers in order of increasing priority."""
282 """Calls the enabled transformers in order of increasing priority."""
288 for transformer in self.transformers:
283 for transformer in self.transformers:
289 if transformer.enabled:
284 if transformer.enabled:
290 line = transformer.transform(line, continue_prompt)
285 line = transformer.transform(line, continue_prompt)
291 return line
286 return line
292
287
293 def prefilter_line(self, line, continue_prompt=False):
288 def prefilter_line(self, line, continue_prompt=False):
294 """Prefilter a single input line as text.
289 """Prefilter a single input line as text.
295
290
296 This method prefilters a single line of text by calling the
291 This method prefilters a single line of text by calling the
297 transformers and then the checkers/handlers.
292 transformers and then the checkers/handlers.
298 """
293 """
299
294
300 # print "prefilter_line: ", line, continue_prompt
295 # print "prefilter_line: ", line, continue_prompt
301 # All handlers *must* return a value, even if it's blank ('').
296 # All handlers *must* return a value, even if it's blank ('').
302
297
303 # save the line away in case we crash, so the post-mortem handler can
298 # save the line away in case we crash, so the post-mortem handler can
304 # record it
299 # record it
305 self.shell._last_input_line = line
300 self.shell._last_input_line = line
306
301
307 if not line:
302 if not line:
308 # Return immediately on purely empty lines, so that if the user
303 # Return immediately on purely empty lines, so that if the user
309 # previously typed some whitespace that started a continuation
304 # previously typed some whitespace that started a continuation
310 # prompt, he can break out of that loop with just an empty line.
305 # prompt, he can break out of that loop with just an empty line.
311 # This is how the default python prompt works.
306 # This is how the default python prompt works.
312 return ''
307 return ''
313
308
314 # At this point, we invoke our transformers.
309 # At this point, we invoke our transformers.
315 if not continue_prompt or (continue_prompt and self.multi_line_specials):
310 if not continue_prompt or (continue_prompt and self.multi_line_specials):
316 line = self.transform_line(line, continue_prompt)
311 line = self.transform_line(line, continue_prompt)
317
312
318 # Now we compute line_info for the checkers and handlers
313 # Now we compute line_info for the checkers and handlers
319 line_info = LineInfo(line, continue_prompt)
314 line_info = LineInfo(line, continue_prompt)
320
315
321 # the input history needs to track even empty lines
316 # the input history needs to track even empty lines
322 stripped = line.strip()
317 stripped = line.strip()
323
318
324 normal_handler = self.get_handler_by_name('normal')
319 normal_handler = self.get_handler_by_name('normal')
325 if not stripped:
320 if not stripped:
326 return normal_handler.handle(line_info)
321 return normal_handler.handle(line_info)
327
322
328 # special handlers are only allowed for single line statements
323 # special handlers are only allowed for single line statements
329 if continue_prompt and not self.multi_line_specials:
324 if continue_prompt and not self.multi_line_specials:
330 return normal_handler.handle(line_info)
325 return normal_handler.handle(line_info)
331
326
332 prefiltered = self.prefilter_line_info(line_info)
327 prefiltered = self.prefilter_line_info(line_info)
333 # print "prefiltered line: %r" % prefiltered
328 # print "prefiltered line: %r" % prefiltered
334 return prefiltered
329 return prefiltered
335
330
336 def prefilter_lines(self, lines, continue_prompt=False):
331 def prefilter_lines(self, lines, continue_prompt=False):
337 """Prefilter multiple input lines of text.
332 """Prefilter multiple input lines of text.
338
333
339 This is the main entry point for prefiltering multiple lines of
334 This is the main entry point for prefiltering multiple lines of
340 input. This simply calls :meth:`prefilter_line` for each line of
335 input. This simply calls :meth:`prefilter_line` for each line of
341 input.
336 input.
342
337
343 This covers cases where there are multiple lines in the user entry,
338 This covers cases where there are multiple lines in the user entry,
344 which is the case when the user goes back to a multiline history
339 which is the case when the user goes back to a multiline history
345 entry and presses enter.
340 entry and presses enter.
346 """
341 """
347 llines = lines.rstrip('\n').split('\n')
342 llines = lines.rstrip('\n').split('\n')
348 # We can get multiple lines in one shot, where multiline input 'blends'
343 # We can get multiple lines in one shot, where multiline input 'blends'
349 # into one line, in cases like recalling from the readline history
344 # into one line, in cases like recalling from the readline history
350 # buffer. We need to make sure that in such cases, we correctly
345 # buffer. We need to make sure that in such cases, we correctly
351 # communicate downstream which line is first and which are continuation
346 # communicate downstream which line is first and which are continuation
352 # ones.
347 # ones.
353 if len(llines) > 1:
348 if len(llines) > 1:
354 out = '\n'.join([self.prefilter_line(line, lnum>0)
349 out = '\n'.join([self.prefilter_line(line, lnum>0)
355 for lnum, line in enumerate(llines) ])
350 for lnum, line in enumerate(llines) ])
356 else:
351 else:
357 out = self.prefilter_line(llines[0], continue_prompt)
352 out = self.prefilter_line(llines[0], continue_prompt)
358
353
359 return out
354 return out
360
355
361 #-----------------------------------------------------------------------------
356 #-----------------------------------------------------------------------------
362 # Prefilter transformers
357 # Prefilter transformers
363 #-----------------------------------------------------------------------------
358 #-----------------------------------------------------------------------------
364
359
365
360
366 class PrefilterTransformer(Configurable):
361 class PrefilterTransformer(Configurable):
367 """Transform a line of user input."""
362 """Transform a line of user input."""
368
363
369 priority = Integer(100, config=True)
364 priority = Integer(100, config=True)
370 # Transformers don't currently use shell or prefilter_manager, but as we
365 # Transformers don't currently use shell or prefilter_manager, but as we
371 # move away from checkers and handlers, they will need them.
366 # move away from checkers and handlers, they will need them.
372 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
367 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
373 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
368 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
374 enabled = Bool(True, config=True)
369 enabled = Bool(True, config=True)
375
370
376 def __init__(self, shell=None, prefilter_manager=None, config=None):
371 def __init__(self, shell=None, prefilter_manager=None, config=None):
377 super(PrefilterTransformer, self).__init__(
372 super(PrefilterTransformer, self).__init__(
378 shell=shell, prefilter_manager=prefilter_manager, config=config
373 shell=shell, prefilter_manager=prefilter_manager, config=config
379 )
374 )
380 self.prefilter_manager.register_transformer(self)
375 self.prefilter_manager.register_transformer(self)
381
376
382 def transform(self, line, continue_prompt):
377 def transform(self, line, continue_prompt):
383 """Transform a line, returning the new one."""
378 """Transform a line, returning the new one."""
384 return None
379 return None
385
380
386 def __repr__(self):
381 def __repr__(self):
387 return "<%s(priority=%r, enabled=%r)>" % (
382 return "<%s(priority=%r, enabled=%r)>" % (
388 self.__class__.__name__, self.priority, self.enabled)
383 self.__class__.__name__, self.priority, self.enabled)
389
384
390
385
391 #-----------------------------------------------------------------------------
386 #-----------------------------------------------------------------------------
392 # Prefilter checkers
387 # Prefilter checkers
393 #-----------------------------------------------------------------------------
388 #-----------------------------------------------------------------------------
394
389
395
390
396 class PrefilterChecker(Configurable):
391 class PrefilterChecker(Configurable):
397 """Inspect an input line and return a handler for that line."""
392 """Inspect an input line and return a handler for that line."""
398
393
399 priority = Integer(100, config=True)
394 priority = Integer(100, config=True)
400 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
395 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
401 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
396 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
402 enabled = Bool(True, config=True)
397 enabled = Bool(True, config=True)
403
398
404 def __init__(self, shell=None, prefilter_manager=None, config=None):
399 def __init__(self, shell=None, prefilter_manager=None, config=None):
405 super(PrefilterChecker, self).__init__(
400 super(PrefilterChecker, self).__init__(
406 shell=shell, prefilter_manager=prefilter_manager, config=config
401 shell=shell, prefilter_manager=prefilter_manager, config=config
407 )
402 )
408 self.prefilter_manager.register_checker(self)
403 self.prefilter_manager.register_checker(self)
409
404
410 def check(self, line_info):
405 def check(self, line_info):
411 """Inspect line_info and return a handler instance or None."""
406 """Inspect line_info and return a handler instance or None."""
412 return None
407 return None
413
408
414 def __repr__(self):
409 def __repr__(self):
415 return "<%s(priority=%r, enabled=%r)>" % (
410 return "<%s(priority=%r, enabled=%r)>" % (
416 self.__class__.__name__, self.priority, self.enabled)
411 self.__class__.__name__, self.priority, self.enabled)
417
412
418
413
419 class EmacsChecker(PrefilterChecker):
414 class EmacsChecker(PrefilterChecker):
420
415
421 priority = Integer(100, config=True)
416 priority = Integer(100, config=True)
422 enabled = Bool(False, config=True)
417 enabled = Bool(False, config=True)
423
418
424 def check(self, line_info):
419 def check(self, line_info):
425 "Emacs ipython-mode tags certain input lines."
420 "Emacs ipython-mode tags certain input lines."
426 if line_info.line.endswith('# PYTHON-MODE'):
421 if line_info.line.endswith('# PYTHON-MODE'):
427 return self.prefilter_manager.get_handler_by_name('emacs')
422 return self.prefilter_manager.get_handler_by_name('emacs')
428 else:
423 else:
429 return None
424 return None
430
425
431
426
432 class MacroChecker(PrefilterChecker):
427 class MacroChecker(PrefilterChecker):
433
428
434 priority = Integer(250, config=True)
429 priority = Integer(250, config=True)
435
430
436 def check(self, line_info):
431 def check(self, line_info):
437 obj = self.shell.user_ns.get(line_info.ifun)
432 obj = self.shell.user_ns.get(line_info.ifun)
438 if isinstance(obj, Macro):
433 if isinstance(obj, Macro):
439 return self.prefilter_manager.get_handler_by_name('macro')
434 return self.prefilter_manager.get_handler_by_name('macro')
440 else:
435 else:
441 return None
436 return None
442
437
443
438
444 class IPyAutocallChecker(PrefilterChecker):
439 class IPyAutocallChecker(PrefilterChecker):
445
440
446 priority = Integer(300, config=True)
441 priority = Integer(300, config=True)
447
442
448 def check(self, line_info):
443 def check(self, line_info):
449 "Instances of IPyAutocall in user_ns get autocalled immediately"
444 "Instances of IPyAutocall in user_ns get autocalled immediately"
450 obj = self.shell.user_ns.get(line_info.ifun, None)
445 obj = self.shell.user_ns.get(line_info.ifun, None)
451 if isinstance(obj, IPyAutocall):
446 if isinstance(obj, IPyAutocall):
452 obj.set_ip(self.shell)
447 obj.set_ip(self.shell)
453 return self.prefilter_manager.get_handler_by_name('auto')
448 return self.prefilter_manager.get_handler_by_name('auto')
454 else:
449 else:
455 return None
450 return None
456
451
457
452
458 class AssignmentChecker(PrefilterChecker):
453 class AssignmentChecker(PrefilterChecker):
459
454
460 priority = Integer(600, config=True)
455 priority = Integer(600, config=True)
461
456
462 def check(self, line_info):
457 def check(self, line_info):
463 """Check to see if user is assigning to a var for the first time, in
458 """Check to see if user is assigning to a var for the first time, in
464 which case we want to avoid any sort of automagic / autocall games.
459 which case we want to avoid any sort of automagic / autocall games.
465
460
466 This allows users to assign to either alias or magic names true python
461 This allows users to assign to either alias or magic names true python
467 variables (the magic/alias systems always take second seat to true
462 variables (the magic/alias systems always take second seat to true
468 python code). E.g. ls='hi', or ls,that=1,2"""
463 python code). E.g. ls='hi', or ls,that=1,2"""
469 if line_info.the_rest:
464 if line_info.the_rest:
470 if line_info.the_rest[0] in '=,':
465 if line_info.the_rest[0] in '=,':
471 return self.prefilter_manager.get_handler_by_name('normal')
466 return self.prefilter_manager.get_handler_by_name('normal')
472 else:
467 else:
473 return None
468 return None
474
469
475
470
476 class AutoMagicChecker(PrefilterChecker):
471 class AutoMagicChecker(PrefilterChecker):
477
472
478 priority = Integer(700, config=True)
473 priority = Integer(700, config=True)
479
474
480 def check(self, line_info):
475 def check(self, line_info):
481 """If the ifun is magic, and automagic is on, run it. Note: normal,
476 """If the ifun is magic, and automagic is on, run it. Note: normal,
482 non-auto magic would already have been triggered via '%' in
477 non-auto magic would already have been triggered via '%' in
483 check_esc_chars. This just checks for automagic. Also, before
478 check_esc_chars. This just checks for automagic. Also, before
484 triggering the magic handler, make sure that there is nothing in the
479 triggering the magic handler, make sure that there is nothing in the
485 user namespace which could shadow it."""
480 user namespace which could shadow it."""
486 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
481 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
487 return None
482 return None
488
483
489 # We have a likely magic method. Make sure we should actually call it.
484 # We have a likely magic method. Make sure we should actually call it.
490 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
485 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
491 return None
486 return None
492
487
493 head = line_info.ifun.split('.',1)[0]
488 head = line_info.ifun.split('.',1)[0]
494 if is_shadowed(head, self.shell):
489 if is_shadowed(head, self.shell):
495 return None
490 return None
496
491
497 return self.prefilter_manager.get_handler_by_name('magic')
492 return self.prefilter_manager.get_handler_by_name('magic')
498
493
499
494
500 class AliasChecker(PrefilterChecker):
495 class AliasChecker(PrefilterChecker):
501
496
502 priority = Integer(800, config=True)
497 priority = Integer(800, config=True)
503
498
504 def check(self, line_info):
499 def check(self, line_info):
505 "Check if the initital identifier on the line is an alias."
500 "Check if the initital identifier on the line is an alias."
506 # Note: aliases can not contain '.'
501 # Note: aliases can not contain '.'
507 head = line_info.ifun.split('.',1)[0]
502 head = line_info.ifun.split('.',1)[0]
508 if line_info.ifun not in self.shell.alias_manager \
503 if line_info.ifun not in self.shell.alias_manager \
509 or head not in self.shell.alias_manager \
504 or head not in self.shell.alias_manager \
510 or is_shadowed(head, self.shell):
505 or is_shadowed(head, self.shell):
511 return None
506 return None
512
507
513 return self.prefilter_manager.get_handler_by_name('alias')
508 return self.prefilter_manager.get_handler_by_name('alias')
514
509
515
510
516 class PythonOpsChecker(PrefilterChecker):
511 class PythonOpsChecker(PrefilterChecker):
517
512
518 priority = Integer(900, config=True)
513 priority = Integer(900, config=True)
519
514
520 def check(self, line_info):
515 def check(self, line_info):
521 """If the 'rest' of the line begins with a function call or pretty much
516 """If the 'rest' of the line begins with a function call or pretty much
522 any python operator, we should simply execute the line (regardless of
517 any python operator, we should simply execute the line (regardless of
523 whether or not there's a possible autocall expansion). This avoids
518 whether or not there's a possible autocall expansion). This avoids
524 spurious (and very confusing) geattr() accesses."""
519 spurious (and very confusing) geattr() accesses."""
525 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
520 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
526 return self.prefilter_manager.get_handler_by_name('normal')
521 return self.prefilter_manager.get_handler_by_name('normal')
527 else:
522 else:
528 return None
523 return None
529
524
530
525
531 class AutocallChecker(PrefilterChecker):
526 class AutocallChecker(PrefilterChecker):
532
527
533 priority = Integer(1000, config=True)
528 priority = Integer(1000, config=True)
534
529
535 function_name_regexp = CRegExp(re_fun_name, config=True,
530 function_name_regexp = CRegExp(re_fun_name, config=True,
536 help="RegExp to identify potential function names.")
531 help="RegExp to identify potential function names.")
537 exclude_regexp = CRegExp(re_exclude_auto, config=True,
532 exclude_regexp = CRegExp(re_exclude_auto, config=True,
538 help="RegExp to exclude strings with this start from autocalling.")
533 help="RegExp to exclude strings with this start from autocalling.")
539
534
540 def check(self, line_info):
535 def check(self, line_info):
541 "Check if the initial word/function is callable and autocall is on."
536 "Check if the initial word/function is callable and autocall is on."
542 if not self.shell.autocall:
537 if not self.shell.autocall:
543 return None
538 return None
544
539
545 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
540 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
546 if not oinfo['found']:
541 if not oinfo['found']:
547 return None
542 return None
548
543
549 if callable(oinfo['obj']) \
544 if callable(oinfo['obj']) \
550 and (not self.exclude_regexp.match(line_info.the_rest)) \
545 and (not self.exclude_regexp.match(line_info.the_rest)) \
551 and self.function_name_regexp.match(line_info.ifun):
546 and self.function_name_regexp.match(line_info.ifun):
552 return self.prefilter_manager.get_handler_by_name('auto')
547 return self.prefilter_manager.get_handler_by_name('auto')
553 else:
548 else:
554 return None
549 return None
555
550
556
551
557 #-----------------------------------------------------------------------------
552 #-----------------------------------------------------------------------------
558 # Prefilter handlers
553 # Prefilter handlers
559 #-----------------------------------------------------------------------------
554 #-----------------------------------------------------------------------------
560
555
561
556
562 class PrefilterHandler(Configurable):
557 class PrefilterHandler(Configurable):
563
558
564 handler_name = Unicode('normal')
559 handler_name = Unicode('normal')
565 esc_strings = List([])
560 esc_strings = List([])
566 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
561 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
567 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
562 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
568
563
569 def __init__(self, shell=None, prefilter_manager=None, config=None):
564 def __init__(self, shell=None, prefilter_manager=None, config=None):
570 super(PrefilterHandler, self).__init__(
565 super(PrefilterHandler, self).__init__(
571 shell=shell, prefilter_manager=prefilter_manager, config=config
566 shell=shell, prefilter_manager=prefilter_manager, config=config
572 )
567 )
573 self.prefilter_manager.register_handler(
568 self.prefilter_manager.register_handler(
574 self.handler_name,
569 self.handler_name,
575 self,
570 self,
576 self.esc_strings
571 self.esc_strings
577 )
572 )
578
573
579 def handle(self, line_info):
574 def handle(self, line_info):
580 # print "normal: ", line_info
575 # print "normal: ", line_info
581 """Handle normal input lines. Use as a template for handlers."""
576 """Handle normal input lines. Use as a template for handlers."""
582
577
583 # With autoindent on, we need some way to exit the input loop, and I
578 # With autoindent on, we need some way to exit the input loop, and I
584 # don't want to force the user to have to backspace all the way to
579 # don't want to force the user to have to backspace all the way to
585 # clear the line. The rule will be in this case, that either two
580 # clear the line. The rule will be in this case, that either two
586 # lines of pure whitespace in a row, or a line of pure whitespace but
581 # lines of pure whitespace in a row, or a line of pure whitespace but
587 # of a size different to the indent level, will exit the input loop.
582 # of a size different to the indent level, will exit the input loop.
588 line = line_info.line
583 line = line_info.line
589 continue_prompt = line_info.continue_prompt
584 continue_prompt = line_info.continue_prompt
590
585
591 if (continue_prompt and
586 if (continue_prompt and
592 self.shell.autoindent and
587 self.shell.autoindent and
593 line.isspace() and
588 line.isspace() and
594 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
589 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
595 line = ''
590 line = ''
596
591
597 return line
592 return line
598
593
599 def __str__(self):
594 def __str__(self):
600 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
595 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
601
596
602
597
603 class AliasHandler(PrefilterHandler):
598 class AliasHandler(PrefilterHandler):
604
599
605 handler_name = Unicode('alias')
600 handler_name = Unicode('alias')
606
601
607 def handle(self, line_info):
602 def handle(self, line_info):
608 """Handle alias input lines. """
603 """Handle alias input lines. """
609 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
604 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
610 # pre is needed, because it carries the leading whitespace. Otherwise
605 # pre is needed, because it carries the leading whitespace. Otherwise
611 # aliases won't work in indented sections.
606 # aliases won't work in indented sections.
612 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
607 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
613
608
614 return line_out
609 return line_out
615
610
616
611
617 class MacroHandler(PrefilterHandler):
612 class MacroHandler(PrefilterHandler):
618 handler_name = Unicode("macro")
613 handler_name = Unicode("macro")
619
614
620 def handle(self, line_info):
615 def handle(self, line_info):
621 obj = self.shell.user_ns.get(line_info.ifun)
616 obj = self.shell.user_ns.get(line_info.ifun)
622 pre_space = line_info.pre_whitespace
617 pre_space = line_info.pre_whitespace
623 line_sep = "\n" + pre_space
618 line_sep = "\n" + pre_space
624 return pre_space + line_sep.join(obj.value.splitlines())
619 return pre_space + line_sep.join(obj.value.splitlines())
625
620
626
621
627 class MagicHandler(PrefilterHandler):
622 class MagicHandler(PrefilterHandler):
628
623
629 handler_name = Unicode('magic')
624 handler_name = Unicode('magic')
630 esc_strings = List([ESC_MAGIC])
625 esc_strings = List([ESC_MAGIC])
631
626
632 def handle(self, line_info):
627 def handle(self, line_info):
633 """Execute magic functions."""
628 """Execute magic functions."""
634 ifun = line_info.ifun
629 ifun = line_info.ifun
635 the_rest = line_info.the_rest
630 the_rest = line_info.the_rest
636 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
631 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
637 (ifun + " " + the_rest))
632 (ifun + " " + the_rest))
638 return cmd
633 return cmd
639
634
640
635
641 class AutoHandler(PrefilterHandler):
636 class AutoHandler(PrefilterHandler):
642
637
643 handler_name = Unicode('auto')
638 handler_name = Unicode('auto')
644 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
639 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
645
640
646 def handle(self, line_info):
641 def handle(self, line_info):
647 """Handle lines which can be auto-executed, quoting if requested."""
642 """Handle lines which can be auto-executed, quoting if requested."""
648 line = line_info.line
643 line = line_info.line
649 ifun = line_info.ifun
644 ifun = line_info.ifun
650 the_rest = line_info.the_rest
645 the_rest = line_info.the_rest
651 pre = line_info.pre
646 pre = line_info.pre
652 esc = line_info.esc
647 esc = line_info.esc
653 continue_prompt = line_info.continue_prompt
648 continue_prompt = line_info.continue_prompt
654 obj = line_info.ofind(self.shell)['obj']
649 obj = line_info.ofind(self.shell)['obj']
655 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
650 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
656
651
657 # This should only be active for single-line input!
652 # This should only be active for single-line input!
658 if continue_prompt:
653 if continue_prompt:
659 return line
654 return line
660
655
661 force_auto = isinstance(obj, IPyAutocall)
656 force_auto = isinstance(obj, IPyAutocall)
662
657
663 # User objects sometimes raise exceptions on attribute access other
658 # User objects sometimes raise exceptions on attribute access other
664 # than AttributeError (we've seen it in the past), so it's safest to be
659 # than AttributeError (we've seen it in the past), so it's safest to be
665 # ultra-conservative here and catch all.
660 # ultra-conservative here and catch all.
666 try:
661 try:
667 auto_rewrite = obj.rewrite
662 auto_rewrite = obj.rewrite
668 except Exception:
663 except Exception:
669 auto_rewrite = True
664 auto_rewrite = True
670
665
671 if esc == ESC_QUOTE:
666 if esc == ESC_QUOTE:
672 # Auto-quote splitting on whitespace
667 # Auto-quote splitting on whitespace
673 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
668 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
674 elif esc == ESC_QUOTE2:
669 elif esc == ESC_QUOTE2:
675 # Auto-quote whole string
670 # Auto-quote whole string
676 newcmd = '%s("%s")' % (ifun,the_rest)
671 newcmd = '%s("%s")' % (ifun,the_rest)
677 elif esc == ESC_PAREN:
672 elif esc == ESC_PAREN:
678 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
673 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
679 else:
674 else:
680 # Auto-paren.
675 # Auto-paren.
681 if force_auto:
676 if force_auto:
682 # Don't rewrite if it is already a call.
677 # Don't rewrite if it is already a call.
683 do_rewrite = not the_rest.startswith('(')
678 do_rewrite = not the_rest.startswith('(')
684 else:
679 else:
685 if not the_rest:
680 if not the_rest:
686 # We only apply it to argument-less calls if the autocall
681 # We only apply it to argument-less calls if the autocall
687 # parameter is set to 2.
682 # parameter is set to 2.
688 do_rewrite = (self.shell.autocall >= 2)
683 do_rewrite = (self.shell.autocall >= 2)
689 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
684 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
690 # Don't autocall in this case: item access for an object
685 # Don't autocall in this case: item access for an object
691 # which is BOTH callable and implements __getitem__.
686 # which is BOTH callable and implements __getitem__.
692 do_rewrite = False
687 do_rewrite = False
693 else:
688 else:
694 do_rewrite = True
689 do_rewrite = True
695
690
696 # Figure out the rewritten command
691 # Figure out the rewritten command
697 if do_rewrite:
692 if do_rewrite:
698 if the_rest.endswith(';'):
693 if the_rest.endswith(';'):
699 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
694 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
700 else:
695 else:
701 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
696 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
702 else:
697 else:
703 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
698 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
704 return normal_handler.handle(line_info)
699 return normal_handler.handle(line_info)
705
700
706 # Display the rewritten call
701 # Display the rewritten call
707 if auto_rewrite:
702 if auto_rewrite:
708 self.shell.auto_rewrite_input(newcmd)
703 self.shell.auto_rewrite_input(newcmd)
709
704
710 return newcmd
705 return newcmd
711
706
712
707
713 class EmacsHandler(PrefilterHandler):
708 class EmacsHandler(PrefilterHandler):
714
709
715 handler_name = Unicode('emacs')
710 handler_name = Unicode('emacs')
716 esc_strings = List([])
711 esc_strings = List([])
717
712
718 def handle(self, line_info):
713 def handle(self, line_info):
719 """Handle input lines marked by python-mode."""
714 """Handle input lines marked by python-mode."""
720
715
721 # Currently, nothing is done. Later more functionality can be added
716 # Currently, nothing is done. Later more functionality can be added
722 # here if needed.
717 # here if needed.
723
718
724 # The input cache shouldn't be updated
719 # The input cache shouldn't be updated
725 return line_info.line
720 return line_info.line
726
721
727
722
728 #-----------------------------------------------------------------------------
723 #-----------------------------------------------------------------------------
729 # Defaults
724 # Defaults
730 #-----------------------------------------------------------------------------
725 #-----------------------------------------------------------------------------
731
726
732
727
733 _default_transformers = [
728 _default_transformers = [
734 ]
729 ]
735
730
736 _default_checkers = [
731 _default_checkers = [
737 EmacsChecker,
732 EmacsChecker,
738 MacroChecker,
733 MacroChecker,
739 IPyAutocallChecker,
734 IPyAutocallChecker,
740 AssignmentChecker,
735 AssignmentChecker,
741 AutoMagicChecker,
736 AutoMagicChecker,
742 AliasChecker,
737 AliasChecker,
743 PythonOpsChecker,
738 PythonOpsChecker,
744 AutocallChecker
739 AutocallChecker
745 ]
740 ]
746
741
747 _default_handlers = [
742 _default_handlers = [
748 PrefilterHandler,
743 PrefilterHandler,
749 AliasHandler,
744 AliasHandler,
750 MacroHandler,
745 MacroHandler,
751 MagicHandler,
746 MagicHandler,
752 AutoHandler,
747 AutoHandler,
753 EmacsHandler
748 EmacsHandler
754 ]
749 ]
@@ -1,307 +1,306 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for managing IPython profiles.
3 An application for managing IPython profiles.
4
4
5 To be invoked as the `ipython profile` subcommand.
5 To be invoked as the `ipython profile` subcommand.
6
6
7 Authors:
7 Authors:
8
8
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import logging
25 import os
24 import os
26
25
27 from IPython.config.application import Application, boolean_flag
26 from IPython.config.application import Application
28 from IPython.core.application import (
27 from IPython.core.application import (
29 BaseIPythonApplication, base_flags, base_aliases
28 BaseIPythonApplication, base_flags
30 )
29 )
31 from IPython.core.profiledir import ProfileDir
30 from IPython.core.profiledir import ProfileDir
32 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
31 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
33 from IPython.utils.traitlets import Unicode, Bool, Dict
32 from IPython.utils.traitlets import Unicode, Bool, Dict
34
33
35 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
36 # Constants
35 # Constants
37 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
38
37
39 create_help = """Create an IPython profile by name
38 create_help = """Create an IPython profile by name
40
39
41 Create an ipython profile directory by its name or
40 Create an ipython profile directory by its name or
42 profile directory path. Profile directories contain
41 profile directory path. Profile directories contain
43 configuration, log and security related files and are named
42 configuration, log and security related files and are named
44 using the convention 'profile_<name>'. By default they are
43 using the convention 'profile_<name>'. By default they are
45 located in your ipython directory. Once created, you will
44 located in your ipython directory. Once created, you will
46 can edit the configuration files in the profile
45 can edit the configuration files in the profile
47 directory to configure IPython. Most users will create a
46 directory to configure IPython. Most users will create a
48 profile directory by name,
47 profile directory by name,
49 `ipython profile create myprofile`, which will put the directory
48 `ipython profile create myprofile`, which will put the directory
50 in `<ipython_dir>/profile_myprofile`.
49 in `<ipython_dir>/profile_myprofile`.
51 """
50 """
52 list_help = """List available IPython profiles
51 list_help = """List available IPython profiles
53
52
54 List all available profiles, by profile location, that can
53 List all available profiles, by profile location, that can
55 be found in the current working directly or in the ipython
54 be found in the current working directly or in the ipython
56 directory. Profile directories are named using the convention
55 directory. Profile directories are named using the convention
57 'profile_<profile>'.
56 'profile_<profile>'.
58 """
57 """
59 profile_help = """Manage IPython profiles
58 profile_help = """Manage IPython profiles
60
59
61 Profile directories contain
60 Profile directories contain
62 configuration, log and security related files and are named
61 configuration, log and security related files and are named
63 using the convention 'profile_<name>'. By default they are
62 using the convention 'profile_<name>'. By default they are
64 located in your ipython directory. You can create profiles
63 located in your ipython directory. You can create profiles
65 with `ipython profile create <name>`, or see the profiles you
64 with `ipython profile create <name>`, or see the profiles you
66 already have with `ipython profile list`
65 already have with `ipython profile list`
67
66
68 To get started configuring IPython, simply do:
67 To get started configuring IPython, simply do:
69
68
70 $> ipython profile create
69 $> ipython profile create
71
70
72 and IPython will create the default profile in <ipython_dir>/profile_default,
71 and IPython will create the default profile in <ipython_dir>/profile_default,
73 where you can edit ipython_config.py to start configuring IPython.
72 where you can edit ipython_config.py to start configuring IPython.
74
73
75 """
74 """
76
75
77 _list_examples = "ipython profile list # list all profiles"
76 _list_examples = "ipython profile list # list all profiles"
78
77
79 _create_examples = """
78 _create_examples = """
80 ipython profile create foo # create profile foo w/ default config files
79 ipython profile create foo # create profile foo w/ default config files
81 ipython profile create foo --reset # restage default config files over current
80 ipython profile create foo --reset # restage default config files over current
82 ipython profile create foo --parallel # also stage parallel config files
81 ipython profile create foo --parallel # also stage parallel config files
83 """
82 """
84
83
85 _main_examples = """
84 _main_examples = """
86 ipython profile create -h # show the help string for the create subcommand
85 ipython profile create -h # show the help string for the create subcommand
87 ipython profile list -h # show the help string for the list subcommand
86 ipython profile list -h # show the help string for the list subcommand
88
87
89 ipython locate profile foo # print the path to the directory for profile 'foo'
88 ipython locate profile foo # print the path to the directory for profile 'foo'
90 """
89 """
91
90
92 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
93 # Profile Application Class (for `ipython profile` subcommand)
92 # Profile Application Class (for `ipython profile` subcommand)
94 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
95
94
96
95
97 def list_profiles_in(path):
96 def list_profiles_in(path):
98 """list profiles in a given root directory"""
97 """list profiles in a given root directory"""
99 files = os.listdir(path)
98 files = os.listdir(path)
100 profiles = []
99 profiles = []
101 for f in files:
100 for f in files:
102 full_path = os.path.join(path, f)
101 full_path = os.path.join(path, f)
103 if os.path.isdir(full_path) and f.startswith('profile_'):
102 if os.path.isdir(full_path) and f.startswith('profile_'):
104 profiles.append(f.split('_',1)[-1])
103 profiles.append(f.split('_',1)[-1])
105 return profiles
104 return profiles
106
105
107
106
108 def list_bundled_profiles():
107 def list_bundled_profiles():
109 """list profiles that are bundled with IPython."""
108 """list profiles that are bundled with IPython."""
110 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
109 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
111 files = os.listdir(path)
110 files = os.listdir(path)
112 profiles = []
111 profiles = []
113 for profile in files:
112 for profile in files:
114 full_path = os.path.join(path, profile)
113 full_path = os.path.join(path, profile)
115 if os.path.isdir(full_path) and profile != "__pycache__":
114 if os.path.isdir(full_path) and profile != "__pycache__":
116 profiles.append(profile)
115 profiles.append(profile)
117 return profiles
116 return profiles
118
117
119
118
120 class ProfileLocate(BaseIPythonApplication):
119 class ProfileLocate(BaseIPythonApplication):
121 description = """print the path an IPython profile dir"""
120 description = """print the path an IPython profile dir"""
122
121
123 def parse_command_line(self, argv=None):
122 def parse_command_line(self, argv=None):
124 super(ProfileLocate, self).parse_command_line(argv)
123 super(ProfileLocate, self).parse_command_line(argv)
125 if self.extra_args:
124 if self.extra_args:
126 self.profile = self.extra_args[0]
125 self.profile = self.extra_args[0]
127
126
128 def start(self):
127 def start(self):
129 print self.profile_dir.location
128 print self.profile_dir.location
130
129
131
130
132 class ProfileList(Application):
131 class ProfileList(Application):
133 name = u'ipython-profile'
132 name = u'ipython-profile'
134 description = list_help
133 description = list_help
135 examples = _list_examples
134 examples = _list_examples
136
135
137 aliases = Dict({
136 aliases = Dict({
138 'ipython-dir' : 'ProfileList.ipython_dir',
137 'ipython-dir' : 'ProfileList.ipython_dir',
139 'log-level' : 'Application.log_level',
138 'log-level' : 'Application.log_level',
140 })
139 })
141 flags = Dict(dict(
140 flags = Dict(dict(
142 debug = ({'Application' : {'log_level' : 0}},
141 debug = ({'Application' : {'log_level' : 0}},
143 "Set Application.log_level to 0, maximizing log output."
142 "Set Application.log_level to 0, maximizing log output."
144 )
143 )
145 ))
144 ))
146
145
147 ipython_dir = Unicode(get_ipython_dir(), config=True,
146 ipython_dir = Unicode(get_ipython_dir(), config=True,
148 help="""
147 help="""
149 The name of the IPython directory. This directory is used for logging
148 The name of the IPython directory. This directory is used for logging
150 configuration (through profiles), history storage, etc. The default
149 configuration (through profiles), history storage, etc. The default
151 is usually $HOME/.ipython. This options can also be specified through
150 is usually $HOME/.ipython. This options can also be specified through
152 the environment variable IPYTHONDIR.
151 the environment variable IPYTHONDIR.
153 """
152 """
154 )
153 )
155
154
156
155
157 def _print_profiles(self, profiles):
156 def _print_profiles(self, profiles):
158 """print list of profiles, indented."""
157 """print list of profiles, indented."""
159 for profile in profiles:
158 for profile in profiles:
160 print ' %s' % profile
159 print ' %s' % profile
161
160
162 def list_profile_dirs(self):
161 def list_profile_dirs(self):
163 profiles = list_bundled_profiles()
162 profiles = list_bundled_profiles()
164 if profiles:
163 if profiles:
165 print
164 print
166 print "Available profiles in IPython:"
165 print "Available profiles in IPython:"
167 self._print_profiles(profiles)
166 self._print_profiles(profiles)
168 print
167 print
169 print " The first request for a bundled profile will copy it"
168 print " The first request for a bundled profile will copy it"
170 print " into your IPython directory (%s)," % self.ipython_dir
169 print " into your IPython directory (%s)," % self.ipython_dir
171 print " where you can customize it."
170 print " where you can customize it."
172
171
173 profiles = list_profiles_in(self.ipython_dir)
172 profiles = list_profiles_in(self.ipython_dir)
174 if profiles:
173 if profiles:
175 print
174 print
176 print "Available profiles in %s:" % self.ipython_dir
175 print "Available profiles in %s:" % self.ipython_dir
177 self._print_profiles(profiles)
176 self._print_profiles(profiles)
178
177
179 profiles = list_profiles_in(os.getcwdu())
178 profiles = list_profiles_in(os.getcwdu())
180 if profiles:
179 if profiles:
181 print
180 print
182 print "Available profiles in current directory (%s):" % os.getcwdu()
181 print "Available profiles in current directory (%s):" % os.getcwdu()
183 self._print_profiles(profiles)
182 self._print_profiles(profiles)
184
183
185 print
184 print
186 print "To use any of the above profiles, start IPython with:"
185 print "To use any of the above profiles, start IPython with:"
187 print " ipython --profile=<name>"
186 print " ipython --profile=<name>"
188 print
187 print
189
188
190 def start(self):
189 def start(self):
191 self.list_profile_dirs()
190 self.list_profile_dirs()
192
191
193
192
194 create_flags = {}
193 create_flags = {}
195 create_flags.update(base_flags)
194 create_flags.update(base_flags)
196 # don't include '--init' flag, which implies running profile create in other apps
195 # don't include '--init' flag, which implies running profile create in other apps
197 create_flags.pop('init')
196 create_flags.pop('init')
198 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
197 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
199 "reset config files in this profile to the defaults.")
198 "reset config files in this profile to the defaults.")
200 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
199 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
201 "Include the config files for parallel "
200 "Include the config files for parallel "
202 "computing apps (ipengine, ipcontroller, etc.)")
201 "computing apps (ipengine, ipcontroller, etc.)")
203
202
204
203
205 class ProfileCreate(BaseIPythonApplication):
204 class ProfileCreate(BaseIPythonApplication):
206 name = u'ipython-profile'
205 name = u'ipython-profile'
207 description = create_help
206 description = create_help
208 examples = _create_examples
207 examples = _create_examples
209 auto_create = Bool(True, config=False)
208 auto_create = Bool(True, config=False)
210
209
211 def _copy_config_files_default(self):
210 def _copy_config_files_default(self):
212 return True
211 return True
213
212
214 parallel = Bool(False, config=True,
213 parallel = Bool(False, config=True,
215 help="whether to include parallel computing config files")
214 help="whether to include parallel computing config files")
216 def _parallel_changed(self, name, old, new):
215 def _parallel_changed(self, name, old, new):
217 parallel_files = [ 'ipcontroller_config.py',
216 parallel_files = [ 'ipcontroller_config.py',
218 'ipengine_config.py',
217 'ipengine_config.py',
219 'ipcluster_config.py'
218 'ipcluster_config.py'
220 ]
219 ]
221 if new:
220 if new:
222 for cf in parallel_files:
221 for cf in parallel_files:
223 self.config_files.append(cf)
222 self.config_files.append(cf)
224 else:
223 else:
225 for cf in parallel_files:
224 for cf in parallel_files:
226 if cf in self.config_files:
225 if cf in self.config_files:
227 self.config_files.remove(cf)
226 self.config_files.remove(cf)
228
227
229 def parse_command_line(self, argv):
228 def parse_command_line(self, argv):
230 super(ProfileCreate, self).parse_command_line(argv)
229 super(ProfileCreate, self).parse_command_line(argv)
231 # accept positional arg as profile name
230 # accept positional arg as profile name
232 if self.extra_args:
231 if self.extra_args:
233 self.profile = self.extra_args[0]
232 self.profile = self.extra_args[0]
234
233
235 flags = Dict(create_flags)
234 flags = Dict(create_flags)
236
235
237 classes = [ProfileDir]
236 classes = [ProfileDir]
238
237
239 def init_config_files(self):
238 def init_config_files(self):
240 super(ProfileCreate, self).init_config_files()
239 super(ProfileCreate, self).init_config_files()
241 # use local imports, since these classes may import from here
240 # use local imports, since these classes may import from here
242 from IPython.frontend.terminal.ipapp import TerminalIPythonApp
241 from IPython.frontend.terminal.ipapp import TerminalIPythonApp
243 apps = [TerminalIPythonApp]
242 apps = [TerminalIPythonApp]
244 try:
243 try:
245 from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp
244 from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp
246 except Exception:
245 except Exception:
247 # this should be ImportError, but under weird circumstances
246 # this should be ImportError, but under weird circumstances
248 # this might be an AttributeError, or possibly others
247 # this might be an AttributeError, or possibly others
249 # in any case, nothing should cause the profile creation to crash.
248 # in any case, nothing should cause the profile creation to crash.
250 pass
249 pass
251 else:
250 else:
252 apps.append(IPythonQtConsoleApp)
251 apps.append(IPythonQtConsoleApp)
253 try:
252 try:
254 from IPython.frontend.html.notebook.notebookapp import NotebookApp
253 from IPython.frontend.html.notebook.notebookapp import NotebookApp
255 except ImportError:
254 except ImportError:
256 pass
255 pass
257 except Exception:
256 except Exception:
258 self.log.debug('Unexpected error when importing NotebookApp',
257 self.log.debug('Unexpected error when importing NotebookApp',
259 exc_info=True
258 exc_info=True
260 )
259 )
261 else:
260 else:
262 apps.append(NotebookApp)
261 apps.append(NotebookApp)
263 if self.parallel:
262 if self.parallel:
264 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
263 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
265 from IPython.parallel.apps.ipengineapp import IPEngineApp
264 from IPython.parallel.apps.ipengineapp import IPEngineApp
266 from IPython.parallel.apps.ipclusterapp import IPClusterStart
265 from IPython.parallel.apps.ipclusterapp import IPClusterStart
267 from IPython.parallel.apps.iploggerapp import IPLoggerApp
266 from IPython.parallel.apps.iploggerapp import IPLoggerApp
268 apps.extend([
267 apps.extend([
269 IPControllerApp,
268 IPControllerApp,
270 IPEngineApp,
269 IPEngineApp,
271 IPClusterStart,
270 IPClusterStart,
272 IPLoggerApp,
271 IPLoggerApp,
273 ])
272 ])
274 for App in apps:
273 for App in apps:
275 app = App()
274 app = App()
276 app.config.update(self.config)
275 app.config.update(self.config)
277 app.log = self.log
276 app.log = self.log
278 app.overwrite = self.overwrite
277 app.overwrite = self.overwrite
279 app.copy_config_files=True
278 app.copy_config_files=True
280 app.profile = self.profile
279 app.profile = self.profile
281 app.init_profile_dir()
280 app.init_profile_dir()
282 app.init_config_files()
281 app.init_config_files()
283
282
284 def stage_default_config_file(self):
283 def stage_default_config_file(self):
285 pass
284 pass
286
285
287
286
288 class ProfileApp(Application):
287 class ProfileApp(Application):
289 name = u'ipython-profile'
288 name = u'ipython-profile'
290 description = profile_help
289 description = profile_help
291 examples = _main_examples
290 examples = _main_examples
292
291
293 subcommands = Dict(dict(
292 subcommands = Dict(dict(
294 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
293 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
295 list = (ProfileList, ProfileList.description.splitlines()[0]),
294 list = (ProfileList, ProfileList.description.splitlines()[0]),
296 ))
295 ))
297
296
298 def start(self):
297 def start(self):
299 if self.subapp is None:
298 if self.subapp is None:
300 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
299 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
301 print
300 print
302 self.print_description()
301 self.print_description()
303 self.print_subcommands()
302 self.print_subcommands()
304 self.exit(1)
303 self.exit(1)
305 else:
304 else:
306 return self.subapp.start()
305 return self.subapp.start()
307
306
@@ -1,228 +1,226 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An object for managing IPython profile directories.
3 An object for managing IPython profile directories.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import os
24 import os
25 import shutil
25 import shutil
26 import sys
27
26
28 from IPython.config.configurable import LoggingConfigurable
27 from IPython.config.configurable import LoggingConfigurable
29 from IPython.config.loader import Config
30 from IPython.utils.path import get_ipython_package_dir, expand_path
28 from IPython.utils.path import get_ipython_package_dir, expand_path
31 from IPython.utils.traitlets import List, Unicode, Bool
29 from IPython.utils.traitlets import Unicode, Bool
32
30
33 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
34 # Classes and functions
32 # Classes and functions
35 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
36
34
37
35
38 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
39 # Module errors
37 # Module errors
40 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
41
39
42 class ProfileDirError(Exception):
40 class ProfileDirError(Exception):
43 pass
41 pass
44
42
45
43
46 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
47 # Class for managing profile directories
45 # Class for managing profile directories
48 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
49
47
50 class ProfileDir(LoggingConfigurable):
48 class ProfileDir(LoggingConfigurable):
51 """An object to manage the profile directory and its resources.
49 """An object to manage the profile directory and its resources.
52
50
53 The profile directory is used by all IPython applications, to manage
51 The profile directory is used by all IPython applications, to manage
54 configuration, logging and security.
52 configuration, logging and security.
55
53
56 This object knows how to find, create and manage these directories. This
54 This object knows how to find, create and manage these directories. This
57 should be used by any code that wants to handle profiles.
55 should be used by any code that wants to handle profiles.
58 """
56 """
59
57
60 security_dir_name = Unicode('security')
58 security_dir_name = Unicode('security')
61 log_dir_name = Unicode('log')
59 log_dir_name = Unicode('log')
62 startup_dir_name = Unicode('startup')
60 startup_dir_name = Unicode('startup')
63 pid_dir_name = Unicode('pid')
61 pid_dir_name = Unicode('pid')
64 security_dir = Unicode(u'')
62 security_dir = Unicode(u'')
65 log_dir = Unicode(u'')
63 log_dir = Unicode(u'')
66 startup_dir = Unicode(u'')
64 startup_dir = Unicode(u'')
67 pid_dir = Unicode(u'')
65 pid_dir = Unicode(u'')
68
66
69 location = Unicode(u'', config=True,
67 location = Unicode(u'', config=True,
70 help="""Set the profile location directly. This overrides the logic used by the
68 help="""Set the profile location directly. This overrides the logic used by the
71 `profile` option.""",
69 `profile` option.""",
72 )
70 )
73
71
74 _location_isset = Bool(False) # flag for detecting multiply set location
72 _location_isset = Bool(False) # flag for detecting multiply set location
75
73
76 def _location_changed(self, name, old, new):
74 def _location_changed(self, name, old, new):
77 if self._location_isset:
75 if self._location_isset:
78 raise RuntimeError("Cannot set profile location more than once.")
76 raise RuntimeError("Cannot set profile location more than once.")
79 self._location_isset = True
77 self._location_isset = True
80 if not os.path.isdir(new):
78 if not os.path.isdir(new):
81 os.makedirs(new)
79 os.makedirs(new)
82
80
83 # ensure config files exist:
81 # ensure config files exist:
84 self.security_dir = os.path.join(new, self.security_dir_name)
82 self.security_dir = os.path.join(new, self.security_dir_name)
85 self.log_dir = os.path.join(new, self.log_dir_name)
83 self.log_dir = os.path.join(new, self.log_dir_name)
86 self.startup_dir = os.path.join(new, self.startup_dir_name)
84 self.startup_dir = os.path.join(new, self.startup_dir_name)
87 self.pid_dir = os.path.join(new, self.pid_dir_name)
85 self.pid_dir = os.path.join(new, self.pid_dir_name)
88 self.check_dirs()
86 self.check_dirs()
89
87
90 def _log_dir_changed(self, name, old, new):
88 def _log_dir_changed(self, name, old, new):
91 self.check_log_dir()
89 self.check_log_dir()
92
90
93 def check_log_dir(self):
91 def check_log_dir(self):
94 if not os.path.isdir(self.log_dir):
92 if not os.path.isdir(self.log_dir):
95 os.mkdir(self.log_dir)
93 os.mkdir(self.log_dir)
96
94
97 def _startup_dir_changed(self, name, old, new):
95 def _startup_dir_changed(self, name, old, new):
98 self.check_startup_dir()
96 self.check_startup_dir()
99
97
100 def check_startup_dir(self):
98 def check_startup_dir(self):
101 if not os.path.isdir(self.startup_dir):
99 if not os.path.isdir(self.startup_dir):
102 os.mkdir(self.startup_dir)
100 os.mkdir(self.startup_dir)
103 readme = os.path.join(self.startup_dir, 'README')
101 readme = os.path.join(self.startup_dir, 'README')
104 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
102 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
105 if not os.path.exists(readme):
103 if not os.path.exists(readme):
106 shutil.copy(src, readme)
104 shutil.copy(src, readme)
107
105
108 def _security_dir_changed(self, name, old, new):
106 def _security_dir_changed(self, name, old, new):
109 self.check_security_dir()
107 self.check_security_dir()
110
108
111 def check_security_dir(self):
109 def check_security_dir(self):
112 if not os.path.isdir(self.security_dir):
110 if not os.path.isdir(self.security_dir):
113 os.mkdir(self.security_dir, 0o700)
111 os.mkdir(self.security_dir, 0o700)
114 else:
112 else:
115 try:
113 try:
116 os.chmod(self.security_dir, 0o700)
114 os.chmod(self.security_dir, 0o700)
117 except OSError:
115 except OSError:
118 self.log.warn("Could not set security dir permissions to private.")
116 self.log.warn("Could not set security dir permissions to private.")
119
117
120 def _pid_dir_changed(self, name, old, new):
118 def _pid_dir_changed(self, name, old, new):
121 self.check_pid_dir()
119 self.check_pid_dir()
122
120
123 def check_pid_dir(self):
121 def check_pid_dir(self):
124 if not os.path.isdir(self.pid_dir):
122 if not os.path.isdir(self.pid_dir):
125 os.mkdir(self.pid_dir, 0o700)
123 os.mkdir(self.pid_dir, 0o700)
126 else:
124 else:
127 try:
125 try:
128 os.chmod(self.pid_dir, 0o700)
126 os.chmod(self.pid_dir, 0o700)
129 except OSError:
127 except OSError:
130 self.log.warn("Could not set pid dir permissions to private.")
128 self.log.warn("Could not set pid dir permissions to private.")
131
129
132 def check_dirs(self):
130 def check_dirs(self):
133 self.check_security_dir()
131 self.check_security_dir()
134 self.check_log_dir()
132 self.check_log_dir()
135 self.check_pid_dir()
133 self.check_pid_dir()
136 self.check_startup_dir()
134 self.check_startup_dir()
137
135
138 def copy_config_file(self, config_file, path=None, overwrite=False):
136 def copy_config_file(self, config_file, path=None, overwrite=False):
139 """Copy a default config file into the active profile directory.
137 """Copy a default config file into the active profile directory.
140
138
141 Default configuration files are kept in :mod:`IPython.config.default`.
139 Default configuration files are kept in :mod:`IPython.config.default`.
142 This function moves these from that location to the working profile
140 This function moves these from that location to the working profile
143 directory.
141 directory.
144 """
142 """
145 dst = os.path.join(self.location, config_file)
143 dst = os.path.join(self.location, config_file)
146 if os.path.isfile(dst) and not overwrite:
144 if os.path.isfile(dst) and not overwrite:
147 return False
145 return False
148 if path is None:
146 if path is None:
149 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
147 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
150 src = os.path.join(path, config_file)
148 src = os.path.join(path, config_file)
151 shutil.copy(src, dst)
149 shutil.copy(src, dst)
152 return True
150 return True
153
151
154 @classmethod
152 @classmethod
155 def create_profile_dir(cls, profile_dir, config=None):
153 def create_profile_dir(cls, profile_dir, config=None):
156 """Create a new profile directory given a full path.
154 """Create a new profile directory given a full path.
157
155
158 Parameters
156 Parameters
159 ----------
157 ----------
160 profile_dir : str
158 profile_dir : str
161 The full path to the profile directory. If it does exist, it will
159 The full path to the profile directory. If it does exist, it will
162 be used. If not, it will be created.
160 be used. If not, it will be created.
163 """
161 """
164 return cls(location=profile_dir, config=config)
162 return cls(location=profile_dir, config=config)
165
163
166 @classmethod
164 @classmethod
167 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
165 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
168 """Create a profile dir by profile name and path.
166 """Create a profile dir by profile name and path.
169
167
170 Parameters
168 Parameters
171 ----------
169 ----------
172 path : unicode
170 path : unicode
173 The path (directory) to put the profile directory in.
171 The path (directory) to put the profile directory in.
174 name : unicode
172 name : unicode
175 The name of the profile. The name of the profile directory will
173 The name of the profile. The name of the profile directory will
176 be "profile_<profile>".
174 be "profile_<profile>".
177 """
175 """
178 if not os.path.isdir(path):
176 if not os.path.isdir(path):
179 raise ProfileDirError('Directory not found: %s' % path)
177 raise ProfileDirError('Directory not found: %s' % path)
180 profile_dir = os.path.join(path, u'profile_' + name)
178 profile_dir = os.path.join(path, u'profile_' + name)
181 return cls(location=profile_dir, config=config)
179 return cls(location=profile_dir, config=config)
182
180
183 @classmethod
181 @classmethod
184 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
182 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
185 """Find an existing profile dir by profile name, return its ProfileDir.
183 """Find an existing profile dir by profile name, return its ProfileDir.
186
184
187 This searches through a sequence of paths for a profile dir. If it
185 This searches through a sequence of paths for a profile dir. If it
188 is not found, a :class:`ProfileDirError` exception will be raised.
186 is not found, a :class:`ProfileDirError` exception will be raised.
189
187
190 The search path algorithm is:
188 The search path algorithm is:
191 1. ``os.getcwdu()``
189 1. ``os.getcwdu()``
192 2. ``ipython_dir``
190 2. ``ipython_dir``
193
191
194 Parameters
192 Parameters
195 ----------
193 ----------
196 ipython_dir : unicode or str
194 ipython_dir : unicode or str
197 The IPython directory to use.
195 The IPython directory to use.
198 name : unicode or str
196 name : unicode or str
199 The name of the profile. The name of the profile directory
197 The name of the profile. The name of the profile directory
200 will be "profile_<profile>".
198 will be "profile_<profile>".
201 """
199 """
202 dirname = u'profile_' + name
200 dirname = u'profile_' + name
203 paths = [os.getcwdu(), ipython_dir]
201 paths = [os.getcwdu(), ipython_dir]
204 for p in paths:
202 for p in paths:
205 profile_dir = os.path.join(p, dirname)
203 profile_dir = os.path.join(p, dirname)
206 if os.path.isdir(profile_dir):
204 if os.path.isdir(profile_dir):
207 return cls(location=profile_dir, config=config)
205 return cls(location=profile_dir, config=config)
208 else:
206 else:
209 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
207 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
210
208
211 @classmethod
209 @classmethod
212 def find_profile_dir(cls, profile_dir, config=None):
210 def find_profile_dir(cls, profile_dir, config=None):
213 """Find/create a profile dir and return its ProfileDir.
211 """Find/create a profile dir and return its ProfileDir.
214
212
215 This will create the profile directory if it doesn't exist.
213 This will create the profile directory if it doesn't exist.
216
214
217 Parameters
215 Parameters
218 ----------
216 ----------
219 profile_dir : unicode or str
217 profile_dir : unicode or str
220 The path of the profile directory. This is expanded using
218 The path of the profile directory. This is expanded using
221 :func:`IPython.utils.genutils.expand_path`.
219 :func:`IPython.utils.genutils.expand_path`.
222 """
220 """
223 profile_dir = expand_path(profile_dir)
221 profile_dir = expand_path(profile_dir)
224 if not os.path.isdir(profile_dir):
222 if not os.path.isdir(profile_dir):
225 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
223 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
226 return cls(location=profile_dir, config=config)
224 return cls(location=profile_dir, config=config)
227
225
228
226
@@ -1,1247 +1,1246 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultratb.py -- Spice up your tracebacks!
3 ultratb.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultratb
12 import sys,ultratb
13 sys.excepthook = ultratb.ColorTB()
13 sys.excepthook = ultratb.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultratb
40 import sys,ultratb
41 sys.excepthook = ultratb.VerboseTB()
41 sys.excepthook = ultratb.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
62
63 Inheritance diagram:
63 Inheritance diagram:
64
64
65 .. inheritance-diagram:: IPython.core.ultratb
65 .. inheritance-diagram:: IPython.core.ultratb
66 :parts: 3
66 :parts: 3
67 """
67 """
68
68
69 #*****************************************************************************
69 #*****************************************************************************
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
72 #
72 #
73 # Distributed under the terms of the BSD License. The full license is in
73 # Distributed under the terms of the BSD License. The full license is in
74 # the file COPYING, distributed as part of this software.
74 # the file COPYING, distributed as part of this software.
75 #*****************************************************************************
75 #*****************************************************************************
76
76
77 from __future__ import unicode_literals
77 from __future__ import unicode_literals
78
78
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import re
84 import re
85 import sys
85 import sys
86 import time
86 import time
87 import tokenize
87 import tokenize
88 import traceback
88 import traceback
89 import types
89 import types
90
90
91 try: # Python 2
91 try: # Python 2
92 generate_tokens = tokenize.generate_tokens
92 generate_tokens = tokenize.generate_tokens
93 except AttributeError: # Python 3
93 except AttributeError: # Python 3
94 generate_tokens = tokenize.tokenize
94 generate_tokens = tokenize.tokenize
95
95
96 # For purposes of monkeypatching inspect to fix a bug in it.
96 # For purposes of monkeypatching inspect to fix a bug in it.
97 from inspect import getsourcefile, getfile, getmodule,\
97 from inspect import getsourcefile, getfile, getmodule,\
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
99
99
100 # IPython's own modules
100 # IPython's own modules
101 # Modified pdb which doesn't damage IPython's readline handling
101 # Modified pdb which doesn't damage IPython's readline handling
102 from IPython.core import debugger, ipapi
102 from IPython.core import debugger, ipapi
103 from IPython.core.display_trap import DisplayTrap
103 from IPython.core.display_trap import DisplayTrap
104 from IPython.core.excolors import exception_colors
104 from IPython.core.excolors import exception_colors
105 from IPython.utils import PyColorize
105 from IPython.utils import PyColorize
106 from IPython.utils import io
106 from IPython.utils import io
107 from IPython.utils import path as util_path
107 from IPython.utils import path as util_path
108 from IPython.utils import py3compat
108 from IPython.utils import py3compat
109 from IPython.utils import pyfile
109 from IPython.utils import pyfile
110 from IPython.utils import ulinecache
110 from IPython.utils import ulinecache
111 from IPython.utils.data import uniq_stable
111 from IPython.utils.data import uniq_stable
112 from IPython.utils.openpy import read_py_file
113 from IPython.utils.warn import info, error
112 from IPython.utils.warn import info, error
114
113
115 # Globals
114 # Globals
116 # amount of space to put line numbers before verbose tracebacks
115 # amount of space to put line numbers before verbose tracebacks
117 INDENT_SIZE = 8
116 INDENT_SIZE = 8
118
117
119 # Default color scheme. This is used, for example, by the traceback
118 # Default color scheme. This is used, for example, by the traceback
120 # formatter. When running in an actual IPython instance, the user's rc.colors
119 # formatter. When running in an actual IPython instance, the user's rc.colors
121 # value is used, but havinga module global makes this functionality available
120 # value is used, but havinga module global makes this functionality available
122 # to users of ultratb who are NOT running inside ipython.
121 # to users of ultratb who are NOT running inside ipython.
123 DEFAULT_SCHEME = 'NoColor'
122 DEFAULT_SCHEME = 'NoColor'
124
123
125 #---------------------------------------------------------------------------
124 #---------------------------------------------------------------------------
126 # Code begins
125 # Code begins
127
126
128 # Utility functions
127 # Utility functions
129 def inspect_error():
128 def inspect_error():
130 """Print a message about internal inspect errors.
129 """Print a message about internal inspect errors.
131
130
132 These are unfortunately quite common."""
131 These are unfortunately quite common."""
133
132
134 error('Internal Python error in the inspect module.\n'
133 error('Internal Python error in the inspect module.\n'
135 'Below is the traceback from this internal error.\n')
134 'Below is the traceback from this internal error.\n')
136
135
137 # This function is a monkeypatch we apply to the Python inspect module. We have
136 # This function is a monkeypatch we apply to the Python inspect module. We have
138 # now found when it's needed (see discussion on issue gh-1456), and we have a
137 # now found when it's needed (see discussion on issue gh-1456), and we have a
139 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
138 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
140 # the monkeypatch is not applied. TK, Aug 2012.
139 # the monkeypatch is not applied. TK, Aug 2012.
141 def findsource(object):
140 def findsource(object):
142 """Return the entire source file and starting line number for an object.
141 """Return the entire source file and starting line number for an object.
143
142
144 The argument may be a module, class, method, function, traceback, frame,
143 The argument may be a module, class, method, function, traceback, frame,
145 or code object. The source code is returned as a list of all the lines
144 or code object. The source code is returned as a list of all the lines
146 in the file and the line number indexes a line in that list. An IOError
145 in the file and the line number indexes a line in that list. An IOError
147 is raised if the source code cannot be retrieved.
146 is raised if the source code cannot be retrieved.
148
147
149 FIXED version with which we monkeypatch the stdlib to work around a bug."""
148 FIXED version with which we monkeypatch the stdlib to work around a bug."""
150
149
151 file = getsourcefile(object) or getfile(object)
150 file = getsourcefile(object) or getfile(object)
152 # If the object is a frame, then trying to get the globals dict from its
151 # If the object is a frame, then trying to get the globals dict from its
153 # module won't work. Instead, the frame object itself has the globals
152 # module won't work. Instead, the frame object itself has the globals
154 # dictionary.
153 # dictionary.
155 globals_dict = None
154 globals_dict = None
156 if inspect.isframe(object):
155 if inspect.isframe(object):
157 # XXX: can this ever be false?
156 # XXX: can this ever be false?
158 globals_dict = object.f_globals
157 globals_dict = object.f_globals
159 else:
158 else:
160 module = getmodule(object, file)
159 module = getmodule(object, file)
161 if module:
160 if module:
162 globals_dict = module.__dict__
161 globals_dict = module.__dict__
163 lines = linecache.getlines(file, globals_dict)
162 lines = linecache.getlines(file, globals_dict)
164 if not lines:
163 if not lines:
165 raise IOError('could not get source code')
164 raise IOError('could not get source code')
166
165
167 if ismodule(object):
166 if ismodule(object):
168 return lines, 0
167 return lines, 0
169
168
170 if isclass(object):
169 if isclass(object):
171 name = object.__name__
170 name = object.__name__
172 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
171 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
173 # make some effort to find the best matching class definition:
172 # make some effort to find the best matching class definition:
174 # use the one with the least indentation, which is the one
173 # use the one with the least indentation, which is the one
175 # that's most probably not inside a function definition.
174 # that's most probably not inside a function definition.
176 candidates = []
175 candidates = []
177 for i in range(len(lines)):
176 for i in range(len(lines)):
178 match = pat.match(lines[i])
177 match = pat.match(lines[i])
179 if match:
178 if match:
180 # if it's at toplevel, it's already the best one
179 # if it's at toplevel, it's already the best one
181 if lines[i][0] == 'c':
180 if lines[i][0] == 'c':
182 return lines, i
181 return lines, i
183 # else add whitespace to candidate list
182 # else add whitespace to candidate list
184 candidates.append((match.group(1), i))
183 candidates.append((match.group(1), i))
185 if candidates:
184 if candidates:
186 # this will sort by whitespace, and by line number,
185 # this will sort by whitespace, and by line number,
187 # less whitespace first
186 # less whitespace first
188 candidates.sort()
187 candidates.sort()
189 return lines, candidates[0][1]
188 return lines, candidates[0][1]
190 else:
189 else:
191 raise IOError('could not find class definition')
190 raise IOError('could not find class definition')
192
191
193 if ismethod(object):
192 if ismethod(object):
194 object = object.im_func
193 object = object.im_func
195 if isfunction(object):
194 if isfunction(object):
196 object = object.func_code
195 object = object.func_code
197 if istraceback(object):
196 if istraceback(object):
198 object = object.tb_frame
197 object = object.tb_frame
199 if isframe(object):
198 if isframe(object):
200 object = object.f_code
199 object = object.f_code
201 if iscode(object):
200 if iscode(object):
202 if not hasattr(object, 'co_firstlineno'):
201 if not hasattr(object, 'co_firstlineno'):
203 raise IOError('could not find function definition')
202 raise IOError('could not find function definition')
204 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
203 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
205 pmatch = pat.match
204 pmatch = pat.match
206 # fperez - fix: sometimes, co_firstlineno can give a number larger than
205 # fperez - fix: sometimes, co_firstlineno can give a number larger than
207 # the length of lines, which causes an error. Safeguard against that.
206 # the length of lines, which causes an error. Safeguard against that.
208 lnum = min(object.co_firstlineno,len(lines))-1
207 lnum = min(object.co_firstlineno,len(lines))-1
209 while lnum > 0:
208 while lnum > 0:
210 if pmatch(lines[lnum]): break
209 if pmatch(lines[lnum]): break
211 lnum -= 1
210 lnum -= 1
212
211
213 return lines, lnum
212 return lines, lnum
214 raise IOError('could not find code object')
213 raise IOError('could not find code object')
215
214
216 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
215 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
217 inspect.findsource = findsource
216 inspect.findsource = findsource
218
217
219 def fix_frame_records_filenames(records):
218 def fix_frame_records_filenames(records):
220 """Try to fix the filenames in each record from inspect.getinnerframes().
219 """Try to fix the filenames in each record from inspect.getinnerframes().
221
220
222 Particularly, modules loaded from within zip files have useless filenames
221 Particularly, modules loaded from within zip files have useless filenames
223 attached to their code object, and inspect.getinnerframes() just uses it.
222 attached to their code object, and inspect.getinnerframes() just uses it.
224 """
223 """
225 fixed_records = []
224 fixed_records = []
226 for frame, filename, line_no, func_name, lines, index in records:
225 for frame, filename, line_no, func_name, lines, index in records:
227 # Look inside the frame's globals dictionary for __file__, which should
226 # Look inside the frame's globals dictionary for __file__, which should
228 # be better.
227 # be better.
229 better_fn = frame.f_globals.get('__file__', None)
228 better_fn = frame.f_globals.get('__file__', None)
230 if isinstance(better_fn, str):
229 if isinstance(better_fn, str):
231 # Check the type just in case someone did something weird with
230 # Check the type just in case someone did something weird with
232 # __file__. It might also be None if the error occurred during
231 # __file__. It might also be None if the error occurred during
233 # import.
232 # import.
234 filename = better_fn
233 filename = better_fn
235 fixed_records.append((frame, filename, line_no, func_name, lines, index))
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
236 return fixed_records
235 return fixed_records
237
236
238
237
239 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
240 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
239 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
241
240
242 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
241 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
243
242
244 # If the error is at the console, don't build any context, since it would
243 # If the error is at the console, don't build any context, since it would
245 # otherwise produce 5 blank lines printed out (there is no file at the
244 # otherwise produce 5 blank lines printed out (there is no file at the
246 # console)
245 # console)
247 rec_check = records[tb_offset:]
246 rec_check = records[tb_offset:]
248 try:
247 try:
249 rname = rec_check[0][1]
248 rname = rec_check[0][1]
250 if rname == '<ipython console>' or rname.endswith('<string>'):
249 if rname == '<ipython console>' or rname.endswith('<string>'):
251 return rec_check
250 return rec_check
252 except IndexError:
251 except IndexError:
253 pass
252 pass
254
253
255 aux = traceback.extract_tb(etb)
254 aux = traceback.extract_tb(etb)
256 assert len(records) == len(aux)
255 assert len(records) == len(aux)
257 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
256 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
258 maybeStart = lnum-1 - context//2
257 maybeStart = lnum-1 - context//2
259 start = max(maybeStart, 0)
258 start = max(maybeStart, 0)
260 end = start + context
259 end = start + context
261 lines = ulinecache.getlines(file)[start:end]
260 lines = ulinecache.getlines(file)[start:end]
262 buf = list(records[i])
261 buf = list(records[i])
263 buf[LNUM_POS] = lnum
262 buf[LNUM_POS] = lnum
264 buf[INDEX_POS] = lnum - 1 - start
263 buf[INDEX_POS] = lnum - 1 - start
265 buf[LINES_POS] = lines
264 buf[LINES_POS] = lines
266 records[i] = tuple(buf)
265 records[i] = tuple(buf)
267 return records[tb_offset:]
266 return records[tb_offset:]
268
267
269 # Helper function -- largely belongs to VerboseTB, but we need the same
268 # Helper function -- largely belongs to VerboseTB, but we need the same
270 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
269 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
271 # can be recognized properly by ipython.el's py-traceback-line-re
270 # can be recognized properly by ipython.el's py-traceback-line-re
272 # (SyntaxErrors have to be treated specially because they have no traceback)
271 # (SyntaxErrors have to be treated specially because they have no traceback)
273
272
274 _parser = PyColorize.Parser()
273 _parser = PyColorize.Parser()
275
274
276 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
275 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
277 numbers_width = INDENT_SIZE - 1
276 numbers_width = INDENT_SIZE - 1
278 res = []
277 res = []
279 i = lnum - index
278 i = lnum - index
280
279
281 # This lets us get fully syntax-highlighted tracebacks.
280 # This lets us get fully syntax-highlighted tracebacks.
282 if scheme is None:
281 if scheme is None:
283 ipinst = ipapi.get()
282 ipinst = ipapi.get()
284 if ipinst is not None:
283 if ipinst is not None:
285 scheme = ipinst.colors
284 scheme = ipinst.colors
286 else:
285 else:
287 scheme = DEFAULT_SCHEME
286 scheme = DEFAULT_SCHEME
288
287
289 _line_format = _parser.format2
288 _line_format = _parser.format2
290
289
291 for line in lines:
290 for line in lines:
292 line = py3compat.cast_unicode(line)
291 line = py3compat.cast_unicode(line)
293
292
294 new_line, err = _line_format(line, 'str', scheme)
293 new_line, err = _line_format(line, 'str', scheme)
295 if not err: line = new_line
294 if not err: line = new_line
296
295
297 if i == lnum:
296 if i == lnum:
298 # This is the line with the error
297 # This is the line with the error
299 pad = numbers_width - len(str(i))
298 pad = numbers_width - len(str(i))
300 if pad >= 3:
299 if pad >= 3:
301 marker = '-'*(pad-3) + '-> '
300 marker = '-'*(pad-3) + '-> '
302 elif pad == 2:
301 elif pad == 2:
303 marker = '> '
302 marker = '> '
304 elif pad == 1:
303 elif pad == 1:
305 marker = '>'
304 marker = '>'
306 else:
305 else:
307 marker = ''
306 marker = ''
308 num = marker + str(i)
307 num = marker + str(i)
309 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
308 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
310 Colors.line, line, Colors.Normal)
309 Colors.line, line, Colors.Normal)
311 else:
310 else:
312 num = '%*s' % (numbers_width,i)
311 num = '%*s' % (numbers_width,i)
313 line = '%s%s%s %s' %(Colors.lineno, num,
312 line = '%s%s%s %s' %(Colors.lineno, num,
314 Colors.Normal, line)
313 Colors.Normal, line)
315
314
316 res.append(line)
315 res.append(line)
317 if lvals and i == lnum:
316 if lvals and i == lnum:
318 res.append(lvals + '\n')
317 res.append(lvals + '\n')
319 i = i + 1
318 i = i + 1
320 return res
319 return res
321
320
322
321
323 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
324 # Module classes
323 # Module classes
325 class TBTools(object):
324 class TBTools(object):
326 """Basic tools used by all traceback printer classes."""
325 """Basic tools used by all traceback printer classes."""
327
326
328 # Number of frames to skip when reporting tracebacks
327 # Number of frames to skip when reporting tracebacks
329 tb_offset = 0
328 tb_offset = 0
330
329
331 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
330 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
332 # Whether to call the interactive pdb debugger after printing
331 # Whether to call the interactive pdb debugger after printing
333 # tracebacks or not
332 # tracebacks or not
334 self.call_pdb = call_pdb
333 self.call_pdb = call_pdb
335
334
336 # Output stream to write to. Note that we store the original value in
335 # Output stream to write to. Note that we store the original value in
337 # a private attribute and then make the public ostream a property, so
336 # a private attribute and then make the public ostream a property, so
338 # that we can delay accessing io.stdout until runtime. The way
337 # that we can delay accessing io.stdout until runtime. The way
339 # things are written now, the io.stdout object is dynamically managed
338 # things are written now, the io.stdout object is dynamically managed
340 # so a reference to it should NEVER be stored statically. This
339 # so a reference to it should NEVER be stored statically. This
341 # property approach confines this detail to a single location, and all
340 # property approach confines this detail to a single location, and all
342 # subclasses can simply access self.ostream for writing.
341 # subclasses can simply access self.ostream for writing.
343 self._ostream = ostream
342 self._ostream = ostream
344
343
345 # Create color table
344 # Create color table
346 self.color_scheme_table = exception_colors()
345 self.color_scheme_table = exception_colors()
347
346
348 self.set_colors(color_scheme)
347 self.set_colors(color_scheme)
349 self.old_scheme = color_scheme # save initial value for toggles
348 self.old_scheme = color_scheme # save initial value for toggles
350
349
351 if call_pdb:
350 if call_pdb:
352 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
351 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
353 else:
352 else:
354 self.pdb = None
353 self.pdb = None
355
354
356 def _get_ostream(self):
355 def _get_ostream(self):
357 """Output stream that exceptions are written to.
356 """Output stream that exceptions are written to.
358
357
359 Valid values are:
358 Valid values are:
360
359
361 - None: the default, which means that IPython will dynamically resolve
360 - None: the default, which means that IPython will dynamically resolve
362 to io.stdout. This ensures compatibility with most tools, including
361 to io.stdout. This ensures compatibility with most tools, including
363 Windows (where plain stdout doesn't recognize ANSI escapes).
362 Windows (where plain stdout doesn't recognize ANSI escapes).
364
363
365 - Any object with 'write' and 'flush' attributes.
364 - Any object with 'write' and 'flush' attributes.
366 """
365 """
367 return io.stdout if self._ostream is None else self._ostream
366 return io.stdout if self._ostream is None else self._ostream
368
367
369 def _set_ostream(self, val):
368 def _set_ostream(self, val):
370 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
369 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
371 self._ostream = val
370 self._ostream = val
372
371
373 ostream = property(_get_ostream, _set_ostream)
372 ostream = property(_get_ostream, _set_ostream)
374
373
375 def set_colors(self,*args,**kw):
374 def set_colors(self,*args,**kw):
376 """Shorthand access to the color table scheme selector method."""
375 """Shorthand access to the color table scheme selector method."""
377
376
378 # Set own color table
377 # Set own color table
379 self.color_scheme_table.set_active_scheme(*args,**kw)
378 self.color_scheme_table.set_active_scheme(*args,**kw)
380 # for convenience, set Colors to the active scheme
379 # for convenience, set Colors to the active scheme
381 self.Colors = self.color_scheme_table.active_colors
380 self.Colors = self.color_scheme_table.active_colors
382 # Also set colors of debugger
381 # Also set colors of debugger
383 if hasattr(self,'pdb') and self.pdb is not None:
382 if hasattr(self,'pdb') and self.pdb is not None:
384 self.pdb.set_colors(*args,**kw)
383 self.pdb.set_colors(*args,**kw)
385
384
386 def color_toggle(self):
385 def color_toggle(self):
387 """Toggle between the currently active color scheme and NoColor."""
386 """Toggle between the currently active color scheme and NoColor."""
388
387
389 if self.color_scheme_table.active_scheme_name == 'NoColor':
388 if self.color_scheme_table.active_scheme_name == 'NoColor':
390 self.color_scheme_table.set_active_scheme(self.old_scheme)
389 self.color_scheme_table.set_active_scheme(self.old_scheme)
391 self.Colors = self.color_scheme_table.active_colors
390 self.Colors = self.color_scheme_table.active_colors
392 else:
391 else:
393 self.old_scheme = self.color_scheme_table.active_scheme_name
392 self.old_scheme = self.color_scheme_table.active_scheme_name
394 self.color_scheme_table.set_active_scheme('NoColor')
393 self.color_scheme_table.set_active_scheme('NoColor')
395 self.Colors = self.color_scheme_table.active_colors
394 self.Colors = self.color_scheme_table.active_colors
396
395
397 def stb2text(self, stb):
396 def stb2text(self, stb):
398 """Convert a structured traceback (a list) to a string."""
397 """Convert a structured traceback (a list) to a string."""
399 return '\n'.join(stb)
398 return '\n'.join(stb)
400
399
401 def text(self, etype, value, tb, tb_offset=None, context=5):
400 def text(self, etype, value, tb, tb_offset=None, context=5):
402 """Return formatted traceback.
401 """Return formatted traceback.
403
402
404 Subclasses may override this if they add extra arguments.
403 Subclasses may override this if they add extra arguments.
405 """
404 """
406 tb_list = self.structured_traceback(etype, value, tb,
405 tb_list = self.structured_traceback(etype, value, tb,
407 tb_offset, context)
406 tb_offset, context)
408 return self.stb2text(tb_list)
407 return self.stb2text(tb_list)
409
408
410 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
409 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
411 context=5, mode=None):
410 context=5, mode=None):
412 """Return a list of traceback frames.
411 """Return a list of traceback frames.
413
412
414 Must be implemented by each class.
413 Must be implemented by each class.
415 """
414 """
416 raise NotImplementedError()
415 raise NotImplementedError()
417
416
418
417
419 #---------------------------------------------------------------------------
418 #---------------------------------------------------------------------------
420 class ListTB(TBTools):
419 class ListTB(TBTools):
421 """Print traceback information from a traceback list, with optional color.
420 """Print traceback information from a traceback list, with optional color.
422
421
423 Calling requires 3 arguments: (etype, evalue, elist)
422 Calling requires 3 arguments: (etype, evalue, elist)
424 as would be obtained by::
423 as would be obtained by::
425
424
426 etype, evalue, tb = sys.exc_info()
425 etype, evalue, tb = sys.exc_info()
427 if tb:
426 if tb:
428 elist = traceback.extract_tb(tb)
427 elist = traceback.extract_tb(tb)
429 else:
428 else:
430 elist = None
429 elist = None
431
430
432 It can thus be used by programs which need to process the traceback before
431 It can thus be used by programs which need to process the traceback before
433 printing (such as console replacements based on the code module from the
432 printing (such as console replacements based on the code module from the
434 standard library).
433 standard library).
435
434
436 Because they are meant to be called without a full traceback (only a
435 Because they are meant to be called without a full traceback (only a
437 list), instances of this class can't call the interactive pdb debugger."""
436 list), instances of this class can't call the interactive pdb debugger."""
438
437
439 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
438 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
440 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
439 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
441 ostream=ostream)
440 ostream=ostream)
442
441
443 def __call__(self, etype, value, elist):
442 def __call__(self, etype, value, elist):
444 self.ostream.flush()
443 self.ostream.flush()
445 self.ostream.write(self.text(etype, value, elist))
444 self.ostream.write(self.text(etype, value, elist))
446 self.ostream.write('\n')
445 self.ostream.write('\n')
447
446
448 def structured_traceback(self, etype, value, elist, tb_offset=None,
447 def structured_traceback(self, etype, value, elist, tb_offset=None,
449 context=5):
448 context=5):
450 """Return a color formatted string with the traceback info.
449 """Return a color formatted string with the traceback info.
451
450
452 Parameters
451 Parameters
453 ----------
452 ----------
454 etype : exception type
453 etype : exception type
455 Type of the exception raised.
454 Type of the exception raised.
456
455
457 value : object
456 value : object
458 Data stored in the exception
457 Data stored in the exception
459
458
460 elist : list
459 elist : list
461 List of frames, see class docstring for details.
460 List of frames, see class docstring for details.
462
461
463 tb_offset : int, optional
462 tb_offset : int, optional
464 Number of frames in the traceback to skip. If not given, the
463 Number of frames in the traceback to skip. If not given, the
465 instance value is used (set in constructor).
464 instance value is used (set in constructor).
466
465
467 context : int, optional
466 context : int, optional
468 Number of lines of context information to print.
467 Number of lines of context information to print.
469
468
470 Returns
469 Returns
471 -------
470 -------
472 String with formatted exception.
471 String with formatted exception.
473 """
472 """
474 tb_offset = self.tb_offset if tb_offset is None else tb_offset
473 tb_offset = self.tb_offset if tb_offset is None else tb_offset
475 Colors = self.Colors
474 Colors = self.Colors
476 out_list = []
475 out_list = []
477 if elist:
476 if elist:
478
477
479 if tb_offset and len(elist) > tb_offset:
478 if tb_offset and len(elist) > tb_offset:
480 elist = elist[tb_offset:]
479 elist = elist[tb_offset:]
481
480
482 out_list.append('Traceback %s(most recent call last)%s:' %
481 out_list.append('Traceback %s(most recent call last)%s:' %
483 (Colors.normalEm, Colors.Normal) + '\n')
482 (Colors.normalEm, Colors.Normal) + '\n')
484 out_list.extend(self._format_list(elist))
483 out_list.extend(self._format_list(elist))
485 # The exception info should be a single entry in the list.
484 # The exception info should be a single entry in the list.
486 lines = ''.join(self._format_exception_only(etype, value))
485 lines = ''.join(self._format_exception_only(etype, value))
487 out_list.append(lines)
486 out_list.append(lines)
488
487
489 # Note: this code originally read:
488 # Note: this code originally read:
490
489
491 ## for line in lines[:-1]:
490 ## for line in lines[:-1]:
492 ## out_list.append(" "+line)
491 ## out_list.append(" "+line)
493 ## out_list.append(lines[-1])
492 ## out_list.append(lines[-1])
494
493
495 # This means it was indenting everything but the last line by a little
494 # This means it was indenting everything but the last line by a little
496 # bit. I've disabled this for now, but if we see ugliness somewhre we
495 # bit. I've disabled this for now, but if we see ugliness somewhre we
497 # can restore it.
496 # can restore it.
498
497
499 return out_list
498 return out_list
500
499
501 def _format_list(self, extracted_list):
500 def _format_list(self, extracted_list):
502 """Format a list of traceback entry tuples for printing.
501 """Format a list of traceback entry tuples for printing.
503
502
504 Given a list of tuples as returned by extract_tb() or
503 Given a list of tuples as returned by extract_tb() or
505 extract_stack(), return a list of strings ready for printing.
504 extract_stack(), return a list of strings ready for printing.
506 Each string in the resulting list corresponds to the item with the
505 Each string in the resulting list corresponds to the item with the
507 same index in the argument list. Each string ends in a newline;
506 same index in the argument list. Each string ends in a newline;
508 the strings may contain internal newlines as well, for those items
507 the strings may contain internal newlines as well, for those items
509 whose source text line is not None.
508 whose source text line is not None.
510
509
511 Lifted almost verbatim from traceback.py
510 Lifted almost verbatim from traceback.py
512 """
511 """
513
512
514 Colors = self.Colors
513 Colors = self.Colors
515 list = []
514 list = []
516 for filename, lineno, name, line in extracted_list[:-1]:
515 for filename, lineno, name, line in extracted_list[:-1]:
517 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
516 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
518 (Colors.filename, filename, Colors.Normal,
517 (Colors.filename, filename, Colors.Normal,
519 Colors.lineno, lineno, Colors.Normal,
518 Colors.lineno, lineno, Colors.Normal,
520 Colors.name, name, Colors.Normal)
519 Colors.name, name, Colors.Normal)
521 if line:
520 if line:
522 item += ' %s\n' % line.strip()
521 item += ' %s\n' % line.strip()
523 list.append(item)
522 list.append(item)
524 # Emphasize the last entry
523 # Emphasize the last entry
525 filename, lineno, name, line = extracted_list[-1]
524 filename, lineno, name, line = extracted_list[-1]
526 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
525 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
527 (Colors.normalEm,
526 (Colors.normalEm,
528 Colors.filenameEm, filename, Colors.normalEm,
527 Colors.filenameEm, filename, Colors.normalEm,
529 Colors.linenoEm, lineno, Colors.normalEm,
528 Colors.linenoEm, lineno, Colors.normalEm,
530 Colors.nameEm, name, Colors.normalEm,
529 Colors.nameEm, name, Colors.normalEm,
531 Colors.Normal)
530 Colors.Normal)
532 if line:
531 if line:
533 item += '%s %s%s\n' % (Colors.line, line.strip(),
532 item += '%s %s%s\n' % (Colors.line, line.strip(),
534 Colors.Normal)
533 Colors.Normal)
535 list.append(item)
534 list.append(item)
536 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
535 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
537 return list
536 return list
538
537
539 def _format_exception_only(self, etype, value):
538 def _format_exception_only(self, etype, value):
540 """Format the exception part of a traceback.
539 """Format the exception part of a traceback.
541
540
542 The arguments are the exception type and value such as given by
541 The arguments are the exception type and value such as given by
543 sys.exc_info()[:2]. The return value is a list of strings, each ending
542 sys.exc_info()[:2]. The return value is a list of strings, each ending
544 in a newline. Normally, the list contains a single string; however,
543 in a newline. Normally, the list contains a single string; however,
545 for SyntaxError exceptions, it contains several lines that (when
544 for SyntaxError exceptions, it contains several lines that (when
546 printed) display detailed information about where the syntax error
545 printed) display detailed information about where the syntax error
547 occurred. The message indicating which exception occurred is the
546 occurred. The message indicating which exception occurred is the
548 always last string in the list.
547 always last string in the list.
549
548
550 Also lifted nearly verbatim from traceback.py
549 Also lifted nearly verbatim from traceback.py
551 """
550 """
552 have_filedata = False
551 have_filedata = False
553 Colors = self.Colors
552 Colors = self.Colors
554 list = []
553 list = []
555 stype = Colors.excName + etype.__name__ + Colors.Normal
554 stype = Colors.excName + etype.__name__ + Colors.Normal
556 if value is None:
555 if value is None:
557 # Not sure if this can still happen in Python 2.6 and above
556 # Not sure if this can still happen in Python 2.6 and above
558 list.append( py3compat.cast_unicode(stype) + '\n')
557 list.append( py3compat.cast_unicode(stype) + '\n')
559 else:
558 else:
560 if issubclass(etype, SyntaxError):
559 if issubclass(etype, SyntaxError):
561 have_filedata = True
560 have_filedata = True
562 #print 'filename is',filename # dbg
561 #print 'filename is',filename # dbg
563 if not value.filename: value.filename = "<string>"
562 if not value.filename: value.filename = "<string>"
564 if value.lineno:
563 if value.lineno:
565 lineno = value.lineno
564 lineno = value.lineno
566 textline = ulinecache.getline(value.filename, value.lineno)
565 textline = ulinecache.getline(value.filename, value.lineno)
567 else:
566 else:
568 lineno = 'unknown'
567 lineno = 'unknown'
569 textline = ''
568 textline = ''
570 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
569 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
571 (Colors.normalEm,
570 (Colors.normalEm,
572 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
571 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
573 Colors.linenoEm, lineno, Colors.Normal ))
572 Colors.linenoEm, lineno, Colors.Normal ))
574 if textline == '':
573 if textline == '':
575 textline = py3compat.cast_unicode(value.text, "utf-8")
574 textline = py3compat.cast_unicode(value.text, "utf-8")
576
575
577 if textline is not None:
576 if textline is not None:
578 i = 0
577 i = 0
579 while i < len(textline) and textline[i].isspace():
578 while i < len(textline) and textline[i].isspace():
580 i += 1
579 i += 1
581 list.append('%s %s%s\n' % (Colors.line,
580 list.append('%s %s%s\n' % (Colors.line,
582 textline.strip(),
581 textline.strip(),
583 Colors.Normal))
582 Colors.Normal))
584 if value.offset is not None:
583 if value.offset is not None:
585 s = ' '
584 s = ' '
586 for c in textline[i:value.offset-1]:
585 for c in textline[i:value.offset-1]:
587 if c.isspace():
586 if c.isspace():
588 s += c
587 s += c
589 else:
588 else:
590 s += ' '
589 s += ' '
591 list.append('%s%s^%s\n' % (Colors.caret, s,
590 list.append('%s%s^%s\n' % (Colors.caret, s,
592 Colors.Normal) )
591 Colors.Normal) )
593
592
594 try:
593 try:
595 s = value.msg
594 s = value.msg
596 except Exception:
595 except Exception:
597 s = self._some_str(value)
596 s = self._some_str(value)
598 if s:
597 if s:
599 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
598 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
600 Colors.Normal, s))
599 Colors.Normal, s))
601 else:
600 else:
602 list.append('%s\n' % str(stype))
601 list.append('%s\n' % str(stype))
603
602
604 # sync with user hooks
603 # sync with user hooks
605 if have_filedata:
604 if have_filedata:
606 ipinst = ipapi.get()
605 ipinst = ipapi.get()
607 if ipinst is not None:
606 if ipinst is not None:
608 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
607 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
609
608
610 return list
609 return list
611
610
612 def get_exception_only(self, etype, value):
611 def get_exception_only(self, etype, value):
613 """Only print the exception type and message, without a traceback.
612 """Only print the exception type and message, without a traceback.
614
613
615 Parameters
614 Parameters
616 ----------
615 ----------
617 etype : exception type
616 etype : exception type
618 value : exception value
617 value : exception value
619 """
618 """
620 return ListTB.structured_traceback(self, etype, value, [])
619 return ListTB.structured_traceback(self, etype, value, [])
621
620
622
621
623 def show_exception_only(self, etype, evalue):
622 def show_exception_only(self, etype, evalue):
624 """Only print the exception type and message, without a traceback.
623 """Only print the exception type and message, without a traceback.
625
624
626 Parameters
625 Parameters
627 ----------
626 ----------
628 etype : exception type
627 etype : exception type
629 value : exception value
628 value : exception value
630 """
629 """
631 # This method needs to use __call__ from *this* class, not the one from
630 # This method needs to use __call__ from *this* class, not the one from
632 # a subclass whose signature or behavior may be different
631 # a subclass whose signature or behavior may be different
633 ostream = self.ostream
632 ostream = self.ostream
634 ostream.flush()
633 ostream.flush()
635 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
634 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
636 ostream.flush()
635 ostream.flush()
637
636
638 def _some_str(self, value):
637 def _some_str(self, value):
639 # Lifted from traceback.py
638 # Lifted from traceback.py
640 try:
639 try:
641 return str(value)
640 return str(value)
642 except:
641 except:
643 return '<unprintable %s object>' % type(value).__name__
642 return '<unprintable %s object>' % type(value).__name__
644
643
645 #----------------------------------------------------------------------------
644 #----------------------------------------------------------------------------
646 class VerboseTB(TBTools):
645 class VerboseTB(TBTools):
647 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
646 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
648 of HTML. Requires inspect and pydoc. Crazy, man.
647 of HTML. Requires inspect and pydoc. Crazy, man.
649
648
650 Modified version which optionally strips the topmost entries from the
649 Modified version which optionally strips the topmost entries from the
651 traceback, to be used with alternate interpreters (because their own code
650 traceback, to be used with alternate interpreters (because their own code
652 would appear in the traceback)."""
651 would appear in the traceback)."""
653
652
654 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
653 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
655 tb_offset=0, long_header=False, include_vars=True,
654 tb_offset=0, long_header=False, include_vars=True,
656 check_cache=None):
655 check_cache=None):
657 """Specify traceback offset, headers and color scheme.
656 """Specify traceback offset, headers and color scheme.
658
657
659 Define how many frames to drop from the tracebacks. Calling it with
658 Define how many frames to drop from the tracebacks. Calling it with
660 tb_offset=1 allows use of this handler in interpreters which will have
659 tb_offset=1 allows use of this handler in interpreters which will have
661 their own code at the top of the traceback (VerboseTB will first
660 their own code at the top of the traceback (VerboseTB will first
662 remove that frame before printing the traceback info)."""
661 remove that frame before printing the traceback info)."""
663 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
662 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
664 ostream=ostream)
663 ostream=ostream)
665 self.tb_offset = tb_offset
664 self.tb_offset = tb_offset
666 self.long_header = long_header
665 self.long_header = long_header
667 self.include_vars = include_vars
666 self.include_vars = include_vars
668 # By default we use linecache.checkcache, but the user can provide a
667 # By default we use linecache.checkcache, but the user can provide a
669 # different check_cache implementation. This is used by the IPython
668 # different check_cache implementation. This is used by the IPython
670 # kernel to provide tracebacks for interactive code that is cached,
669 # kernel to provide tracebacks for interactive code that is cached,
671 # by a compiler instance that flushes the linecache but preserves its
670 # by a compiler instance that flushes the linecache but preserves its
672 # own code cache.
671 # own code cache.
673 if check_cache is None:
672 if check_cache is None:
674 check_cache = linecache.checkcache
673 check_cache = linecache.checkcache
675 self.check_cache = check_cache
674 self.check_cache = check_cache
676
675
677 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
676 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
678 context=5):
677 context=5):
679 """Return a nice text document describing the traceback."""
678 """Return a nice text document describing the traceback."""
680
679
681 tb_offset = self.tb_offset if tb_offset is None else tb_offset
680 tb_offset = self.tb_offset if tb_offset is None else tb_offset
682
681
683 # some locals
682 # some locals
684 try:
683 try:
685 etype = etype.__name__
684 etype = etype.__name__
686 except AttributeError:
685 except AttributeError:
687 pass
686 pass
688 Colors = self.Colors # just a shorthand + quicker name lookup
687 Colors = self.Colors # just a shorthand + quicker name lookup
689 ColorsNormal = Colors.Normal # used a lot
688 ColorsNormal = Colors.Normal # used a lot
690 col_scheme = self.color_scheme_table.active_scheme_name
689 col_scheme = self.color_scheme_table.active_scheme_name
691 indent = ' '*INDENT_SIZE
690 indent = ' '*INDENT_SIZE
692 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
691 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
693 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
692 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
694 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
693 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
695
694
696 # some internal-use functions
695 # some internal-use functions
697 def text_repr(value):
696 def text_repr(value):
698 """Hopefully pretty robust repr equivalent."""
697 """Hopefully pretty robust repr equivalent."""
699 # this is pretty horrible but should always return *something*
698 # this is pretty horrible but should always return *something*
700 try:
699 try:
701 return pydoc.text.repr(value)
700 return pydoc.text.repr(value)
702 except KeyboardInterrupt:
701 except KeyboardInterrupt:
703 raise
702 raise
704 except:
703 except:
705 try:
704 try:
706 return repr(value)
705 return repr(value)
707 except KeyboardInterrupt:
706 except KeyboardInterrupt:
708 raise
707 raise
709 except:
708 except:
710 try:
709 try:
711 # all still in an except block so we catch
710 # all still in an except block so we catch
712 # getattr raising
711 # getattr raising
713 name = getattr(value, '__name__', None)
712 name = getattr(value, '__name__', None)
714 if name:
713 if name:
715 # ick, recursion
714 # ick, recursion
716 return text_repr(name)
715 return text_repr(name)
717 klass = getattr(value, '__class__', None)
716 klass = getattr(value, '__class__', None)
718 if klass:
717 if klass:
719 return '%s instance' % text_repr(klass)
718 return '%s instance' % text_repr(klass)
720 except KeyboardInterrupt:
719 except KeyboardInterrupt:
721 raise
720 raise
722 except:
721 except:
723 return 'UNRECOVERABLE REPR FAILURE'
722 return 'UNRECOVERABLE REPR FAILURE'
724 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
723 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
725 def nullrepr(value, repr=text_repr): return ''
724 def nullrepr(value, repr=text_repr): return ''
726
725
727 # meat of the code begins
726 # meat of the code begins
728 try:
727 try:
729 etype = etype.__name__
728 etype = etype.__name__
730 except AttributeError:
729 except AttributeError:
731 pass
730 pass
732
731
733 if self.long_header:
732 if self.long_header:
734 # Header with the exception type, python version, and date
733 # Header with the exception type, python version, and date
735 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
734 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
736 date = time.ctime(time.time())
735 date = time.ctime(time.time())
737
736
738 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
737 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
739 exc, ' '*(75-len(str(etype))-len(pyver)),
738 exc, ' '*(75-len(str(etype))-len(pyver)),
740 pyver, date.rjust(75) )
739 pyver, date.rjust(75) )
741 head += "\nA problem occured executing Python code. Here is the sequence of function"\
740 head += "\nA problem occured executing Python code. Here is the sequence of function"\
742 "\ncalls leading up to the error, with the most recent (innermost) call last."
741 "\ncalls leading up to the error, with the most recent (innermost) call last."
743 else:
742 else:
744 # Simplified header
743 # Simplified header
745 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
744 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
746 'Traceback (most recent call last)'.\
745 'Traceback (most recent call last)'.\
747 rjust(75 - len(str(etype)) ) )
746 rjust(75 - len(str(etype)) ) )
748 frames = []
747 frames = []
749 # Flush cache before calling inspect. This helps alleviate some of the
748 # Flush cache before calling inspect. This helps alleviate some of the
750 # problems with python 2.3's inspect.py.
749 # problems with python 2.3's inspect.py.
751 ##self.check_cache()
750 ##self.check_cache()
752 # Drop topmost frames if requested
751 # Drop topmost frames if requested
753 try:
752 try:
754 # Try the default getinnerframes and Alex's: Alex's fixes some
753 # Try the default getinnerframes and Alex's: Alex's fixes some
755 # problems, but it generates empty tracebacks for console errors
754 # problems, but it generates empty tracebacks for console errors
756 # (5 blanks lines) where none should be returned.
755 # (5 blanks lines) where none should be returned.
757 #records = inspect.getinnerframes(etb, context)[tb_offset:]
756 #records = inspect.getinnerframes(etb, context)[tb_offset:]
758 #print 'python records:', records # dbg
757 #print 'python records:', records # dbg
759 records = _fixed_getinnerframes(etb, context, tb_offset)
758 records = _fixed_getinnerframes(etb, context, tb_offset)
760 #print 'alex records:', records # dbg
759 #print 'alex records:', records # dbg
761 except:
760 except:
762
761
763 # FIXME: I've been getting many crash reports from python 2.3
762 # FIXME: I've been getting many crash reports from python 2.3
764 # users, traceable to inspect.py. If I can find a small test-case
763 # users, traceable to inspect.py. If I can find a small test-case
765 # to reproduce this, I should either write a better workaround or
764 # to reproduce this, I should either write a better workaround or
766 # file a bug report against inspect (if that's the real problem).
765 # file a bug report against inspect (if that's the real problem).
767 # So far, I haven't been able to find an isolated example to
766 # So far, I haven't been able to find an isolated example to
768 # reproduce the problem.
767 # reproduce the problem.
769 inspect_error()
768 inspect_error()
770 traceback.print_exc(file=self.ostream)
769 traceback.print_exc(file=self.ostream)
771 info('\nUnfortunately, your original traceback can not be constructed.\n')
770 info('\nUnfortunately, your original traceback can not be constructed.\n')
772 return ''
771 return ''
773
772
774 # build some color string templates outside these nested loops
773 # build some color string templates outside these nested loops
775 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
774 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
776 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
775 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
777 ColorsNormal)
776 ColorsNormal)
778 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
777 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
779 (Colors.vName, Colors.valEm, ColorsNormal)
778 (Colors.vName, Colors.valEm, ColorsNormal)
780 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
779 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
781 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
780 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
782 Colors.vName, ColorsNormal)
781 Colors.vName, ColorsNormal)
783 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
782 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
784 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
783 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
785 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
784 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
786 ColorsNormal)
785 ColorsNormal)
787
786
788 # now, loop over all records printing context and info
787 # now, loop over all records printing context and info
789 abspath = os.path.abspath
788 abspath = os.path.abspath
790 for frame, file, lnum, func, lines, index in records:
789 for frame, file, lnum, func, lines, index in records:
791 #print '*** record:',file,lnum,func,lines,index # dbg
790 #print '*** record:',file,lnum,func,lines,index # dbg
792 if not file:
791 if not file:
793 file = '?'
792 file = '?'
794 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
793 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
795 # Guess that filenames like <string> aren't real filenames, so
794 # Guess that filenames like <string> aren't real filenames, so
796 # don't call abspath on them.
795 # don't call abspath on them.
797 try:
796 try:
798 file = abspath(file)
797 file = abspath(file)
799 except OSError:
798 except OSError:
800 # Not sure if this can still happen: abspath now works with
799 # Not sure if this can still happen: abspath now works with
801 # file names like <string>
800 # file names like <string>
802 pass
801 pass
803 file = py3compat.cast_unicode(file, util_path.fs_encoding)
802 file = py3compat.cast_unicode(file, util_path.fs_encoding)
804 link = tpl_link % file
803 link = tpl_link % file
805 args, varargs, varkw, locals = inspect.getargvalues(frame)
804 args, varargs, varkw, locals = inspect.getargvalues(frame)
806
805
807 if func == '?':
806 if func == '?':
808 call = ''
807 call = ''
809 else:
808 else:
810 # Decide whether to include variable details or not
809 # Decide whether to include variable details or not
811 var_repr = self.include_vars and eqrepr or nullrepr
810 var_repr = self.include_vars and eqrepr or nullrepr
812 try:
811 try:
813 call = tpl_call % (func,inspect.formatargvalues(args,
812 call = tpl_call % (func,inspect.formatargvalues(args,
814 varargs, varkw,
813 varargs, varkw,
815 locals,formatvalue=var_repr))
814 locals,formatvalue=var_repr))
816 except KeyError:
815 except KeyError:
817 # This happens in situations like errors inside generator
816 # This happens in situations like errors inside generator
818 # expressions, where local variables are listed in the
817 # expressions, where local variables are listed in the
819 # line, but can't be extracted from the frame. I'm not
818 # line, but can't be extracted from the frame. I'm not
820 # 100% sure this isn't actually a bug in inspect itself,
819 # 100% sure this isn't actually a bug in inspect itself,
821 # but since there's no info for us to compute with, the
820 # but since there's no info for us to compute with, the
822 # best we can do is report the failure and move on. Here
821 # best we can do is report the failure and move on. Here
823 # we must *not* call any traceback construction again,
822 # we must *not* call any traceback construction again,
824 # because that would mess up use of %debug later on. So we
823 # because that would mess up use of %debug later on. So we
825 # simply report the failure and move on. The only
824 # simply report the failure and move on. The only
826 # limitation will be that this frame won't have locals
825 # limitation will be that this frame won't have locals
827 # listed in the call signature. Quite subtle problem...
826 # listed in the call signature. Quite subtle problem...
828 # I can't think of a good way to validate this in a unit
827 # I can't think of a good way to validate this in a unit
829 # test, but running a script consisting of:
828 # test, but running a script consisting of:
830 # dict( (k,v.strip()) for (k,v) in range(10) )
829 # dict( (k,v.strip()) for (k,v) in range(10) )
831 # will illustrate the error, if this exception catch is
830 # will illustrate the error, if this exception catch is
832 # disabled.
831 # disabled.
833 call = tpl_call_fail % func
832 call = tpl_call_fail % func
834
833
835 # Don't attempt to tokenize binary files.
834 # Don't attempt to tokenize binary files.
836 if file.endswith(('.so', '.pyd', '.dll')):
835 if file.endswith(('.so', '.pyd', '.dll')):
837 frames.append('%s %s\n' % (link,call))
836 frames.append('%s %s\n' % (link,call))
838 continue
837 continue
839 elif file.endswith(('.pyc','.pyo')):
838 elif file.endswith(('.pyc','.pyo')):
840 # Look up the corresponding source file.
839 # Look up the corresponding source file.
841 file = pyfile.source_from_cache(file)
840 file = pyfile.source_from_cache(file)
842
841
843 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
842 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
844 line = getline(file, lnum[0])
843 line = getline(file, lnum[0])
845 lnum[0] += 1
844 lnum[0] += 1
846 return line
845 return line
847
846
848 # Build the list of names on this line of code where the exception
847 # Build the list of names on this line of code where the exception
849 # occurred.
848 # occurred.
850 try:
849 try:
851 names = []
850 names = []
852 name_cont = False
851 name_cont = False
853
852
854 for token_type, token, start, end, line in generate_tokens(linereader):
853 for token_type, token, start, end, line in generate_tokens(linereader):
855 # build composite names
854 # build composite names
856 if token_type == tokenize.NAME and token not in keyword.kwlist:
855 if token_type == tokenize.NAME and token not in keyword.kwlist:
857 if name_cont:
856 if name_cont:
858 # Continuation of a dotted name
857 # Continuation of a dotted name
859 try:
858 try:
860 names[-1].append(token)
859 names[-1].append(token)
861 except IndexError:
860 except IndexError:
862 names.append([token])
861 names.append([token])
863 name_cont = False
862 name_cont = False
864 else:
863 else:
865 # Regular new names. We append everything, the caller
864 # Regular new names. We append everything, the caller
866 # will be responsible for pruning the list later. It's
865 # will be responsible for pruning the list later. It's
867 # very tricky to try to prune as we go, b/c composite
866 # very tricky to try to prune as we go, b/c composite
868 # names can fool us. The pruning at the end is easy
867 # names can fool us. The pruning at the end is easy
869 # to do (or the caller can print a list with repeated
868 # to do (or the caller can print a list with repeated
870 # names if so desired.
869 # names if so desired.
871 names.append([token])
870 names.append([token])
872 elif token == '.':
871 elif token == '.':
873 name_cont = True
872 name_cont = True
874 elif token_type == tokenize.NEWLINE:
873 elif token_type == tokenize.NEWLINE:
875 break
874 break
876
875
877 except (IndexError, UnicodeDecodeError):
876 except (IndexError, UnicodeDecodeError):
878 # signals exit of tokenizer
877 # signals exit of tokenizer
879 pass
878 pass
880 except tokenize.TokenError as msg:
879 except tokenize.TokenError as msg:
881 _m = ("An unexpected error occurred while tokenizing input\n"
880 _m = ("An unexpected error occurred while tokenizing input\n"
882 "The following traceback may be corrupted or invalid\n"
881 "The following traceback may be corrupted or invalid\n"
883 "The error message is: %s\n" % msg)
882 "The error message is: %s\n" % msg)
884 error(_m)
883 error(_m)
885
884
886 # Join composite names (e.g. "dict.fromkeys")
885 # Join composite names (e.g. "dict.fromkeys")
887 names = ['.'.join(n) for n in names]
886 names = ['.'.join(n) for n in names]
888 # prune names list of duplicates, but keep the right order
887 # prune names list of duplicates, but keep the right order
889 unique_names = uniq_stable(names)
888 unique_names = uniq_stable(names)
890
889
891 # Start loop over vars
890 # Start loop over vars
892 lvals = []
891 lvals = []
893 if self.include_vars:
892 if self.include_vars:
894 for name_full in unique_names:
893 for name_full in unique_names:
895 name_base = name_full.split('.',1)[0]
894 name_base = name_full.split('.',1)[0]
896 if name_base in frame.f_code.co_varnames:
895 if name_base in frame.f_code.co_varnames:
897 if name_base in locals:
896 if name_base in locals:
898 try:
897 try:
899 value = repr(eval(name_full,locals))
898 value = repr(eval(name_full,locals))
900 except:
899 except:
901 value = undefined
900 value = undefined
902 else:
901 else:
903 value = undefined
902 value = undefined
904 name = tpl_local_var % name_full
903 name = tpl_local_var % name_full
905 else:
904 else:
906 if name_base in frame.f_globals:
905 if name_base in frame.f_globals:
907 try:
906 try:
908 value = repr(eval(name_full,frame.f_globals))
907 value = repr(eval(name_full,frame.f_globals))
909 except:
908 except:
910 value = undefined
909 value = undefined
911 else:
910 else:
912 value = undefined
911 value = undefined
913 name = tpl_global_var % name_full
912 name = tpl_global_var % name_full
914 lvals.append(tpl_name_val % (name,value))
913 lvals.append(tpl_name_val % (name,value))
915 if lvals:
914 if lvals:
916 lvals = '%s%s' % (indent,em_normal.join(lvals))
915 lvals = '%s%s' % (indent,em_normal.join(lvals))
917 else:
916 else:
918 lvals = ''
917 lvals = ''
919
918
920 level = '%s %s\n' % (link,call)
919 level = '%s %s\n' % (link,call)
921
920
922 if index is None:
921 if index is None:
923 frames.append(level)
922 frames.append(level)
924 else:
923 else:
925 frames.append('%s%s' % (level,''.join(
924 frames.append('%s%s' % (level,''.join(
926 _format_traceback_lines(lnum,index,lines,Colors,lvals,
925 _format_traceback_lines(lnum,index,lines,Colors,lvals,
927 col_scheme))))
926 col_scheme))))
928
927
929 # Get (safely) a string form of the exception info
928 # Get (safely) a string form of the exception info
930 try:
929 try:
931 etype_str,evalue_str = map(str,(etype,evalue))
930 etype_str,evalue_str = map(str,(etype,evalue))
932 except:
931 except:
933 # User exception is improperly defined.
932 # User exception is improperly defined.
934 etype,evalue = str,sys.exc_info()[:2]
933 etype,evalue = str,sys.exc_info()[:2]
935 etype_str,evalue_str = map(str,(etype,evalue))
934 etype_str,evalue_str = map(str,(etype,evalue))
936 # ... and format it
935 # ... and format it
937 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
936 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
938 ColorsNormal, py3compat.cast_unicode(evalue_str))]
937 ColorsNormal, py3compat.cast_unicode(evalue_str))]
939 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
938 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
940 try:
939 try:
941 names = [w for w in dir(evalue) if isinstance(w, basestring)]
940 names = [w for w in dir(evalue) if isinstance(w, basestring)]
942 except:
941 except:
943 # Every now and then, an object with funny inernals blows up
942 # Every now and then, an object with funny inernals blows up
944 # when dir() is called on it. We do the best we can to report
943 # when dir() is called on it. We do the best we can to report
945 # the problem and continue
944 # the problem and continue
946 _m = '%sException reporting error (object with broken dir())%s:'
945 _m = '%sException reporting error (object with broken dir())%s:'
947 exception.append(_m % (Colors.excName,ColorsNormal))
946 exception.append(_m % (Colors.excName,ColorsNormal))
948 etype_str,evalue_str = map(str,sys.exc_info()[:2])
947 etype_str,evalue_str = map(str,sys.exc_info()[:2])
949 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
948 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
950 ColorsNormal, py3compat.cast_unicode(evalue_str)))
949 ColorsNormal, py3compat.cast_unicode(evalue_str)))
951 names = []
950 names = []
952 for name in names:
951 for name in names:
953 value = text_repr(getattr(evalue, name))
952 value = text_repr(getattr(evalue, name))
954 exception.append('\n%s%s = %s' % (indent, name, value))
953 exception.append('\n%s%s = %s' % (indent, name, value))
955
954
956 # vds: >>
955 # vds: >>
957 if records:
956 if records:
958 filepath, lnum = records[-1][1:3]
957 filepath, lnum = records[-1][1:3]
959 #print "file:", str(file), "linenb", str(lnum) # dbg
958 #print "file:", str(file), "linenb", str(lnum) # dbg
960 filepath = os.path.abspath(filepath)
959 filepath = os.path.abspath(filepath)
961 ipinst = ipapi.get()
960 ipinst = ipapi.get()
962 if ipinst is not None:
961 if ipinst is not None:
963 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
962 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
964 # vds: <<
963 # vds: <<
965
964
966 # return all our info assembled as a single string
965 # return all our info assembled as a single string
967 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
966 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
968 return [head] + frames + [''.join(exception[0])]
967 return [head] + frames + [''.join(exception[0])]
969
968
970 def debugger(self,force=False):
969 def debugger(self,force=False):
971 """Call up the pdb debugger if desired, always clean up the tb
970 """Call up the pdb debugger if desired, always clean up the tb
972 reference.
971 reference.
973
972
974 Keywords:
973 Keywords:
975
974
976 - force(False): by default, this routine checks the instance call_pdb
975 - force(False): by default, this routine checks the instance call_pdb
977 flag and does not actually invoke the debugger if the flag is false.
976 flag and does not actually invoke the debugger if the flag is false.
978 The 'force' option forces the debugger to activate even if the flag
977 The 'force' option forces the debugger to activate even if the flag
979 is false.
978 is false.
980
979
981 If the call_pdb flag is set, the pdb interactive debugger is
980 If the call_pdb flag is set, the pdb interactive debugger is
982 invoked. In all cases, the self.tb reference to the current traceback
981 invoked. In all cases, the self.tb reference to the current traceback
983 is deleted to prevent lingering references which hamper memory
982 is deleted to prevent lingering references which hamper memory
984 management.
983 management.
985
984
986 Note that each call to pdb() does an 'import readline', so if your app
985 Note that each call to pdb() does an 'import readline', so if your app
987 requires a special setup for the readline completers, you'll have to
986 requires a special setup for the readline completers, you'll have to
988 fix that by hand after invoking the exception handler."""
987 fix that by hand after invoking the exception handler."""
989
988
990 if force or self.call_pdb:
989 if force or self.call_pdb:
991 if self.pdb is None:
990 if self.pdb is None:
992 self.pdb = debugger.Pdb(
991 self.pdb = debugger.Pdb(
993 self.color_scheme_table.active_scheme_name)
992 self.color_scheme_table.active_scheme_name)
994 # the system displayhook may have changed, restore the original
993 # the system displayhook may have changed, restore the original
995 # for pdb
994 # for pdb
996 display_trap = DisplayTrap(hook=sys.__displayhook__)
995 display_trap = DisplayTrap(hook=sys.__displayhook__)
997 with display_trap:
996 with display_trap:
998 self.pdb.reset()
997 self.pdb.reset()
999 # Find the right frame so we don't pop up inside ipython itself
998 # Find the right frame so we don't pop up inside ipython itself
1000 if hasattr(self,'tb') and self.tb is not None:
999 if hasattr(self,'tb') and self.tb is not None:
1001 etb = self.tb
1000 etb = self.tb
1002 else:
1001 else:
1003 etb = self.tb = sys.last_traceback
1002 etb = self.tb = sys.last_traceback
1004 while self.tb is not None and self.tb.tb_next is not None:
1003 while self.tb is not None and self.tb.tb_next is not None:
1005 self.tb = self.tb.tb_next
1004 self.tb = self.tb.tb_next
1006 if etb and etb.tb_next:
1005 if etb and etb.tb_next:
1007 etb = etb.tb_next
1006 etb = etb.tb_next
1008 self.pdb.botframe = etb.tb_frame
1007 self.pdb.botframe = etb.tb_frame
1009 self.pdb.interaction(self.tb.tb_frame, self.tb)
1008 self.pdb.interaction(self.tb.tb_frame, self.tb)
1010
1009
1011 if hasattr(self,'tb'):
1010 if hasattr(self,'tb'):
1012 del self.tb
1011 del self.tb
1013
1012
1014 def handler(self, info=None):
1013 def handler(self, info=None):
1015 (etype, evalue, etb) = info or sys.exc_info()
1014 (etype, evalue, etb) = info or sys.exc_info()
1016 self.tb = etb
1015 self.tb = etb
1017 ostream = self.ostream
1016 ostream = self.ostream
1018 ostream.flush()
1017 ostream.flush()
1019 ostream.write(self.text(etype, evalue, etb))
1018 ostream.write(self.text(etype, evalue, etb))
1020 ostream.write('\n')
1019 ostream.write('\n')
1021 ostream.flush()
1020 ostream.flush()
1022
1021
1023 # Changed so an instance can just be called as VerboseTB_inst() and print
1022 # Changed so an instance can just be called as VerboseTB_inst() and print
1024 # out the right info on its own.
1023 # out the right info on its own.
1025 def __call__(self, etype=None, evalue=None, etb=None):
1024 def __call__(self, etype=None, evalue=None, etb=None):
1026 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1025 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1027 if etb is None:
1026 if etb is None:
1028 self.handler()
1027 self.handler()
1029 else:
1028 else:
1030 self.handler((etype, evalue, etb))
1029 self.handler((etype, evalue, etb))
1031 try:
1030 try:
1032 self.debugger()
1031 self.debugger()
1033 except KeyboardInterrupt:
1032 except KeyboardInterrupt:
1034 print "\nKeyboardInterrupt"
1033 print "\nKeyboardInterrupt"
1035
1034
1036 #----------------------------------------------------------------------------
1035 #----------------------------------------------------------------------------
1037 class FormattedTB(VerboseTB, ListTB):
1036 class FormattedTB(VerboseTB, ListTB):
1038 """Subclass ListTB but allow calling with a traceback.
1037 """Subclass ListTB but allow calling with a traceback.
1039
1038
1040 It can thus be used as a sys.excepthook for Python > 2.1.
1039 It can thus be used as a sys.excepthook for Python > 2.1.
1041
1040
1042 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1041 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1043
1042
1044 Allows a tb_offset to be specified. This is useful for situations where
1043 Allows a tb_offset to be specified. This is useful for situations where
1045 one needs to remove a number of topmost frames from the traceback (such as
1044 one needs to remove a number of topmost frames from the traceback (such as
1046 occurs with python programs that themselves execute other python code,
1045 occurs with python programs that themselves execute other python code,
1047 like Python shells). """
1046 like Python shells). """
1048
1047
1049 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1048 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1050 ostream=None,
1049 ostream=None,
1051 tb_offset=0, long_header=False, include_vars=False,
1050 tb_offset=0, long_header=False, include_vars=False,
1052 check_cache=None):
1051 check_cache=None):
1053
1052
1054 # NEVER change the order of this list. Put new modes at the end:
1053 # NEVER change the order of this list. Put new modes at the end:
1055 self.valid_modes = ['Plain','Context','Verbose']
1054 self.valid_modes = ['Plain','Context','Verbose']
1056 self.verbose_modes = self.valid_modes[1:3]
1055 self.verbose_modes = self.valid_modes[1:3]
1057
1056
1058 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1057 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1059 ostream=ostream, tb_offset=tb_offset,
1058 ostream=ostream, tb_offset=tb_offset,
1060 long_header=long_header, include_vars=include_vars,
1059 long_header=long_header, include_vars=include_vars,
1061 check_cache=check_cache)
1060 check_cache=check_cache)
1062
1061
1063 # Different types of tracebacks are joined with different separators to
1062 # Different types of tracebacks are joined with different separators to
1064 # form a single string. They are taken from this dict
1063 # form a single string. They are taken from this dict
1065 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1064 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1066 # set_mode also sets the tb_join_char attribute
1065 # set_mode also sets the tb_join_char attribute
1067 self.set_mode(mode)
1066 self.set_mode(mode)
1068
1067
1069 def _extract_tb(self,tb):
1068 def _extract_tb(self,tb):
1070 if tb:
1069 if tb:
1071 return traceback.extract_tb(tb)
1070 return traceback.extract_tb(tb)
1072 else:
1071 else:
1073 return None
1072 return None
1074
1073
1075 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1074 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1076 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1075 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1077 mode = self.mode
1076 mode = self.mode
1078 if mode in self.verbose_modes:
1077 if mode in self.verbose_modes:
1079 # Verbose modes need a full traceback
1078 # Verbose modes need a full traceback
1080 return VerboseTB.structured_traceback(
1079 return VerboseTB.structured_traceback(
1081 self, etype, value, tb, tb_offset, context
1080 self, etype, value, tb, tb_offset, context
1082 )
1081 )
1083 else:
1082 else:
1084 # We must check the source cache because otherwise we can print
1083 # We must check the source cache because otherwise we can print
1085 # out-of-date source code.
1084 # out-of-date source code.
1086 self.check_cache()
1085 self.check_cache()
1087 # Now we can extract and format the exception
1086 # Now we can extract and format the exception
1088 elist = self._extract_tb(tb)
1087 elist = self._extract_tb(tb)
1089 return ListTB.structured_traceback(
1088 return ListTB.structured_traceback(
1090 self, etype, value, elist, tb_offset, context
1089 self, etype, value, elist, tb_offset, context
1091 )
1090 )
1092
1091
1093 def stb2text(self, stb):
1092 def stb2text(self, stb):
1094 """Convert a structured traceback (a list) to a string."""
1093 """Convert a structured traceback (a list) to a string."""
1095 return self.tb_join_char.join(stb)
1094 return self.tb_join_char.join(stb)
1096
1095
1097
1096
1098 def set_mode(self,mode=None):
1097 def set_mode(self,mode=None):
1099 """Switch to the desired mode.
1098 """Switch to the desired mode.
1100
1099
1101 If mode is not specified, cycles through the available modes."""
1100 If mode is not specified, cycles through the available modes."""
1102
1101
1103 if not mode:
1102 if not mode:
1104 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1103 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1105 len(self.valid_modes)
1104 len(self.valid_modes)
1106 self.mode = self.valid_modes[new_idx]
1105 self.mode = self.valid_modes[new_idx]
1107 elif mode not in self.valid_modes:
1106 elif mode not in self.valid_modes:
1108 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1107 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1109 'Valid modes: '+str(self.valid_modes))
1108 'Valid modes: '+str(self.valid_modes))
1110 else:
1109 else:
1111 self.mode = mode
1110 self.mode = mode
1112 # include variable details only in 'Verbose' mode
1111 # include variable details only in 'Verbose' mode
1113 self.include_vars = (self.mode == self.valid_modes[2])
1112 self.include_vars = (self.mode == self.valid_modes[2])
1114 # Set the join character for generating text tracebacks
1113 # Set the join character for generating text tracebacks
1115 self.tb_join_char = self._join_chars[self.mode]
1114 self.tb_join_char = self._join_chars[self.mode]
1116
1115
1117 # some convenient shorcuts
1116 # some convenient shorcuts
1118 def plain(self):
1117 def plain(self):
1119 self.set_mode(self.valid_modes[0])
1118 self.set_mode(self.valid_modes[0])
1120
1119
1121 def context(self):
1120 def context(self):
1122 self.set_mode(self.valid_modes[1])
1121 self.set_mode(self.valid_modes[1])
1123
1122
1124 def verbose(self):
1123 def verbose(self):
1125 self.set_mode(self.valid_modes[2])
1124 self.set_mode(self.valid_modes[2])
1126
1125
1127 #----------------------------------------------------------------------------
1126 #----------------------------------------------------------------------------
1128 class AutoFormattedTB(FormattedTB):
1127 class AutoFormattedTB(FormattedTB):
1129 """A traceback printer which can be called on the fly.
1128 """A traceback printer which can be called on the fly.
1130
1129
1131 It will find out about exceptions by itself.
1130 It will find out about exceptions by itself.
1132
1131
1133 A brief example::
1132 A brief example::
1134
1133
1135 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1134 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1136 try:
1135 try:
1137 ...
1136 ...
1138 except:
1137 except:
1139 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1138 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1140 """
1139 """
1141
1140
1142 def __call__(self,etype=None,evalue=None,etb=None,
1141 def __call__(self,etype=None,evalue=None,etb=None,
1143 out=None,tb_offset=None):
1142 out=None,tb_offset=None):
1144 """Print out a formatted exception traceback.
1143 """Print out a formatted exception traceback.
1145
1144
1146 Optional arguments:
1145 Optional arguments:
1147 - out: an open file-like object to direct output to.
1146 - out: an open file-like object to direct output to.
1148
1147
1149 - tb_offset: the number of frames to skip over in the stack, on a
1148 - tb_offset: the number of frames to skip over in the stack, on a
1150 per-call basis (this overrides temporarily the instance's tb_offset
1149 per-call basis (this overrides temporarily the instance's tb_offset
1151 given at initialization time. """
1150 given at initialization time. """
1152
1151
1153
1152
1154 if out is None:
1153 if out is None:
1155 out = self.ostream
1154 out = self.ostream
1156 out.flush()
1155 out.flush()
1157 out.write(self.text(etype, evalue, etb, tb_offset))
1156 out.write(self.text(etype, evalue, etb, tb_offset))
1158 out.write('\n')
1157 out.write('\n')
1159 out.flush()
1158 out.flush()
1160 # FIXME: we should remove the auto pdb behavior from here and leave
1159 # FIXME: we should remove the auto pdb behavior from here and leave
1161 # that to the clients.
1160 # that to the clients.
1162 try:
1161 try:
1163 self.debugger()
1162 self.debugger()
1164 except KeyboardInterrupt:
1163 except KeyboardInterrupt:
1165 print "\nKeyboardInterrupt"
1164 print "\nKeyboardInterrupt"
1166
1165
1167 def structured_traceback(self, etype=None, value=None, tb=None,
1166 def structured_traceback(self, etype=None, value=None, tb=None,
1168 tb_offset=None, context=5):
1167 tb_offset=None, context=5):
1169 if etype is None:
1168 if etype is None:
1170 etype,value,tb = sys.exc_info()
1169 etype,value,tb = sys.exc_info()
1171 self.tb = tb
1170 self.tb = tb
1172 return FormattedTB.structured_traceback(
1171 return FormattedTB.structured_traceback(
1173 self, etype, value, tb, tb_offset, context)
1172 self, etype, value, tb, tb_offset, context)
1174
1173
1175 #---------------------------------------------------------------------------
1174 #---------------------------------------------------------------------------
1176
1175
1177 # A simple class to preserve Nathan's original functionality.
1176 # A simple class to preserve Nathan's original functionality.
1178 class ColorTB(FormattedTB):
1177 class ColorTB(FormattedTB):
1179 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1178 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1180 def __init__(self,color_scheme='Linux',call_pdb=0):
1179 def __init__(self,color_scheme='Linux',call_pdb=0):
1181 FormattedTB.__init__(self,color_scheme=color_scheme,
1180 FormattedTB.__init__(self,color_scheme=color_scheme,
1182 call_pdb=call_pdb)
1181 call_pdb=call_pdb)
1183
1182
1184
1183
1185 class SyntaxTB(ListTB):
1184 class SyntaxTB(ListTB):
1186 """Extension which holds some state: the last exception value"""
1185 """Extension which holds some state: the last exception value"""
1187
1186
1188 def __init__(self,color_scheme = 'NoColor'):
1187 def __init__(self,color_scheme = 'NoColor'):
1189 ListTB.__init__(self,color_scheme)
1188 ListTB.__init__(self,color_scheme)
1190 self.last_syntax_error = None
1189 self.last_syntax_error = None
1191
1190
1192 def __call__(self, etype, value, elist):
1191 def __call__(self, etype, value, elist):
1193 self.last_syntax_error = value
1192 self.last_syntax_error = value
1194 ListTB.__call__(self,etype,value,elist)
1193 ListTB.__call__(self,etype,value,elist)
1195
1194
1196 def clear_err_state(self):
1195 def clear_err_state(self):
1197 """Return the current error state and clear it"""
1196 """Return the current error state and clear it"""
1198 e = self.last_syntax_error
1197 e = self.last_syntax_error
1199 self.last_syntax_error = None
1198 self.last_syntax_error = None
1200 return e
1199 return e
1201
1200
1202 def stb2text(self, stb):
1201 def stb2text(self, stb):
1203 """Convert a structured traceback (a list) to a string."""
1202 """Convert a structured traceback (a list) to a string."""
1204 return ''.join(stb)
1203 return ''.join(stb)
1205
1204
1206
1205
1207 #----------------------------------------------------------------------------
1206 #----------------------------------------------------------------------------
1208 # module testing (minimal)
1207 # module testing (minimal)
1209 if __name__ == "__main__":
1208 if __name__ == "__main__":
1210 def spam(c, d_e):
1209 def spam(c, d_e):
1211 (d, e) = d_e
1210 (d, e) = d_e
1212 x = c + d
1211 x = c + d
1213 y = c * d
1212 y = c * d
1214 foo(x, y)
1213 foo(x, y)
1215
1214
1216 def foo(a, b, bar=1):
1215 def foo(a, b, bar=1):
1217 eggs(a, b + bar)
1216 eggs(a, b + bar)
1218
1217
1219 def eggs(f, g, z=globals()):
1218 def eggs(f, g, z=globals()):
1220 h = f + g
1219 h = f + g
1221 i = f - g
1220 i = f - g
1222 return h / i
1221 return h / i
1223
1222
1224 print ''
1223 print ''
1225 print '*** Before ***'
1224 print '*** Before ***'
1226 try:
1225 try:
1227 print spam(1, (2, 3))
1226 print spam(1, (2, 3))
1228 except:
1227 except:
1229 traceback.print_exc()
1228 traceback.print_exc()
1230 print ''
1229 print ''
1231
1230
1232 handler = ColorTB()
1231 handler = ColorTB()
1233 print '*** ColorTB ***'
1232 print '*** ColorTB ***'
1234 try:
1233 try:
1235 print spam(1, (2, 3))
1234 print spam(1, (2, 3))
1236 except:
1235 except:
1237 handler(*sys.exc_info())
1236 handler(*sys.exc_info())
1238 print ''
1237 print ''
1239
1238
1240 handler = VerboseTB()
1239 handler = VerboseTB()
1241 print '*** VerboseTB ***'
1240 print '*** VerboseTB ***'
1242 try:
1241 try:
1243 print spam(1, (2, 3))
1242 print spam(1, (2, 3))
1244 except:
1243 except:
1245 handler(*sys.exc_info())
1244 handler(*sys.exc_info())
1246 print ''
1245 print ''
1247
1246
@@ -1,483 +1,483 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Manage background (threaded) jobs conveniently from an interactive shell.
2 """Manage background (threaded) jobs conveniently from an interactive shell.
3
3
4 This module provides a BackgroundJobManager class. This is the main class
4 This module provides a BackgroundJobManager class. This is the main class
5 meant for public usage, it implements an object which can create and manage
5 meant for public usage, it implements an object which can create and manage
6 new background jobs.
6 new background jobs.
7
7
8 It also provides the actual job classes managed by these BackgroundJobManager
8 It also provides the actual job classes managed by these BackgroundJobManager
9 objects, see their docstrings below.
9 objects, see their docstrings below.
10
10
11
11
12 This system was inspired by discussions with B. Granger and the
12 This system was inspired by discussions with B. Granger and the
13 BackgroundCommand class described in the book Python Scripting for
13 BackgroundCommand class described in the book Python Scripting for
14 Computational Science, by H. P. Langtangen:
14 Computational Science, by H. P. Langtangen:
15
15
16 http://folk.uio.no/hpl/scripting
16 http://folk.uio.no/hpl/scripting
17
17
18 (although ultimately no code from this text was used, as IPython's system is a
18 (although ultimately no code from this text was used, as IPython's system is a
19 separate implementation).
19 separate implementation).
20
20
21 An example notebook is provided in our documentation illustrating interactive
21 An example notebook is provided in our documentation illustrating interactive
22 use of the system.
22 use of the system.
23 """
23 """
24
24
25 #*****************************************************************************
25 #*****************************************************************************
26 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
26 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
27 #
27 #
28 # Distributed under the terms of the BSD License. The full license is in
28 # Distributed under the terms of the BSD License. The full license is in
29 # the file COPYING, distributed as part of this software.
29 # the file COPYING, distributed as part of this software.
30 #*****************************************************************************
30 #*****************************************************************************
31
31
32 # Code begins
32 # Code begins
33 import sys
33 import sys
34 import threading
34 import threading
35
35
36 from IPython.core.ultratb import AutoFormattedTB
36 from IPython.core.ultratb import AutoFormattedTB
37 from IPython.utils.warn import warn, error
37 from IPython.utils.warn import error
38
38
39
39
40 class BackgroundJobManager(object):
40 class BackgroundJobManager(object):
41 """Class to manage a pool of backgrounded threaded jobs.
41 """Class to manage a pool of backgrounded threaded jobs.
42
42
43 Below, we assume that 'jobs' is a BackgroundJobManager instance.
43 Below, we assume that 'jobs' is a BackgroundJobManager instance.
44
44
45 Usage summary (see the method docstrings for details):
45 Usage summary (see the method docstrings for details):
46
46
47 jobs.new(...) -> start a new job
47 jobs.new(...) -> start a new job
48
48
49 jobs() or jobs.status() -> print status summary of all jobs
49 jobs() or jobs.status() -> print status summary of all jobs
50
50
51 jobs[N] -> returns job number N.
51 jobs[N] -> returns job number N.
52
52
53 foo = jobs[N].result -> assign to variable foo the result of job N
53 foo = jobs[N].result -> assign to variable foo the result of job N
54
54
55 jobs[N].traceback() -> print the traceback of dead job N
55 jobs[N].traceback() -> print the traceback of dead job N
56
56
57 jobs.remove(N) -> remove (finished) job N
57 jobs.remove(N) -> remove (finished) job N
58
58
59 jobs.flush() -> remove all finished jobs
59 jobs.flush() -> remove all finished jobs
60
60
61 As a convenience feature, BackgroundJobManager instances provide the
61 As a convenience feature, BackgroundJobManager instances provide the
62 utility result and traceback methods which retrieve the corresponding
62 utility result and traceback methods which retrieve the corresponding
63 information from the jobs list:
63 information from the jobs list:
64
64
65 jobs.result(N) <--> jobs[N].result
65 jobs.result(N) <--> jobs[N].result
66 jobs.traceback(N) <--> jobs[N].traceback()
66 jobs.traceback(N) <--> jobs[N].traceback()
67
67
68 While this appears minor, it allows you to use tab completion
68 While this appears minor, it allows you to use tab completion
69 interactively on the job manager instance.
69 interactively on the job manager instance.
70 """
70 """
71
71
72 def __init__(self):
72 def __init__(self):
73 # Lists for job management, accessed via a property to ensure they're
73 # Lists for job management, accessed via a property to ensure they're
74 # up to date.x
74 # up to date.x
75 self._running = []
75 self._running = []
76 self._completed = []
76 self._completed = []
77 self._dead = []
77 self._dead = []
78 # A dict of all jobs, so users can easily access any of them
78 # A dict of all jobs, so users can easily access any of them
79 self.all = {}
79 self.all = {}
80 # For reporting
80 # For reporting
81 self._comp_report = []
81 self._comp_report = []
82 self._dead_report = []
82 self._dead_report = []
83 # Store status codes locally for fast lookups
83 # Store status codes locally for fast lookups
84 self._s_created = BackgroundJobBase.stat_created_c
84 self._s_created = BackgroundJobBase.stat_created_c
85 self._s_running = BackgroundJobBase.stat_running_c
85 self._s_running = BackgroundJobBase.stat_running_c
86 self._s_completed = BackgroundJobBase.stat_completed_c
86 self._s_completed = BackgroundJobBase.stat_completed_c
87 self._s_dead = BackgroundJobBase.stat_dead_c
87 self._s_dead = BackgroundJobBase.stat_dead_c
88
88
89 @property
89 @property
90 def running(self):
90 def running(self):
91 self._update_status()
91 self._update_status()
92 return self._running
92 return self._running
93
93
94 @property
94 @property
95 def dead(self):
95 def dead(self):
96 self._update_status()
96 self._update_status()
97 return self._dead
97 return self._dead
98
98
99 @property
99 @property
100 def completed(self):
100 def completed(self):
101 self._update_status()
101 self._update_status()
102 return self._completed
102 return self._completed
103
103
104 def new(self, func_or_exp, *args, **kwargs):
104 def new(self, func_or_exp, *args, **kwargs):
105 """Add a new background job and start it in a separate thread.
105 """Add a new background job and start it in a separate thread.
106
106
107 There are two types of jobs which can be created:
107 There are two types of jobs which can be created:
108
108
109 1. Jobs based on expressions which can be passed to an eval() call.
109 1. Jobs based on expressions which can be passed to an eval() call.
110 The expression must be given as a string. For example:
110 The expression must be given as a string. For example:
111
111
112 job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]])
112 job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]])
113
113
114 The given expression is passed to eval(), along with the optional
114 The given expression is passed to eval(), along with the optional
115 global/local dicts provided. If no dicts are given, they are
115 global/local dicts provided. If no dicts are given, they are
116 extracted automatically from the caller's frame.
116 extracted automatically from the caller's frame.
117
117
118 A Python statement is NOT a valid eval() expression. Basically, you
118 A Python statement is NOT a valid eval() expression. Basically, you
119 can only use as an eval() argument something which can go on the right
119 can only use as an eval() argument something which can go on the right
120 of an '=' sign and be assigned to a variable.
120 of an '=' sign and be assigned to a variable.
121
121
122 For example,"print 'hello'" is not valid, but '2+3' is.
122 For example,"print 'hello'" is not valid, but '2+3' is.
123
123
124 2. Jobs given a function object, optionally passing additional
124 2. Jobs given a function object, optionally passing additional
125 positional arguments:
125 positional arguments:
126
126
127 job_manager.new(myfunc, x, y)
127 job_manager.new(myfunc, x, y)
128
128
129 The function is called with the given arguments.
129 The function is called with the given arguments.
130
130
131 If you need to pass keyword arguments to your function, you must
131 If you need to pass keyword arguments to your function, you must
132 supply them as a dict named kw:
132 supply them as a dict named kw:
133
133
134 job_manager.new(myfunc, x, y, kw=dict(z=1))
134 job_manager.new(myfunc, x, y, kw=dict(z=1))
135
135
136 The reason for this assymmetry is that the new() method needs to
136 The reason for this assymmetry is that the new() method needs to
137 maintain access to its own keywords, and this prevents name collisions
137 maintain access to its own keywords, and this prevents name collisions
138 between arguments to new() and arguments to your own functions.
138 between arguments to new() and arguments to your own functions.
139
139
140 In both cases, the result is stored in the job.result field of the
140 In both cases, the result is stored in the job.result field of the
141 background job object.
141 background job object.
142
142
143 You can set `daemon` attribute of the thread by giving the keyword
143 You can set `daemon` attribute of the thread by giving the keyword
144 argument `daemon`.
144 argument `daemon`.
145
145
146 Notes and caveats:
146 Notes and caveats:
147
147
148 1. All threads running share the same standard output. Thus, if your
148 1. All threads running share the same standard output. Thus, if your
149 background jobs generate output, it will come out on top of whatever
149 background jobs generate output, it will come out on top of whatever
150 you are currently writing. For this reason, background jobs are best
150 you are currently writing. For this reason, background jobs are best
151 used with silent functions which simply return their output.
151 used with silent functions which simply return their output.
152
152
153 2. Threads also all work within the same global namespace, and this
153 2. Threads also all work within the same global namespace, and this
154 system does not lock interactive variables. So if you send job to the
154 system does not lock interactive variables. So if you send job to the
155 background which operates on a mutable object for a long time, and
155 background which operates on a mutable object for a long time, and
156 start modifying that same mutable object interactively (or in another
156 start modifying that same mutable object interactively (or in another
157 backgrounded job), all sorts of bizarre behaviour will occur.
157 backgrounded job), all sorts of bizarre behaviour will occur.
158
158
159 3. If a background job is spending a lot of time inside a C extension
159 3. If a background job is spending a lot of time inside a C extension
160 module which does not release the Python Global Interpreter Lock
160 module which does not release the Python Global Interpreter Lock
161 (GIL), this will block the IPython prompt. This is simply because the
161 (GIL), this will block the IPython prompt. This is simply because the
162 Python interpreter can only switch between threads at Python
162 Python interpreter can only switch between threads at Python
163 bytecodes. While the execution is inside C code, the interpreter must
163 bytecodes. While the execution is inside C code, the interpreter must
164 simply wait unless the extension module releases the GIL.
164 simply wait unless the extension module releases the GIL.
165
165
166 4. There is no way, due to limitations in the Python threads library,
166 4. There is no way, due to limitations in the Python threads library,
167 to kill a thread once it has started."""
167 to kill a thread once it has started."""
168
168
169 if callable(func_or_exp):
169 if callable(func_or_exp):
170 kw = kwargs.get('kw',{})
170 kw = kwargs.get('kw',{})
171 job = BackgroundJobFunc(func_or_exp,*args,**kw)
171 job = BackgroundJobFunc(func_or_exp,*args,**kw)
172 elif isinstance(func_or_exp, basestring):
172 elif isinstance(func_or_exp, basestring):
173 if not args:
173 if not args:
174 frame = sys._getframe(1)
174 frame = sys._getframe(1)
175 glob, loc = frame.f_globals, frame.f_locals
175 glob, loc = frame.f_globals, frame.f_locals
176 elif len(args)==1:
176 elif len(args)==1:
177 glob = loc = args[0]
177 glob = loc = args[0]
178 elif len(args)==2:
178 elif len(args)==2:
179 glob,loc = args
179 glob,loc = args
180 else:
180 else:
181 raise ValueError(
181 raise ValueError(
182 'Expression jobs take at most 2 args (globals,locals)')
182 'Expression jobs take at most 2 args (globals,locals)')
183 job = BackgroundJobExpr(func_or_exp, glob, loc)
183 job = BackgroundJobExpr(func_or_exp, glob, loc)
184 else:
184 else:
185 raise TypeError('invalid args for new job')
185 raise TypeError('invalid args for new job')
186
186
187 if kwargs.get('daemon', False):
187 if kwargs.get('daemon', False):
188 job.daemon = True
188 job.daemon = True
189 job.num = len(self.all)+1 if self.all else 0
189 job.num = len(self.all)+1 if self.all else 0
190 self.running.append(job)
190 self.running.append(job)
191 self.all[job.num] = job
191 self.all[job.num] = job
192 print 'Starting job # %s in a separate thread.' % job.num
192 print 'Starting job # %s in a separate thread.' % job.num
193 job.start()
193 job.start()
194 return job
194 return job
195
195
196 def __getitem__(self, job_key):
196 def __getitem__(self, job_key):
197 num = job_key if isinstance(job_key, int) else job_key.num
197 num = job_key if isinstance(job_key, int) else job_key.num
198 return self.all[num]
198 return self.all[num]
199
199
200 def __call__(self):
200 def __call__(self):
201 """An alias to self.status(),
201 """An alias to self.status(),
202
202
203 This allows you to simply call a job manager instance much like the
203 This allows you to simply call a job manager instance much like the
204 Unix `jobs` shell command."""
204 Unix `jobs` shell command."""
205
205
206 return self.status()
206 return self.status()
207
207
208 def _update_status(self):
208 def _update_status(self):
209 """Update the status of the job lists.
209 """Update the status of the job lists.
210
210
211 This method moves finished jobs to one of two lists:
211 This method moves finished jobs to one of two lists:
212 - self.completed: jobs which completed successfully
212 - self.completed: jobs which completed successfully
213 - self.dead: jobs which finished but died.
213 - self.dead: jobs which finished but died.
214
214
215 It also copies those jobs to corresponding _report lists. These lists
215 It also copies those jobs to corresponding _report lists. These lists
216 are used to report jobs completed/dead since the last update, and are
216 are used to report jobs completed/dead since the last update, and are
217 then cleared by the reporting function after each call."""
217 then cleared by the reporting function after each call."""
218
218
219 # Status codes
219 # Status codes
220 srun, scomp, sdead = self._s_running, self._s_completed, self._s_dead
220 srun, scomp, sdead = self._s_running, self._s_completed, self._s_dead
221 # State lists, use the actual lists b/c the public names are properties
221 # State lists, use the actual lists b/c the public names are properties
222 # that call this very function on access
222 # that call this very function on access
223 running, completed, dead = self._running, self._completed, self._dead
223 running, completed, dead = self._running, self._completed, self._dead
224
224
225 # Now, update all state lists
225 # Now, update all state lists
226 for num, job in enumerate(running):
226 for num, job in enumerate(running):
227 stat = job.stat_code
227 stat = job.stat_code
228 if stat == srun:
228 if stat == srun:
229 continue
229 continue
230 elif stat == scomp:
230 elif stat == scomp:
231 completed.append(job)
231 completed.append(job)
232 self._comp_report.append(job)
232 self._comp_report.append(job)
233 running[num] = False
233 running[num] = False
234 elif stat == sdead:
234 elif stat == sdead:
235 dead.append(job)
235 dead.append(job)
236 self._dead_report.append(job)
236 self._dead_report.append(job)
237 running[num] = False
237 running[num] = False
238 # Remove dead/completed jobs from running list
238 # Remove dead/completed jobs from running list
239 running[:] = filter(None, running)
239 running[:] = filter(None, running)
240
240
241 def _group_report(self,group,name):
241 def _group_report(self,group,name):
242 """Report summary for a given job group.
242 """Report summary for a given job group.
243
243
244 Return True if the group had any elements."""
244 Return True if the group had any elements."""
245
245
246 if group:
246 if group:
247 print '%s jobs:' % name
247 print '%s jobs:' % name
248 for job in group:
248 for job in group:
249 print '%s : %s' % (job.num,job)
249 print '%s : %s' % (job.num,job)
250 print
250 print
251 return True
251 return True
252
252
253 def _group_flush(self,group,name):
253 def _group_flush(self,group,name):
254 """Flush a given job group
254 """Flush a given job group
255
255
256 Return True if the group had any elements."""
256 Return True if the group had any elements."""
257
257
258 njobs = len(group)
258 njobs = len(group)
259 if njobs:
259 if njobs:
260 plural = {1:''}.setdefault(njobs,'s')
260 plural = {1:''}.setdefault(njobs,'s')
261 print 'Flushing %s %s job%s.' % (njobs,name,plural)
261 print 'Flushing %s %s job%s.' % (njobs,name,plural)
262 group[:] = []
262 group[:] = []
263 return True
263 return True
264
264
265 def _status_new(self):
265 def _status_new(self):
266 """Print the status of newly finished jobs.
266 """Print the status of newly finished jobs.
267
267
268 Return True if any new jobs are reported.
268 Return True if any new jobs are reported.
269
269
270 This call resets its own state every time, so it only reports jobs
270 This call resets its own state every time, so it only reports jobs
271 which have finished since the last time it was called."""
271 which have finished since the last time it was called."""
272
272
273 self._update_status()
273 self._update_status()
274 new_comp = self._group_report(self._comp_report, 'Completed')
274 new_comp = self._group_report(self._comp_report, 'Completed')
275 new_dead = self._group_report(self._dead_report,
275 new_dead = self._group_report(self._dead_report,
276 'Dead, call jobs.traceback() for details')
276 'Dead, call jobs.traceback() for details')
277 self._comp_report[:] = []
277 self._comp_report[:] = []
278 self._dead_report[:] = []
278 self._dead_report[:] = []
279 return new_comp or new_dead
279 return new_comp or new_dead
280
280
281 def status(self,verbose=0):
281 def status(self,verbose=0):
282 """Print a status of all jobs currently being managed."""
282 """Print a status of all jobs currently being managed."""
283
283
284 self._update_status()
284 self._update_status()
285 self._group_report(self.running,'Running')
285 self._group_report(self.running,'Running')
286 self._group_report(self.completed,'Completed')
286 self._group_report(self.completed,'Completed')
287 self._group_report(self.dead,'Dead')
287 self._group_report(self.dead,'Dead')
288 # Also flush the report queues
288 # Also flush the report queues
289 self._comp_report[:] = []
289 self._comp_report[:] = []
290 self._dead_report[:] = []
290 self._dead_report[:] = []
291
291
292 def remove(self,num):
292 def remove(self,num):
293 """Remove a finished (completed or dead) job."""
293 """Remove a finished (completed or dead) job."""
294
294
295 try:
295 try:
296 job = self.all[num]
296 job = self.all[num]
297 except KeyError:
297 except KeyError:
298 error('Job #%s not found' % num)
298 error('Job #%s not found' % num)
299 else:
299 else:
300 stat_code = job.stat_code
300 stat_code = job.stat_code
301 if stat_code == self._s_running:
301 if stat_code == self._s_running:
302 error('Job #%s is still running, it can not be removed.' % num)
302 error('Job #%s is still running, it can not be removed.' % num)
303 return
303 return
304 elif stat_code == self._s_completed:
304 elif stat_code == self._s_completed:
305 self.completed.remove(job)
305 self.completed.remove(job)
306 elif stat_code == self._s_dead:
306 elif stat_code == self._s_dead:
307 self.dead.remove(job)
307 self.dead.remove(job)
308
308
309 def flush(self):
309 def flush(self):
310 """Flush all finished jobs (completed and dead) from lists.
310 """Flush all finished jobs (completed and dead) from lists.
311
311
312 Running jobs are never flushed.
312 Running jobs are never flushed.
313
313
314 It first calls _status_new(), to update info. If any jobs have
314 It first calls _status_new(), to update info. If any jobs have
315 completed since the last _status_new() call, the flush operation
315 completed since the last _status_new() call, the flush operation
316 aborts."""
316 aborts."""
317
317
318 # Remove the finished jobs from the master dict
318 # Remove the finished jobs from the master dict
319 alljobs = self.all
319 alljobs = self.all
320 for job in self.completed+self.dead:
320 for job in self.completed+self.dead:
321 del(alljobs[job.num])
321 del(alljobs[job.num])
322
322
323 # Now flush these lists completely
323 # Now flush these lists completely
324 fl_comp = self._group_flush(self.completed, 'Completed')
324 fl_comp = self._group_flush(self.completed, 'Completed')
325 fl_dead = self._group_flush(self.dead, 'Dead')
325 fl_dead = self._group_flush(self.dead, 'Dead')
326 if not (fl_comp or fl_dead):
326 if not (fl_comp or fl_dead):
327 print 'No jobs to flush.'
327 print 'No jobs to flush.'
328
328
329 def result(self,num):
329 def result(self,num):
330 """result(N) -> return the result of job N."""
330 """result(N) -> return the result of job N."""
331 try:
331 try:
332 return self.all[num].result
332 return self.all[num].result
333 except KeyError:
333 except KeyError:
334 error('Job #%s not found' % num)
334 error('Job #%s not found' % num)
335
335
336 def _traceback(self, job):
336 def _traceback(self, job):
337 num = job if isinstance(job, int) else job.num
337 num = job if isinstance(job, int) else job.num
338 try:
338 try:
339 self.all[num].traceback()
339 self.all[num].traceback()
340 except KeyError:
340 except KeyError:
341 error('Job #%s not found' % num)
341 error('Job #%s not found' % num)
342
342
343 def traceback(self, job=None):
343 def traceback(self, job=None):
344 if job is None:
344 if job is None:
345 self._update_status()
345 self._update_status()
346 for deadjob in self.dead:
346 for deadjob in self.dead:
347 print "Traceback for: %r" % deadjob
347 print "Traceback for: %r" % deadjob
348 self._traceback(deadjob)
348 self._traceback(deadjob)
349 print
349 print
350 else:
350 else:
351 self._traceback(job)
351 self._traceback(job)
352
352
353
353
354 class BackgroundJobBase(threading.Thread):
354 class BackgroundJobBase(threading.Thread):
355 """Base class to build BackgroundJob classes.
355 """Base class to build BackgroundJob classes.
356
356
357 The derived classes must implement:
357 The derived classes must implement:
358
358
359 - Their own __init__, since the one here raises NotImplementedError. The
359 - Their own __init__, since the one here raises NotImplementedError. The
360 derived constructor must call self._init() at the end, to provide common
360 derived constructor must call self._init() at the end, to provide common
361 initialization.
361 initialization.
362
362
363 - A strform attribute used in calls to __str__.
363 - A strform attribute used in calls to __str__.
364
364
365 - A call() method, which will make the actual execution call and must
365 - A call() method, which will make the actual execution call and must
366 return a value to be held in the 'result' field of the job object."""
366 return a value to be held in the 'result' field of the job object."""
367
367
368 # Class constants for status, in string and as numerical codes (when
368 # Class constants for status, in string and as numerical codes (when
369 # updating jobs lists, we don't want to do string comparisons). This will
369 # updating jobs lists, we don't want to do string comparisons). This will
370 # be done at every user prompt, so it has to be as fast as possible
370 # be done at every user prompt, so it has to be as fast as possible
371 stat_created = 'Created'; stat_created_c = 0
371 stat_created = 'Created'; stat_created_c = 0
372 stat_running = 'Running'; stat_running_c = 1
372 stat_running = 'Running'; stat_running_c = 1
373 stat_completed = 'Completed'; stat_completed_c = 2
373 stat_completed = 'Completed'; stat_completed_c = 2
374 stat_dead = 'Dead (Exception), call jobs.traceback() for details'
374 stat_dead = 'Dead (Exception), call jobs.traceback() for details'
375 stat_dead_c = -1
375 stat_dead_c = -1
376
376
377 def __init__(self):
377 def __init__(self):
378 raise NotImplementedError("This class can not be instantiated directly.")
378 raise NotImplementedError("This class can not be instantiated directly.")
379
379
380 def _init(self):
380 def _init(self):
381 """Common initialization for all BackgroundJob objects"""
381 """Common initialization for all BackgroundJob objects"""
382
382
383 for attr in ['call','strform']:
383 for attr in ['call','strform']:
384 assert hasattr(self,attr), "Missing attribute <%s>" % attr
384 assert hasattr(self,attr), "Missing attribute <%s>" % attr
385
385
386 # The num tag can be set by an external job manager
386 # The num tag can be set by an external job manager
387 self.num = None
387 self.num = None
388
388
389 self.status = BackgroundJobBase.stat_created
389 self.status = BackgroundJobBase.stat_created
390 self.stat_code = BackgroundJobBase.stat_created_c
390 self.stat_code = BackgroundJobBase.stat_created_c
391 self.finished = False
391 self.finished = False
392 self.result = '<BackgroundJob has not completed>'
392 self.result = '<BackgroundJob has not completed>'
393
393
394 # reuse the ipython traceback handler if we can get to it, otherwise
394 # reuse the ipython traceback handler if we can get to it, otherwise
395 # make a new one
395 # make a new one
396 try:
396 try:
397 make_tb = get_ipython().InteractiveTB.text
397 make_tb = get_ipython().InteractiveTB.text
398 except:
398 except:
399 make_tb = AutoFormattedTB(mode = 'Context',
399 make_tb = AutoFormattedTB(mode = 'Context',
400 color_scheme='NoColor',
400 color_scheme='NoColor',
401 tb_offset = 1).text
401 tb_offset = 1).text
402 # Note that the actual API for text() requires the three args to be
402 # Note that the actual API for text() requires the three args to be
403 # passed in, so we wrap it in a simple lambda.
403 # passed in, so we wrap it in a simple lambda.
404 self._make_tb = lambda : make_tb(None, None, None)
404 self._make_tb = lambda : make_tb(None, None, None)
405
405
406 # Hold a formatted traceback if one is generated.
406 # Hold a formatted traceback if one is generated.
407 self._tb = None
407 self._tb = None
408
408
409 threading.Thread.__init__(self)
409 threading.Thread.__init__(self)
410
410
411 def __str__(self):
411 def __str__(self):
412 return self.strform
412 return self.strform
413
413
414 def __repr__(self):
414 def __repr__(self):
415 return '<BackgroundJob #%d: %s>' % (self.num, self.strform)
415 return '<BackgroundJob #%d: %s>' % (self.num, self.strform)
416
416
417 def traceback(self):
417 def traceback(self):
418 print self._tb
418 print self._tb
419
419
420 def run(self):
420 def run(self):
421 try:
421 try:
422 self.status = BackgroundJobBase.stat_running
422 self.status = BackgroundJobBase.stat_running
423 self.stat_code = BackgroundJobBase.stat_running_c
423 self.stat_code = BackgroundJobBase.stat_running_c
424 self.result = self.call()
424 self.result = self.call()
425 except:
425 except:
426 self.status = BackgroundJobBase.stat_dead
426 self.status = BackgroundJobBase.stat_dead
427 self.stat_code = BackgroundJobBase.stat_dead_c
427 self.stat_code = BackgroundJobBase.stat_dead_c
428 self.finished = None
428 self.finished = None
429 self.result = ('<BackgroundJob died, call jobs.traceback() for details>')
429 self.result = ('<BackgroundJob died, call jobs.traceback() for details>')
430 self._tb = self._make_tb()
430 self._tb = self._make_tb()
431 else:
431 else:
432 self.status = BackgroundJobBase.stat_completed
432 self.status = BackgroundJobBase.stat_completed
433 self.stat_code = BackgroundJobBase.stat_completed_c
433 self.stat_code = BackgroundJobBase.stat_completed_c
434 self.finished = True
434 self.finished = True
435
435
436
436
437 class BackgroundJobExpr(BackgroundJobBase):
437 class BackgroundJobExpr(BackgroundJobBase):
438 """Evaluate an expression as a background job (uses a separate thread)."""
438 """Evaluate an expression as a background job (uses a separate thread)."""
439
439
440 def __init__(self, expression, glob=None, loc=None):
440 def __init__(self, expression, glob=None, loc=None):
441 """Create a new job from a string which can be fed to eval().
441 """Create a new job from a string which can be fed to eval().
442
442
443 global/locals dicts can be provided, which will be passed to the eval
443 global/locals dicts can be provided, which will be passed to the eval
444 call."""
444 call."""
445
445
446 # fail immediately if the given expression can't be compiled
446 # fail immediately if the given expression can't be compiled
447 self.code = compile(expression,'<BackgroundJob compilation>','eval')
447 self.code = compile(expression,'<BackgroundJob compilation>','eval')
448
448
449 glob = {} if glob is None else glob
449 glob = {} if glob is None else glob
450 loc = {} if loc is None else loc
450 loc = {} if loc is None else loc
451 self.expression = self.strform = expression
451 self.expression = self.strform = expression
452 self.glob = glob
452 self.glob = glob
453 self.loc = loc
453 self.loc = loc
454 self._init()
454 self._init()
455
455
456 def call(self):
456 def call(self):
457 return eval(self.code,self.glob,self.loc)
457 return eval(self.code,self.glob,self.loc)
458
458
459
459
460 class BackgroundJobFunc(BackgroundJobBase):
460 class BackgroundJobFunc(BackgroundJobBase):
461 """Run a function call as a background job (uses a separate thread)."""
461 """Run a function call as a background job (uses a separate thread)."""
462
462
463 def __init__(self, func, *args, **kwargs):
463 def __init__(self, func, *args, **kwargs):
464 """Create a new job from a callable object.
464 """Create a new job from a callable object.
465
465
466 Any positional arguments and keyword args given to this constructor
466 Any positional arguments and keyword args given to this constructor
467 after the initial callable are passed directly to it."""
467 after the initial callable are passed directly to it."""
468
468
469 if not callable(func):
469 if not callable(func):
470 raise TypeError(
470 raise TypeError(
471 'first argument to BackgroundJobFunc must be callable')
471 'first argument to BackgroundJobFunc must be callable')
472
472
473 self.func = func
473 self.func = func
474 self.args = args
474 self.args = args
475 self.kwargs = kwargs
475 self.kwargs = kwargs
476 # The string form will only include the function passed, because
476 # The string form will only include the function passed, because
477 # generating string representations of the arguments is a potentially
477 # generating string representations of the arguments is a potentially
478 # _very_ expensive operation (e.g. with large arrays).
478 # _very_ expensive operation (e.g. with large arrays).
479 self.strform = str(func)
479 self.strform = str(func)
480 self._init()
480 self._init()
481
481
482 def call(self):
482 def call(self):
483 return self.func(*self.args, **self.kwargs)
483 return self.func(*self.args, **self.kwargs)
@@ -1,56 +1,55 b''
1 """ Utilities for accessing the platform's clipboard.
1 """ Utilities for accessing the platform's clipboard.
2 """
2 """
3
3
4 import subprocess
4 import subprocess
5 import sys
6
5
7 from IPython.core.error import TryNext
6 from IPython.core.error import TryNext
8 import IPython.utils.py3compat as py3compat
7 import IPython.utils.py3compat as py3compat
9
8
10 def win32_clipboard_get():
9 def win32_clipboard_get():
11 """ Get the current clipboard's text on Windows.
10 """ Get the current clipboard's text on Windows.
12
11
13 Requires Mark Hammond's pywin32 extensions.
12 Requires Mark Hammond's pywin32 extensions.
14 """
13 """
15 try:
14 try:
16 import win32clipboard
15 import win32clipboard
17 except ImportError:
16 except ImportError:
18 raise TryNext("Getting text from the clipboard requires the pywin32 "
17 raise TryNext("Getting text from the clipboard requires the pywin32 "
19 "extensions: http://sourceforge.net/projects/pywin32/")
18 "extensions: http://sourceforge.net/projects/pywin32/")
20 win32clipboard.OpenClipboard()
19 win32clipboard.OpenClipboard()
21 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
20 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
22 # FIXME: convert \r\n to \n?
21 # FIXME: convert \r\n to \n?
23 win32clipboard.CloseClipboard()
22 win32clipboard.CloseClipboard()
24 return text
23 return text
25
24
26 def osx_clipboard_get():
25 def osx_clipboard_get():
27 """ Get the clipboard's text on OS X.
26 """ Get the clipboard's text on OS X.
28 """
27 """
29 p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
28 p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
30 stdout=subprocess.PIPE)
29 stdout=subprocess.PIPE)
31 text, stderr = p.communicate()
30 text, stderr = p.communicate()
32 # Text comes in with old Mac \r line endings. Change them to \n.
31 # Text comes in with old Mac \r line endings. Change them to \n.
33 text = text.replace(b'\r', b'\n')
32 text = text.replace(b'\r', b'\n')
34 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
33 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
35 return text
34 return text
36
35
37 def tkinter_clipboard_get():
36 def tkinter_clipboard_get():
38 """ Get the clipboard's text using Tkinter.
37 """ Get the clipboard's text using Tkinter.
39
38
40 This is the default on systems that are not Windows or OS X. It may
39 This is the default on systems that are not Windows or OS X. It may
41 interfere with other UI toolkits and should be replaced with an
40 interfere with other UI toolkits and should be replaced with an
42 implementation that uses that toolkit.
41 implementation that uses that toolkit.
43 """
42 """
44 try:
43 try:
45 import Tkinter
44 import Tkinter
46 except ImportError:
45 except ImportError:
47 raise TryNext("Getting text from the clipboard on this platform "
46 raise TryNext("Getting text from the clipboard on this platform "
48 "requires Tkinter.")
47 "requires Tkinter.")
49 root = Tkinter.Tk()
48 root = Tkinter.Tk()
50 root.withdraw()
49 root.withdraw()
51 text = root.clipboard_get()
50 text = root.clipboard_get()
52 root.destroy()
51 root.destroy()
53 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
52 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
54 return text
53 return text
55
54
56
55
@@ -1,583 +1,582 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ----------------
10 ----------------
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33 Inheritance diagram:
33 Inheritance diagram:
34
34
35 .. inheritance-diagram:: IPython.lib.demo
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36 :parts: 3
37
37
38 Subclassing
38 Subclassing
39 -----------
39 -----------
40
40
41 The classes here all include a few methods meant to make customization by
41 The classes here all include a few methods meant to make customization by
42 subclassing more convenient. Their docstrings below have some more details:
42 subclassing more convenient. Their docstrings below have some more details:
43
43
44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 - marquee(): generates a marquee to provide visible on-screen markers at each
45 block start and end.
45 block start and end.
46
46
47 - pre_cmd(): run right before the execution of each block.
47 - pre_cmd(): run right before the execution of each block.
48
48
49 - post_cmd(): run right after the execution of each block. If the block
49 - post_cmd(): run right after the execution of each block. If the block
50 raises an exception, this is NOT called.
50 raises an exception, this is NOT called.
51
51
52
52
53 Operation
53 Operation
54 ---------
54 ---------
55
55
56 The file is run in its own empty namespace (though you can pass it a string of
56 The file is run in its own empty namespace (though you can pass it a string of
57 arguments as if in a command line environment, and it will see those as
57 arguments as if in a command line environment, and it will see those as
58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 sys.argv). But at each stop, the global IPython namespace is updated with the
59 current internal demo namespace, so you can work interactively with the data
59 current internal demo namespace, so you can work interactively with the data
60 accumulated so far.
60 accumulated so far.
61
61
62 By default, each block of code is printed (with syntax highlighting) before
62 By default, each block of code is printed (with syntax highlighting) before
63 executing it and you have to confirm execution. This is intended to show the
63 executing it and you have to confirm execution. This is intended to show the
64 code to an audience first so you can discuss it, and only proceed with
64 code to an audience first so you can discuss it, and only proceed with
65 execution once you agree. There are a few tags which allow you to modify this
65 execution once you agree. There are a few tags which allow you to modify this
66 behavior.
66 behavior.
67
67
68 The supported tags are:
68 The supported tags are:
69
69
70 # <demo> stop
70 # <demo> stop
71
71
72 Defines block boundaries, the points where IPython stops execution of the
72 Defines block boundaries, the points where IPython stops execution of the
73 file and returns to the interactive prompt.
73 file and returns to the interactive prompt.
74
74
75 You can optionally mark the stop tag with extra dashes before and after the
75 You can optionally mark the stop tag with extra dashes before and after the
76 word 'stop', to help visually distinguish the blocks in a text editor:
76 word 'stop', to help visually distinguish the blocks in a text editor:
77
77
78 # <demo> --- stop ---
78 # <demo> --- stop ---
79
79
80
80
81 # <demo> silent
81 # <demo> silent
82
82
83 Make a block execute silently (and hence automatically). Typically used in
83 Make a block execute silently (and hence automatically). Typically used in
84 cases where you have some boilerplate or initialization code which you need
84 cases where you have some boilerplate or initialization code which you need
85 executed but do not want to be seen in the demo.
85 executed but do not want to be seen in the demo.
86
86
87 # <demo> auto
87 # <demo> auto
88
88
89 Make a block execute automatically, but still being printed. Useful for
89 Make a block execute automatically, but still being printed. Useful for
90 simple code which does not warrant discussion, since it avoids the extra
90 simple code which does not warrant discussion, since it avoids the extra
91 manual confirmation.
91 manual confirmation.
92
92
93 # <demo> auto_all
93 # <demo> auto_all
94
94
95 This tag can _only_ be in the first block, and if given it overrides the
95 This tag can _only_ be in the first block, and if given it overrides the
96 individual auto tags to make the whole demo fully automatic (no block asks
96 individual auto tags to make the whole demo fully automatic (no block asks
97 for confirmation). It can also be given at creation time (or the attribute
97 for confirmation). It can also be given at creation time (or the attribute
98 set later) to override what's in the file.
98 set later) to override what's in the file.
99
99
100 While _any_ python file can be run as a Demo instance, if there are no stop
100 While _any_ python file can be run as a Demo instance, if there are no stop
101 tags the whole file will run in a single block (no different that calling
101 tags the whole file will run in a single block (no different that calling
102 first %pycat and then %run). The minimal markup to make this useful is to
102 first %pycat and then %run). The minimal markup to make this useful is to
103 place a set of stop tags; the other tags are only there to let you fine-tune
103 place a set of stop tags; the other tags are only there to let you fine-tune
104 the execution.
104 the execution.
105
105
106 This is probably best explained with the simple example file below. You can
106 This is probably best explained with the simple example file below. You can
107 copy this into a file named ex_demo.py, and try running it via::
107 copy this into a file named ex_demo.py, and try running it via::
108
108
109 from IPython.demo import Demo
109 from IPython.demo import Demo
110 d = Demo('ex_demo.py')
110 d = Demo('ex_demo.py')
111 d()
111 d()
112
112
113 Each time you call the demo object, it runs the next block. The demo object
113 Each time you call the demo object, it runs the next block. The demo object
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 and back(). It can be reset for a new run via reset() or reloaded from disk
116 (in case you've edited the source) via reload(). See their docstrings below.
116 (in case you've edited the source) via reload(). See their docstrings below.
117
117
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 been added to the "docs/examples/core" directory. Just cd to this directory in
120 an IPython session, and type::
120 an IPython session, and type::
121
121
122 %run demo-exercizer.py
122 %run demo-exercizer.py
123
123
124 and then follow the directions.
124 and then follow the directions.
125
125
126 Example
126 Example
127 -------
127 -------
128
128
129 The following is a very simple example of a valid demo file.
129 The following is a very simple example of a valid demo file.
130
130
131 ::
131 ::
132
132
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
135
135
136 print 'Hello, welcome to an interactive IPython demo.'
136 print 'Hello, welcome to an interactive IPython demo.'
137
137
138 # The mark below defines a block boundary, which is a point where IPython will
138 # The mark below defines a block boundary, which is a point where IPython will
139 # stop execution and return to the interactive prompt. The dashes are actually
139 # stop execution and return to the interactive prompt. The dashes are actually
140 # optional and used only as a visual aid to clearly separate blocks while
140 # optional and used only as a visual aid to clearly separate blocks while
141 # editing the demo code.
141 # editing the demo code.
142 # <demo> stop
142 # <demo> stop
143
143
144 x = 1
144 x = 1
145 y = 2
145 y = 2
146
146
147 # <demo> stop
147 # <demo> stop
148
148
149 # the mark below makes this block as silent
149 # the mark below makes this block as silent
150 # <demo> silent
150 # <demo> silent
151
151
152 print 'This is a silent block, which gets executed but not printed.'
152 print 'This is a silent block, which gets executed but not printed.'
153
153
154 # <demo> stop
154 # <demo> stop
155 # <demo> auto
155 # <demo> auto
156 print 'This is an automatic block.'
156 print 'This is an automatic block.'
157 print 'It is executed without asking for confirmation, but printed.'
157 print 'It is executed without asking for confirmation, but printed.'
158 z = x+y
158 z = x+y
159
159
160 print 'z=',x
160 print 'z=',x
161
161
162 # <demo> stop
162 # <demo> stop
163 # This is just another normal block.
163 # This is just another normal block.
164 print 'z is now:', z
164 print 'z is now:', z
165
165
166 print 'bye!'
166 print 'bye!'
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
168 """
168 """
169
169
170 from __future__ import unicode_literals
170 from __future__ import unicode_literals
171
171
172 #*****************************************************************************
172 #*****************************************************************************
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
174 #
174 #
175 # Distributed under the terms of the BSD License. The full license is in
175 # Distributed under the terms of the BSD License. The full license is in
176 # the file COPYING, distributed as part of this software.
176 # the file COPYING, distributed as part of this software.
177 #
177 #
178 #*****************************************************************************
178 #*****************************************************************************
179 from __future__ import print_function
179 from __future__ import print_function
180
180
181 import os
181 import os
182 import re
182 import re
183 import shlex
183 import shlex
184 import sys
184 import sys
185
185
186 from IPython.utils.PyColorize import Parser
187 from IPython.utils import io
186 from IPython.utils import io
188 from IPython.utils.io import file_read, file_readlines
187 from IPython.utils.io import file_read
189 from IPython.utils.text import marquee
188 from IPython.utils.text import marquee
190 from IPython.utils import openpy
189 from IPython.utils import openpy
191 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
192
191
193 class DemoError(Exception): pass
192 class DemoError(Exception): pass
194
193
195 def re_mark(mark):
194 def re_mark(mark):
196 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
197
196
198 class Demo(object):
197 class Demo(object):
199
198
200 re_stop = re_mark('-*\s?stop\s?-*')
199 re_stop = re_mark('-*\s?stop\s?-*')
201 re_silent = re_mark('silent')
200 re_silent = re_mark('silent')
202 re_auto = re_mark('auto')
201 re_auto = re_mark('auto')
203 re_auto_all = re_mark('auto_all')
202 re_auto_all = re_mark('auto_all')
204
203
205 def __init__(self,src,title='',arg_str='',auto_all=None):
204 def __init__(self,src,title='',arg_str='',auto_all=None):
206 """Make a new demo object. To run the demo, simply call the object.
205 """Make a new demo object. To run the demo, simply call the object.
207
206
208 See the module docstring for full details and an example (you can use
207 See the module docstring for full details and an example (you can use
209 IPython.Demo? in IPython to see it).
208 IPython.Demo? in IPython to see it).
210
209
211 Inputs:
210 Inputs:
212
211
213 - src is either a file, or file-like object, or a
212 - src is either a file, or file-like object, or a
214 string that can be resolved to a filename.
213 string that can be resolved to a filename.
215
214
216 Optional inputs:
215 Optional inputs:
217
216
218 - title: a string to use as the demo name. Of most use when the demo
217 - title: a string to use as the demo name. Of most use when the demo
219 you are making comes from an object that has no filename, or if you
218 you are making comes from an object that has no filename, or if you
220 want an alternate denotation distinct from the filename.
219 want an alternate denotation distinct from the filename.
221
220
222 - arg_str(''): a string of arguments, internally converted to a list
221 - arg_str(''): a string of arguments, internally converted to a list
223 just like sys.argv, so the demo script can see a similar
222 just like sys.argv, so the demo script can see a similar
224 environment.
223 environment.
225
224
226 - auto_all(None): global flag to run all blocks automatically without
225 - auto_all(None): global flag to run all blocks automatically without
227 confirmation. This attribute overrides the block-level tags and
226 confirmation. This attribute overrides the block-level tags and
228 applies to the whole demo. It is an attribute of the object, and
227 applies to the whole demo. It is an attribute of the object, and
229 can be changed at runtime simply by reassigning it to a boolean
228 can be changed at runtime simply by reassigning it to a boolean
230 value.
229 value.
231 """
230 """
232 if hasattr(src, "read"):
231 if hasattr(src, "read"):
233 # It seems to be a file or a file-like object
232 # It seems to be a file or a file-like object
234 self.fname = "from a file-like object"
233 self.fname = "from a file-like object"
235 if title == '':
234 if title == '':
236 self.title = "from a file-like object"
235 self.title = "from a file-like object"
237 else:
236 else:
238 self.title = title
237 self.title = title
239 else:
238 else:
240 # Assume it's a string or something that can be converted to one
239 # Assume it's a string or something that can be converted to one
241 self.fname = src
240 self.fname = src
242 if title == '':
241 if title == '':
243 (filepath, filename) = os.path.split(src)
242 (filepath, filename) = os.path.split(src)
244 self.title = filename
243 self.title = filename
245 else:
244 else:
246 self.title = title
245 self.title = title
247 self.sys_argv = [src] + shlex.split(arg_str)
246 self.sys_argv = [src] + shlex.split(arg_str)
248 self.auto_all = auto_all
247 self.auto_all = auto_all
249 self.src = src
248 self.src = src
250
249
251 # get a few things from ipython. While it's a bit ugly design-wise,
250 # get a few things from ipython. While it's a bit ugly design-wise,
252 # it ensures that things like color scheme and the like are always in
251 # it ensures that things like color scheme and the like are always in
253 # sync with the ipython mode being used. This class is only meant to
252 # sync with the ipython mode being used. This class is only meant to
254 # be used inside ipython anyways, so it's OK.
253 # be used inside ipython anyways, so it's OK.
255 ip = get_ipython() # this is in builtins whenever IPython is running
254 ip = get_ipython() # this is in builtins whenever IPython is running
256 self.ip_ns = ip.user_ns
255 self.ip_ns = ip.user_ns
257 self.ip_colorize = ip.pycolorize
256 self.ip_colorize = ip.pycolorize
258 self.ip_showtb = ip.showtraceback
257 self.ip_showtb = ip.showtraceback
259 self.ip_run_cell = ip.run_cell
258 self.ip_run_cell = ip.run_cell
260 self.shell = ip
259 self.shell = ip
261
260
262 # load user data and initialize data structures
261 # load user data and initialize data structures
263 self.reload()
262 self.reload()
264
263
265 def fload(self):
264 def fload(self):
266 """Load file object."""
265 """Load file object."""
267 # read data and parse into blocks
266 # read data and parse into blocks
268 if hasattr(self, 'fobj') and self.fobj is not None:
267 if hasattr(self, 'fobj') and self.fobj is not None:
269 self.fobj.close()
268 self.fobj.close()
270 if hasattr(self.src, "read"):
269 if hasattr(self.src, "read"):
271 # It seems to be a file or a file-like object
270 # It seems to be a file or a file-like object
272 self.fobj = self.src
271 self.fobj = self.src
273 else:
272 else:
274 # Assume it's a string or something that can be converted to one
273 # Assume it's a string or something that can be converted to one
275 self.fobj = openpy.open(self.fname)
274 self.fobj = openpy.open(self.fname)
276
275
277 def reload(self):
276 def reload(self):
278 """Reload source from disk and initialize state."""
277 """Reload source from disk and initialize state."""
279 self.fload()
278 self.fload()
280
279
281 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
282 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
283 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
284 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
285
284
286 # if auto_all is not given (def. None), we read it from the file
285 # if auto_all is not given (def. None), we read it from the file
287 if self.auto_all is None:
286 if self.auto_all is None:
288 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
289 else:
288 else:
290 self.auto_all = bool(self.auto_all)
289 self.auto_all = bool(self.auto_all)
291
290
292 # Clean the sources from all markup so it doesn't get displayed when
291 # Clean the sources from all markup so it doesn't get displayed when
293 # running the demo
292 # running the demo
294 src_blocks = []
293 src_blocks = []
295 auto_strip = lambda s: self.re_auto.sub('',s)
294 auto_strip = lambda s: self.re_auto.sub('',s)
296 for i,b in enumerate(src_b):
295 for i,b in enumerate(src_b):
297 if self._auto[i]:
296 if self._auto[i]:
298 src_blocks.append(auto_strip(b))
297 src_blocks.append(auto_strip(b))
299 else:
298 else:
300 src_blocks.append(b)
299 src_blocks.append(b)
301 # remove the auto_all marker
300 # remove the auto_all marker
302 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
303
302
304 self.nblocks = len(src_blocks)
303 self.nblocks = len(src_blocks)
305 self.src_blocks = src_blocks
304 self.src_blocks = src_blocks
306
305
307 # also build syntax-highlighted source
306 # also build syntax-highlighted source
308 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
307 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
309
308
310 # ensure clean namespace and seek offset
309 # ensure clean namespace and seek offset
311 self.reset()
310 self.reset()
312
311
313 def reset(self):
312 def reset(self):
314 """Reset the namespace and seek pointer to restart the demo"""
313 """Reset the namespace and seek pointer to restart the demo"""
315 self.user_ns = {}
314 self.user_ns = {}
316 self.finished = False
315 self.finished = False
317 self.block_index = 0
316 self.block_index = 0
318
317
319 def _validate_index(self,index):
318 def _validate_index(self,index):
320 if index<0 or index>=self.nblocks:
319 if index<0 or index>=self.nblocks:
321 raise ValueError('invalid block index %s' % index)
320 raise ValueError('invalid block index %s' % index)
322
321
323 def _get_index(self,index):
322 def _get_index(self,index):
324 """Get the current block index, validating and checking status.
323 """Get the current block index, validating and checking status.
325
324
326 Returns None if the demo is finished"""
325 Returns None if the demo is finished"""
327
326
328 if index is None:
327 if index is None:
329 if self.finished:
328 if self.finished:
330 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
331 return None
330 return None
332 index = self.block_index
331 index = self.block_index
333 else:
332 else:
334 self._validate_index(index)
333 self._validate_index(index)
335 return index
334 return index
336
335
337 def seek(self,index):
336 def seek(self,index):
338 """Move the current seek pointer to the given block.
337 """Move the current seek pointer to the given block.
339
338
340 You can use negative indices to seek from the end, with identical
339 You can use negative indices to seek from the end, with identical
341 semantics to those of Python lists."""
340 semantics to those of Python lists."""
342 if index<0:
341 if index<0:
343 index = self.nblocks + index
342 index = self.nblocks + index
344 self._validate_index(index)
343 self._validate_index(index)
345 self.block_index = index
344 self.block_index = index
346 self.finished = False
345 self.finished = False
347
346
348 def back(self,num=1):
347 def back(self,num=1):
349 """Move the seek pointer back num blocks (default is 1)."""
348 """Move the seek pointer back num blocks (default is 1)."""
350 self.seek(self.block_index-num)
349 self.seek(self.block_index-num)
351
350
352 def jump(self,num=1):
351 def jump(self,num=1):
353 """Jump a given number of blocks relative to the current one.
352 """Jump a given number of blocks relative to the current one.
354
353
355 The offset can be positive or negative, defaults to 1."""
354 The offset can be positive or negative, defaults to 1."""
356 self.seek(self.block_index+num)
355 self.seek(self.block_index+num)
357
356
358 def again(self):
357 def again(self):
359 """Move the seek pointer back one block and re-execute."""
358 """Move the seek pointer back one block and re-execute."""
360 self.back(1)
359 self.back(1)
361 self()
360 self()
362
361
363 def edit(self,index=None):
362 def edit(self,index=None):
364 """Edit a block.
363 """Edit a block.
365
364
366 If no number is given, use the last block executed.
365 If no number is given, use the last block executed.
367
366
368 This edits the in-memory copy of the demo, it does NOT modify the
367 This edits the in-memory copy of the demo, it does NOT modify the
369 original source file. If you want to do that, simply open the file in
368 original source file. If you want to do that, simply open the file in
370 an editor and use reload() when you make changes to the file. This
369 an editor and use reload() when you make changes to the file. This
371 method is meant to let you change a block during a demonstration for
370 method is meant to let you change a block during a demonstration for
372 explanatory purposes, without damaging your original script."""
371 explanatory purposes, without damaging your original script."""
373
372
374 index = self._get_index(index)
373 index = self._get_index(index)
375 if index is None:
374 if index is None:
376 return
375 return
377 # decrease the index by one (unless we're at the very beginning), so
376 # decrease the index by one (unless we're at the very beginning), so
378 # that the default demo.edit() call opens up the sblock we've last run
377 # that the default demo.edit() call opens up the sblock we've last run
379 if index>0:
378 if index>0:
380 index -= 1
379 index -= 1
381
380
382 filename = self.shell.mktempfile(self.src_blocks[index])
381 filename = self.shell.mktempfile(self.src_blocks[index])
383 self.shell.hooks.editor(filename,1)
382 self.shell.hooks.editor(filename,1)
384 new_block = file_read(filename)
383 new_block = file_read(filename)
385 # update the source and colored block
384 # update the source and colored block
386 self.src_blocks[index] = new_block
385 self.src_blocks[index] = new_block
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
386 self.src_blocks_colored[index] = self.ip_colorize(new_block)
388 self.block_index = index
387 self.block_index = index
389 # call to run with the newly edited index
388 # call to run with the newly edited index
390 self()
389 self()
391
390
392 def show(self,index=None):
391 def show(self,index=None):
393 """Show a single block on screen"""
392 """Show a single block on screen"""
394
393
395 index = self._get_index(index)
394 index = self._get_index(index)
396 if index is None:
395 if index is None:
397 return
396 return
398
397
399 print(self.marquee('<%s> block # %s (%s remaining)' %
398 print(self.marquee('<%s> block # %s (%s remaining)' %
400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
399 (self.title,index,self.nblocks-index-1)), file=io.stdout)
401 print((self.src_blocks_colored[index]), file=io.stdout)
400 print((self.src_blocks_colored[index]), file=io.stdout)
402 sys.stdout.flush()
401 sys.stdout.flush()
403
402
404 def show_all(self):
403 def show_all(self):
405 """Show entire demo on screen, block by block"""
404 """Show entire demo on screen, block by block"""
406
405
407 fname = self.title
406 fname = self.title
408 title = self.title
407 title = self.title
409 nblocks = self.nblocks
408 nblocks = self.nblocks
410 silent = self._silent
409 silent = self._silent
411 marquee = self.marquee
410 marquee = self.marquee
412 for index,block in enumerate(self.src_blocks_colored):
411 for index,block in enumerate(self.src_blocks_colored):
413 if silent[index]:
412 if silent[index]:
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
413 print(marquee('<%s> SILENT block # %s (%s remaining)' %
415 (title,index,nblocks-index-1)), file=io.stdout)
414 (title,index,nblocks-index-1)), file=io.stdout)
416 else:
415 else:
417 print(marquee('<%s> block # %s (%s remaining)' %
416 print(marquee('<%s> block # %s (%s remaining)' %
418 (title,index,nblocks-index-1)), file=io.stdout)
417 (title,index,nblocks-index-1)), file=io.stdout)
419 print(block, end=' ', file=io.stdout)
418 print(block, end=' ', file=io.stdout)
420 sys.stdout.flush()
419 sys.stdout.flush()
421
420
422 def run_cell(self,source):
421 def run_cell(self,source):
423 """Execute a string with one or more lines of code"""
422 """Execute a string with one or more lines of code"""
424
423
425 exec source in self.user_ns
424 exec source in self.user_ns
426
425
427 def __call__(self,index=None):
426 def __call__(self,index=None):
428 """run a block of the demo.
427 """run a block of the demo.
429
428
430 If index is given, it should be an integer >=1 and <= nblocks. This
429 If index is given, it should be an integer >=1 and <= nblocks. This
431 means that the calling convention is one off from typical Python
430 means that the calling convention is one off from typical Python
432 lists. The reason for the inconsistency is that the demo always
431 lists. The reason for the inconsistency is that the demo always
433 prints 'Block n/N, and N is the total, so it would be very odd to use
432 prints 'Block n/N, and N is the total, so it would be very odd to use
434 zero-indexing here."""
433 zero-indexing here."""
435
434
436 index = self._get_index(index)
435 index = self._get_index(index)
437 if index is None:
436 if index is None:
438 return
437 return
439 try:
438 try:
440 marquee = self.marquee
439 marquee = self.marquee
441 next_block = self.src_blocks[index]
440 next_block = self.src_blocks[index]
442 self.block_index += 1
441 self.block_index += 1
443 if self._silent[index]:
442 if self._silent[index]:
444 print(marquee('Executing silent block # %s (%s remaining)' %
443 print(marquee('Executing silent block # %s (%s remaining)' %
445 (index,self.nblocks-index-1)), file=io.stdout)
444 (index,self.nblocks-index-1)), file=io.stdout)
446 else:
445 else:
447 self.pre_cmd()
446 self.pre_cmd()
448 self.show(index)
447 self.show(index)
449 if self.auto_all or self._auto[index]:
448 if self.auto_all or self._auto[index]:
450 print(marquee('output:'), file=io.stdout)
449 print(marquee('output:'), file=io.stdout)
451 else:
450 else:
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
451 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
453 ans = raw_input().strip()
452 ans = raw_input().strip()
454 if ans:
453 if ans:
455 print(marquee('Block NOT executed'), file=io.stdout)
454 print(marquee('Block NOT executed'), file=io.stdout)
456 return
455 return
457 try:
456 try:
458 save_argv = sys.argv
457 save_argv = sys.argv
459 sys.argv = self.sys_argv
458 sys.argv = self.sys_argv
460 self.run_cell(next_block)
459 self.run_cell(next_block)
461 self.post_cmd()
460 self.post_cmd()
462 finally:
461 finally:
463 sys.argv = save_argv
462 sys.argv = save_argv
464
463
465 except:
464 except:
466 self.ip_showtb(filename=self.fname)
465 self.ip_showtb(filename=self.fname)
467 else:
466 else:
468 self.ip_ns.update(self.user_ns)
467 self.ip_ns.update(self.user_ns)
469
468
470 if self.block_index == self.nblocks:
469 if self.block_index == self.nblocks:
471 mq1 = self.marquee('END OF DEMO')
470 mq1 = self.marquee('END OF DEMO')
472 if mq1:
471 if mq1:
473 # avoid spurious print >>io.stdout,s if empty marquees are used
472 # avoid spurious print >>io.stdout,s if empty marquees are used
474 print(file=io.stdout)
473 print(file=io.stdout)
475 print(mq1, file=io.stdout)
474 print(mq1, file=io.stdout)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
475 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
477 self.finished = True
476 self.finished = True
478
477
479 # These methods are meant to be overridden by subclasses who may wish to
478 # These methods are meant to be overridden by subclasses who may wish to
480 # customize the behavior of of their demos.
479 # customize the behavior of of their demos.
481 def marquee(self,txt='',width=78,mark='*'):
480 def marquee(self,txt='',width=78,mark='*'):
482 """Return the input string centered in a 'marquee'."""
481 """Return the input string centered in a 'marquee'."""
483 return marquee(txt,width,mark)
482 return marquee(txt,width,mark)
484
483
485 def pre_cmd(self):
484 def pre_cmd(self):
486 """Method called before executing each block."""
485 """Method called before executing each block."""
487 pass
486 pass
488
487
489 def post_cmd(self):
488 def post_cmd(self):
490 """Method called after executing each block."""
489 """Method called after executing each block."""
491 pass
490 pass
492
491
493
492
494 class IPythonDemo(Demo):
493 class IPythonDemo(Demo):
495 """Class for interactive demos with IPython's input processing applied.
494 """Class for interactive demos with IPython's input processing applied.
496
495
497 This subclasses Demo, but instead of executing each block by the Python
496 This subclasses Demo, but instead of executing each block by the Python
498 interpreter (via exec), it actually calls IPython on it, so that any input
497 interpreter (via exec), it actually calls IPython on it, so that any input
499 filters which may be in place are applied to the input block.
498 filters which may be in place are applied to the input block.
500
499
501 If you have an interactive environment which exposes special input
500 If you have an interactive environment which exposes special input
502 processing, you can use this class instead to write demo scripts which
501 processing, you can use this class instead to write demo scripts which
503 operate exactly as if you had typed them interactively. The default Demo
502 operate exactly as if you had typed them interactively. The default Demo
504 class requires the input to be valid, pure Python code.
503 class requires the input to be valid, pure Python code.
505 """
504 """
506
505
507 def run_cell(self,source):
506 def run_cell(self,source):
508 """Execute a string with one or more lines of code"""
507 """Execute a string with one or more lines of code"""
509
508
510 self.shell.run_cell(source)
509 self.shell.run_cell(source)
511
510
512 class LineDemo(Demo):
511 class LineDemo(Demo):
513 """Demo where each line is executed as a separate block.
512 """Demo where each line is executed as a separate block.
514
513
515 The input script should be valid Python code.
514 The input script should be valid Python code.
516
515
517 This class doesn't require any markup at all, and it's meant for simple
516 This class doesn't require any markup at all, and it's meant for simple
518 scripts (with no nesting or any kind of indentation) which consist of
517 scripts (with no nesting or any kind of indentation) which consist of
519 multiple lines of input to be executed, one at a time, as if they had been
518 multiple lines of input to be executed, one at a time, as if they had been
520 typed in the interactive prompt.
519 typed in the interactive prompt.
521
520
522 Note: the input can not have *any* indentation, which means that only
521 Note: the input can not have *any* indentation, which means that only
523 single-lines of input are accepted, not even function definitions are
522 single-lines of input are accepted, not even function definitions are
524 valid."""
523 valid."""
525
524
526 def reload(self):
525 def reload(self):
527 """Reload source from disk and initialize state."""
526 """Reload source from disk and initialize state."""
528 # read data and parse into blocks
527 # read data and parse into blocks
529 self.fload()
528 self.fload()
530 lines = self.fobj.readlines()
529 lines = self.fobj.readlines()
531 src_b = [l for l in lines if l.strip()]
530 src_b = [l for l in lines if l.strip()]
532 nblocks = len(src_b)
531 nblocks = len(src_b)
533 self.src = ''.join(lines)
532 self.src = ''.join(lines)
534 self._silent = [False]*nblocks
533 self._silent = [False]*nblocks
535 self._auto = [True]*nblocks
534 self._auto = [True]*nblocks
536 self.auto_all = True
535 self.auto_all = True
537 self.nblocks = nblocks
536 self.nblocks = nblocks
538 self.src_blocks = src_b
537 self.src_blocks = src_b
539
538
540 # also build syntax-highlighted source
539 # also build syntax-highlighted source
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
540 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
542
541
543 # ensure clean namespace and seek offset
542 # ensure clean namespace and seek offset
544 self.reset()
543 self.reset()
545
544
546
545
547 class IPythonLineDemo(IPythonDemo,LineDemo):
546 class IPythonLineDemo(IPythonDemo,LineDemo):
548 """Variant of the LineDemo class whose input is processed by IPython."""
547 """Variant of the LineDemo class whose input is processed by IPython."""
549 pass
548 pass
550
549
551
550
552 class ClearMixin(object):
551 class ClearMixin(object):
553 """Use this mixin to make Demo classes with less visual clutter.
552 """Use this mixin to make Demo classes with less visual clutter.
554
553
555 Demos using this mixin will clear the screen before every block and use
554 Demos using this mixin will clear the screen before every block and use
556 blank marquees.
555 blank marquees.
557
556
558 Note that in order for the methods defined here to actually override those
557 Note that in order for the methods defined here to actually override those
559 of the classes it's mixed with, it must go /first/ in the inheritance
558 of the classes it's mixed with, it must go /first/ in the inheritance
560 tree. For example:
559 tree. For example:
561
560
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
561 class ClearIPDemo(ClearMixin,IPythonDemo): pass
563
562
564 will provide an IPythonDemo class with the mixin's features.
563 will provide an IPythonDemo class with the mixin's features.
565 """
564 """
566
565
567 def marquee(self,txt='',width=78,mark='*'):
566 def marquee(self,txt='',width=78,mark='*'):
568 """Blank marquee that returns '' no matter what the input."""
567 """Blank marquee that returns '' no matter what the input."""
569 return ''
568 return ''
570
569
571 def pre_cmd(self):
570 def pre_cmd(self):
572 """Method called before executing each block.
571 """Method called before executing each block.
573
572
574 This one simply clears the screen."""
573 This one simply clears the screen."""
575 from IPython.utils.terminal import term_clear
574 from IPython.utils.terminal import term_clear
576 term_clear()
575 term_clear()
577
576
578 class ClearDemo(ClearMixin,Demo):
577 class ClearDemo(ClearMixin,Demo):
579 pass
578 pass
580
579
581
580
582 class ClearIPDemo(ClearMixin,IPythonDemo):
581 class ClearIPDemo(ClearMixin,IPythonDemo):
583 pass
582 pass
@@ -1,165 +1,163 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """
3 """
4 Enable wxPython to be used interacive by setting PyOS_InputHook.
4 Enable wxPython to be used interacive by setting PyOS_InputHook.
5
5
6 Authors: Robin Dunn, Brian Granger, Ondrej Certik
6 Authors: Robin Dunn, Brian Granger, Ondrej Certik
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2011 The IPython Development Team
10 # Copyright (C) 2008-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 import os
21 import signal
20 import signal
22 import sys
23 import time
21 import time
24 from timeit import default_timer as clock
22 from timeit import default_timer as clock
25 import wx
23 import wx
26
24
27 from IPython.lib.inputhook import stdin_ready
25 from IPython.lib.inputhook import stdin_ready
28
26
29
27
30 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
31 # Code
29 # Code
32 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
33
31
34 def inputhook_wx1():
32 def inputhook_wx1():
35 """Run the wx event loop by processing pending events only.
33 """Run the wx event loop by processing pending events only.
36
34
37 This approach seems to work, but its performance is not great as it
35 This approach seems to work, but its performance is not great as it
38 relies on having PyOS_InputHook called regularly.
36 relies on having PyOS_InputHook called regularly.
39 """
37 """
40 try:
38 try:
41 app = wx.GetApp()
39 app = wx.GetApp()
42 if app is not None:
40 if app is not None:
43 assert wx.Thread_IsMain()
41 assert wx.Thread_IsMain()
44
42
45 # Make a temporary event loop and process system events until
43 # Make a temporary event loop and process system events until
46 # there are no more waiting, then allow idle events (which
44 # there are no more waiting, then allow idle events (which
47 # will also deal with pending or posted wx events.)
45 # will also deal with pending or posted wx events.)
48 evtloop = wx.EventLoop()
46 evtloop = wx.EventLoop()
49 ea = wx.EventLoopActivator(evtloop)
47 ea = wx.EventLoopActivator(evtloop)
50 while evtloop.Pending():
48 while evtloop.Pending():
51 evtloop.Dispatch()
49 evtloop.Dispatch()
52 app.ProcessIdle()
50 app.ProcessIdle()
53 del ea
51 del ea
54 except KeyboardInterrupt:
52 except KeyboardInterrupt:
55 pass
53 pass
56 return 0
54 return 0
57
55
58 class EventLoopTimer(wx.Timer):
56 class EventLoopTimer(wx.Timer):
59
57
60 def __init__(self, func):
58 def __init__(self, func):
61 self.func = func
59 self.func = func
62 wx.Timer.__init__(self)
60 wx.Timer.__init__(self)
63
61
64 def Notify(self):
62 def Notify(self):
65 self.func()
63 self.func()
66
64
67 class EventLoopRunner(object):
65 class EventLoopRunner(object):
68
66
69 def Run(self, time):
67 def Run(self, time):
70 self.evtloop = wx.EventLoop()
68 self.evtloop = wx.EventLoop()
71 self.timer = EventLoopTimer(self.check_stdin)
69 self.timer = EventLoopTimer(self.check_stdin)
72 self.timer.Start(time)
70 self.timer.Start(time)
73 self.evtloop.Run()
71 self.evtloop.Run()
74
72
75 def check_stdin(self):
73 def check_stdin(self):
76 if stdin_ready():
74 if stdin_ready():
77 self.timer.Stop()
75 self.timer.Stop()
78 self.evtloop.Exit()
76 self.evtloop.Exit()
79
77
80 def inputhook_wx2():
78 def inputhook_wx2():
81 """Run the wx event loop, polling for stdin.
79 """Run the wx event loop, polling for stdin.
82
80
83 This version runs the wx eventloop for an undetermined amount of time,
81 This version runs the wx eventloop for an undetermined amount of time,
84 during which it periodically checks to see if anything is ready on
82 during which it periodically checks to see if anything is ready on
85 stdin. If anything is ready on stdin, the event loop exits.
83 stdin. If anything is ready on stdin, the event loop exits.
86
84
87 The argument to elr.Run controls how often the event loop looks at stdin.
85 The argument to elr.Run controls how often the event loop looks at stdin.
88 This determines the responsiveness at the keyboard. A setting of 1000
86 This determines the responsiveness at the keyboard. A setting of 1000
89 enables a user to type at most 1 char per second. I have found that a
87 enables a user to type at most 1 char per second. I have found that a
90 setting of 10 gives good keyboard response. We can shorten it further,
88 setting of 10 gives good keyboard response. We can shorten it further,
91 but eventually performance would suffer from calling select/kbhit too
89 but eventually performance would suffer from calling select/kbhit too
92 often.
90 often.
93 """
91 """
94 try:
92 try:
95 app = wx.GetApp()
93 app = wx.GetApp()
96 if app is not None:
94 if app is not None:
97 assert wx.Thread_IsMain()
95 assert wx.Thread_IsMain()
98 elr = EventLoopRunner()
96 elr = EventLoopRunner()
99 # As this time is made shorter, keyboard response improves, but idle
97 # As this time is made shorter, keyboard response improves, but idle
100 # CPU load goes up. 10 ms seems like a good compromise.
98 # CPU load goes up. 10 ms seems like a good compromise.
101 elr.Run(time=10) # CHANGE time here to control polling interval
99 elr.Run(time=10) # CHANGE time here to control polling interval
102 except KeyboardInterrupt:
100 except KeyboardInterrupt:
103 pass
101 pass
104 return 0
102 return 0
105
103
106 def inputhook_wx3():
104 def inputhook_wx3():
107 """Run the wx event loop by processing pending events only.
105 """Run the wx event loop by processing pending events only.
108
106
109 This is like inputhook_wx1, but it keeps processing pending events
107 This is like inputhook_wx1, but it keeps processing pending events
110 until stdin is ready. After processing all pending events, a call to
108 until stdin is ready. After processing all pending events, a call to
111 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
109 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
112 This sleep time should be tuned though for best performance.
110 This sleep time should be tuned though for best performance.
113 """
111 """
114 # We need to protect against a user pressing Control-C when IPython is
112 # We need to protect against a user pressing Control-C when IPython is
115 # idle and this is running. We trap KeyboardInterrupt and pass.
113 # idle and this is running. We trap KeyboardInterrupt and pass.
116 try:
114 try:
117 app = wx.GetApp()
115 app = wx.GetApp()
118 if app is not None:
116 if app is not None:
119 assert wx.Thread_IsMain()
117 assert wx.Thread_IsMain()
120
118
121 # The import of wx on Linux sets the handler for signal.SIGINT
119 # The import of wx on Linux sets the handler for signal.SIGINT
122 # to 0. This is a bug in wx or gtk. We fix by just setting it
120 # to 0. This is a bug in wx or gtk. We fix by just setting it
123 # back to the Python default.
121 # back to the Python default.
124 if not callable(signal.getsignal(signal.SIGINT)):
122 if not callable(signal.getsignal(signal.SIGINT)):
125 signal.signal(signal.SIGINT, signal.default_int_handler)
123 signal.signal(signal.SIGINT, signal.default_int_handler)
126
124
127 evtloop = wx.EventLoop()
125 evtloop = wx.EventLoop()
128 ea = wx.EventLoopActivator(evtloop)
126 ea = wx.EventLoopActivator(evtloop)
129 t = clock()
127 t = clock()
130 while not stdin_ready():
128 while not stdin_ready():
131 while evtloop.Pending():
129 while evtloop.Pending():
132 t = clock()
130 t = clock()
133 evtloop.Dispatch()
131 evtloop.Dispatch()
134 app.ProcessIdle()
132 app.ProcessIdle()
135 # We need to sleep at this point to keep the idle CPU load
133 # We need to sleep at this point to keep the idle CPU load
136 # low. However, if sleep to long, GUI response is poor. As
134 # low. However, if sleep to long, GUI response is poor. As
137 # a compromise, we watch how often GUI events are being processed
135 # a compromise, we watch how often GUI events are being processed
138 # and switch between a short and long sleep time. Here are some
136 # and switch between a short and long sleep time. Here are some
139 # stats useful in helping to tune this.
137 # stats useful in helping to tune this.
140 # time CPU load
138 # time CPU load
141 # 0.001 13%
139 # 0.001 13%
142 # 0.005 3%
140 # 0.005 3%
143 # 0.01 1.5%
141 # 0.01 1.5%
144 # 0.05 0.5%
142 # 0.05 0.5%
145 used_time = clock() - t
143 used_time = clock() - t
146 if used_time > 5*60.0:
144 if used_time > 5*60.0:
147 # print 'Sleep for 5 s' # dbg
145 # print 'Sleep for 5 s' # dbg
148 time.sleep(5.0)
146 time.sleep(5.0)
149 elif used_time > 10.0:
147 elif used_time > 10.0:
150 # print 'Sleep for 1 s' # dbg
148 # print 'Sleep for 1 s' # dbg
151 time.sleep(1.0)
149 time.sleep(1.0)
152 elif used_time > 0.1:
150 elif used_time > 0.1:
153 # Few GUI events coming in, so we can sleep longer
151 # Few GUI events coming in, so we can sleep longer
154 # print 'Sleep for 0.05 s' # dbg
152 # print 'Sleep for 0.05 s' # dbg
155 time.sleep(0.05)
153 time.sleep(0.05)
156 else:
154 else:
157 # Many GUI events coming in, so sleep only very little
155 # Many GUI events coming in, so sleep only very little
158 time.sleep(0.001)
156 time.sleep(0.001)
159 del ea
157 del ea
160 except KeyboardInterrupt:
158 except KeyboardInterrupt:
161 pass
159 pass
162 return 0
160 return 0
163
161
164 # This is our default implementation
162 # This is our default implementation
165 inputhook_wx = inputhook_wx3
163 inputhook_wx = inputhook_wx3
@@ -1,252 +1,252 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for handling LaTeX.
2 """Tools for handling LaTeX.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010 IPython Development Team.
9 # Copyright (C) 2010 IPython Development Team.
10 #
10 #
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12 #
12 #
13 # The full license is in the file COPYING.txt, distributed with this software.
13 # The full license is in the file COPYING.txt, distributed with this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from io import BytesIO
20 from io import BytesIO
21 from base64 import encodestring
21 from base64 import encodestring
22 import os
22 import os
23 import tempfile
23 import tempfile
24 import shutil
24 import shutil
25 import subprocess
25 import subprocess
26
26
27 from IPython.utils.process import find_cmd, FindCmdError
27 from IPython.utils.process import find_cmd, FindCmdError
28 from IPython.config.configurable import SingletonConfigurable
28 from IPython.config.configurable import SingletonConfigurable
29 from IPython.utils.traitlets import Instance, List, CBool, CUnicode
29 from IPython.utils.traitlets import List, CBool, CUnicode
30 from IPython.utils.py3compat import bytes_to_str
30 from IPython.utils.py3compat import bytes_to_str
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Tools
33 # Tools
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36
36
37 class LaTeXTool(SingletonConfigurable):
37 class LaTeXTool(SingletonConfigurable):
38 """An object to store configuration of the LaTeX tool."""
38 """An object to store configuration of the LaTeX tool."""
39
39
40 backends = List(
40 backends = List(
41 CUnicode, ["matplotlib", "dvipng"],
41 CUnicode, ["matplotlib", "dvipng"],
42 help="Preferred backend to draw LaTeX math equations. "
42 help="Preferred backend to draw LaTeX math equations. "
43 "Backends in the list are checked one by one and the first "
43 "Backends in the list are checked one by one and the first "
44 "usable one is used. Note that `matplotlib` backend "
44 "usable one is used. Note that `matplotlib` backend "
45 "is usable only for inline style equations. To draw "
45 "is usable only for inline style equations. To draw "
46 "display style equations, `dvipng` backend must be specified. ",
46 "display style equations, `dvipng` backend must be specified. ",
47 # It is a List instead of Enum, to make configuration more
47 # It is a List instead of Enum, to make configuration more
48 # flexible. For example, to use matplotlib mainly but dvipng
48 # flexible. For example, to use matplotlib mainly but dvipng
49 # for display style, the default ["matplotlib", "dvipng"] can
49 # for display style, the default ["matplotlib", "dvipng"] can
50 # be used. To NOT use dvipng so that other repr such as
50 # be used. To NOT use dvipng so that other repr such as
51 # unicode pretty printing is used, you can use ["matplotlib"].
51 # unicode pretty printing is used, you can use ["matplotlib"].
52 config=True)
52 config=True)
53
53
54 use_breqn = CBool(
54 use_breqn = CBool(
55 True,
55 True,
56 help="Use breqn.sty to automatically break long equations. "
56 help="Use breqn.sty to automatically break long equations. "
57 "This configuration takes effect only for dvipng backend.",
57 "This configuration takes effect only for dvipng backend.",
58 config=True)
58 config=True)
59
59
60 packages = List(
60 packages = List(
61 ['amsmath', 'amsthm', 'amssymb', 'bm'],
61 ['amsmath', 'amsthm', 'amssymb', 'bm'],
62 help="A list of packages to use for dvipng backend. "
62 help="A list of packages to use for dvipng backend. "
63 "'breqn' will be automatically appended when use_breqn=True.",
63 "'breqn' will be automatically appended when use_breqn=True.",
64 config=True)
64 config=True)
65
65
66 preamble = CUnicode(
66 preamble = CUnicode(
67 help="Additional preamble to use when generating LaTeX source "
67 help="Additional preamble to use when generating LaTeX source "
68 "for dvipng backend.",
68 "for dvipng backend.",
69 config=True)
69 config=True)
70
70
71
71
72 def latex_to_png(s, encode=False, backend=None, wrap=False):
72 def latex_to_png(s, encode=False, backend=None, wrap=False):
73 """Render a LaTeX string to PNG.
73 """Render a LaTeX string to PNG.
74
74
75 Parameters
75 Parameters
76 ----------
76 ----------
77 s : str
77 s : str
78 The raw string containing valid inline LaTeX.
78 The raw string containing valid inline LaTeX.
79 encode : bool, optional
79 encode : bool, optional
80 Should the PNG data bebase64 encoded to make it JSON'able.
80 Should the PNG data bebase64 encoded to make it JSON'able.
81 backend : {matplotlib, dvipng}
81 backend : {matplotlib, dvipng}
82 Backend for producing PNG data.
82 Backend for producing PNG data.
83 wrap : bool
83 wrap : bool
84 If true, Automatically wrap `s` as a LaTeX equation.
84 If true, Automatically wrap `s` as a LaTeX equation.
85
85
86 None is returned when the backend cannot be used.
86 None is returned when the backend cannot be used.
87
87
88 """
88 """
89 allowed_backends = LaTeXTool.instance().backends
89 allowed_backends = LaTeXTool.instance().backends
90 if backend is None:
90 if backend is None:
91 backend = allowed_backends[0]
91 backend = allowed_backends[0]
92 if backend not in allowed_backends:
92 if backend not in allowed_backends:
93 return None
93 return None
94 if backend == 'matplotlib':
94 if backend == 'matplotlib':
95 f = latex_to_png_mpl
95 f = latex_to_png_mpl
96 elif backend == 'dvipng':
96 elif backend == 'dvipng':
97 f = latex_to_png_dvipng
97 f = latex_to_png_dvipng
98 else:
98 else:
99 raise ValueError('No such backend {0}'.format(backend))
99 raise ValueError('No such backend {0}'.format(backend))
100 bin_data = f(s, wrap)
100 bin_data = f(s, wrap)
101 if encode and bin_data:
101 if encode and bin_data:
102 bin_data = encodestring(bin_data)
102 bin_data = encodestring(bin_data)
103 return bin_data
103 return bin_data
104
104
105
105
106 def latex_to_png_mpl(s, wrap):
106 def latex_to_png_mpl(s, wrap):
107 try:
107 try:
108 from matplotlib import mathtext
108 from matplotlib import mathtext
109 except ImportError:
109 except ImportError:
110 return None
110 return None
111
111
112 if wrap:
112 if wrap:
113 s = '${0}$'.format(s)
113 s = '${0}$'.format(s)
114 mt = mathtext.MathTextParser('bitmap')
114 mt = mathtext.MathTextParser('bitmap')
115 f = BytesIO()
115 f = BytesIO()
116 mt.to_png(f, s, fontsize=12)
116 mt.to_png(f, s, fontsize=12)
117 return f.getvalue()
117 return f.getvalue()
118
118
119
119
120 def latex_to_png_dvipng(s, wrap):
120 def latex_to_png_dvipng(s, wrap):
121 try:
121 try:
122 find_cmd('latex')
122 find_cmd('latex')
123 find_cmd('dvipng')
123 find_cmd('dvipng')
124 except FindCmdError:
124 except FindCmdError:
125 return None
125 return None
126 try:
126 try:
127 workdir = tempfile.mkdtemp()
127 workdir = tempfile.mkdtemp()
128 tmpfile = os.path.join(workdir, "tmp.tex")
128 tmpfile = os.path.join(workdir, "tmp.tex")
129 dvifile = os.path.join(workdir, "tmp.dvi")
129 dvifile = os.path.join(workdir, "tmp.dvi")
130 outfile = os.path.join(workdir, "tmp.png")
130 outfile = os.path.join(workdir, "tmp.png")
131
131
132 with open(tmpfile, "w") as f:
132 with open(tmpfile, "w") as f:
133 f.writelines(genelatex(s, wrap))
133 f.writelines(genelatex(s, wrap))
134
134
135 with open(os.devnull, 'w') as devnull:
135 with open(os.devnull, 'w') as devnull:
136 subprocess.check_call(
136 subprocess.check_call(
137 ["latex", "-halt-on-error", tmpfile], cwd=workdir,
137 ["latex", "-halt-on-error", tmpfile], cwd=workdir,
138 stdout=devnull, stderr=devnull)
138 stdout=devnull, stderr=devnull)
139
139
140 subprocess.check_call(
140 subprocess.check_call(
141 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
141 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
142 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir,
142 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir,
143 stdout=devnull, stderr=devnull)
143 stdout=devnull, stderr=devnull)
144
144
145 with open(outfile, "rb") as f:
145 with open(outfile, "rb") as f:
146 bin_data = f.read()
146 bin_data = f.read()
147 finally:
147 finally:
148 shutil.rmtree(workdir)
148 shutil.rmtree(workdir)
149 return bin_data
149 return bin_data
150
150
151
151
152 def kpsewhich(filename):
152 def kpsewhich(filename):
153 """Invoke kpsewhich command with an argument `filename`."""
153 """Invoke kpsewhich command with an argument `filename`."""
154 try:
154 try:
155 find_cmd("kpsewhich")
155 find_cmd("kpsewhich")
156 proc = subprocess.Popen(
156 proc = subprocess.Popen(
157 ["kpsewhich", filename],
157 ["kpsewhich", filename],
158 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
158 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
159 (stdout, stderr) = proc.communicate()
159 (stdout, stderr) = proc.communicate()
160 return stdout.strip()
160 return stdout.strip()
161 except FindCmdError:
161 except FindCmdError:
162 pass
162 pass
163
163
164
164
165 def genelatex(body, wrap):
165 def genelatex(body, wrap):
166 """Generate LaTeX document for dvipng backend."""
166 """Generate LaTeX document for dvipng backend."""
167 lt = LaTeXTool.instance()
167 lt = LaTeXTool.instance()
168 breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty")
168 breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty")
169 yield r'\documentclass{article}'
169 yield r'\documentclass{article}'
170 packages = lt.packages
170 packages = lt.packages
171 if breqn:
171 if breqn:
172 packages = packages + ['breqn']
172 packages = packages + ['breqn']
173 for pack in packages:
173 for pack in packages:
174 yield r'\usepackage{{{0}}}'.format(pack)
174 yield r'\usepackage{{{0}}}'.format(pack)
175 yield r'\pagestyle{empty}'
175 yield r'\pagestyle{empty}'
176 if lt.preamble:
176 if lt.preamble:
177 yield lt.preamble
177 yield lt.preamble
178 yield r'\begin{document}'
178 yield r'\begin{document}'
179 if breqn:
179 if breqn:
180 yield r'\begin{dmath*}'
180 yield r'\begin{dmath*}'
181 yield body
181 yield body
182 yield r'\end{dmath*}'
182 yield r'\end{dmath*}'
183 elif wrap:
183 elif wrap:
184 yield '$${0}$$'.format(body)
184 yield '$${0}$$'.format(body)
185 else:
185 else:
186 yield body
186 yield body
187 yield r'\end{document}'
187 yield r'\end{document}'
188
188
189
189
190 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
190 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
191
191
192 def latex_to_html(s, alt='image'):
192 def latex_to_html(s, alt='image'):
193 """Render LaTeX to HTML with embedded PNG data using data URIs.
193 """Render LaTeX to HTML with embedded PNG data using data URIs.
194
194
195 Parameters
195 Parameters
196 ----------
196 ----------
197 s : str
197 s : str
198 The raw string containing valid inline LateX.
198 The raw string containing valid inline LateX.
199 alt : str
199 alt : str
200 The alt text to use for the HTML.
200 The alt text to use for the HTML.
201 """
201 """
202 base64_data = bytes_to_str(latex_to_png(s, encode=True), 'ascii')
202 base64_data = bytes_to_str(latex_to_png(s, encode=True), 'ascii')
203 if base64_data:
203 if base64_data:
204 return _data_uri_template_png % (base64_data, alt)
204 return _data_uri_template_png % (base64_data, alt)
205
205
206
206
207 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
207 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
208 # will remove.
208 # will remove.
209 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
209 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
210 """
210 """
211 Given a math expression, renders it in a closely-clipped bounding
211 Given a math expression, renders it in a closely-clipped bounding
212 box to an image file.
212 box to an image file.
213
213
214 *s*
214 *s*
215 A math expression. The math portion should be enclosed in
215 A math expression. The math portion should be enclosed in
216 dollar signs.
216 dollar signs.
217
217
218 *filename_or_obj*
218 *filename_or_obj*
219 A filepath or writable file-like object to write the image data
219 A filepath or writable file-like object to write the image data
220 to.
220 to.
221
221
222 *prop*
222 *prop*
223 If provided, a FontProperties() object describing the size and
223 If provided, a FontProperties() object describing the size and
224 style of the text.
224 style of the text.
225
225
226 *dpi*
226 *dpi*
227 Override the output dpi, otherwise use the default associated
227 Override the output dpi, otherwise use the default associated
228 with the output format.
228 with the output format.
229
229
230 *format*
230 *format*
231 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
231 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
232 provided, will be deduced from the filename.
232 provided, will be deduced from the filename.
233 """
233 """
234 from matplotlib import figure
234 from matplotlib import figure
235 # backend_agg supports all of the core output formats
235 # backend_agg supports all of the core output formats
236 from matplotlib.backends import backend_agg
236 from matplotlib.backends import backend_agg
237 from matplotlib.font_manager import FontProperties
237 from matplotlib.font_manager import FontProperties
238 from matplotlib.mathtext import MathTextParser
238 from matplotlib.mathtext import MathTextParser
239
239
240 if prop is None:
240 if prop is None:
241 prop = FontProperties()
241 prop = FontProperties()
242
242
243 parser = MathTextParser('path')
243 parser = MathTextParser('path')
244 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
244 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
245
245
246 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
246 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
247 fig.text(0, depth/height, s, fontproperties=prop)
247 fig.text(0, depth/height, s, fontproperties=prop)
248 backend_agg.FigureCanvasAgg(fig)
248 backend_agg.FigureCanvasAgg(fig)
249 fig.savefig(filename_or_obj, dpi=dpi, format=format)
249 fig.savefig(filename_or_obj, dpi=dpi, format=format)
250
250
251 return depth
251 return depth
252
252
@@ -1,198 +1,197 b''
1 """Posix-specific implementation of process utilities.
1 """Posix-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import subprocess as sp
19 import subprocess as sp
20 import sys
20 import sys
21
21
22 from IPython.external import pexpect
22 from IPython.external import pexpect
23
23
24 # Our own
24 # Our own
25 from .autoattr import auto_attr
25 from .autoattr import auto_attr
26 from ._process_common import getoutput, arg_split
26 from ._process_common import getoutput, arg_split
27 from IPython.utils import text
28 from IPython.utils import py3compat
27 from IPython.utils import py3compat
29 from IPython.utils.encoding import DEFAULT_ENCODING
28 from IPython.utils.encoding import DEFAULT_ENCODING
30
29
31 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
32 # Function definitions
31 # Function definitions
33 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
34
33
35 def _find_cmd(cmd):
34 def _find_cmd(cmd):
36 """Find the full path to a command using which."""
35 """Find the full path to a command using which."""
37
36
38 path = sp.Popen(['/usr/bin/env', 'which', cmd],
37 path = sp.Popen(['/usr/bin/env', 'which', cmd],
39 stdout=sp.PIPE, stderr=sp.PIPE).communicate()[0]
38 stdout=sp.PIPE, stderr=sp.PIPE).communicate()[0]
40 return py3compat.bytes_to_str(path)
39 return py3compat.bytes_to_str(path)
41
40
42
41
43 class ProcessHandler(object):
42 class ProcessHandler(object):
44 """Execute subprocesses under the control of pexpect.
43 """Execute subprocesses under the control of pexpect.
45 """
44 """
46 # Timeout in seconds to wait on each reading of the subprocess' output.
45 # Timeout in seconds to wait on each reading of the subprocess' output.
47 # This should not be set too low to avoid cpu overusage from our side,
46 # This should not be set too low to avoid cpu overusage from our side,
48 # since we read in a loop whose period is controlled by this timeout.
47 # since we read in a loop whose period is controlled by this timeout.
49 read_timeout = 0.05
48 read_timeout = 0.05
50
49
51 # Timeout to give a process if we receive SIGINT, between sending the
50 # Timeout to give a process if we receive SIGINT, between sending the
52 # SIGINT to the process and forcefully terminating it.
51 # SIGINT to the process and forcefully terminating it.
53 terminate_timeout = 0.2
52 terminate_timeout = 0.2
54
53
55 # File object where stdout and stderr of the subprocess will be written
54 # File object where stdout and stderr of the subprocess will be written
56 logfile = None
55 logfile = None
57
56
58 # Shell to call for subprocesses to execute
57 # Shell to call for subprocesses to execute
59 sh = None
58 sh = None
60
59
61 @auto_attr
60 @auto_attr
62 def sh(self):
61 def sh(self):
63 sh = pexpect.which('sh')
62 sh = pexpect.which('sh')
64 if sh is None:
63 if sh is None:
65 raise OSError('"sh" shell not found')
64 raise OSError('"sh" shell not found')
66 return sh
65 return sh
67
66
68 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
67 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
69 """Arguments are used for pexpect calls."""
68 """Arguments are used for pexpect calls."""
70 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
69 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
71 None else read_timeout)
70 None else read_timeout)
72 self.terminate_timeout = (ProcessHandler.terminate_timeout if
71 self.terminate_timeout = (ProcessHandler.terminate_timeout if
73 terminate_timeout is None else
72 terminate_timeout is None else
74 terminate_timeout)
73 terminate_timeout)
75 self.logfile = sys.stdout if logfile is None else logfile
74 self.logfile = sys.stdout if logfile is None else logfile
76
75
77 def getoutput(self, cmd):
76 def getoutput(self, cmd):
78 """Run a command and return its stdout/stderr as a string.
77 """Run a command and return its stdout/stderr as a string.
79
78
80 Parameters
79 Parameters
81 ----------
80 ----------
82 cmd : str
81 cmd : str
83 A command to be executed in the system shell.
82 A command to be executed in the system shell.
84
83
85 Returns
84 Returns
86 -------
85 -------
87 output : str
86 output : str
88 A string containing the combination of stdout and stderr from the
87 A string containing the combination of stdout and stderr from the
89 subprocess, in whatever order the subprocess originally wrote to its
88 subprocess, in whatever order the subprocess originally wrote to its
90 file descriptors (so the order of the information in this string is the
89 file descriptors (so the order of the information in this string is the
91 correct order as would be seen if running the command in a terminal).
90 correct order as would be seen if running the command in a terminal).
92 """
91 """
93 try:
92 try:
94 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
93 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
95 except KeyboardInterrupt:
94 except KeyboardInterrupt:
96 print('^C', file=sys.stderr, end='')
95 print('^C', file=sys.stderr, end='')
97
96
98 def getoutput_pexpect(self, cmd):
97 def getoutput_pexpect(self, cmd):
99 """Run a command and return its stdout/stderr as a string.
98 """Run a command and return its stdout/stderr as a string.
100
99
101 Parameters
100 Parameters
102 ----------
101 ----------
103 cmd : str
102 cmd : str
104 A command to be executed in the system shell.
103 A command to be executed in the system shell.
105
104
106 Returns
105 Returns
107 -------
106 -------
108 output : str
107 output : str
109 A string containing the combination of stdout and stderr from the
108 A string containing the combination of stdout and stderr from the
110 subprocess, in whatever order the subprocess originally wrote to its
109 subprocess, in whatever order the subprocess originally wrote to its
111 file descriptors (so the order of the information in this string is the
110 file descriptors (so the order of the information in this string is the
112 correct order as would be seen if running the command in a terminal).
111 correct order as would be seen if running the command in a terminal).
113 """
112 """
114 try:
113 try:
115 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
114 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
116 except KeyboardInterrupt:
115 except KeyboardInterrupt:
117 print('^C', file=sys.stderr, end='')
116 print('^C', file=sys.stderr, end='')
118
117
119 def system(self, cmd):
118 def system(self, cmd):
120 """Execute a command in a subshell.
119 """Execute a command in a subshell.
121
120
122 Parameters
121 Parameters
123 ----------
122 ----------
124 cmd : str
123 cmd : str
125 A command to be executed in the system shell.
124 A command to be executed in the system shell.
126
125
127 Returns
126 Returns
128 -------
127 -------
129 int : child's exitstatus
128 int : child's exitstatus
130 """
129 """
131 # Get likely encoding for the output.
130 # Get likely encoding for the output.
132 enc = DEFAULT_ENCODING
131 enc = DEFAULT_ENCODING
133
132
134 # Patterns to match on the output, for pexpect. We read input and
133 # Patterns to match on the output, for pexpect. We read input and
135 # allow either a short timeout or EOF
134 # allow either a short timeout or EOF
136 patterns = [pexpect.TIMEOUT, pexpect.EOF]
135 patterns = [pexpect.TIMEOUT, pexpect.EOF]
137 # the index of the EOF pattern in the list.
136 # the index of the EOF pattern in the list.
138 # even though we know it's 1, this call means we don't have to worry if
137 # even though we know it's 1, this call means we don't have to worry if
139 # we change the above list, and forget to change this value:
138 # we change the above list, and forget to change this value:
140 EOF_index = patterns.index(pexpect.EOF)
139 EOF_index = patterns.index(pexpect.EOF)
141 # The size of the output stored so far in the process output buffer.
140 # The size of the output stored so far in the process output buffer.
142 # Since pexpect only appends to this buffer, each time we print we
141 # Since pexpect only appends to this buffer, each time we print we
143 # record how far we've printed, so that next time we only print *new*
142 # record how far we've printed, so that next time we only print *new*
144 # content from the buffer.
143 # content from the buffer.
145 out_size = 0
144 out_size = 0
146 try:
145 try:
147 # Since we're not really searching the buffer for text patterns, we
146 # Since we're not really searching the buffer for text patterns, we
148 # can set pexpect's search window to be tiny and it won't matter.
147 # can set pexpect's search window to be tiny and it won't matter.
149 # We only search for the 'patterns' timeout or EOF, which aren't in
148 # We only search for the 'patterns' timeout or EOF, which aren't in
150 # the text itself.
149 # the text itself.
151 #child = pexpect.spawn(pcmd, searchwindowsize=1)
150 #child = pexpect.spawn(pcmd, searchwindowsize=1)
152 if hasattr(pexpect, 'spawnb'):
151 if hasattr(pexpect, 'spawnb'):
153 child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
152 child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
154 else:
153 else:
155 child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
154 child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
156 flush = sys.stdout.flush
155 flush = sys.stdout.flush
157 while True:
156 while True:
158 # res is the index of the pattern that caused the match, so we
157 # res is the index of the pattern that caused the match, so we
159 # know whether we've finished (if we matched EOF) or not
158 # know whether we've finished (if we matched EOF) or not
160 res_idx = child.expect_list(patterns, self.read_timeout)
159 res_idx = child.expect_list(patterns, self.read_timeout)
161 print(child.before[out_size:].decode(enc, 'replace'), end='')
160 print(child.before[out_size:].decode(enc, 'replace'), end='')
162 flush()
161 flush()
163 if res_idx==EOF_index:
162 if res_idx==EOF_index:
164 break
163 break
165 # Update the pointer to what we've already printed
164 # Update the pointer to what we've already printed
166 out_size = len(child.before)
165 out_size = len(child.before)
167 except KeyboardInterrupt:
166 except KeyboardInterrupt:
168 # We need to send ^C to the process. The ascii code for '^C' is 3
167 # We need to send ^C to the process. The ascii code for '^C' is 3
169 # (the character is known as ETX for 'End of Text', see
168 # (the character is known as ETX for 'End of Text', see
170 # curses.ascii.ETX).
169 # curses.ascii.ETX).
171 child.sendline(chr(3))
170 child.sendline(chr(3))
172 # Read and print any more output the program might produce on its
171 # Read and print any more output the program might produce on its
173 # way out.
172 # way out.
174 try:
173 try:
175 out_size = len(child.before)
174 out_size = len(child.before)
176 child.expect_list(patterns, self.terminate_timeout)
175 child.expect_list(patterns, self.terminate_timeout)
177 print(child.before[out_size:].decode(enc, 'replace'), end='')
176 print(child.before[out_size:].decode(enc, 'replace'), end='')
178 sys.stdout.flush()
177 sys.stdout.flush()
179 except KeyboardInterrupt:
178 except KeyboardInterrupt:
180 # Impatient users tend to type it multiple times
179 # Impatient users tend to type it multiple times
181 pass
180 pass
182 finally:
181 finally:
183 # Ensure the subprocess really is terminated
182 # Ensure the subprocess really is terminated
184 child.terminate(force=True)
183 child.terminate(force=True)
185 # add isalive check, to ensure exitstatus is set:
184 # add isalive check, to ensure exitstatus is set:
186 child.isalive()
185 child.isalive()
187 return child.exitstatus
186 return child.exitstatus
188
187
189
188
190 # Make system() with a functional interface for outside use. Note that we use
189 # Make system() with a functional interface for outside use. Note that we use
191 # getoutput() from the _common utils, which is built on top of popen(). Using
190 # getoutput() from the _common utils, which is built on top of popen(). Using
192 # pexpect to get subprocess output produces difficult to parse output, since
191 # pexpect to get subprocess output produces difficult to parse output, since
193 # programs think they are talking to a tty and produce highly formatted output
192 # programs think they are talking to a tty and produce highly formatted output
194 # (ls is a good example) that makes them hard.
193 # (ls is a good example) that makes them hard.
195 system = ProcessHandler().system
194 system = ProcessHandler().system
196
195
197
196
198
197
@@ -1,189 +1,188 b''
1 """Windows-specific implementation of process utilities.
1 """Windows-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # stdlib
18 # stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import ctypes
21 import ctypes
22 import msvcrt
22 import msvcrt
23
23
24 from ctypes import c_int, POINTER
24 from ctypes import c_int, POINTER
25 from ctypes.wintypes import LPCWSTR, HLOCAL
25 from ctypes.wintypes import LPCWSTR, HLOCAL
26 from subprocess import STDOUT
26 from subprocess import STDOUT
27
27
28 # our own imports
28 # our own imports
29 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
29 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
30 from . import py3compat
30 from . import py3compat
31 from . import text
32 from .encoding import DEFAULT_ENCODING
31 from .encoding import DEFAULT_ENCODING
33
32
34 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
35 # Function definitions
34 # Function definitions
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37
36
38 class AvoidUNCPath(object):
37 class AvoidUNCPath(object):
39 """A context manager to protect command execution from UNC paths.
38 """A context manager to protect command execution from UNC paths.
40
39
41 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
40 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
42 This context manager temporarily changes directory to the 'C:' drive on
41 This context manager temporarily changes directory to the 'C:' drive on
43 entering, and restores the original working directory on exit.
42 entering, and restores the original working directory on exit.
44
43
45 The context manager returns the starting working directory *if* it made a
44 The context manager returns the starting working directory *if* it made a
46 change and None otherwise, so that users can apply the necessary adjustment
45 change and None otherwise, so that users can apply the necessary adjustment
47 to their system calls in the event of a change.
46 to their system calls in the event of a change.
48
47
49 Example
48 Example
50 -------
49 -------
51 ::
50 ::
52 cmd = 'dir'
51 cmd = 'dir'
53 with AvoidUNCPath() as path:
52 with AvoidUNCPath() as path:
54 if path is not None:
53 if path is not None:
55 cmd = '"pushd %s &&"%s' % (path, cmd)
54 cmd = '"pushd %s &&"%s' % (path, cmd)
56 os.system(cmd)
55 os.system(cmd)
57 """
56 """
58 def __enter__(self):
57 def __enter__(self):
59 self.path = os.getcwdu()
58 self.path = os.getcwdu()
60 self.is_unc_path = self.path.startswith(r"\\")
59 self.is_unc_path = self.path.startswith(r"\\")
61 if self.is_unc_path:
60 if self.is_unc_path:
62 # change to c drive (as cmd.exe cannot handle UNC addresses)
61 # change to c drive (as cmd.exe cannot handle UNC addresses)
63 os.chdir("C:")
62 os.chdir("C:")
64 return self.path
63 return self.path
65 else:
64 else:
66 # We return None to signal that there was no change in the working
65 # We return None to signal that there was no change in the working
67 # directory
66 # directory
68 return None
67 return None
69
68
70 def __exit__(self, exc_type, exc_value, traceback):
69 def __exit__(self, exc_type, exc_value, traceback):
71 if self.is_unc_path:
70 if self.is_unc_path:
72 os.chdir(self.path)
71 os.chdir(self.path)
73
72
74
73
75 def _find_cmd(cmd):
74 def _find_cmd(cmd):
76 """Find the full path to a .bat or .exe using the win32api module."""
75 """Find the full path to a .bat or .exe using the win32api module."""
77 try:
76 try:
78 from win32api import SearchPath
77 from win32api import SearchPath
79 except ImportError:
78 except ImportError:
80 raise ImportError('you need to have pywin32 installed for this to work')
79 raise ImportError('you need to have pywin32 installed for this to work')
81 else:
80 else:
82 PATH = os.environ['PATH']
81 PATH = os.environ['PATH']
83 extensions = ['.exe', '.com', '.bat', '.py']
82 extensions = ['.exe', '.com', '.bat', '.py']
84 path = None
83 path = None
85 for ext in extensions:
84 for ext in extensions:
86 try:
85 try:
87 path = SearchPath(PATH, cmd + ext)[0]
86 path = SearchPath(PATH, cmd + ext)[0]
88 except:
87 except:
89 pass
88 pass
90 if path is None:
89 if path is None:
91 raise OSError("command %r not found" % cmd)
90 raise OSError("command %r not found" % cmd)
92 else:
91 else:
93 return path
92 return path
94
93
95
94
96 def _system_body(p):
95 def _system_body(p):
97 """Callback for _system."""
96 """Callback for _system."""
98 enc = DEFAULT_ENCODING
97 enc = DEFAULT_ENCODING
99 for line in read_no_interrupt(p.stdout).splitlines():
98 for line in read_no_interrupt(p.stdout).splitlines():
100 line = line.decode(enc, 'replace')
99 line = line.decode(enc, 'replace')
101 print(line, file=sys.stdout)
100 print(line, file=sys.stdout)
102 for line in read_no_interrupt(p.stderr).splitlines():
101 for line in read_no_interrupt(p.stderr).splitlines():
103 line = line.decode(enc, 'replace')
102 line = line.decode(enc, 'replace')
104 print(line, file=sys.stderr)
103 print(line, file=sys.stderr)
105
104
106 # Wait to finish for returncode
105 # Wait to finish for returncode
107 return p.wait()
106 return p.wait()
108
107
109
108
110 def system(cmd):
109 def system(cmd):
111 """Win32 version of os.system() that works with network shares.
110 """Win32 version of os.system() that works with network shares.
112
111
113 Note that this implementation returns None, as meant for use in IPython.
112 Note that this implementation returns None, as meant for use in IPython.
114
113
115 Parameters
114 Parameters
116 ----------
115 ----------
117 cmd : str
116 cmd : str
118 A command to be executed in the system shell.
117 A command to be executed in the system shell.
119
118
120 Returns
119 Returns
121 -------
120 -------
122 None : we explicitly do NOT return the subprocess status code, as this
121 None : we explicitly do NOT return the subprocess status code, as this
123 utility is meant to be used extensively in IPython, where any return value
122 utility is meant to be used extensively in IPython, where any return value
124 would trigger :func:`sys.displayhook` calls.
123 would trigger :func:`sys.displayhook` calls.
125 """
124 """
126 # The controller provides interactivity with both
125 # The controller provides interactivity with both
127 # stdin and stdout
126 # stdin and stdout
128 #import _process_win32_controller
127 #import _process_win32_controller
129 #_process_win32_controller.system(cmd)
128 #_process_win32_controller.system(cmd)
130
129
131 with AvoidUNCPath() as path:
130 with AvoidUNCPath() as path:
132 if path is not None:
131 if path is not None:
133 cmd = '"pushd %s &&"%s' % (path, cmd)
132 cmd = '"pushd %s &&"%s' % (path, cmd)
134 return process_handler(cmd, _system_body)
133 return process_handler(cmd, _system_body)
135
134
136 def getoutput(cmd):
135 def getoutput(cmd):
137 """Return standard output of executing cmd in a shell.
136 """Return standard output of executing cmd in a shell.
138
137
139 Accepts the same arguments as os.system().
138 Accepts the same arguments as os.system().
140
139
141 Parameters
140 Parameters
142 ----------
141 ----------
143 cmd : str
142 cmd : str
144 A command to be executed in the system shell.
143 A command to be executed in the system shell.
145
144
146 Returns
145 Returns
147 -------
146 -------
148 stdout : str
147 stdout : str
149 """
148 """
150
149
151 with AvoidUNCPath() as path:
150 with AvoidUNCPath() as path:
152 if path is not None:
151 if path is not None:
153 cmd = '"pushd %s &&"%s' % (path, cmd)
152 cmd = '"pushd %s &&"%s' % (path, cmd)
154 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
153 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
155
154
156 if out is None:
155 if out is None:
157 out = b''
156 out = b''
158 return py3compat.bytes_to_str(out)
157 return py3compat.bytes_to_str(out)
159
158
160 try:
159 try:
161 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
160 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
162 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
161 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
163 CommandLineToArgvW.restype = POINTER(LPCWSTR)
162 CommandLineToArgvW.restype = POINTER(LPCWSTR)
164 LocalFree = ctypes.windll.kernel32.LocalFree
163 LocalFree = ctypes.windll.kernel32.LocalFree
165 LocalFree.res_type = HLOCAL
164 LocalFree.res_type = HLOCAL
166 LocalFree.arg_types = [HLOCAL]
165 LocalFree.arg_types = [HLOCAL]
167
166
168 def arg_split(commandline, posix=False, strict=True):
167 def arg_split(commandline, posix=False, strict=True):
169 """Split a command line's arguments in a shell-like manner.
168 """Split a command line's arguments in a shell-like manner.
170
169
171 This is a special version for windows that use a ctypes call to CommandLineToArgvW
170 This is a special version for windows that use a ctypes call to CommandLineToArgvW
172 to do the argv splitting. The posix paramter is ignored.
171 to do the argv splitting. The posix paramter is ignored.
173
172
174 If strict=False, process_common.arg_split(...strict=False) is used instead.
173 If strict=False, process_common.arg_split(...strict=False) is used instead.
175 """
174 """
176 #CommandLineToArgvW returns path to executable if called with empty string.
175 #CommandLineToArgvW returns path to executable if called with empty string.
177 if commandline.strip() == "":
176 if commandline.strip() == "":
178 return []
177 return []
179 if not strict:
178 if not strict:
180 # not really a cl-arg, fallback on _process_common
179 # not really a cl-arg, fallback on _process_common
181 return py_arg_split(commandline, posix=posix, strict=strict)
180 return py_arg_split(commandline, posix=posix, strict=strict)
182 argvn = c_int()
181 argvn = c_int()
183 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
182 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
184 result_array_type = LPCWSTR * argvn.value
183 result_array_type = LPCWSTR * argvn.value
185 result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))]
184 result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))]
186 retval = LocalFree(result_pointer)
185 retval = LocalFree(result_pointer)
187 return result
186 return result
188 except AttributeError:
187 except AttributeError:
189 arg_split = py_arg_split
188 arg_split = py_arg_split
@@ -1,213 +1,211 b''
1 """Utilities to manipulate JSON objects.
1 """Utilities to manipulate JSON objects.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # stdlib
13 # stdlib
14 import math
14 import math
15 import re
15 import re
16 import sys
17 import types
16 import types
18 from datetime import datetime
17 from datetime import datetime
19
18
20 try:
19 try:
21 # base64.encodestring is deprecated in Python 3.x
20 # base64.encodestring is deprecated in Python 3.x
22 from base64 import encodebytes
21 from base64 import encodebytes
23 except ImportError:
22 except ImportError:
24 # Python 2.x
23 # Python 2.x
25 from base64 import encodestring as encodebytes
24 from base64 import encodestring as encodebytes
26
25
27 from IPython.utils import py3compat
26 from IPython.utils import py3compat
28 from IPython.utils.encoding import DEFAULT_ENCODING
27 from IPython.utils.encoding import DEFAULT_ENCODING
29 from IPython.utils import text
30 next_attr_name = '__next__' if py3compat.PY3 else 'next'
28 next_attr_name = '__next__' if py3compat.PY3 else 'next'
31
29
32 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
33 # Globals and constants
31 # Globals and constants
34 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
35
33
36 # timestamp formats
34 # timestamp formats
37 ISO8601="%Y-%m-%dT%H:%M:%S.%f"
35 ISO8601="%Y-%m-%dT%H:%M:%S.%f"
38 ISO8601_PAT=re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+$")
36 ISO8601_PAT=re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+$")
39
37
40 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
41 # Classes and functions
39 # Classes and functions
42 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
43
41
44 def rekey(dikt):
42 def rekey(dikt):
45 """Rekey a dict that has been forced to use str keys where there should be
43 """Rekey a dict that has been forced to use str keys where there should be
46 ints by json."""
44 ints by json."""
47 for k in dikt.iterkeys():
45 for k in dikt.iterkeys():
48 if isinstance(k, basestring):
46 if isinstance(k, basestring):
49 ik=fk=None
47 ik=fk=None
50 try:
48 try:
51 ik = int(k)
49 ik = int(k)
52 except ValueError:
50 except ValueError:
53 try:
51 try:
54 fk = float(k)
52 fk = float(k)
55 except ValueError:
53 except ValueError:
56 continue
54 continue
57 if ik is not None:
55 if ik is not None:
58 nk = ik
56 nk = ik
59 else:
57 else:
60 nk = fk
58 nk = fk
61 if nk in dikt:
59 if nk in dikt:
62 raise KeyError("already have key %r"%nk)
60 raise KeyError("already have key %r"%nk)
63 dikt[nk] = dikt.pop(k)
61 dikt[nk] = dikt.pop(k)
64 return dikt
62 return dikt
65
63
66
64
67 def extract_dates(obj):
65 def extract_dates(obj):
68 """extract ISO8601 dates from unpacked JSON"""
66 """extract ISO8601 dates from unpacked JSON"""
69 if isinstance(obj, dict):
67 if isinstance(obj, dict):
70 obj = dict(obj) # don't clobber
68 obj = dict(obj) # don't clobber
71 for k,v in obj.iteritems():
69 for k,v in obj.iteritems():
72 obj[k] = extract_dates(v)
70 obj[k] = extract_dates(v)
73 elif isinstance(obj, (list, tuple)):
71 elif isinstance(obj, (list, tuple)):
74 obj = [ extract_dates(o) for o in obj ]
72 obj = [ extract_dates(o) for o in obj ]
75 elif isinstance(obj, basestring):
73 elif isinstance(obj, basestring):
76 if ISO8601_PAT.match(obj):
74 if ISO8601_PAT.match(obj):
77 obj = datetime.strptime(obj, ISO8601)
75 obj = datetime.strptime(obj, ISO8601)
78 return obj
76 return obj
79
77
80 def squash_dates(obj):
78 def squash_dates(obj):
81 """squash datetime objects into ISO8601 strings"""
79 """squash datetime objects into ISO8601 strings"""
82 if isinstance(obj, dict):
80 if isinstance(obj, dict):
83 obj = dict(obj) # don't clobber
81 obj = dict(obj) # don't clobber
84 for k,v in obj.iteritems():
82 for k,v in obj.iteritems():
85 obj[k] = squash_dates(v)
83 obj[k] = squash_dates(v)
86 elif isinstance(obj, (list, tuple)):
84 elif isinstance(obj, (list, tuple)):
87 obj = [ squash_dates(o) for o in obj ]
85 obj = [ squash_dates(o) for o in obj ]
88 elif isinstance(obj, datetime):
86 elif isinstance(obj, datetime):
89 obj = obj.strftime(ISO8601)
87 obj = obj.strftime(ISO8601)
90 return obj
88 return obj
91
89
92 def date_default(obj):
90 def date_default(obj):
93 """default function for packing datetime objects in JSON."""
91 """default function for packing datetime objects in JSON."""
94 if isinstance(obj, datetime):
92 if isinstance(obj, datetime):
95 return obj.strftime(ISO8601)
93 return obj.strftime(ISO8601)
96 else:
94 else:
97 raise TypeError("%r is not JSON serializable"%obj)
95 raise TypeError("%r is not JSON serializable"%obj)
98
96
99
97
100 # constants for identifying png/jpeg data
98 # constants for identifying png/jpeg data
101 PNG = b'\x89PNG\r\n\x1a\n'
99 PNG = b'\x89PNG\r\n\x1a\n'
102 JPEG = b'\xff\xd8'
100 JPEG = b'\xff\xd8'
103
101
104 def encode_images(format_dict):
102 def encode_images(format_dict):
105 """b64-encodes images in a displaypub format dict
103 """b64-encodes images in a displaypub format dict
106
104
107 Perhaps this should be handled in json_clean itself?
105 Perhaps this should be handled in json_clean itself?
108
106
109 Parameters
107 Parameters
110 ----------
108 ----------
111
109
112 format_dict : dict
110 format_dict : dict
113 A dictionary of display data keyed by mime-type
111 A dictionary of display data keyed by mime-type
114
112
115 Returns
113 Returns
116 -------
114 -------
117
115
118 format_dict : dict
116 format_dict : dict
119 A copy of the same dictionary,
117 A copy of the same dictionary,
120 but binary image data ('image/png' or 'image/jpeg')
118 but binary image data ('image/png' or 'image/jpeg')
121 is base64-encoded.
119 is base64-encoded.
122
120
123 """
121 """
124 encoded = format_dict.copy()
122 encoded = format_dict.copy()
125 pngdata = format_dict.get('image/png')
123 pngdata = format_dict.get('image/png')
126 if isinstance(pngdata, bytes) and pngdata[:8] == PNG:
124 if isinstance(pngdata, bytes) and pngdata[:8] == PNG:
127 encoded['image/png'] = encodebytes(pngdata).decode('ascii')
125 encoded['image/png'] = encodebytes(pngdata).decode('ascii')
128 jpegdata = format_dict.get('image/jpeg')
126 jpegdata = format_dict.get('image/jpeg')
129 if isinstance(jpegdata, bytes) and jpegdata[:2] == JPEG:
127 if isinstance(jpegdata, bytes) and jpegdata[:2] == JPEG:
130 encoded['image/jpeg'] = encodebytes(jpegdata).decode('ascii')
128 encoded['image/jpeg'] = encodebytes(jpegdata).decode('ascii')
131 return encoded
129 return encoded
132
130
133
131
134 def json_clean(obj):
132 def json_clean(obj):
135 """Clean an object to ensure it's safe to encode in JSON.
133 """Clean an object to ensure it's safe to encode in JSON.
136
134
137 Atomic, immutable objects are returned unmodified. Sets and tuples are
135 Atomic, immutable objects are returned unmodified. Sets and tuples are
138 converted to lists, lists are copied and dicts are also copied.
136 converted to lists, lists are copied and dicts are also copied.
139
137
140 Note: dicts whose keys could cause collisions upon encoding (such as a dict
138 Note: dicts whose keys could cause collisions upon encoding (such as a dict
141 with both the number 1 and the string '1' as keys) will cause a ValueError
139 with both the number 1 and the string '1' as keys) will cause a ValueError
142 to be raised.
140 to be raised.
143
141
144 Parameters
142 Parameters
145 ----------
143 ----------
146 obj : any python object
144 obj : any python object
147
145
148 Returns
146 Returns
149 -------
147 -------
150 out : object
148 out : object
151
149
152 A version of the input which will not cause an encoding error when
150 A version of the input which will not cause an encoding error when
153 encoded as JSON. Note that this function does not *encode* its inputs,
151 encoded as JSON. Note that this function does not *encode* its inputs,
154 it simply sanitizes it so that there will be no encoding errors later.
152 it simply sanitizes it so that there will be no encoding errors later.
155
153
156 Examples
154 Examples
157 --------
155 --------
158 >>> json_clean(4)
156 >>> json_clean(4)
159 4
157 4
160 >>> json_clean(range(10))
158 >>> json_clean(range(10))
161 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
159 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
162 >>> sorted(json_clean(dict(x=1, y=2)).items())
160 >>> sorted(json_clean(dict(x=1, y=2)).items())
163 [('x', 1), ('y', 2)]
161 [('x', 1), ('y', 2)]
164 >>> sorted(json_clean(dict(x=1, y=2, z=[1,2,3])).items())
162 >>> sorted(json_clean(dict(x=1, y=2, z=[1,2,3])).items())
165 [('x', 1), ('y', 2), ('z', [1, 2, 3])]
163 [('x', 1), ('y', 2), ('z', [1, 2, 3])]
166 >>> json_clean(True)
164 >>> json_clean(True)
167 True
165 True
168 """
166 """
169 # types that are 'atomic' and ok in json as-is. bool doesn't need to be
167 # types that are 'atomic' and ok in json as-is. bool doesn't need to be
170 # listed explicitly because bools pass as int instances
168 # listed explicitly because bools pass as int instances
171 atomic_ok = (unicode, int, types.NoneType)
169 atomic_ok = (unicode, int, types.NoneType)
172
170
173 # containers that we need to convert into lists
171 # containers that we need to convert into lists
174 container_to_list = (tuple, set, types.GeneratorType)
172 container_to_list = (tuple, set, types.GeneratorType)
175
173
176 if isinstance(obj, float):
174 if isinstance(obj, float):
177 # cast out-of-range floats to their reprs
175 # cast out-of-range floats to their reprs
178 if math.isnan(obj) or math.isinf(obj):
176 if math.isnan(obj) or math.isinf(obj):
179 return repr(obj)
177 return repr(obj)
180 return obj
178 return obj
181
179
182 if isinstance(obj, atomic_ok):
180 if isinstance(obj, atomic_ok):
183 return obj
181 return obj
184
182
185 if isinstance(obj, bytes):
183 if isinstance(obj, bytes):
186 return obj.decode(DEFAULT_ENCODING, 'replace')
184 return obj.decode(DEFAULT_ENCODING, 'replace')
187
185
188 if isinstance(obj, container_to_list) or (
186 if isinstance(obj, container_to_list) or (
189 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
187 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
190 obj = list(obj)
188 obj = list(obj)
191
189
192 if isinstance(obj, list):
190 if isinstance(obj, list):
193 return [json_clean(x) for x in obj]
191 return [json_clean(x) for x in obj]
194
192
195 if isinstance(obj, dict):
193 if isinstance(obj, dict):
196 # First, validate that the dict won't lose data in conversion due to
194 # First, validate that the dict won't lose data in conversion due to
197 # key collisions after stringification. This can happen with keys like
195 # key collisions after stringification. This can happen with keys like
198 # True and 'true' or 1 and '1', which collide in JSON.
196 # True and 'true' or 1 and '1', which collide in JSON.
199 nkeys = len(obj)
197 nkeys = len(obj)
200 nkeys_collapsed = len(set(map(str, obj)))
198 nkeys_collapsed = len(set(map(str, obj)))
201 if nkeys != nkeys_collapsed:
199 if nkeys != nkeys_collapsed:
202 raise ValueError('dict can not be safely converted to JSON: '
200 raise ValueError('dict can not be safely converted to JSON: '
203 'key collision would lead to dropped values')
201 'key collision would lead to dropped values')
204 # If all OK, proceed by making the new dict that will be json-safe
202 # If all OK, proceed by making the new dict that will be json-safe
205 out = {}
203 out = {}
206 for k,v in obj.iteritems():
204 for k,v in obj.iteritems():
207 out[str(k)] = json_clean(v)
205 out[str(k)] = json_clean(v)
208 return out
206 return out
209
207
210 # If we get here, we don't know how to handle the object, so we just get
208 # If we get here, we don't know how to handle the object, so we just get
211 # its repr and return that. This will catch lambdas, open sockets, class
209 # its repr and return that. This will catch lambdas, open sockets, class
212 # objects, and any other complicated contraption that json can't encode
210 # objects, and any other complicated contraption that json can't encode
213 return repr(obj)
211 return repr(obj)
@@ -1,325 +1,324 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """Pickle related utilities. Perhaps this should be called 'can'."""
3 """Pickle related utilities. Perhaps this should be called 'can'."""
4
4
5 __docformat__ = "restructuredtext en"
5 __docformat__ = "restructuredtext en"
6
6
7 #-------------------------------------------------------------------------------
7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008-2011 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 import copy
18 import copy
19 import logging
19 import logging
20 import sys
20 import sys
21 from types import FunctionType
21 from types import FunctionType
22
22
23 try:
23 try:
24 import cPickle as pickle
24 import cPickle as pickle
25 except ImportError:
25 except ImportError:
26 import pickle
26 import pickle
27
27
28 try:
28 try:
29 import numpy
29 import numpy
30 except:
30 except:
31 numpy = None
31 numpy = None
32
32
33 import codeutil
34 import py3compat
33 import py3compat
35 from importstring import import_item
34 from importstring import import_item
36
35
37 from IPython.config import Application
36 from IPython.config import Application
38
37
39 if py3compat.PY3:
38 if py3compat.PY3:
40 buffer = memoryview
39 buffer = memoryview
41 class_type = type
40 class_type = type
42 else:
41 else:
43 from types import ClassType
42 from types import ClassType
44 class_type = (type, ClassType)
43 class_type = (type, ClassType)
45
44
46 #-------------------------------------------------------------------------------
45 #-------------------------------------------------------------------------------
47 # Classes
46 # Classes
48 #-------------------------------------------------------------------------------
47 #-------------------------------------------------------------------------------
49
48
50
49
51 class CannedObject(object):
50 class CannedObject(object):
52 def __init__(self, obj, keys=[]):
51 def __init__(self, obj, keys=[]):
53 self.keys = keys
52 self.keys = keys
54 self.obj = copy.copy(obj)
53 self.obj = copy.copy(obj)
55 for key in keys:
54 for key in keys:
56 setattr(self.obj, key, can(getattr(obj, key)))
55 setattr(self.obj, key, can(getattr(obj, key)))
57
56
58 self.buffers = []
57 self.buffers = []
59
58
60 def get_object(self, g=None):
59 def get_object(self, g=None):
61 if g is None:
60 if g is None:
62 g = {}
61 g = {}
63 for key in self.keys:
62 for key in self.keys:
64 setattr(self.obj, key, uncan(getattr(self.obj, key), g))
63 setattr(self.obj, key, uncan(getattr(self.obj, key), g))
65 return self.obj
64 return self.obj
66
65
67
66
68 class Reference(CannedObject):
67 class Reference(CannedObject):
69 """object for wrapping a remote reference by name."""
68 """object for wrapping a remote reference by name."""
70 def __init__(self, name):
69 def __init__(self, name):
71 if not isinstance(name, basestring):
70 if not isinstance(name, basestring):
72 raise TypeError("illegal name: %r"%name)
71 raise TypeError("illegal name: %r"%name)
73 self.name = name
72 self.name = name
74 self.buffers = []
73 self.buffers = []
75
74
76 def __repr__(self):
75 def __repr__(self):
77 return "<Reference: %r>"%self.name
76 return "<Reference: %r>"%self.name
78
77
79 def get_object(self, g=None):
78 def get_object(self, g=None):
80 if g is None:
79 if g is None:
81 g = {}
80 g = {}
82
81
83 return eval(self.name, g)
82 return eval(self.name, g)
84
83
85
84
86 class CannedFunction(CannedObject):
85 class CannedFunction(CannedObject):
87
86
88 def __init__(self, f):
87 def __init__(self, f):
89 self._check_type(f)
88 self._check_type(f)
90 self.code = f.func_code
89 self.code = f.func_code
91 if f.func_defaults:
90 if f.func_defaults:
92 self.defaults = [ can(fd) for fd in f.func_defaults ]
91 self.defaults = [ can(fd) for fd in f.func_defaults ]
93 else:
92 else:
94 self.defaults = None
93 self.defaults = None
95 self.module = f.__module__ or '__main__'
94 self.module = f.__module__ or '__main__'
96 self.__name__ = f.__name__
95 self.__name__ = f.__name__
97 self.buffers = []
96 self.buffers = []
98
97
99 def _check_type(self, obj):
98 def _check_type(self, obj):
100 assert isinstance(obj, FunctionType), "Not a function type"
99 assert isinstance(obj, FunctionType), "Not a function type"
101
100
102 def get_object(self, g=None):
101 def get_object(self, g=None):
103 # try to load function back into its module:
102 # try to load function back into its module:
104 if not self.module.startswith('__'):
103 if not self.module.startswith('__'):
105 __import__(self.module)
104 __import__(self.module)
106 g = sys.modules[self.module].__dict__
105 g = sys.modules[self.module].__dict__
107
106
108 if g is None:
107 if g is None:
109 g = {}
108 g = {}
110 if self.defaults:
109 if self.defaults:
111 defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
110 defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
112 else:
111 else:
113 defaults = None
112 defaults = None
114 newFunc = FunctionType(self.code, g, self.__name__, defaults)
113 newFunc = FunctionType(self.code, g, self.__name__, defaults)
115 return newFunc
114 return newFunc
116
115
117 class CannedClass(CannedObject):
116 class CannedClass(CannedObject):
118
117
119 def __init__(self, cls):
118 def __init__(self, cls):
120 self._check_type(cls)
119 self._check_type(cls)
121 self.name = cls.__name__
120 self.name = cls.__name__
122 self.old_style = not isinstance(cls, type)
121 self.old_style = not isinstance(cls, type)
123 self._canned_dict = {}
122 self._canned_dict = {}
124 for k,v in cls.__dict__.items():
123 for k,v in cls.__dict__.items():
125 if k not in ('__weakref__', '__dict__'):
124 if k not in ('__weakref__', '__dict__'):
126 self._canned_dict[k] = can(v)
125 self._canned_dict[k] = can(v)
127 if self.old_style:
126 if self.old_style:
128 mro = []
127 mro = []
129 else:
128 else:
130 mro = cls.mro()
129 mro = cls.mro()
131
130
132 self.parents = [ can(c) for c in mro[1:] ]
131 self.parents = [ can(c) for c in mro[1:] ]
133 self.buffers = []
132 self.buffers = []
134
133
135 def _check_type(self, obj):
134 def _check_type(self, obj):
136 assert isinstance(obj, class_type), "Not a class type"
135 assert isinstance(obj, class_type), "Not a class type"
137
136
138 def get_object(self, g=None):
137 def get_object(self, g=None):
139 parents = tuple(uncan(p, g) for p in self.parents)
138 parents = tuple(uncan(p, g) for p in self.parents)
140 return type(self.name, parents, uncan_dict(self._canned_dict, g=g))
139 return type(self.name, parents, uncan_dict(self._canned_dict, g=g))
141
140
142 class CannedArray(CannedObject):
141 class CannedArray(CannedObject):
143 def __init__(self, obj):
142 def __init__(self, obj):
144 self.shape = obj.shape
143 self.shape = obj.shape
145 self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
144 self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
146 if sum(obj.shape) == 0:
145 if sum(obj.shape) == 0:
147 # just pickle it
146 # just pickle it
148 self.buffers = [pickle.dumps(obj, -1)]
147 self.buffers = [pickle.dumps(obj, -1)]
149 else:
148 else:
150 # ensure contiguous
149 # ensure contiguous
151 obj = numpy.ascontiguousarray(obj, dtype=None)
150 obj = numpy.ascontiguousarray(obj, dtype=None)
152 self.buffers = [buffer(obj)]
151 self.buffers = [buffer(obj)]
153
152
154 def get_object(self, g=None):
153 def get_object(self, g=None):
155 data = self.buffers[0]
154 data = self.buffers[0]
156 if sum(self.shape) == 0:
155 if sum(self.shape) == 0:
157 # no shape, we just pickled it
156 # no shape, we just pickled it
158 return pickle.loads(data)
157 return pickle.loads(data)
159 else:
158 else:
160 return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)
159 return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)
161
160
162
161
163 class CannedBytes(CannedObject):
162 class CannedBytes(CannedObject):
164 wrap = bytes
163 wrap = bytes
165 def __init__(self, obj):
164 def __init__(self, obj):
166 self.buffers = [obj]
165 self.buffers = [obj]
167
166
168 def get_object(self, g=None):
167 def get_object(self, g=None):
169 data = self.buffers[0]
168 data = self.buffers[0]
170 return self.wrap(data)
169 return self.wrap(data)
171
170
172 def CannedBuffer(CannedBytes):
171 def CannedBuffer(CannedBytes):
173 wrap = buffer
172 wrap = buffer
174
173
175 #-------------------------------------------------------------------------------
174 #-------------------------------------------------------------------------------
176 # Functions
175 # Functions
177 #-------------------------------------------------------------------------------
176 #-------------------------------------------------------------------------------
178
177
179 def _logger():
178 def _logger():
180 """get the logger for the current Application
179 """get the logger for the current Application
181
180
182 the root logger will be used if no Application is running
181 the root logger will be used if no Application is running
183 """
182 """
184 if Application.initialized():
183 if Application.initialized():
185 logger = Application.instance().log
184 logger = Application.instance().log
186 else:
185 else:
187 logger = logging.getLogger()
186 logger = logging.getLogger()
188 if not logger.handlers:
187 if not logger.handlers:
189 logging.basicConfig()
188 logging.basicConfig()
190
189
191 return logger
190 return logger
192
191
193 def _import_mapping(mapping, original=None):
192 def _import_mapping(mapping, original=None):
194 """import any string-keys in a type mapping
193 """import any string-keys in a type mapping
195
194
196 """
195 """
197 log = _logger()
196 log = _logger()
198 log.debug("Importing canning map")
197 log.debug("Importing canning map")
199 for key,value in mapping.items():
198 for key,value in mapping.items():
200 if isinstance(key, basestring):
199 if isinstance(key, basestring):
201 try:
200 try:
202 cls = import_item(key)
201 cls = import_item(key)
203 except Exception:
202 except Exception:
204 if original and key not in original:
203 if original and key not in original:
205 # only message on user-added classes
204 # only message on user-added classes
206 log.error("cannning class not importable: %r", key, exc_info=True)
205 log.error("cannning class not importable: %r", key, exc_info=True)
207 mapping.pop(key)
206 mapping.pop(key)
208 else:
207 else:
209 mapping[cls] = mapping.pop(key)
208 mapping[cls] = mapping.pop(key)
210
209
211 def istype(obj, check):
210 def istype(obj, check):
212 """like isinstance(obj, check), but strict
211 """like isinstance(obj, check), but strict
213
212
214 This won't catch subclasses.
213 This won't catch subclasses.
215 """
214 """
216 if isinstance(check, tuple):
215 if isinstance(check, tuple):
217 for cls in check:
216 for cls in check:
218 if type(obj) is cls:
217 if type(obj) is cls:
219 return True
218 return True
220 return False
219 return False
221 else:
220 else:
222 return type(obj) is check
221 return type(obj) is check
223
222
224 def can(obj):
223 def can(obj):
225 """prepare an object for pickling"""
224 """prepare an object for pickling"""
226
225
227 import_needed = False
226 import_needed = False
228
227
229 for cls,canner in can_map.iteritems():
228 for cls,canner in can_map.iteritems():
230 if isinstance(cls, basestring):
229 if isinstance(cls, basestring):
231 import_needed = True
230 import_needed = True
232 break
231 break
233 elif istype(obj, cls):
232 elif istype(obj, cls):
234 return canner(obj)
233 return canner(obj)
235
234
236 if import_needed:
235 if import_needed:
237 # perform can_map imports, then try again
236 # perform can_map imports, then try again
238 # this will usually only happen once
237 # this will usually only happen once
239 _import_mapping(can_map, _original_can_map)
238 _import_mapping(can_map, _original_can_map)
240 return can(obj)
239 return can(obj)
241
240
242 return obj
241 return obj
243
242
244 def can_class(obj):
243 def can_class(obj):
245 if isinstance(obj, class_type) and obj.__module__ == '__main__':
244 if isinstance(obj, class_type) and obj.__module__ == '__main__':
246 return CannedClass(obj)
245 return CannedClass(obj)
247 else:
246 else:
248 return obj
247 return obj
249
248
250 def can_dict(obj):
249 def can_dict(obj):
251 """can the *values* of a dict"""
250 """can the *values* of a dict"""
252 if isinstance(obj, dict):
251 if isinstance(obj, dict):
253 newobj = {}
252 newobj = {}
254 for k, v in obj.iteritems():
253 for k, v in obj.iteritems():
255 newobj[k] = can(v)
254 newobj[k] = can(v)
256 return newobj
255 return newobj
257 else:
256 else:
258 return obj
257 return obj
259
258
260 def can_sequence(obj):
259 def can_sequence(obj):
261 """can the elements of a sequence"""
260 """can the elements of a sequence"""
262 if isinstance(obj, (list, tuple)):
261 if isinstance(obj, (list, tuple)):
263 t = type(obj)
262 t = type(obj)
264 return t([can(i) for i in obj])
263 return t([can(i) for i in obj])
265 else:
264 else:
266 return obj
265 return obj
267
266
268 def uncan(obj, g=None):
267 def uncan(obj, g=None):
269 """invert canning"""
268 """invert canning"""
270
269
271 import_needed = False
270 import_needed = False
272 for cls,uncanner in uncan_map.iteritems():
271 for cls,uncanner in uncan_map.iteritems():
273 if isinstance(cls, basestring):
272 if isinstance(cls, basestring):
274 import_needed = True
273 import_needed = True
275 break
274 break
276 elif isinstance(obj, cls):
275 elif isinstance(obj, cls):
277 return uncanner(obj, g)
276 return uncanner(obj, g)
278
277
279 if import_needed:
278 if import_needed:
280 # perform uncan_map imports, then try again
279 # perform uncan_map imports, then try again
281 # this will usually only happen once
280 # this will usually only happen once
282 _import_mapping(uncan_map, _original_uncan_map)
281 _import_mapping(uncan_map, _original_uncan_map)
283 return uncan(obj, g)
282 return uncan(obj, g)
284
283
285 return obj
284 return obj
286
285
287 def uncan_dict(obj, g=None):
286 def uncan_dict(obj, g=None):
288 if isinstance(obj, dict):
287 if isinstance(obj, dict):
289 newobj = {}
288 newobj = {}
290 for k, v in obj.iteritems():
289 for k, v in obj.iteritems():
291 newobj[k] = uncan(v,g)
290 newobj[k] = uncan(v,g)
292 return newobj
291 return newobj
293 else:
292 else:
294 return obj
293 return obj
295
294
296 def uncan_sequence(obj, g=None):
295 def uncan_sequence(obj, g=None):
297 if isinstance(obj, (list, tuple)):
296 if isinstance(obj, (list, tuple)):
298 t = type(obj)
297 t = type(obj)
299 return t([uncan(i,g) for i in obj])
298 return t([uncan(i,g) for i in obj])
300 else:
299 else:
301 return obj
300 return obj
302
301
303
302
304 #-------------------------------------------------------------------------------
303 #-------------------------------------------------------------------------------
305 # API dictionaries
304 # API dictionaries
306 #-------------------------------------------------------------------------------
305 #-------------------------------------------------------------------------------
307
306
308 # These dicts can be extended for custom serialization of new objects
307 # These dicts can be extended for custom serialization of new objects
309
308
310 can_map = {
309 can_map = {
311 'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),
310 'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),
312 'numpy.ndarray' : CannedArray,
311 'numpy.ndarray' : CannedArray,
313 FunctionType : CannedFunction,
312 FunctionType : CannedFunction,
314 bytes : CannedBytes,
313 bytes : CannedBytes,
315 buffer : CannedBuffer,
314 buffer : CannedBuffer,
316 class_type : can_class,
315 class_type : can_class,
317 }
316 }
318
317
319 uncan_map = {
318 uncan_map = {
320 CannedObject : lambda obj, g: obj.get_object(g),
319 CannedObject : lambda obj, g: obj.get_object(g),
321 }
320 }
322
321
323 # for use in _import_mapping:
322 # for use in _import_mapping:
324 _original_can_map = can_map.copy()
323 _original_can_map = can_map.copy()
325 _original_uncan_map = uncan_map.copy()
324 _original_uncan_map = uncan_map.copy()
@@ -1,126 +1,125 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with external processes.
3 Utilities for working with external processes.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import shlex
21 import shlex
22
22
23 # Our own
23 # Our own
24 if sys.platform == 'win32':
24 if sys.platform == 'win32':
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath, arg_split
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath, arg_split
26 else:
26 else:
27 from ._process_posix import _find_cmd, system, getoutput, arg_split
27 from ._process_posix import _find_cmd, system, getoutput, arg_split
28
28
29
29
30 from ._process_common import getoutputerror
30 from ._process_common import getoutputerror
31 from IPython.utils import py3compat
32
31
33 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
34 # Code
33 # Code
35 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
36
35
37
36
38 class FindCmdError(Exception):
37 class FindCmdError(Exception):
39 pass
38 pass
40
39
41
40
42 def find_cmd(cmd):
41 def find_cmd(cmd):
43 """Find absolute path to executable cmd in a cross platform manner.
42 """Find absolute path to executable cmd in a cross platform manner.
44
43
45 This function tries to determine the full path to a command line program
44 This function tries to determine the full path to a command line program
46 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
45 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
47 time it will use the version that is first on the users `PATH`. If
46 time it will use the version that is first on the users `PATH`. If
48 cmd is `python` return `sys.executable`.
47 cmd is `python` return `sys.executable`.
49
48
50 Warning, don't use this to find IPython command line programs as there
49 Warning, don't use this to find IPython command line programs as there
51 is a risk you will find the wrong one. Instead find those using the
50 is a risk you will find the wrong one. Instead find those using the
52 following code and looking for the application itself::
51 following code and looking for the application itself::
53
52
54 from IPython.utils.path import get_ipython_module_path
53 from IPython.utils.path import get_ipython_module_path
55 from IPython.utils.process import pycmd2argv
54 from IPython.utils.process import pycmd2argv
56 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
55 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
57
56
58 Parameters
57 Parameters
59 ----------
58 ----------
60 cmd : str
59 cmd : str
61 The command line program to look for.
60 The command line program to look for.
62 """
61 """
63 if cmd == 'python':
62 if cmd == 'python':
64 return os.path.abspath(sys.executable)
63 return os.path.abspath(sys.executable)
65 try:
64 try:
66 path = _find_cmd(cmd).rstrip()
65 path = _find_cmd(cmd).rstrip()
67 except OSError:
66 except OSError:
68 raise FindCmdError('command could not be found: %s' % cmd)
67 raise FindCmdError('command could not be found: %s' % cmd)
69 # which returns empty if not found
68 # which returns empty if not found
70 if path == '':
69 if path == '':
71 raise FindCmdError('command could not be found: %s' % cmd)
70 raise FindCmdError('command could not be found: %s' % cmd)
72 return os.path.abspath(path)
71 return os.path.abspath(path)
73
72
74
73
75 def is_cmd_found(cmd):
74 def is_cmd_found(cmd):
76 """Check whether executable `cmd` exists or not and return a bool."""
75 """Check whether executable `cmd` exists or not and return a bool."""
77 try:
76 try:
78 find_cmd(cmd)
77 find_cmd(cmd)
79 return True
78 return True
80 except FindCmdError:
79 except FindCmdError:
81 return False
80 return False
82
81
83
82
84 def pycmd2argv(cmd):
83 def pycmd2argv(cmd):
85 r"""Take the path of a python command and return a list (argv-style).
84 r"""Take the path of a python command and return a list (argv-style).
86
85
87 This only works on Python based command line programs and will find the
86 This only works on Python based command line programs and will find the
88 location of the ``python`` executable using ``sys.executable`` to make
87 location of the ``python`` executable using ``sys.executable`` to make
89 sure the right version is used.
88 sure the right version is used.
90
89
91 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
90 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
92 .com or .bat, and [, cmd] otherwise.
91 .com or .bat, and [, cmd] otherwise.
93
92
94 Parameters
93 Parameters
95 ----------
94 ----------
96 cmd : string
95 cmd : string
97 The path of the command.
96 The path of the command.
98
97
99 Returns
98 Returns
100 -------
99 -------
101 argv-style list.
100 argv-style list.
102 """
101 """
103 ext = os.path.splitext(cmd)[1]
102 ext = os.path.splitext(cmd)[1]
104 if ext in ['.exe', '.com', '.bat']:
103 if ext in ['.exe', '.com', '.bat']:
105 return [cmd]
104 return [cmd]
106 else:
105 else:
107 return [sys.executable, cmd]
106 return [sys.executable, cmd]
108
107
109
108
110 def abbrev_cwd():
109 def abbrev_cwd():
111 """ Return abbreviated version of cwd, e.g. d:mydir """
110 """ Return abbreviated version of cwd, e.g. d:mydir """
112 cwd = os.getcwdu().replace('\\','/')
111 cwd = os.getcwdu().replace('\\','/')
113 drivepart = ''
112 drivepart = ''
114 tail = cwd
113 tail = cwd
115 if sys.platform == 'win32':
114 if sys.platform == 'win32':
116 if len(cwd) < 4:
115 if len(cwd) < 4:
117 return cwd
116 return cwd
118 drivepart,tail = os.path.splitdrive(cwd)
117 drivepart,tail = os.path.splitdrive(cwd)
119
118
120
119
121 parts = tail.split('/')
120 parts = tail.split('/')
122 if len(parts) > 2:
121 if len(parts) > 2:
123 tail = '/'.join(parts[-2:])
122 tail = '/'.join(parts[-2:])
124
123
125 return (drivepart + (
124 return (drivepart + (
126 cwd == '/' and '/' or tail))
125 cwd == '/' and '/' or tail))
@@ -1,124 +1,119 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """ Imports and provides the 'correct' version of readline for the platform.
2 """ Imports and provides the 'correct' version of readline for the platform.
3
3
4 Readline is used throughout IPython as::
4 Readline is used throughout IPython as::
5
5
6 import IPython.utils.rlineimpl as readline
6 import IPython.utils.rlineimpl as readline
7
7
8 In addition to normal readline stuff, this module provides have_readline
8 In addition to normal readline stuff, this module provides have_readline
9 boolean and _outputfile variable used in IPython.utils.
9 boolean and _outputfile variable used in IPython.utils.
10 """
10 """
11
11
12 import os
13 import re
14 import sys
12 import sys
15 import time
16 import warnings
13 import warnings
17
14
18 from subprocess import Popen, PIPE
19
20 if sys.platform == 'darwin':
15 if sys.platform == 'darwin':
21 # dirty trick, to skip the system readline, because pip-installed readline
16 # dirty trick, to skip the system readline, because pip-installed readline
22 # will never be found on OSX, since lib-dynload always comes ahead of site-packages
17 # will never be found on OSX, since lib-dynload always comes ahead of site-packages
23 from distutils import sysconfig
18 from distutils import sysconfig
24 lib_dynload = sysconfig.get_config_var('DESTSHARED')
19 lib_dynload = sysconfig.get_config_var('DESTSHARED')
25 del sysconfig
20 del sysconfig
26 try:
21 try:
27 dynload_idx = sys.path.index(lib_dynload)
22 dynload_idx = sys.path.index(lib_dynload)
28 except ValueError:
23 except ValueError:
29 dynload_idx = None
24 dynload_idx = None
30 else:
25 else:
31 sys.path.pop(dynload_idx)
26 sys.path.pop(dynload_idx)
32 try:
27 try:
33 from readline import *
28 from readline import *
34 import readline as _rl
29 import readline as _rl
35 have_readline = True
30 have_readline = True
36 except ImportError:
31 except ImportError:
37 try:
32 try:
38 from pyreadline import *
33 from pyreadline import *
39 import pyreadline as _rl
34 import pyreadline as _rl
40 have_readline = True
35 have_readline = True
41 except ImportError:
36 except ImportError:
42 have_readline = False
37 have_readline = False
43
38
44 if sys.platform == 'darwin':
39 if sys.platform == 'darwin':
45 # dirty trick, part II:
40 # dirty trick, part II:
46 if dynload_idx is not None:
41 if dynload_idx is not None:
47 # restore path
42 # restore path
48 sys.path.insert(dynload_idx, lib_dynload)
43 sys.path.insert(dynload_idx, lib_dynload)
49 if not have_readline:
44 if not have_readline:
50 # *only* have system readline, try import again
45 # *only* have system readline, try import again
51 try:
46 try:
52 from readline import *
47 from readline import *
53 import readline as _rl
48 import readline as _rl
54 have_readline = True
49 have_readline = True
55 except ImportError:
50 except ImportError:
56 have_readline = False
51 have_readline = False
57 else:
52 else:
58 # if we want to warn about EPD / Fink having bad readline
53 # if we want to warn about EPD / Fink having bad readline
59 # we would do it here
54 # we would do it here
60 pass
55 pass
61 # cleanup dirty trick vars
56 # cleanup dirty trick vars
62 del dynload_idx, lib_dynload
57 del dynload_idx, lib_dynload
63
58
64 if have_readline and hasattr(_rl, 'rlmain'):
59 if have_readline and hasattr(_rl, 'rlmain'):
65 # patch add_history to allow for strings in pyreadline <= 1.5:
60 # patch add_history to allow for strings in pyreadline <= 1.5:
66 # fix copied from pyreadline 1.6
61 # fix copied from pyreadline 1.6
67 import pyreadline
62 import pyreadline
68 if pyreadline.release.version <= '1.5':
63 if pyreadline.release.version <= '1.5':
69 def add_history(line):
64 def add_history(line):
70 """add a line to the history buffer."""
65 """add a line to the history buffer."""
71 from pyreadline import lineobj
66 from pyreadline import lineobj
72 if not isinstance(line, lineobj.TextLine):
67 if not isinstance(line, lineobj.TextLine):
73 line = lineobj.TextLine(line)
68 line = lineobj.TextLine(line)
74 return _rl.add_history(line)
69 return _rl.add_history(line)
75
70
76 if (sys.platform == 'win32' or sys.platform == 'cli') and have_readline:
71 if (sys.platform == 'win32' or sys.platform == 'cli') and have_readline:
77 try:
72 try:
78 _outputfile=_rl.GetOutputFile()
73 _outputfile=_rl.GetOutputFile()
79 except AttributeError:
74 except AttributeError:
80 warnings.warn("Failed GetOutputFile")
75 warnings.warn("Failed GetOutputFile")
81 have_readline = False
76 have_readline = False
82
77
83 # Test to see if libedit is being used instead of GNU readline.
78 # Test to see if libedit is being used instead of GNU readline.
84 # Thanks to Boyd Waters for the original patch.
79 # Thanks to Boyd Waters for the original patch.
85 uses_libedit = False
80 uses_libedit = False
86
81
87 if have_readline:
82 if have_readline:
88 # Official Python docs state that 'libedit' is in the docstring for libedit readline:
83 # Official Python docs state that 'libedit' is in the docstring for libedit readline:
89 uses_libedit = _rl.__doc__ and 'libedit' in _rl.__doc__
84 uses_libedit = _rl.__doc__ and 'libedit' in _rl.__doc__
90 # Note that many non-System Pythons also do not use proper readline,
85 # Note that many non-System Pythons also do not use proper readline,
91 # but do not report libedit at all, nor are they linked dynamically against libedit.
86 # but do not report libedit at all, nor are they linked dynamically against libedit.
92 # known culprits of this include: EPD, Fink
87 # known culprits of this include: EPD, Fink
93 # There is not much we can do to detect this, until we find a specific failure
88 # There is not much we can do to detect this, until we find a specific failure
94 # case, rather than relying on the readline module to self-identify as broken.
89 # case, rather than relying on the readline module to self-identify as broken.
95
90
96 if uses_libedit and sys.platform == 'darwin':
91 if uses_libedit and sys.platform == 'darwin':
97 _rl.parse_and_bind("bind ^I rl_complete")
92 _rl.parse_and_bind("bind ^I rl_complete")
98 warnings.warn('\n'.join(['', "*"*78,
93 warnings.warn('\n'.join(['', "*"*78,
99 "libedit detected - readline will not be well behaved, including but not limited to:",
94 "libedit detected - readline will not be well behaved, including but not limited to:",
100 " * crashes on tab completion",
95 " * crashes on tab completion",
101 " * incorrect history navigation",
96 " * incorrect history navigation",
102 " * corrupting long-lines",
97 " * corrupting long-lines",
103 " * failure to wrap or indent lines properly",
98 " * failure to wrap or indent lines properly",
104 "It is highly recommended that you install readline, which is easy_installable:",
99 "It is highly recommended that you install readline, which is easy_installable:",
105 " easy_install readline",
100 " easy_install readline",
106 "Note that `pip install readline` generally DOES NOT WORK, because",
101 "Note that `pip install readline` generally DOES NOT WORK, because",
107 "it installs to site-packages, which come *after* lib-dynload in sys.path,",
102 "it installs to site-packages, which come *after* lib-dynload in sys.path,",
108 "where readline is located. It must be `easy_install readline`, or to a custom",
103 "where readline is located. It must be `easy_install readline`, or to a custom",
109 "location on your PYTHONPATH (even --user comes after lib-dyload).",
104 "location on your PYTHONPATH (even --user comes after lib-dyload).",
110 "*"*78]),
105 "*"*78]),
111 RuntimeWarning)
106 RuntimeWarning)
112
107
113 # the clear_history() function was only introduced in Python 2.4 and is
108 # the clear_history() function was only introduced in Python 2.4 and is
114 # actually optional in the readline API, so we must explicitly check for its
109 # actually optional in the readline API, so we must explicitly check for its
115 # existence. Some known platforms actually don't have it. This thread:
110 # existence. Some known platforms actually don't have it. This thread:
116 # http://mail.python.org/pipermail/python-dev/2003-August/037845.html
111 # http://mail.python.org/pipermail/python-dev/2003-August/037845.html
117 # has the original discussion.
112 # has the original discussion.
118
113
119 if have_readline:
114 if have_readline:
120 try:
115 try:
121 _rl.clear_history
116 _rl.clear_history
122 except AttributeError:
117 except AttributeError:
123 def clear_history(): pass
118 def clear_history(): pass
124 _rl.clear_history = clear_history
119 _rl.clear_history = clear_history
@@ -1,168 +1,166 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for getting information about IPython and the system it's running in.
3 Utilities for getting information about IPython and the system it's running in.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import platform
18 import platform
19 import pprint
19 import pprint
20 import sys
20 import sys
21 import subprocess
21 import subprocess
22
22
23 from ConfigParser import ConfigParser
24
25 from IPython.core import release
23 from IPython.core import release
26 from IPython.utils import py3compat, _sysinfo, encoding
24 from IPython.utils import py3compat, _sysinfo, encoding
27
25
28 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
29 # Code
27 # Code
30 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
31
29
32 def pkg_commit_hash(pkg_path):
30 def pkg_commit_hash(pkg_path):
33 """Get short form of commit hash given directory `pkg_path`
31 """Get short form of commit hash given directory `pkg_path`
34
32
35 We get the commit hash from (in order of preference):
33 We get the commit hash from (in order of preference):
36
34
37 * IPython.utils._sysinfo.commit
35 * IPython.utils._sysinfo.commit
38 * git output, if we are in a git repository
36 * git output, if we are in a git repository
39
37
40 If these fail, we return a not-found placeholder tuple
38 If these fail, we return a not-found placeholder tuple
41
39
42 Parameters
40 Parameters
43 ----------
41 ----------
44 pkg_path : str
42 pkg_path : str
45 directory containing package
43 directory containing package
46 only used for getting commit from active repo
44 only used for getting commit from active repo
47
45
48 Returns
46 Returns
49 -------
47 -------
50 hash_from : str
48 hash_from : str
51 Where we got the hash from - description
49 Where we got the hash from - description
52 hash_str : str
50 hash_str : str
53 short form of hash
51 short form of hash
54 """
52 """
55 # Try and get commit from written commit text file
53 # Try and get commit from written commit text file
56 if _sysinfo.commit:
54 if _sysinfo.commit:
57 return "installation", _sysinfo.commit
55 return "installation", _sysinfo.commit
58
56
59 # maybe we are in a repository
57 # maybe we are in a repository
60 proc = subprocess.Popen('git rev-parse --short HEAD',
58 proc = subprocess.Popen('git rev-parse --short HEAD',
61 stdout=subprocess.PIPE,
59 stdout=subprocess.PIPE,
62 stderr=subprocess.PIPE,
60 stderr=subprocess.PIPE,
63 cwd=pkg_path, shell=True)
61 cwd=pkg_path, shell=True)
64 repo_commit, _ = proc.communicate()
62 repo_commit, _ = proc.communicate()
65 if repo_commit:
63 if repo_commit:
66 return 'repository', repo_commit.strip()
64 return 'repository', repo_commit.strip()
67 return '(none found)', '<not found>'
65 return '(none found)', '<not found>'
68
66
69
67
70 def pkg_info(pkg_path):
68 def pkg_info(pkg_path):
71 """Return dict describing the context of this package
69 """Return dict describing the context of this package
72
70
73 Parameters
71 Parameters
74 ----------
72 ----------
75 pkg_path : str
73 pkg_path : str
76 path containing __init__.py for package
74 path containing __init__.py for package
77
75
78 Returns
76 Returns
79 -------
77 -------
80 context : dict
78 context : dict
81 with named parameters of interest
79 with named parameters of interest
82 """
80 """
83 src, hsh = pkg_commit_hash(pkg_path)
81 src, hsh = pkg_commit_hash(pkg_path)
84 return dict(
82 return dict(
85 ipython_version=release.version,
83 ipython_version=release.version,
86 ipython_path=pkg_path,
84 ipython_path=pkg_path,
87 commit_source=src,
85 commit_source=src,
88 commit_hash=hsh,
86 commit_hash=hsh,
89 sys_version=sys.version,
87 sys_version=sys.version,
90 sys_executable=sys.executable,
88 sys_executable=sys.executable,
91 sys_platform=sys.platform,
89 sys_platform=sys.platform,
92 platform=platform.platform(),
90 platform=platform.platform(),
93 os_name=os.name,
91 os_name=os.name,
94 default_encoding=encoding.DEFAULT_ENCODING,
92 default_encoding=encoding.DEFAULT_ENCODING,
95 )
93 )
96
94
97
95
98 @py3compat.doctest_refactor_print
96 @py3compat.doctest_refactor_print
99 def sys_info():
97 def sys_info():
100 """Return useful information about IPython and the system, as a string.
98 """Return useful information about IPython and the system, as a string.
101
99
102 Example
100 Example
103 -------
101 -------
104 In [2]: print sys_info()
102 In [2]: print sys_info()
105 {'commit_hash': '144fdae', # random
103 {'commit_hash': '144fdae', # random
106 'commit_source': 'repository',
104 'commit_source': 'repository',
107 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
105 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
108 'ipython_version': '0.11.dev',
106 'ipython_version': '0.11.dev',
109 'os_name': 'posix',
107 'os_name': 'posix',
110 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
108 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
111 'sys_executable': '/usr/bin/python',
109 'sys_executable': '/usr/bin/python',
112 'sys_platform': 'linux2',
110 'sys_platform': 'linux2',
113 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
111 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
114 """
112 """
115 p = os.path
113 p = os.path
116 path = p.dirname(p.abspath(p.join(__file__, '..')))
114 path = p.dirname(p.abspath(p.join(__file__, '..')))
117 return pprint.pformat(pkg_info(path))
115 return pprint.pformat(pkg_info(path))
118
116
119
117
120 def _num_cpus_unix():
118 def _num_cpus_unix():
121 """Return the number of active CPUs on a Unix system."""
119 """Return the number of active CPUs on a Unix system."""
122 return os.sysconf("SC_NPROCESSORS_ONLN")
120 return os.sysconf("SC_NPROCESSORS_ONLN")
123
121
124
122
125 def _num_cpus_darwin():
123 def _num_cpus_darwin():
126 """Return the number of active CPUs on a Darwin system."""
124 """Return the number of active CPUs on a Darwin system."""
127 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
125 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
128 return p.stdout.read()
126 return p.stdout.read()
129
127
130
128
131 def _num_cpus_windows():
129 def _num_cpus_windows():
132 """Return the number of active CPUs on a Windows system."""
130 """Return the number of active CPUs on a Windows system."""
133 return os.environ.get("NUMBER_OF_PROCESSORS")
131 return os.environ.get("NUMBER_OF_PROCESSORS")
134
132
135
133
136 def num_cpus():
134 def num_cpus():
137 """Return the effective number of CPUs in the system as an integer.
135 """Return the effective number of CPUs in the system as an integer.
138
136
139 This cross-platform function makes an attempt at finding the total number of
137 This cross-platform function makes an attempt at finding the total number of
140 available CPUs in the system, as returned by various underlying system and
138 available CPUs in the system, as returned by various underlying system and
141 python calls.
139 python calls.
142
140
143 If it can't find a sensible answer, it returns 1 (though an error *may* make
141 If it can't find a sensible answer, it returns 1 (though an error *may* make
144 it return a large positive number that's actually incorrect).
142 it return a large positive number that's actually incorrect).
145 """
143 """
146
144
147 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
145 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
148 # for the names of the keys we needed to look up for this function. This
146 # for the names of the keys we needed to look up for this function. This
149 # code was inspired by their equivalent function.
147 # code was inspired by their equivalent function.
150
148
151 ncpufuncs = {'Linux':_num_cpus_unix,
149 ncpufuncs = {'Linux':_num_cpus_unix,
152 'Darwin':_num_cpus_darwin,
150 'Darwin':_num_cpus_darwin,
153 'Windows':_num_cpus_windows,
151 'Windows':_num_cpus_windows,
154 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
152 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
155 # See http://bugs.python.org/issue1082 for details.
153 # See http://bugs.python.org/issue1082 for details.
156 'Microsoft':_num_cpus_windows,
154 'Microsoft':_num_cpus_windows,
157 }
155 }
158
156
159 ncpufunc = ncpufuncs.get(platform.system(),
157 ncpufunc = ncpufuncs.get(platform.system(),
160 # default to unix version (Solaris, AIX, etc)
158 # default to unix version (Solaris, AIX, etc)
161 _num_cpus_unix)
159 _num_cpus_unix)
162
160
163 try:
161 try:
164 ncpus = max(1,int(ncpufunc()))
162 ncpus = max(1,int(ncpufunc()))
165 except:
163 except:
166 ncpus = 1
164 ncpus = 1
167 return ncpus
165 return ncpus
168
166
General Comments 0
You need to be logged in to leave comments. Login now