##// END OF EJS Templates
Convert print statements to print function calls...
Thomas Kluyver -
Show More

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

@@ -1,580 +1,581 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A base class for a configurable application.
3 A base class for a configurable application.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Min RK
8 * Min RK
9 """
9 """
10 from __future__ import print_function
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
13 #
14 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17
18
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 # Imports
20 # Imports
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21
22
22 import logging
23 import logging
23 import os
24 import os
24 import re
25 import re
25 import sys
26 import sys
26 from copy import deepcopy
27 from copy import deepcopy
27 from collections import defaultdict
28 from collections import defaultdict
28
29
29 from IPython.external.decorator import decorator
30 from IPython.external.decorator import decorator
30
31
31 from IPython.config.configurable import SingletonConfigurable
32 from IPython.config.configurable import SingletonConfigurable
32 from IPython.config.loader import (
33 from IPython.config.loader import (
33 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound,
34 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound,
34 )
35 )
35
36
36 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
37 Unicode, List, Enum, Dict, Instance, TraitError
38 Unicode, List, Enum, Dict, Instance, TraitError
38 )
39 )
39 from IPython.utils.importstring import import_item
40 from IPython.utils.importstring import import_item
40 from IPython.utils.text import indent, wrap_paragraphs, dedent
41 from IPython.utils.text import indent, wrap_paragraphs, dedent
41 from IPython.utils import py3compat
42 from IPython.utils import py3compat
42
43
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44 # function for re-wrapping a helpstring
45 # function for re-wrapping a helpstring
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46
47
47 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
48 # Descriptions for the various sections
49 # Descriptions for the various sections
49 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
50
51
51 # merge flags&aliases into options
52 # merge flags&aliases into options
52 option_description = """
53 option_description = """
53 Arguments that take values are actually convenience aliases to full
54 Arguments that take values are actually convenience aliases to full
54 Configurables, whose aliases are listed on the help line. For more information
55 Configurables, whose aliases are listed on the help line. For more information
55 on full configurables, see '--help-all'.
56 on full configurables, see '--help-all'.
56 """.strip() # trim newlines of front and back
57 """.strip() # trim newlines of front and back
57
58
58 keyvalue_description = """
59 keyvalue_description = """
59 Parameters are set from command-line arguments of the form:
60 Parameters are set from command-line arguments of the form:
60 `--Class.trait=value`.
61 `--Class.trait=value`.
61 This line is evaluated in Python, so simple expressions are allowed, e.g.::
62 This line is evaluated in Python, so simple expressions are allowed, e.g.::
62 `--C.a='range(3)'` For setting C.a=[0,1,2].
63 `--C.a='range(3)'` For setting C.a=[0,1,2].
63 """.strip() # trim newlines of front and back
64 """.strip() # trim newlines of front and back
64
65
65 # sys.argv can be missing, for example when python is embedded. See the docs
66 # sys.argv can be missing, for example when python is embedded. See the docs
66 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
67 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
67 if not hasattr(sys, "argv"):
68 if not hasattr(sys, "argv"):
68 sys.argv = [""]
69 sys.argv = [""]
69
70
70 subcommand_description = """
71 subcommand_description = """
71 Subcommands are launched as `{app} cmd [args]`. For information on using
72 Subcommands are launched as `{app} cmd [args]`. For information on using
72 subcommand 'cmd', do: `{app} cmd -h`.
73 subcommand 'cmd', do: `{app} cmd -h`.
73 """.strip().format(app=os.path.basename(sys.argv[0]))
74 """.strip().format(app=os.path.basename(sys.argv[0]))
74 # get running program name
75 # get running program name
75
76
76 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
77 # Application class
78 # Application class
78 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
79
80
80 @decorator
81 @decorator
81 def catch_config_error(method, app, *args, **kwargs):
82 def catch_config_error(method, app, *args, **kwargs):
82 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
83 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
83
84
84 On a TraitError (generally caused by bad config), this will print the trait's
85 On a TraitError (generally caused by bad config), this will print the trait's
85 message, and exit the app.
86 message, and exit the app.
86
87
87 For use on init methods, to prevent invoking excepthook on invalid input.
88 For use on init methods, to prevent invoking excepthook on invalid input.
88 """
89 """
89 try:
90 try:
90 return method(app, *args, **kwargs)
91 return method(app, *args, **kwargs)
91 except (TraitError, ArgumentError) as e:
92 except (TraitError, ArgumentError) as e:
92 app.print_help()
93 app.print_help()
93 app.log.fatal("Bad config encountered during initialization:")
94 app.log.fatal("Bad config encountered during initialization:")
94 app.log.fatal(str(e))
95 app.log.fatal(str(e))
95 app.log.debug("Config at the time: %s", app.config)
96 app.log.debug("Config at the time: %s", app.config)
96 app.exit(1)
97 app.exit(1)
97
98
98
99
99 class ApplicationError(Exception):
100 class ApplicationError(Exception):
100 pass
101 pass
101
102
102 class LevelFormatter(logging.Formatter):
103 class LevelFormatter(logging.Formatter):
103 """Formatter with additional `highlevel` record
104 """Formatter with additional `highlevel` record
104
105
105 This field is empty if log level is less than highlevel_limit,
106 This field is empty if log level is less than highlevel_limit,
106 otherwise it is formatted with self.highlevel_format.
107 otherwise it is formatted with self.highlevel_format.
107
108
108 Useful for adding 'WARNING' to warning messages,
109 Useful for adding 'WARNING' to warning messages,
109 without adding 'INFO' to info, etc.
110 without adding 'INFO' to info, etc.
110 """
111 """
111 highlevel_limit = logging.WARN
112 highlevel_limit = logging.WARN
112 highlevel_format = " %(levelname)s |"
113 highlevel_format = " %(levelname)s |"
113
114
114 def format(self, record):
115 def format(self, record):
115 if record.levelno >= self.highlevel_limit:
116 if record.levelno >= self.highlevel_limit:
116 record.highlevel = self.highlevel_format % record.__dict__
117 record.highlevel = self.highlevel_format % record.__dict__
117 else:
118 else:
118 record.highlevel = ""
119 record.highlevel = ""
119 return super(LevelFormatter, self).format(record)
120 return super(LevelFormatter, self).format(record)
120
121
121
122
122 class Application(SingletonConfigurable):
123 class Application(SingletonConfigurable):
123 """A singleton application with full configuration support."""
124 """A singleton application with full configuration support."""
124
125
125 # The name of the application, will usually match the name of the command
126 # The name of the application, will usually match the name of the command
126 # line application
127 # line application
127 name = Unicode(u'application')
128 name = Unicode(u'application')
128
129
129 # The description of the application that is printed at the beginning
130 # The description of the application that is printed at the beginning
130 # of the help.
131 # of the help.
131 description = Unicode(u'This is an application.')
132 description = Unicode(u'This is an application.')
132 # default section descriptions
133 # default section descriptions
133 option_description = Unicode(option_description)
134 option_description = Unicode(option_description)
134 keyvalue_description = Unicode(keyvalue_description)
135 keyvalue_description = Unicode(keyvalue_description)
135 subcommand_description = Unicode(subcommand_description)
136 subcommand_description = Unicode(subcommand_description)
136
137
137 # The usage and example string that goes at the end of the help string.
138 # The usage and example string that goes at the end of the help string.
138 examples = Unicode()
139 examples = Unicode()
139
140
140 # A sequence of Configurable subclasses whose config=True attributes will
141 # A sequence of Configurable subclasses whose config=True attributes will
141 # be exposed at the command line.
142 # be exposed at the command line.
142 classes = List([])
143 classes = List([])
143
144
144 # The version string of this application.
145 # The version string of this application.
145 version = Unicode(u'0.0')
146 version = Unicode(u'0.0')
146
147
147 # the argv used to initialize the application
148 # the argv used to initialize the application
148 argv = List()
149 argv = List()
149
150
150 # The log level for the application
151 # The log level for the application
151 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
152 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
152 default_value=logging.WARN,
153 default_value=logging.WARN,
153 config=True,
154 config=True,
154 help="Set the log level by value or name.")
155 help="Set the log level by value or name.")
155 def _log_level_changed(self, name, old, new):
156 def _log_level_changed(self, name, old, new):
156 """Adjust the log level when log_level is set."""
157 """Adjust the log level when log_level is set."""
157 if isinstance(new, basestring):
158 if isinstance(new, basestring):
158 new = getattr(logging, new)
159 new = getattr(logging, new)
159 self.log_level = new
160 self.log_level = new
160 self.log.setLevel(new)
161 self.log.setLevel(new)
161
162
162 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
163 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
163 help="The date format used by logging formatters for %(asctime)s"
164 help="The date format used by logging formatters for %(asctime)s"
164 )
165 )
165 def _log_datefmt_changed(self, name, old, new):
166 def _log_datefmt_changed(self, name, old, new):
166 self._log_format_changed()
167 self._log_format_changed()
167
168
168 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
169 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
169 help="The Logging format template",
170 help="The Logging format template",
170 )
171 )
171 def _log_format_changed(self, name, old, new):
172 def _log_format_changed(self, name, old, new):
172 """Change the log formatter when log_format is set."""
173 """Change the log formatter when log_format is set."""
173 _log_handler = self.log.handlers[0]
174 _log_handler = self.log.handlers[0]
174 _log_formatter = LevelFormatter(new, datefmt=self.log_datefmt)
175 _log_formatter = LevelFormatter(new, datefmt=self.log_datefmt)
175 _log_handler.setFormatter(_log_formatter)
176 _log_handler.setFormatter(_log_formatter)
176
177
177 log = Instance(logging.Logger)
178 log = Instance(logging.Logger)
178 def _log_default(self):
179 def _log_default(self):
179 """Start logging for this application.
180 """Start logging for this application.
180
181
181 The default is to log to stderr using a StreamHandler, if no default
182 The default is to log to stderr using a StreamHandler, if no default
182 handler already exists. The log level starts at logging.WARN, but this
183 handler already exists. The log level starts at logging.WARN, but this
183 can be adjusted by setting the ``log_level`` attribute.
184 can be adjusted by setting the ``log_level`` attribute.
184 """
185 """
185 log = logging.getLogger(self.__class__.__name__)
186 log = logging.getLogger(self.__class__.__name__)
186 log.setLevel(self.log_level)
187 log.setLevel(self.log_level)
187 log.propagate = False
188 log.propagate = False
188 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
189 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
189 while _log:
190 while _log:
190 if _log.handlers:
191 if _log.handlers:
191 return log
192 return log
192 if not _log.propagate:
193 if not _log.propagate:
193 break
194 break
194 else:
195 else:
195 _log = _log.parent
196 _log = _log.parent
196 if sys.executable.endswith('pythonw.exe'):
197 if sys.executable.endswith('pythonw.exe'):
197 # this should really go to a file, but file-logging is only
198 # this should really go to a file, but file-logging is only
198 # hooked up in parallel applications
199 # hooked up in parallel applications
199 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
200 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
200 else:
201 else:
201 _log_handler = logging.StreamHandler()
202 _log_handler = logging.StreamHandler()
202 _log_formatter = LevelFormatter(self.log_format, datefmt=self.log_datefmt)
203 _log_formatter = LevelFormatter(self.log_format, datefmt=self.log_datefmt)
203 _log_handler.setFormatter(_log_formatter)
204 _log_handler.setFormatter(_log_formatter)
204 log.addHandler(_log_handler)
205 log.addHandler(_log_handler)
205 return log
206 return log
206
207
207 # the alias map for configurables
208 # the alias map for configurables
208 aliases = Dict({'log-level' : 'Application.log_level'})
209 aliases = Dict({'log-level' : 'Application.log_level'})
209
210
210 # flags for loading Configurables or store_const style flags
211 # flags for loading Configurables or store_const style flags
211 # flags are loaded from this dict by '--key' flags
212 # flags are loaded from this dict by '--key' flags
212 # this must be a dict of two-tuples, the first element being the Config/dict
213 # this must be a dict of two-tuples, the first element being the Config/dict
213 # and the second being the help string for the flag
214 # and the second being the help string for the flag
214 flags = Dict()
215 flags = Dict()
215 def _flags_changed(self, name, old, new):
216 def _flags_changed(self, name, old, new):
216 """ensure flags dict is valid"""
217 """ensure flags dict is valid"""
217 for key,value in new.iteritems():
218 for key,value in new.iteritems():
218 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
219 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
219 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
220 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
220 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
221 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
221
222
222
223
223 # subcommands for launching other applications
224 # subcommands for launching other applications
224 # if this is not empty, this will be a parent Application
225 # if this is not empty, this will be a parent Application
225 # this must be a dict of two-tuples,
226 # this must be a dict of two-tuples,
226 # the first element being the application class/import string
227 # the first element being the application class/import string
227 # and the second being the help string for the subcommand
228 # and the second being the help string for the subcommand
228 subcommands = Dict()
229 subcommands = Dict()
229 # parse_command_line will initialize a subapp, if requested
230 # parse_command_line will initialize a subapp, if requested
230 subapp = Instance('IPython.config.application.Application', allow_none=True)
231 subapp = Instance('IPython.config.application.Application', allow_none=True)
231
232
232 # extra command-line arguments that don't set config values
233 # extra command-line arguments that don't set config values
233 extra_args = List(Unicode)
234 extra_args = List(Unicode)
234
235
235
236
236 def __init__(self, **kwargs):
237 def __init__(self, **kwargs):
237 SingletonConfigurable.__init__(self, **kwargs)
238 SingletonConfigurable.__init__(self, **kwargs)
238 # Ensure my class is in self.classes, so my attributes appear in command line
239 # Ensure my class is in self.classes, so my attributes appear in command line
239 # options and config files.
240 # options and config files.
240 if self.__class__ not in self.classes:
241 if self.__class__ not in self.classes:
241 self.classes.insert(0, self.__class__)
242 self.classes.insert(0, self.__class__)
242
243
243 def _config_changed(self, name, old, new):
244 def _config_changed(self, name, old, new):
244 SingletonConfigurable._config_changed(self, name, old, new)
245 SingletonConfigurable._config_changed(self, name, old, new)
245 self.log.debug('Config changed:')
246 self.log.debug('Config changed:')
246 self.log.debug(repr(new))
247 self.log.debug(repr(new))
247
248
248 @catch_config_error
249 @catch_config_error
249 def initialize(self, argv=None):
250 def initialize(self, argv=None):
250 """Do the basic steps to configure me.
251 """Do the basic steps to configure me.
251
252
252 Override in subclasses.
253 Override in subclasses.
253 """
254 """
254 self.parse_command_line(argv)
255 self.parse_command_line(argv)
255
256
256
257
257 def start(self):
258 def start(self):
258 """Start the app mainloop.
259 """Start the app mainloop.
259
260
260 Override in subclasses.
261 Override in subclasses.
261 """
262 """
262 if self.subapp is not None:
263 if self.subapp is not None:
263 return self.subapp.start()
264 return self.subapp.start()
264
265
265 def print_alias_help(self):
266 def print_alias_help(self):
266 """Print the alias part of the help."""
267 """Print the alias part of the help."""
267 if not self.aliases:
268 if not self.aliases:
268 return
269 return
269
270
270 lines = []
271 lines = []
271 classdict = {}
272 classdict = {}
272 for cls in self.classes:
273 for cls in self.classes:
273 # include all parents (up to, but excluding Configurable) in available names
274 # include all parents (up to, but excluding Configurable) in available names
274 for c in cls.mro()[:-3]:
275 for c in cls.mro()[:-3]:
275 classdict[c.__name__] = c
276 classdict[c.__name__] = c
276
277
277 for alias, longname in self.aliases.iteritems():
278 for alias, longname in self.aliases.iteritems():
278 classname, traitname = longname.split('.',1)
279 classname, traitname = longname.split('.',1)
279 cls = classdict[classname]
280 cls = classdict[classname]
280
281
281 trait = cls.class_traits(config=True)[traitname]
282 trait = cls.class_traits(config=True)[traitname]
282 help = cls.class_get_trait_help(trait).splitlines()
283 help = cls.class_get_trait_help(trait).splitlines()
283 # reformat first line
284 # reformat first line
284 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
285 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
285 if len(alias) == 1:
286 if len(alias) == 1:
286 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
287 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
287 lines.extend(help)
288 lines.extend(help)
288 # lines.append('')
289 # lines.append('')
289 print os.linesep.join(lines)
290 print(os.linesep.join(lines))
290
291
291 def print_flag_help(self):
292 def print_flag_help(self):
292 """Print the flag part of the help."""
293 """Print the flag part of the help."""
293 if not self.flags:
294 if not self.flags:
294 return
295 return
295
296
296 lines = []
297 lines = []
297 for m, (cfg,help) in self.flags.iteritems():
298 for m, (cfg,help) in self.flags.iteritems():
298 prefix = '--' if len(m) > 1 else '-'
299 prefix = '--' if len(m) > 1 else '-'
299 lines.append(prefix+m)
300 lines.append(prefix+m)
300 lines.append(indent(dedent(help.strip())))
301 lines.append(indent(dedent(help.strip())))
301 # lines.append('')
302 # lines.append('')
302 print os.linesep.join(lines)
303 print(os.linesep.join(lines))
303
304
304 def print_options(self):
305 def print_options(self):
305 if not self.flags and not self.aliases:
306 if not self.flags and not self.aliases:
306 return
307 return
307 lines = ['Options']
308 lines = ['Options']
308 lines.append('-'*len(lines[0]))
309 lines.append('-'*len(lines[0]))
309 lines.append('')
310 lines.append('')
310 for p in wrap_paragraphs(self.option_description):
311 for p in wrap_paragraphs(self.option_description):
311 lines.append(p)
312 lines.append(p)
312 lines.append('')
313 lines.append('')
313 print os.linesep.join(lines)
314 print(os.linesep.join(lines))
314 self.print_flag_help()
315 self.print_flag_help()
315 self.print_alias_help()
316 self.print_alias_help()
316 print
317 print()
317
318
318 def print_subcommands(self):
319 def print_subcommands(self):
319 """Print the subcommand part of the help."""
320 """Print the subcommand part of the help."""
320 if not self.subcommands:
321 if not self.subcommands:
321 return
322 return
322
323
323 lines = ["Subcommands"]
324 lines = ["Subcommands"]
324 lines.append('-'*len(lines[0]))
325 lines.append('-'*len(lines[0]))
325 lines.append('')
326 lines.append('')
326 for p in wrap_paragraphs(self.subcommand_description):
327 for p in wrap_paragraphs(self.subcommand_description):
327 lines.append(p)
328 lines.append(p)
328 lines.append('')
329 lines.append('')
329 for subc, (cls, help) in self.subcommands.iteritems():
330 for subc, (cls, help) in self.subcommands.iteritems():
330 lines.append(subc)
331 lines.append(subc)
331 if help:
332 if help:
332 lines.append(indent(dedent(help.strip())))
333 lines.append(indent(dedent(help.strip())))
333 lines.append('')
334 lines.append('')
334 print os.linesep.join(lines)
335 print(os.linesep.join(lines))
335
336
336 def print_help(self, classes=False):
337 def print_help(self, classes=False):
337 """Print the help for each Configurable class in self.classes.
338 """Print the help for each Configurable class in self.classes.
338
339
339 If classes=False (the default), only flags and aliases are printed.
340 If classes=False (the default), only flags and aliases are printed.
340 """
341 """
341 self.print_description()
342 self.print_description()
342 self.print_subcommands()
343 self.print_subcommands()
343 self.print_options()
344 self.print_options()
344
345
345 if classes:
346 if classes:
346 if self.classes:
347 if self.classes:
347 print "Class parameters"
348 print("Class parameters")
348 print "----------------"
349 print("----------------")
349 print
350 print()
350 for p in wrap_paragraphs(self.keyvalue_description):
351 for p in wrap_paragraphs(self.keyvalue_description):
351 print p
352 print(p)
352 print
353 print()
353
354
354 for cls in self.classes:
355 for cls in self.classes:
355 cls.class_print_help()
356 cls.class_print_help()
356 print
357 print()
357 else:
358 else:
358 print "To see all available configurables, use `--help-all`"
359 print("To see all available configurables, use `--help-all`")
359 print
360 print()
360
361
361 self.print_examples()
362 self.print_examples()
362
363
363
364
364 def print_description(self):
365 def print_description(self):
365 """Print the application description."""
366 """Print the application description."""
366 for p in wrap_paragraphs(self.description):
367 for p in wrap_paragraphs(self.description):
367 print p
368 print(p)
368 print
369 print()
369
370
370 def print_examples(self):
371 def print_examples(self):
371 """Print usage and examples.
372 """Print usage and examples.
372
373
373 This usage string goes at the end of the command line help string
374 This usage string goes at the end of the command line help string
374 and should contain examples of the application's usage.
375 and should contain examples of the application's usage.
375 """
376 """
376 if self.examples:
377 if self.examples:
377 print "Examples"
378 print("Examples")
378 print "--------"
379 print("--------")
379 print
380 print()
380 print indent(dedent(self.examples.strip()))
381 print(indent(dedent(self.examples.strip())))
381 print
382 print()
382
383
383 def print_version(self):
384 def print_version(self):
384 """Print the version string."""
385 """Print the version string."""
385 print self.version
386 print(self.version)
386
387
387 def update_config(self, config):
388 def update_config(self, config):
388 """Fire the traits events when the config is updated."""
389 """Fire the traits events when the config is updated."""
389 # Save a copy of the current config.
390 # Save a copy of the current config.
390 newconfig = deepcopy(self.config)
391 newconfig = deepcopy(self.config)
391 # Merge the new config into the current one.
392 # Merge the new config into the current one.
392 newconfig.merge(config)
393 newconfig.merge(config)
393 # Save the combined config as self.config, which triggers the traits
394 # Save the combined config as self.config, which triggers the traits
394 # events.
395 # events.
395 self.config = newconfig
396 self.config = newconfig
396
397
397 @catch_config_error
398 @catch_config_error
398 def initialize_subcommand(self, subc, argv=None):
399 def initialize_subcommand(self, subc, argv=None):
399 """Initialize a subcommand with argv."""
400 """Initialize a subcommand with argv."""
400 subapp,help = self.subcommands.get(subc)
401 subapp,help = self.subcommands.get(subc)
401
402
402 if isinstance(subapp, basestring):
403 if isinstance(subapp, basestring):
403 subapp = import_item(subapp)
404 subapp = import_item(subapp)
404
405
405 # clear existing instances
406 # clear existing instances
406 self.__class__.clear_instance()
407 self.__class__.clear_instance()
407 # instantiate
408 # instantiate
408 self.subapp = subapp.instance(config=self.config)
409 self.subapp = subapp.instance(config=self.config)
409 # and initialize subapp
410 # and initialize subapp
410 self.subapp.initialize(argv)
411 self.subapp.initialize(argv)
411
412
412 def flatten_flags(self):
413 def flatten_flags(self):
413 """flatten flags and aliases, so cl-args override as expected.
414 """flatten flags and aliases, so cl-args override as expected.
414
415
415 This prevents issues such as an alias pointing to InteractiveShell,
416 This prevents issues such as an alias pointing to InteractiveShell,
416 but a config file setting the same trait in TerminalInteraciveShell
417 but a config file setting the same trait in TerminalInteraciveShell
417 getting inappropriate priority over the command-line arg.
418 getting inappropriate priority over the command-line arg.
418
419
419 Only aliases with exactly one descendent in the class list
420 Only aliases with exactly one descendent in the class list
420 will be promoted.
421 will be promoted.
421
422
422 """
423 """
423 # build a tree of classes in our list that inherit from a particular
424 # build a tree of classes in our list that inherit from a particular
424 # it will be a dict by parent classname of classes in our list
425 # it will be a dict by parent classname of classes in our list
425 # that are descendents
426 # that are descendents
426 mro_tree = defaultdict(list)
427 mro_tree = defaultdict(list)
427 for cls in self.classes:
428 for cls in self.classes:
428 clsname = cls.__name__
429 clsname = cls.__name__
429 for parent in cls.mro()[1:-3]:
430 for parent in cls.mro()[1:-3]:
430 # exclude cls itself and Configurable,HasTraits,object
431 # exclude cls itself and Configurable,HasTraits,object
431 mro_tree[parent.__name__].append(clsname)
432 mro_tree[parent.__name__].append(clsname)
432 # flatten aliases, which have the form:
433 # flatten aliases, which have the form:
433 # { 'alias' : 'Class.trait' }
434 # { 'alias' : 'Class.trait' }
434 aliases = {}
435 aliases = {}
435 for alias, cls_trait in self.aliases.iteritems():
436 for alias, cls_trait in self.aliases.iteritems():
436 cls,trait = cls_trait.split('.',1)
437 cls,trait = cls_trait.split('.',1)
437 children = mro_tree[cls]
438 children = mro_tree[cls]
438 if len(children) == 1:
439 if len(children) == 1:
439 # exactly one descendent, promote alias
440 # exactly one descendent, promote alias
440 cls = children[0]
441 cls = children[0]
441 aliases[alias] = '.'.join([cls,trait])
442 aliases[alias] = '.'.join([cls,trait])
442
443
443 # flatten flags, which are of the form:
444 # flatten flags, which are of the form:
444 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
445 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
445 flags = {}
446 flags = {}
446 for key, (flagdict, help) in self.flags.iteritems():
447 for key, (flagdict, help) in self.flags.iteritems():
447 newflag = {}
448 newflag = {}
448 for cls, subdict in flagdict.iteritems():
449 for cls, subdict in flagdict.iteritems():
449 children = mro_tree[cls]
450 children = mro_tree[cls]
450 # exactly one descendent, promote flag section
451 # exactly one descendent, promote flag section
451 if len(children) == 1:
452 if len(children) == 1:
452 cls = children[0]
453 cls = children[0]
453 newflag[cls] = subdict
454 newflag[cls] = subdict
454 flags[key] = (newflag, help)
455 flags[key] = (newflag, help)
455 return flags, aliases
456 return flags, aliases
456
457
457 @catch_config_error
458 @catch_config_error
458 def parse_command_line(self, argv=None):
459 def parse_command_line(self, argv=None):
459 """Parse the command line arguments."""
460 """Parse the command line arguments."""
460 argv = sys.argv[1:] if argv is None else argv
461 argv = sys.argv[1:] if argv is None else argv
461 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
462 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
462
463
463 if argv and argv[0] == 'help':
464 if argv and argv[0] == 'help':
464 # turn `ipython help notebook` into `ipython notebook -h`
465 # turn `ipython help notebook` into `ipython notebook -h`
465 argv = argv[1:] + ['-h']
466 argv = argv[1:] + ['-h']
466
467
467 if self.subcommands and len(argv) > 0:
468 if self.subcommands and len(argv) > 0:
468 # we have subcommands, and one may have been specified
469 # we have subcommands, and one may have been specified
469 subc, subargv = argv[0], argv[1:]
470 subc, subargv = argv[0], argv[1:]
470 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
471 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
471 # it's a subcommand, and *not* a flag or class parameter
472 # it's a subcommand, and *not* a flag or class parameter
472 return self.initialize_subcommand(subc, subargv)
473 return self.initialize_subcommand(subc, subargv)
473
474
474 # Arguments after a '--' argument are for the script IPython may be
475 # Arguments after a '--' argument are for the script IPython may be
475 # about to run, not IPython iteslf. For arguments parsed here (help and
476 # about to run, not IPython iteslf. For arguments parsed here (help and
476 # version), we want to only search the arguments up to the first
477 # version), we want to only search the arguments up to the first
477 # occurrence of '--', which we're calling interpreted_argv.
478 # occurrence of '--', which we're calling interpreted_argv.
478 try:
479 try:
479 interpreted_argv = argv[:argv.index('--')]
480 interpreted_argv = argv[:argv.index('--')]
480 except ValueError:
481 except ValueError:
481 interpreted_argv = argv
482 interpreted_argv = argv
482
483
483 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
484 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
484 self.print_help('--help-all' in interpreted_argv)
485 self.print_help('--help-all' in interpreted_argv)
485 self.exit(0)
486 self.exit(0)
486
487
487 if '--version' in interpreted_argv or '-V' in interpreted_argv:
488 if '--version' in interpreted_argv or '-V' in interpreted_argv:
488 self.print_version()
489 self.print_version()
489 self.exit(0)
490 self.exit(0)
490
491
491 # flatten flags&aliases, so cl-args get appropriate priority:
492 # flatten flags&aliases, so cl-args get appropriate priority:
492 flags,aliases = self.flatten_flags()
493 flags,aliases = self.flatten_flags()
493
494
494 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
495 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
495 flags=flags)
496 flags=flags)
496 config = loader.load_config()
497 config = loader.load_config()
497 self.update_config(config)
498 self.update_config(config)
498 # store unparsed args in extra_args
499 # store unparsed args in extra_args
499 self.extra_args = loader.extra_args
500 self.extra_args = loader.extra_args
500
501
501 @catch_config_error
502 @catch_config_error
502 def load_config_file(self, filename, path=None):
503 def load_config_file(self, filename, path=None):
503 """Load a .py based config file by filename and path."""
504 """Load a .py based config file by filename and path."""
504 loader = PyFileConfigLoader(filename, path=path)
505 loader = PyFileConfigLoader(filename, path=path)
505 try:
506 try:
506 config = loader.load_config()
507 config = loader.load_config()
507 except ConfigFileNotFound:
508 except ConfigFileNotFound:
508 # problem finding the file, raise
509 # problem finding the file, raise
509 raise
510 raise
510 except Exception:
511 except Exception:
511 # try to get the full filename, but it will be empty in the
512 # try to get the full filename, but it will be empty in the
512 # unlikely event that the error raised before filefind finished
513 # unlikely event that the error raised before filefind finished
513 filename = loader.full_filename or filename
514 filename = loader.full_filename or filename
514 # problem while running the file
515 # problem while running the file
515 self.log.error("Exception while loading config file %s",
516 self.log.error("Exception while loading config file %s",
516 filename, exc_info=True)
517 filename, exc_info=True)
517 else:
518 else:
518 self.log.debug("Loaded config file: %s", loader.full_filename)
519 self.log.debug("Loaded config file: %s", loader.full_filename)
519 self.update_config(config)
520 self.update_config(config)
520
521
521 def generate_config_file(self):
522 def generate_config_file(self):
522 """generate default config file from Configurables"""
523 """generate default config file from Configurables"""
523 lines = ["# Configuration file for %s."%self.name]
524 lines = ["# Configuration file for %s."%self.name]
524 lines.append('')
525 lines.append('')
525 lines.append('c = get_config()')
526 lines.append('c = get_config()')
526 lines.append('')
527 lines.append('')
527 for cls in self.classes:
528 for cls in self.classes:
528 lines.append(cls.class_config_section())
529 lines.append(cls.class_config_section())
529 return '\n'.join(lines)
530 return '\n'.join(lines)
530
531
531 def exit(self, exit_status=0):
532 def exit(self, exit_status=0):
532 self.log.debug("Exiting application: %s" % self.name)
533 self.log.debug("Exiting application: %s" % self.name)
533 sys.exit(exit_status)
534 sys.exit(exit_status)
534
535
535 @classmethod
536 @classmethod
536 def launch_instance(cls, argv=None, **kwargs):
537 def launch_instance(cls, argv=None, **kwargs):
537 """Launch a global instance of this Application
538 """Launch a global instance of this Application
538
539
539 If a global instance already exists, this reinitializes and starts it
540 If a global instance already exists, this reinitializes and starts it
540 """
541 """
541 app = cls.instance(**kwargs)
542 app = cls.instance(**kwargs)
542 app.initialize(argv)
543 app.initialize(argv)
543 app.start()
544 app.start()
544
545
545 #-----------------------------------------------------------------------------
546 #-----------------------------------------------------------------------------
546 # utility functions, for convenience
547 # utility functions, for convenience
547 #-----------------------------------------------------------------------------
548 #-----------------------------------------------------------------------------
548
549
549 def boolean_flag(name, configurable, set_help='', unset_help=''):
550 def boolean_flag(name, configurable, set_help='', unset_help=''):
550 """Helper for building basic --trait, --no-trait flags.
551 """Helper for building basic --trait, --no-trait flags.
551
552
552 Parameters
553 Parameters
553 ----------
554 ----------
554
555
555 name : str
556 name : str
556 The name of the flag.
557 The name of the flag.
557 configurable : str
558 configurable : str
558 The 'Class.trait' string of the trait to be set/unset with the flag
559 The 'Class.trait' string of the trait to be set/unset with the flag
559 set_help : unicode
560 set_help : unicode
560 help string for --name flag
561 help string for --name flag
561 unset_help : unicode
562 unset_help : unicode
562 help string for --no-name flag
563 help string for --no-name flag
563
564
564 Returns
565 Returns
565 -------
566 -------
566
567
567 cfg : dict
568 cfg : dict
568 A dict with two keys: 'name', and 'no-name', for setting and unsetting
569 A dict with two keys: 'name', and 'no-name', for setting and unsetting
569 the trait, respectively.
570 the trait, respectively.
570 """
571 """
571 # default helpstrings
572 # default helpstrings
572 set_help = set_help or "set %s=True"%configurable
573 set_help = set_help or "set %s=True"%configurable
573 unset_help = unset_help or "set %s=False"%configurable
574 unset_help = unset_help or "set %s=False"%configurable
574
575
575 cls,trait = configurable.split('.')
576 cls,trait = configurable.split('.')
576
577
577 setter = {cls : {trait : True}}
578 setter = {cls : {trait : True}}
578 unsetter = {cls : {trait : False}}
579 unsetter = {cls : {trait : False}}
579 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
580 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
580
581
@@ -1,387 +1,388 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A base class for objects that are configurable.
3 A base class for objects that are configurable.
4
4
5 Inheritance diagram:
5 Inheritance diagram:
6
6
7 .. inheritance-diagram:: IPython.config.configurable
7 .. inheritance-diagram:: IPython.config.configurable
8 :parts: 3
8 :parts: 3
9
9
10 Authors:
10 Authors:
11
11
12 * Brian Granger
12 * Brian Granger
13 * Fernando Perez
13 * Fernando Perez
14 * Min RK
14 * Min RK
15 """
15 """
16 from __future__ import print_function
16
17
17 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
18 # Copyright (C) 2008-2011 The IPython Development Team
19 # Copyright (C) 2008-2011 The IPython Development Team
19 #
20 #
20 # 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
21 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23
24
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
25 # Imports
26 # Imports
26 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
27
28
28 import datetime
29 import datetime
29 from copy import deepcopy
30 from copy import deepcopy
30
31
31 from .loader import Config, LazyConfigValue
32 from .loader import Config, LazyConfigValue
32 from IPython.utils.traitlets import HasTraits, Instance
33 from IPython.utils.traitlets import HasTraits, Instance
33 from IPython.utils.text import indent, wrap_paragraphs
34 from IPython.utils.text import indent, wrap_paragraphs
34
35
35
36
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37 # Helper classes for Configurables
38 # Helper classes for Configurables
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39
40
40
41
41 class ConfigurableError(Exception):
42 class ConfigurableError(Exception):
42 pass
43 pass
43
44
44
45
45 class MultipleInstanceError(ConfigurableError):
46 class MultipleInstanceError(ConfigurableError):
46 pass
47 pass
47
48
48 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
49 # Configurable implementation
50 # Configurable implementation
50 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
51
52
52 class Configurable(HasTraits):
53 class Configurable(HasTraits):
53
54
54 config = Instance(Config, (), {})
55 config = Instance(Config, (), {})
55 parent = Instance('IPython.config.configurable.Configurable')
56 parent = Instance('IPython.config.configurable.Configurable')
56 created = None
57 created = None
57
58
58 def __init__(self, **kwargs):
59 def __init__(self, **kwargs):
59 """Create a configurable given a config config.
60 """Create a configurable given a config config.
60
61
61 Parameters
62 Parameters
62 ----------
63 ----------
63 config : Config
64 config : Config
64 If this is empty, default values are used. If config is a
65 If this is empty, default values are used. If config is a
65 :class:`Config` instance, it will be used to configure the
66 :class:`Config` instance, it will be used to configure the
66 instance.
67 instance.
67 parent : Configurable instance, optional
68 parent : Configurable instance, optional
68 The parent Configurable instance of this object.
69 The parent Configurable instance of this object.
69
70
70 Notes
71 Notes
71 -----
72 -----
72 Subclasses of Configurable must call the :meth:`__init__` method of
73 Subclasses of Configurable must call the :meth:`__init__` method of
73 :class:`Configurable` *before* doing anything else and using
74 :class:`Configurable` *before* doing anything else and using
74 :func:`super`::
75 :func:`super`::
75
76
76 class MyConfigurable(Configurable):
77 class MyConfigurable(Configurable):
77 def __init__(self, config=None):
78 def __init__(self, config=None):
78 super(MyConfigurable, self).__init__(config=config)
79 super(MyConfigurable, self).__init__(config=config)
79 # Then any other code you need to finish initialization.
80 # Then any other code you need to finish initialization.
80
81
81 This ensures that instances will be configured properly.
82 This ensures that instances will be configured properly.
82 """
83 """
83 parent = kwargs.pop('parent', None)
84 parent = kwargs.pop('parent', None)
84 if parent is not None:
85 if parent is not None:
85 # config is implied from parent
86 # config is implied from parent
86 if kwargs.get('config', None) is None:
87 if kwargs.get('config', None) is None:
87 kwargs['config'] = parent.config
88 kwargs['config'] = parent.config
88 self.parent = parent
89 self.parent = parent
89
90
90 config = kwargs.pop('config', None)
91 config = kwargs.pop('config', None)
91 if config is not None:
92 if config is not None:
92 # We used to deepcopy, but for now we are trying to just save
93 # We used to deepcopy, but for now we are trying to just save
93 # by reference. This *could* have side effects as all components
94 # by reference. This *could* have side effects as all components
94 # will share config. In fact, I did find such a side effect in
95 # will share config. In fact, I did find such a side effect in
95 # _config_changed below. If a config attribute value was a mutable type
96 # _config_changed below. If a config attribute value was a mutable type
96 # all instances of a component were getting the same copy, effectively
97 # all instances of a component were getting the same copy, effectively
97 # making that a class attribute.
98 # making that a class attribute.
98 # self.config = deepcopy(config)
99 # self.config = deepcopy(config)
99 self.config = config
100 self.config = config
100 # This should go second so individual keyword arguments override
101 # This should go second so individual keyword arguments override
101 # the values in config.
102 # the values in config.
102 super(Configurable, self).__init__(**kwargs)
103 super(Configurable, self).__init__(**kwargs)
103 self.created = datetime.datetime.now()
104 self.created = datetime.datetime.now()
104
105
105 #-------------------------------------------------------------------------
106 #-------------------------------------------------------------------------
106 # Static trait notifiations
107 # Static trait notifiations
107 #-------------------------------------------------------------------------
108 #-------------------------------------------------------------------------
108
109
109 @classmethod
110 @classmethod
110 def section_names(cls):
111 def section_names(cls):
111 """return section names as a list"""
112 """return section names as a list"""
112 return [c.__name__ for c in reversed(cls.__mro__) if
113 return [c.__name__ for c in reversed(cls.__mro__) if
113 issubclass(c, Configurable) and issubclass(cls, c)
114 issubclass(c, Configurable) and issubclass(cls, c)
114 ]
115 ]
115
116
116 def _find_my_config(self, cfg):
117 def _find_my_config(self, cfg):
117 """extract my config from a global Config object
118 """extract my config from a global Config object
118
119
119 will construct a Config object of only the config values that apply to me
120 will construct a Config object of only the config values that apply to me
120 based on my mro(), as well as those of my parent(s) if they exist.
121 based on my mro(), as well as those of my parent(s) if they exist.
121
122
122 If I am Bar and my parent is Foo, and their parent is Tim,
123 If I am Bar and my parent is Foo, and their parent is Tim,
123 this will return merge following config sections, in this order::
124 this will return merge following config sections, in this order::
124
125
125 [Bar, Foo.bar, Tim.Foo.Bar]
126 [Bar, Foo.bar, Tim.Foo.Bar]
126
127
127 With the last item being the highest priority.
128 With the last item being the highest priority.
128 """
129 """
129 cfgs = [cfg]
130 cfgs = [cfg]
130 if self.parent:
131 if self.parent:
131 cfgs.append(self.parent._find_my_config(cfg))
132 cfgs.append(self.parent._find_my_config(cfg))
132 my_config = Config()
133 my_config = Config()
133 for c in cfgs:
134 for c in cfgs:
134 for sname in self.section_names():
135 for sname in self.section_names():
135 # Don't do a blind getattr as that would cause the config to
136 # Don't do a blind getattr as that would cause the config to
136 # dynamically create the section with name Class.__name__.
137 # dynamically create the section with name Class.__name__.
137 if c._has_section(sname):
138 if c._has_section(sname):
138 my_config.merge(c[sname])
139 my_config.merge(c[sname])
139 return my_config
140 return my_config
140
141
141 def _load_config(self, cfg, section_names=None, traits=None):
142 def _load_config(self, cfg, section_names=None, traits=None):
142 """load traits from a Config object"""
143 """load traits from a Config object"""
143
144
144 if traits is None:
145 if traits is None:
145 traits = self.traits(config=True)
146 traits = self.traits(config=True)
146 if section_names is None:
147 if section_names is None:
147 section_names = self.section_names()
148 section_names = self.section_names()
148
149
149 my_config = self._find_my_config(cfg)
150 my_config = self._find_my_config(cfg)
150 for name, config_value in my_config.iteritems():
151 for name, config_value in my_config.iteritems():
151 if name in traits:
152 if name in traits:
152 if isinstance(config_value, LazyConfigValue):
153 if isinstance(config_value, LazyConfigValue):
153 # ConfigValue is a wrapper for using append / update on containers
154 # ConfigValue is a wrapper for using append / update on containers
154 # without having to copy the
155 # without having to copy the
155 initial = getattr(self, name)
156 initial = getattr(self, name)
156 config_value = config_value.get_value(initial)
157 config_value = config_value.get_value(initial)
157 # We have to do a deepcopy here if we don't deepcopy the entire
158 # We have to do a deepcopy here if we don't deepcopy the entire
158 # config object. If we don't, a mutable config_value will be
159 # config object. If we don't, a mutable config_value will be
159 # shared by all instances, effectively making it a class attribute.
160 # shared by all instances, effectively making it a class attribute.
160 setattr(self, name, deepcopy(config_value))
161 setattr(self, name, deepcopy(config_value))
161
162
162 def _config_changed(self, name, old, new):
163 def _config_changed(self, name, old, new):
163 """Update all the class traits having ``config=True`` as metadata.
164 """Update all the class traits having ``config=True`` as metadata.
164
165
165 For any class trait with a ``config`` metadata attribute that is
166 For any class trait with a ``config`` metadata attribute that is
166 ``True``, we update the trait with the value of the corresponding
167 ``True``, we update the trait with the value of the corresponding
167 config entry.
168 config entry.
168 """
169 """
169 # Get all traits with a config metadata entry that is True
170 # Get all traits with a config metadata entry that is True
170 traits = self.traits(config=True)
171 traits = self.traits(config=True)
171
172
172 # We auto-load config section for this class as well as any parent
173 # We auto-load config section for this class as well as any parent
173 # classes that are Configurable subclasses. This starts with Configurable
174 # classes that are Configurable subclasses. This starts with Configurable
174 # and works down the mro loading the config for each section.
175 # and works down the mro loading the config for each section.
175 section_names = self.section_names()
176 section_names = self.section_names()
176 self._load_config(new, traits=traits, section_names=section_names)
177 self._load_config(new, traits=traits, section_names=section_names)
177
178
178 def update_config(self, config):
179 def update_config(self, config):
179 """Fire the traits events when the config is updated."""
180 """Fire the traits events when the config is updated."""
180 # Save a copy of the current config.
181 # Save a copy of the current config.
181 newconfig = deepcopy(self.config)
182 newconfig = deepcopy(self.config)
182 # Merge the new config into the current one.
183 # Merge the new config into the current one.
183 newconfig.merge(config)
184 newconfig.merge(config)
184 # Save the combined config as self.config, which triggers the traits
185 # Save the combined config as self.config, which triggers the traits
185 # events.
186 # events.
186 self.config = newconfig
187 self.config = newconfig
187
188
188 @classmethod
189 @classmethod
189 def class_get_help(cls, inst=None):
190 def class_get_help(cls, inst=None):
190 """Get the help string for this class in ReST format.
191 """Get the help string for this class in ReST format.
191
192
192 If `inst` is given, it's current trait values will be used in place of
193 If `inst` is given, it's current trait values will be used in place of
193 class defaults.
194 class defaults.
194 """
195 """
195 assert inst is None or isinstance(inst, cls)
196 assert inst is None or isinstance(inst, cls)
196 final_help = []
197 final_help = []
197 final_help.append(u'%s options' % cls.__name__)
198 final_help.append(u'%s options' % cls.__name__)
198 final_help.append(len(final_help[0])*u'-')
199 final_help.append(len(final_help[0])*u'-')
199 for k, v in sorted(cls.class_traits(config=True).iteritems()):
200 for k, v in sorted(cls.class_traits(config=True).iteritems()):
200 help = cls.class_get_trait_help(v, inst)
201 help = cls.class_get_trait_help(v, inst)
201 final_help.append(help)
202 final_help.append(help)
202 return '\n'.join(final_help)
203 return '\n'.join(final_help)
203
204
204 @classmethod
205 @classmethod
205 def class_get_trait_help(cls, trait, inst=None):
206 def class_get_trait_help(cls, trait, inst=None):
206 """Get the help string for a single trait.
207 """Get the help string for a single trait.
207
208
208 If `inst` is given, it's current trait values will be used in place of
209 If `inst` is given, it's current trait values will be used in place of
209 the class default.
210 the class default.
210 """
211 """
211 assert inst is None or isinstance(inst, cls)
212 assert inst is None or isinstance(inst, cls)
212 lines = []
213 lines = []
213 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
214 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
214 lines.append(header)
215 lines.append(header)
215 if inst is not None:
216 if inst is not None:
216 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
217 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
217 else:
218 else:
218 try:
219 try:
219 dvr = repr(trait.get_default_value())
220 dvr = repr(trait.get_default_value())
220 except Exception:
221 except Exception:
221 dvr = None # ignore defaults we can't construct
222 dvr = None # ignore defaults we can't construct
222 if dvr is not None:
223 if dvr is not None:
223 if len(dvr) > 64:
224 if len(dvr) > 64:
224 dvr = dvr[:61]+'...'
225 dvr = dvr[:61]+'...'
225 lines.append(indent('Default: %s' % dvr, 4))
226 lines.append(indent('Default: %s' % dvr, 4))
226 if 'Enum' in trait.__class__.__name__:
227 if 'Enum' in trait.__class__.__name__:
227 # include Enum choices
228 # include Enum choices
228 lines.append(indent('Choices: %r' % (trait.values,)))
229 lines.append(indent('Choices: %r' % (trait.values,)))
229
230
230 help = trait.get_metadata('help')
231 help = trait.get_metadata('help')
231 if help is not None:
232 if help is not None:
232 help = '\n'.join(wrap_paragraphs(help, 76))
233 help = '\n'.join(wrap_paragraphs(help, 76))
233 lines.append(indent(help, 4))
234 lines.append(indent(help, 4))
234 return '\n'.join(lines)
235 return '\n'.join(lines)
235
236
236 @classmethod
237 @classmethod
237 def class_print_help(cls, inst=None):
238 def class_print_help(cls, inst=None):
238 """Get the help string for a single trait and print it."""
239 """Get the help string for a single trait and print it."""
239 print cls.class_get_help(inst)
240 print(cls.class_get_help(inst))
240
241
241 @classmethod
242 @classmethod
242 def class_config_section(cls):
243 def class_config_section(cls):
243 """Get the config class config section"""
244 """Get the config class config section"""
244 def c(s):
245 def c(s):
245 """return a commented, wrapped block."""
246 """return a commented, wrapped block."""
246 s = '\n\n'.join(wrap_paragraphs(s, 78))
247 s = '\n\n'.join(wrap_paragraphs(s, 78))
247
248
248 return '# ' + s.replace('\n', '\n# ')
249 return '# ' + s.replace('\n', '\n# ')
249
250
250 # section header
251 # section header
251 breaker = '#' + '-'*78
252 breaker = '#' + '-'*78
252 s = "# %s configuration" % cls.__name__
253 s = "# %s configuration" % cls.__name__
253 lines = [breaker, s, breaker, '']
254 lines = [breaker, s, breaker, '']
254 # get the description trait
255 # get the description trait
255 desc = cls.class_traits().get('description')
256 desc = cls.class_traits().get('description')
256 if desc:
257 if desc:
257 desc = desc.default_value
258 desc = desc.default_value
258 else:
259 else:
259 # no description trait, use __doc__
260 # no description trait, use __doc__
260 desc = getattr(cls, '__doc__', '')
261 desc = getattr(cls, '__doc__', '')
261 if desc:
262 if desc:
262 lines.append(c(desc))
263 lines.append(c(desc))
263 lines.append('')
264 lines.append('')
264
265
265 parents = []
266 parents = []
266 for parent in cls.mro():
267 for parent in cls.mro():
267 # only include parents that are not base classes
268 # only include parents that are not base classes
268 # and are not the class itself
269 # and are not the class itself
269 # and have some configurable traits to inherit
270 # and have some configurable traits to inherit
270 if parent is not cls and issubclass(parent, Configurable) and \
271 if parent is not cls and issubclass(parent, Configurable) and \
271 parent.class_traits(config=True):
272 parent.class_traits(config=True):
272 parents.append(parent)
273 parents.append(parent)
273
274
274 if parents:
275 if parents:
275 pstr = ', '.join([ p.__name__ for p in parents ])
276 pstr = ', '.join([ p.__name__ for p in parents ])
276 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
277 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
277 lines.append('')
278 lines.append('')
278
279
279 for name, trait in cls.class_traits(config=True).iteritems():
280 for name, trait in cls.class_traits(config=True).iteritems():
280 help = trait.get_metadata('help') or ''
281 help = trait.get_metadata('help') or ''
281 lines.append(c(help))
282 lines.append(c(help))
282 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
283 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
283 lines.append('')
284 lines.append('')
284 return '\n'.join(lines)
285 return '\n'.join(lines)
285
286
286
287
287
288
288 class SingletonConfigurable(Configurable):
289 class SingletonConfigurable(Configurable):
289 """A configurable that only allows one instance.
290 """A configurable that only allows one instance.
290
291
291 This class is for classes that should only have one instance of itself
292 This class is for classes that should only have one instance of itself
292 or *any* subclass. To create and retrieve such a class use the
293 or *any* subclass. To create and retrieve such a class use the
293 :meth:`SingletonConfigurable.instance` method.
294 :meth:`SingletonConfigurable.instance` method.
294 """
295 """
295
296
296 _instance = None
297 _instance = None
297
298
298 @classmethod
299 @classmethod
299 def _walk_mro(cls):
300 def _walk_mro(cls):
300 """Walk the cls.mro() for parent classes that are also singletons
301 """Walk the cls.mro() for parent classes that are also singletons
301
302
302 For use in instance()
303 For use in instance()
303 """
304 """
304
305
305 for subclass in cls.mro():
306 for subclass in cls.mro():
306 if issubclass(cls, subclass) and \
307 if issubclass(cls, subclass) and \
307 issubclass(subclass, SingletonConfigurable) and \
308 issubclass(subclass, SingletonConfigurable) and \
308 subclass != SingletonConfigurable:
309 subclass != SingletonConfigurable:
309 yield subclass
310 yield subclass
310
311
311 @classmethod
312 @classmethod
312 def clear_instance(cls):
313 def clear_instance(cls):
313 """unset _instance for this class and singleton parents.
314 """unset _instance for this class and singleton parents.
314 """
315 """
315 if not cls.initialized():
316 if not cls.initialized():
316 return
317 return
317 for subclass in cls._walk_mro():
318 for subclass in cls._walk_mro():
318 if isinstance(subclass._instance, cls):
319 if isinstance(subclass._instance, cls):
319 # only clear instances that are instances
320 # only clear instances that are instances
320 # of the calling class
321 # of the calling class
321 subclass._instance = None
322 subclass._instance = None
322
323
323 @classmethod
324 @classmethod
324 def instance(cls, *args, **kwargs):
325 def instance(cls, *args, **kwargs):
325 """Returns a global instance of this class.
326 """Returns a global instance of this class.
326
327
327 This method create a new instance if none have previously been created
328 This method create a new instance if none have previously been created
328 and returns a previously created instance is one already exists.
329 and returns a previously created instance is one already exists.
329
330
330 The arguments and keyword arguments passed to this method are passed
331 The arguments and keyword arguments passed to this method are passed
331 on to the :meth:`__init__` method of the class upon instantiation.
332 on to the :meth:`__init__` method of the class upon instantiation.
332
333
333 Examples
334 Examples
334 --------
335 --------
335
336
336 Create a singleton class using instance, and retrieve it::
337 Create a singleton class using instance, and retrieve it::
337
338
338 >>> from IPython.config.configurable import SingletonConfigurable
339 >>> from IPython.config.configurable import SingletonConfigurable
339 >>> class Foo(SingletonConfigurable): pass
340 >>> class Foo(SingletonConfigurable): pass
340 >>> foo = Foo.instance()
341 >>> foo = Foo.instance()
341 >>> foo == Foo.instance()
342 >>> foo == Foo.instance()
342 True
343 True
343
344
344 Create a subclass that is retrived using the base class instance::
345 Create a subclass that is retrived using the base class instance::
345
346
346 >>> class Bar(SingletonConfigurable): pass
347 >>> class Bar(SingletonConfigurable): pass
347 >>> class Bam(Bar): pass
348 >>> class Bam(Bar): pass
348 >>> bam = Bam.instance()
349 >>> bam = Bam.instance()
349 >>> bam == Bar.instance()
350 >>> bam == Bar.instance()
350 True
351 True
351 """
352 """
352 # Create and save the instance
353 # Create and save the instance
353 if cls._instance is None:
354 if cls._instance is None:
354 inst = cls(*args, **kwargs)
355 inst = cls(*args, **kwargs)
355 # Now make sure that the instance will also be returned by
356 # Now make sure that the instance will also be returned by
356 # parent classes' _instance attribute.
357 # parent classes' _instance attribute.
357 for subclass in cls._walk_mro():
358 for subclass in cls._walk_mro():
358 subclass._instance = inst
359 subclass._instance = inst
359
360
360 if isinstance(cls._instance, cls):
361 if isinstance(cls._instance, cls):
361 return cls._instance
362 return cls._instance
362 else:
363 else:
363 raise MultipleInstanceError(
364 raise MultipleInstanceError(
364 'Multiple incompatible subclass instances of '
365 'Multiple incompatible subclass instances of '
365 '%s are being created.' % cls.__name__
366 '%s are being created.' % cls.__name__
366 )
367 )
367
368
368 @classmethod
369 @classmethod
369 def initialized(cls):
370 def initialized(cls):
370 """Has an instance been created?"""
371 """Has an instance been created?"""
371 return hasattr(cls, "_instance") and cls._instance is not None
372 return hasattr(cls, "_instance") and cls._instance is not None
372
373
373
374
374 class LoggingConfigurable(Configurable):
375 class LoggingConfigurable(Configurable):
375 """A parent class for Configurables that log.
376 """A parent class for Configurables that log.
376
377
377 Subclasses have a log trait, and the default behavior
378 Subclasses have a log trait, and the default behavior
378 is to get the logger from the currently running Application
379 is to get the logger from the currently running Application
379 via Application.instance().log.
380 via Application.instance().log.
380 """
381 """
381
382
382 log = Instance('logging.Logger')
383 log = Instance('logging.Logger')
383 def _log_default(self):
384 def _log_default(self):
384 from IPython.config.application import Application
385 from IPython.config.application import Application
385 return Application.instance().log
386 return Application.instance().log
386
387
387
388
@@ -1,220 +1,221 b''
1 """Logger class for IPython's logging facilities.
1 """Logger class for IPython's logging facilities.
2 """
2 """
3 from __future__ import print_function
3
4
4 #*****************************************************************************
5 #*****************************************************************************
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
7 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
7 #
8 #
8 # 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
9 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
10 #*****************************************************************************
11 #*****************************************************************************
11
12
12 #****************************************************************************
13 #****************************************************************************
13 # Modules and globals
14 # Modules and globals
14
15
15 # Python standard modules
16 # Python standard modules
16 import glob
17 import glob
17 import io
18 import io
18 import os
19 import os
19 import time
20 import time
20
21
21 from IPython.utils.py3compat import str_to_unicode
22 from IPython.utils.py3compat import str_to_unicode
22
23
23 #****************************************************************************
24 #****************************************************************************
24 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
25 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
25 # ipython and does input cache management. Finish cleanup later...
26 # ipython and does input cache management. Finish cleanup later...
26
27
27 class Logger(object):
28 class Logger(object):
28 """A Logfile class with different policies for file creation"""
29 """A Logfile class with different policies for file creation"""
29
30
30 def __init__(self, home_dir, logfname='Logger.log', loghead=u'',
31 def __init__(self, home_dir, logfname='Logger.log', loghead=u'',
31 logmode='over'):
32 logmode='over'):
32
33
33 # this is the full ipython instance, we need some attributes from it
34 # this is the full ipython instance, we need some attributes from it
34 # which won't exist until later. What a mess, clean up later...
35 # which won't exist until later. What a mess, clean up later...
35 self.home_dir = home_dir
36 self.home_dir = home_dir
36
37
37 self.logfname = logfname
38 self.logfname = logfname
38 self.loghead = loghead
39 self.loghead = loghead
39 self.logmode = logmode
40 self.logmode = logmode
40 self.logfile = None
41 self.logfile = None
41
42
42 # Whether to log raw or processed input
43 # Whether to log raw or processed input
43 self.log_raw_input = False
44 self.log_raw_input = False
44
45
45 # whether to also log output
46 # whether to also log output
46 self.log_output = False
47 self.log_output = False
47
48
48 # whether to put timestamps before each log entry
49 # whether to put timestamps before each log entry
49 self.timestamp = False
50 self.timestamp = False
50
51
51 # activity control flags
52 # activity control flags
52 self.log_active = False
53 self.log_active = False
53
54
54 # logmode is a validated property
55 # logmode is a validated property
55 def _set_mode(self,mode):
56 def _set_mode(self,mode):
56 if mode not in ['append','backup','global','over','rotate']:
57 if mode not in ['append','backup','global','over','rotate']:
57 raise ValueError('invalid log mode %s given' % mode)
58 raise ValueError('invalid log mode %s given' % mode)
58 self._logmode = mode
59 self._logmode = mode
59
60
60 def _get_mode(self):
61 def _get_mode(self):
61 return self._logmode
62 return self._logmode
62
63
63 logmode = property(_get_mode,_set_mode)
64 logmode = property(_get_mode,_set_mode)
64
65
65 def logstart(self, logfname=None, loghead=None, logmode=None,
66 def logstart(self, logfname=None, loghead=None, logmode=None,
66 log_output=False, timestamp=False, log_raw_input=False):
67 log_output=False, timestamp=False, log_raw_input=False):
67 """Generate a new log-file with a default header.
68 """Generate a new log-file with a default header.
68
69
69 Raises RuntimeError if the log has already been started"""
70 Raises RuntimeError if the log has already been started"""
70
71
71 if self.logfile is not None:
72 if self.logfile is not None:
72 raise RuntimeError('Log file is already active: %s' %
73 raise RuntimeError('Log file is already active: %s' %
73 self.logfname)
74 self.logfname)
74
75
75 # The parameters can override constructor defaults
76 # The parameters can override constructor defaults
76 if logfname is not None: self.logfname = logfname
77 if logfname is not None: self.logfname = logfname
77 if loghead is not None: self.loghead = loghead
78 if loghead is not None: self.loghead = loghead
78 if logmode is not None: self.logmode = logmode
79 if logmode is not None: self.logmode = logmode
79
80
80 # Parameters not part of the constructor
81 # Parameters not part of the constructor
81 self.timestamp = timestamp
82 self.timestamp = timestamp
82 self.log_output = log_output
83 self.log_output = log_output
83 self.log_raw_input = log_raw_input
84 self.log_raw_input = log_raw_input
84
85
85 # init depending on the log mode requested
86 # init depending on the log mode requested
86 isfile = os.path.isfile
87 isfile = os.path.isfile
87 logmode = self.logmode
88 logmode = self.logmode
88
89
89 if logmode == 'append':
90 if logmode == 'append':
90 self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
91 self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
91
92
92 elif logmode == 'backup':
93 elif logmode == 'backup':
93 if isfile(self.logfname):
94 if isfile(self.logfname):
94 backup_logname = self.logfname+'~'
95 backup_logname = self.logfname+'~'
95 # Manually remove any old backup, since os.rename may fail
96 # Manually remove any old backup, since os.rename may fail
96 # under Windows.
97 # under Windows.
97 if isfile(backup_logname):
98 if isfile(backup_logname):
98 os.remove(backup_logname)
99 os.remove(backup_logname)
99 os.rename(self.logfname,backup_logname)
100 os.rename(self.logfname,backup_logname)
100 self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
101 self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
101
102
102 elif logmode == 'global':
103 elif logmode == 'global':
103 self.logfname = os.path.join(self.home_dir,self.logfname)
104 self.logfname = os.path.join(self.home_dir,self.logfname)
104 self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
105 self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
105
106
106 elif logmode == 'over':
107 elif logmode == 'over':
107 if isfile(self.logfname):
108 if isfile(self.logfname):
108 os.remove(self.logfname)
109 os.remove(self.logfname)
109 self.logfile = io.open(self.logfname,'w', encoding='utf-8')
110 self.logfile = io.open(self.logfname,'w', encoding='utf-8')
110
111
111 elif logmode == 'rotate':
112 elif logmode == 'rotate':
112 if isfile(self.logfname):
113 if isfile(self.logfname):
113 if isfile(self.logfname+'.001~'):
114 if isfile(self.logfname+'.001~'):
114 old = glob.glob(self.logfname+'.*~')
115 old = glob.glob(self.logfname+'.*~')
115 old.sort()
116 old.sort()
116 old.reverse()
117 old.reverse()
117 for f in old:
118 for f in old:
118 root, ext = os.path.splitext(f)
119 root, ext = os.path.splitext(f)
119 num = int(ext[1:-1])+1
120 num = int(ext[1:-1])+1
120 os.rename(f, root+'.'+repr(num).zfill(3)+'~')
121 os.rename(f, root+'.'+repr(num).zfill(3)+'~')
121 os.rename(self.logfname, self.logfname+'.001~')
122 os.rename(self.logfname, self.logfname+'.001~')
122 self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
123 self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
123
124
124 if logmode != 'append':
125 if logmode != 'append':
125 self.logfile.write(self.loghead)
126 self.logfile.write(self.loghead)
126
127
127 self.logfile.flush()
128 self.logfile.flush()
128 self.log_active = True
129 self.log_active = True
129
130
130 def switch_log(self,val):
131 def switch_log(self,val):
131 """Switch logging on/off. val should be ONLY a boolean."""
132 """Switch logging on/off. val should be ONLY a boolean."""
132
133
133 if val not in [False,True,0,1]:
134 if val not in [False,True,0,1]:
134 raise ValueError('Call switch_log ONLY with a boolean argument, '
135 raise ValueError('Call switch_log ONLY with a boolean argument, '
135 'not with: %s' % val)
136 'not with: %s' % val)
136
137
137 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
138 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
138
139
139 if self.logfile is None:
140 if self.logfile is None:
140 print """
141 print("""
141 Logging hasn't been started yet (use logstart for that).
142 Logging hasn't been started yet (use logstart for that).
142
143
143 %logon/%logoff are for temporarily starting and stopping logging for a logfile
144 %logon/%logoff are for temporarily starting and stopping logging for a logfile
144 which already exists. But you must first start the logging process with
145 which already exists. But you must first start the logging process with
145 %logstart (optionally giving a logfile name)."""
146 %logstart (optionally giving a logfile name).""")
146
147
147 else:
148 else:
148 if self.log_active == val:
149 if self.log_active == val:
149 print 'Logging is already',label[val]
150 print('Logging is already',label[val])
150 else:
151 else:
151 print 'Switching logging',label[val]
152 print('Switching logging',label[val])
152 self.log_active = not self.log_active
153 self.log_active = not self.log_active
153 self.log_active_out = self.log_active
154 self.log_active_out = self.log_active
154
155
155 def logstate(self):
156 def logstate(self):
156 """Print a status message about the logger."""
157 """Print a status message about the logger."""
157 if self.logfile is None:
158 if self.logfile is None:
158 print 'Logging has not been activated.'
159 print('Logging has not been activated.')
159 else:
160 else:
160 state = self.log_active and 'active' or 'temporarily suspended'
161 state = self.log_active and 'active' or 'temporarily suspended'
161 print 'Filename :',self.logfname
162 print('Filename :',self.logfname)
162 print 'Mode :',self.logmode
163 print('Mode :',self.logmode)
163 print 'Output logging :',self.log_output
164 print('Output logging :',self.log_output)
164 print 'Raw input log :',self.log_raw_input
165 print('Raw input log :',self.log_raw_input)
165 print 'Timestamping :',self.timestamp
166 print('Timestamping :',self.timestamp)
166 print 'State :',state
167 print('State :',state)
167
168
168 def log(self, line_mod, line_ori):
169 def log(self, line_mod, line_ori):
169 """Write the sources to a log.
170 """Write the sources to a log.
170
171
171 Inputs:
172 Inputs:
172
173
173 - line_mod: possibly modified input, such as the transformations made
174 - line_mod: possibly modified input, such as the transformations made
174 by input prefilters or input handlers of various kinds. This should
175 by input prefilters or input handlers of various kinds. This should
175 always be valid Python.
176 always be valid Python.
176
177
177 - line_ori: unmodified input line from the user. This is not
178 - line_ori: unmodified input line from the user. This is not
178 necessarily valid Python.
179 necessarily valid Python.
179 """
180 """
180
181
181 # Write the log line, but decide which one according to the
182 # Write the log line, but decide which one according to the
182 # log_raw_input flag, set when the log is started.
183 # log_raw_input flag, set when the log is started.
183 if self.log_raw_input:
184 if self.log_raw_input:
184 self.log_write(line_ori)
185 self.log_write(line_ori)
185 else:
186 else:
186 self.log_write(line_mod)
187 self.log_write(line_mod)
187
188
188 def log_write(self, data, kind='input'):
189 def log_write(self, data, kind='input'):
189 """Write data to the log file, if active"""
190 """Write data to the log file, if active"""
190
191
191 #print 'data: %r' % data # dbg
192 #print 'data: %r' % data # dbg
192 if self.log_active and data:
193 if self.log_active and data:
193 write = self.logfile.write
194 write = self.logfile.write
194 if kind=='input':
195 if kind=='input':
195 if self.timestamp:
196 if self.timestamp:
196 write(str_to_unicode(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
197 write(str_to_unicode(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
197 time.localtime())))
198 time.localtime())))
198 write(data)
199 write(data)
199 elif kind=='output' and self.log_output:
200 elif kind=='output' and self.log_output:
200 odata = u'\n'.join([u'#[Out]# %s' % s
201 odata = u'\n'.join([u'#[Out]# %s' % s
201 for s in data.splitlines()])
202 for s in data.splitlines()])
202 write(u'%s\n' % odata)
203 write(u'%s\n' % odata)
203 self.logfile.flush()
204 self.logfile.flush()
204
205
205 def logstop(self):
206 def logstop(self):
206 """Fully stop logging and close log file.
207 """Fully stop logging and close log file.
207
208
208 In order to start logging again, a new logstart() call needs to be
209 In order to start logging again, a new logstart() call needs to be
209 made, possibly (though not necessarily) with a new filename, mode and
210 made, possibly (though not necessarily) with a new filename, mode and
210 other options."""
211 other options."""
211
212
212 if self.logfile is not None:
213 if self.logfile is not None:
213 self.logfile.close()
214 self.logfile.close()
214 self.logfile = None
215 self.logfile = None
215 else:
216 else:
216 print "Logging hadn't been started."
217 print("Logging hadn't been started.")
217 self.log_active = False
218 self.log_active = False
218
219
219 # For backwards compatibility, in case anyone was using this.
220 # For backwards compatibility, in case anyone was using this.
220 close_log = logstop
221 close_log = logstop
@@ -1,688 +1,689 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3 """
3 """
4 from __future__ import print_function
4
5
5 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
9
10
10 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
13
14
14 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
15 # Imports
16 # Imports
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17 # Stdlib
18 # Stdlib
18 import os
19 import os
19 import re
20 import re
20 import sys
21 import sys
21 import types
22 import types
22 from getopt import getopt, GetoptError
23 from getopt import getopt, GetoptError
23
24
24 # Our own
25 # Our own
25 from IPython.config.configurable import Configurable
26 from IPython.config.configurable import Configurable
26 from IPython.core import oinspect
27 from IPython.core import oinspect
27 from IPython.core.error import UsageError
28 from IPython.core.error import UsageError
28 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
29 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
29 from IPython.external.decorator import decorator
30 from IPython.external.decorator import decorator
30 from IPython.utils.ipstruct import Struct
31 from IPython.utils.ipstruct import Struct
31 from IPython.utils.process import arg_split
32 from IPython.utils.process import arg_split
32 from IPython.utils.text import dedent
33 from IPython.utils.text import dedent
33 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
34 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
34 from IPython.utils.warn import error
35 from IPython.utils.warn import error
35
36
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37 # Globals
38 # Globals
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39
40
40 # A dict we'll use for each class that has magics, used as temporary storage to
41 # 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
42 # pass information between the @line/cell_magic method decorators and the
42 # @magics_class class decorator, because the method decorators have no
43 # @magics_class class decorator, because the method decorators have no
43 # access to the class when they run. See for more details:
44 # 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
45 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
45
46
46 magics = dict(line={}, cell={})
47 magics = dict(line={}, cell={})
47
48
48 magic_kinds = ('line', 'cell')
49 magic_kinds = ('line', 'cell')
49 magic_spec = ('line', 'cell', 'line_cell')
50 magic_spec = ('line', 'cell', 'line_cell')
50 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
51 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
51
52
52 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
53 # Utility classes and functions
54 # Utility classes and functions
54 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
55
56
56 class Bunch: pass
57 class Bunch: pass
57
58
58
59
59 def on_off(tag):
60 def on_off(tag):
60 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
61 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
61 return ['OFF','ON'][tag]
62 return ['OFF','ON'][tag]
62
63
63
64
64 def compress_dhist(dh):
65 def compress_dhist(dh):
65 """Compress a directory history into a new one with at most 20 entries.
66 """Compress a directory history into a new one with at most 20 entries.
66
67
67 Return a new list made from the first and last 10 elements of dhist after
68 Return a new list made from the first and last 10 elements of dhist after
68 removal of duplicates.
69 removal of duplicates.
69 """
70 """
70 head, tail = dh[:-10], dh[-10:]
71 head, tail = dh[:-10], dh[-10:]
71
72
72 newhead = []
73 newhead = []
73 done = set()
74 done = set()
74 for h in head:
75 for h in head:
75 if h in done:
76 if h in done:
76 continue
77 continue
77 newhead.append(h)
78 newhead.append(h)
78 done.add(h)
79 done.add(h)
79
80
80 return newhead + tail
81 return newhead + tail
81
82
82
83
83 def needs_local_scope(func):
84 def needs_local_scope(func):
84 """Decorator to mark magic functions which need to local scope to run."""
85 """Decorator to mark magic functions which need to local scope to run."""
85 func.needs_local_scope = True
86 func.needs_local_scope = True
86 return func
87 return func
87
88
88 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
89 # Class and method decorators for registering magics
90 # Class and method decorators for registering magics
90 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
91
92
92 def magics_class(cls):
93 def magics_class(cls):
93 """Class decorator for all subclasses of the main Magics class.
94 """Class decorator for all subclasses of the main Magics class.
94
95
95 Any class that subclasses Magics *must* also apply this decorator, to
96 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
97 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
98 get correctly registered in the class instance. This is necessary because
98 when method decorators run, the class does not exist yet, so they
99 when method decorators run, the class does not exist yet, so they
99 temporarily store their information into a module global. Application of
100 temporarily store their information into a module global. Application of
100 this class decorator copies that global data to the class instance and
101 this class decorator copies that global data to the class instance and
101 clears the global.
102 clears the global.
102
103
103 Obviously, this mechanism is not thread-safe, which means that the
104 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
105 *creation* of subclasses of Magic should only be done in a single-thread
105 context. Instantiation of the classes has no restrictions. Given that
106 context. Instantiation of the classes has no restrictions. Given that
106 these classes are typically created at IPython startup time and before user
107 these classes are typically created at IPython startup time and before user
107 application code becomes active, in practice this should not pose any
108 application code becomes active, in practice this should not pose any
108 problems.
109 problems.
109 """
110 """
110 cls.registered = True
111 cls.registered = True
111 cls.magics = dict(line = magics['line'],
112 cls.magics = dict(line = magics['line'],
112 cell = magics['cell'])
113 cell = magics['cell'])
113 magics['line'] = {}
114 magics['line'] = {}
114 magics['cell'] = {}
115 magics['cell'] = {}
115 return cls
116 return cls
116
117
117
118
118 def record_magic(dct, magic_kind, magic_name, func):
119 def record_magic(dct, magic_kind, magic_name, func):
119 """Utility function to store a function as a magic of a specific kind.
120 """Utility function to store a function as a magic of a specific kind.
120
121
121 Parameters
122 Parameters
122 ----------
123 ----------
123 dct : dict
124 dct : dict
124 A dictionary with 'line' and 'cell' subdicts.
125 A dictionary with 'line' and 'cell' subdicts.
125
126
126 magic_kind : str
127 magic_kind : str
127 Kind of magic to be stored.
128 Kind of magic to be stored.
128
129
129 magic_name : str
130 magic_name : str
130 Key to store the magic as.
131 Key to store the magic as.
131
132
132 func : function
133 func : function
133 Callable object to store.
134 Callable object to store.
134 """
135 """
135 if magic_kind == 'line_cell':
136 if magic_kind == 'line_cell':
136 dct['line'][magic_name] = dct['cell'][magic_name] = func
137 dct['line'][magic_name] = dct['cell'][magic_name] = func
137 else:
138 else:
138 dct[magic_kind][magic_name] = func
139 dct[magic_kind][magic_name] = func
139
140
140
141
141 def validate_type(magic_kind):
142 def validate_type(magic_kind):
142 """Ensure that the given magic_kind is valid.
143 """Ensure that the given magic_kind is valid.
143
144
144 Check that the given magic_kind is one of the accepted spec types (stored
145 Check that the given magic_kind is one of the accepted spec types (stored
145 in the global `magic_spec`), raise ValueError otherwise.
146 in the global `magic_spec`), raise ValueError otherwise.
146 """
147 """
147 if magic_kind not in magic_spec:
148 if magic_kind not in magic_spec:
148 raise ValueError('magic_kind must be one of %s, %s given' %
149 raise ValueError('magic_kind must be one of %s, %s given' %
149 magic_kinds, magic_kind)
150 magic_kinds, magic_kind)
150
151
151
152
152 # The docstrings for the decorator below will be fairly similar for the two
153 # 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
154 # types (method and function), so we generate them here once and reuse the
154 # templates below.
155 # templates below.
155 _docstring_template = \
156 _docstring_template = \
156 """Decorate the given {0} as {1} magic.
157 """Decorate the given {0} as {1} magic.
157
158
158 The decorator can be used with or without arguments, as follows.
159 The decorator can be used with or without arguments, as follows.
159
160
160 i) without arguments: it will create a {1} magic named as the {0} being
161 i) without arguments: it will create a {1} magic named as the {0} being
161 decorated::
162 decorated::
162
163
163 @deco
164 @deco
164 def foo(...)
165 def foo(...)
165
166
166 will create a {1} magic named `foo`.
167 will create a {1} magic named `foo`.
167
168
168 ii) with one string argument: which will be used as the actual name of the
169 ii) with one string argument: which will be used as the actual name of the
169 resulting magic::
170 resulting magic::
170
171
171 @deco('bar')
172 @deco('bar')
172 def foo(...)
173 def foo(...)
173
174
174 will create a {1} magic named `bar`.
175 will create a {1} magic named `bar`.
175 """
176 """
176
177
177 # These two are decorator factories. While they are conceptually very similar,
178 # 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
179 # 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
180 # written as completely standalone functions rather than trying to share code
180 # and make a single one with convoluted logic.
181 # and make a single one with convoluted logic.
181
182
182 def _method_magic_marker(magic_kind):
183 def _method_magic_marker(magic_kind):
183 """Decorator factory for methods in Magics subclasses.
184 """Decorator factory for methods in Magics subclasses.
184 """
185 """
185
186
186 validate_type(magic_kind)
187 validate_type(magic_kind)
187
188
188 # This is a closure to capture the magic_kind. We could also use a class,
189 # 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.
190 # but it's overkill for just that one bit of state.
190 def magic_deco(arg):
191 def magic_deco(arg):
191 call = lambda f, *a, **k: f(*a, **k)
192 call = lambda f, *a, **k: f(*a, **k)
192
193
193 if callable(arg):
194 if callable(arg):
194 # "Naked" decorator call (just @foo, no args)
195 # "Naked" decorator call (just @foo, no args)
195 func = arg
196 func = arg
196 name = func.func_name
197 name = func.func_name
197 retval = decorator(call, func)
198 retval = decorator(call, func)
198 record_magic(magics, magic_kind, name, name)
199 record_magic(magics, magic_kind, name, name)
199 elif isinstance(arg, basestring):
200 elif isinstance(arg, basestring):
200 # Decorator called with arguments (@foo('bar'))
201 # Decorator called with arguments (@foo('bar'))
201 name = arg
202 name = arg
202 def mark(func, *a, **kw):
203 def mark(func, *a, **kw):
203 record_magic(magics, magic_kind, name, func.func_name)
204 record_magic(magics, magic_kind, name, func.func_name)
204 return decorator(call, func)
205 return decorator(call, func)
205 retval = mark
206 retval = mark
206 else:
207 else:
207 raise TypeError("Decorator can only be called with "
208 raise TypeError("Decorator can only be called with "
208 "string or function")
209 "string or function")
209 return retval
210 return retval
210
211
211 # Ensure the resulting decorator has a usable docstring
212 # Ensure the resulting decorator has a usable docstring
212 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
213 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
213 return magic_deco
214 return magic_deco
214
215
215
216
216 def _function_magic_marker(magic_kind):
217 def _function_magic_marker(magic_kind):
217 """Decorator factory for standalone functions.
218 """Decorator factory for standalone functions.
218 """
219 """
219 validate_type(magic_kind)
220 validate_type(magic_kind)
220
221
221 # This is a closure to capture the magic_kind. We could also use a class,
222 # 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.
223 # but it's overkill for just that one bit of state.
223 def magic_deco(arg):
224 def magic_deco(arg):
224 call = lambda f, *a, **k: f(*a, **k)
225 call = lambda f, *a, **k: f(*a, **k)
225
226
226 # Find get_ipython() in the caller's namespace
227 # Find get_ipython() in the caller's namespace
227 caller = sys._getframe(1)
228 caller = sys._getframe(1)
228 for ns in ['f_locals', 'f_globals', 'f_builtins']:
229 for ns in ['f_locals', 'f_globals', 'f_builtins']:
229 get_ipython = getattr(caller, ns).get('get_ipython')
230 get_ipython = getattr(caller, ns).get('get_ipython')
230 if get_ipython is not None:
231 if get_ipython is not None:
231 break
232 break
232 else:
233 else:
233 raise NameError('Decorator can only run in context where '
234 raise NameError('Decorator can only run in context where '
234 '`get_ipython` exists')
235 '`get_ipython` exists')
235
236
236 ip = get_ipython()
237 ip = get_ipython()
237
238
238 if callable(arg):
239 if callable(arg):
239 # "Naked" decorator call (just @foo, no args)
240 # "Naked" decorator call (just @foo, no args)
240 func = arg
241 func = arg
241 name = func.func_name
242 name = func.func_name
242 ip.register_magic_function(func, magic_kind, name)
243 ip.register_magic_function(func, magic_kind, name)
243 retval = decorator(call, func)
244 retval = decorator(call, func)
244 elif isinstance(arg, basestring):
245 elif isinstance(arg, basestring):
245 # Decorator called with arguments (@foo('bar'))
246 # Decorator called with arguments (@foo('bar'))
246 name = arg
247 name = arg
247 def mark(func, *a, **kw):
248 def mark(func, *a, **kw):
248 ip.register_magic_function(func, magic_kind, name)
249 ip.register_magic_function(func, magic_kind, name)
249 return decorator(call, func)
250 return decorator(call, func)
250 retval = mark
251 retval = mark
251 else:
252 else:
252 raise TypeError("Decorator can only be called with "
253 raise TypeError("Decorator can only be called with "
253 "string or function")
254 "string or function")
254 return retval
255 return retval
255
256
256 # Ensure the resulting decorator has a usable docstring
257 # Ensure the resulting decorator has a usable docstring
257 ds = _docstring_template.format('function', magic_kind)
258 ds = _docstring_template.format('function', magic_kind)
258
259
259 ds += dedent("""
260 ds += dedent("""
260 Note: this decorator can only be used in a context where IPython is already
261 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
262 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
263 it in your startup files loaded after IPython initializes, but *not* in the
263 IPython configuration file itself, which is executed before IPython is
264 IPython configuration file itself, which is executed before IPython is
264 fully up and running. Any file located in the `startup` subdirectory of
265 fully up and running. Any file located in the `startup` subdirectory of
265 your configuration profile will be OK in this sense.
266 your configuration profile will be OK in this sense.
266 """)
267 """)
267
268
268 magic_deco.__doc__ = ds
269 magic_deco.__doc__ = ds
269 return magic_deco
270 return magic_deco
270
271
271
272
272 # Create the actual decorators for public use
273 # Create the actual decorators for public use
273
274
274 # These three are used to decorate methods in class definitions
275 # These three are used to decorate methods in class definitions
275 line_magic = _method_magic_marker('line')
276 line_magic = _method_magic_marker('line')
276 cell_magic = _method_magic_marker('cell')
277 cell_magic = _method_magic_marker('cell')
277 line_cell_magic = _method_magic_marker('line_cell')
278 line_cell_magic = _method_magic_marker('line_cell')
278
279
279 # These three decorate standalone functions and perform the decoration
280 # These three decorate standalone functions and perform the decoration
280 # immediately. They can only run where get_ipython() works
281 # immediately. They can only run where get_ipython() works
281 register_line_magic = _function_magic_marker('line')
282 register_line_magic = _function_magic_marker('line')
282 register_cell_magic = _function_magic_marker('cell')
283 register_cell_magic = _function_magic_marker('cell')
283 register_line_cell_magic = _function_magic_marker('line_cell')
284 register_line_cell_magic = _function_magic_marker('line_cell')
284
285
285 #-----------------------------------------------------------------------------
286 #-----------------------------------------------------------------------------
286 # Core Magic classes
287 # Core Magic classes
287 #-----------------------------------------------------------------------------
288 #-----------------------------------------------------------------------------
288
289
289 class MagicsManager(Configurable):
290 class MagicsManager(Configurable):
290 """Object that handles all magic-related functionality for IPython.
291 """Object that handles all magic-related functionality for IPython.
291 """
292 """
292 # Non-configurable class attributes
293 # Non-configurable class attributes
293
294
294 # A two-level dict, first keyed by magic type, then by magic function, and
295 # 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
296 # holding the actual callable object as value. This is the dict used for
296 # magic function dispatch
297 # magic function dispatch
297 magics = Dict
298 magics = Dict
298
299
299 # A registry of the original objects that we've been given holding magics.
300 # A registry of the original objects that we've been given holding magics.
300 registry = Dict
301 registry = Dict
301
302
302 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
303 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
303
304
304 auto_magic = Bool(True, config=True, help=
305 auto_magic = Bool(True, config=True, help=
305 "Automatically call line magics without requiring explicit % prefix")
306 "Automatically call line magics without requiring explicit % prefix")
306
307
307 def _auto_magic_changed(self, name, value):
308 def _auto_magic_changed(self, name, value):
308 self.shell.automagic = value
309 self.shell.automagic = value
309
310
310 _auto_status = [
311 _auto_status = [
311 'Automagic is OFF, % prefix IS needed for line magics.',
312 'Automagic is OFF, % prefix IS needed for line magics.',
312 'Automagic is ON, % prefix IS NOT needed for line magics.']
313 'Automagic is ON, % prefix IS NOT needed for line magics.']
313
314
314 user_magics = Instance('IPython.core.magics.UserMagics')
315 user_magics = Instance('IPython.core.magics.UserMagics')
315
316
316 def __init__(self, shell=None, config=None, user_magics=None, **traits):
317 def __init__(self, shell=None, config=None, user_magics=None, **traits):
317
318
318 super(MagicsManager, self).__init__(shell=shell, config=config,
319 super(MagicsManager, self).__init__(shell=shell, config=config,
319 user_magics=user_magics, **traits)
320 user_magics=user_magics, **traits)
320 self.magics = dict(line={}, cell={})
321 self.magics = dict(line={}, cell={})
321 # Let's add the user_magics to the registry for uniformity, so *all*
322 # Let's add the user_magics to the registry for uniformity, so *all*
322 # registered magic containers can be found there.
323 # registered magic containers can be found there.
323 self.registry[user_magics.__class__.__name__] = user_magics
324 self.registry[user_magics.__class__.__name__] = user_magics
324
325
325 def auto_status(self):
326 def auto_status(self):
326 """Return descriptive string with automagic status."""
327 """Return descriptive string with automagic status."""
327 return self._auto_status[self.auto_magic]
328 return self._auto_status[self.auto_magic]
328
329
329 def lsmagic(self):
330 def lsmagic(self):
330 """Return a dict of currently available magic functions.
331 """Return a dict of currently available magic functions.
331
332
332 The return dict has the keys 'line' and 'cell', corresponding to the
333 The return dict has the keys 'line' and 'cell', corresponding to the
333 two types of magics we support. Each value is a list of names.
334 two types of magics we support. Each value is a list of names.
334 """
335 """
335 return self.magics
336 return self.magics
336
337
337 def lsmagic_docs(self, brief=False, missing=''):
338 def lsmagic_docs(self, brief=False, missing=''):
338 """Return dict of documentation of magic functions.
339 """Return dict of documentation of magic functions.
339
340
340 The return dict has the keys 'line' and 'cell', corresponding to the
341 The return dict has the keys 'line' and 'cell', corresponding to the
341 two types of magics we support. Each value is a dict keyed by magic
342 two types of magics we support. Each value is a dict keyed by magic
342 name whose value is the function docstring. If a docstring is
343 name whose value is the function docstring. If a docstring is
343 unavailable, the value of `missing` is used instead.
344 unavailable, the value of `missing` is used instead.
344
345
345 If brief is True, only the first line of each docstring will be returned.
346 If brief is True, only the first line of each docstring will be returned.
346 """
347 """
347 docs = {}
348 docs = {}
348 for m_type in self.magics:
349 for m_type in self.magics:
349 m_docs = {}
350 m_docs = {}
350 for m_name, m_func in self.magics[m_type].iteritems():
351 for m_name, m_func in self.magics[m_type].iteritems():
351 if m_func.__doc__:
352 if m_func.__doc__:
352 if brief:
353 if brief:
353 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
354 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
354 else:
355 else:
355 m_docs[m_name] = m_func.__doc__.rstrip()
356 m_docs[m_name] = m_func.__doc__.rstrip()
356 else:
357 else:
357 m_docs[m_name] = missing
358 m_docs[m_name] = missing
358 docs[m_type] = m_docs
359 docs[m_type] = m_docs
359 return docs
360 return docs
360
361
361 def register(self, *magic_objects):
362 def register(self, *magic_objects):
362 """Register one or more instances of Magics.
363 """Register one or more instances of Magics.
363
364
364 Take one or more classes or instances of classes that subclass the main
365 Take one or more classes or instances of classes that subclass the main
365 `core.Magic` class, and register them with IPython to use the magic
366 `core.Magic` class, and register them with IPython to use the magic
366 functions they provide. The registration process will then ensure that
367 functions they provide. The registration process will then ensure that
367 any methods that have decorated to provide line and/or cell magics will
368 any methods that have decorated to provide line and/or cell magics will
368 be recognized with the `%x`/`%%x` syntax as a line/cell magic
369 be recognized with the `%x`/`%%x` syntax as a line/cell magic
369 respectively.
370 respectively.
370
371
371 If classes are given, they will be instantiated with the default
372 If classes are given, they will be instantiated with the default
372 constructor. If your classes need a custom constructor, you should
373 constructor. If your classes need a custom constructor, you should
373 instanitate them first and pass the instance.
374 instanitate them first and pass the instance.
374
375
375 The provided arguments can be an arbitrary mix of classes and instances.
376 The provided arguments can be an arbitrary mix of classes and instances.
376
377
377 Parameters
378 Parameters
378 ----------
379 ----------
379 magic_objects : one or more classes or instances
380 magic_objects : one or more classes or instances
380 """
381 """
381 # Start by validating them to ensure they have all had their magic
382 # Start by validating them to ensure they have all had their magic
382 # methods registered at the instance level
383 # methods registered at the instance level
383 for m in magic_objects:
384 for m in magic_objects:
384 if not m.registered:
385 if not m.registered:
385 raise ValueError("Class of magics %r was constructed without "
386 raise ValueError("Class of magics %r was constructed without "
386 "the @register_magics class decorator")
387 "the @register_magics class decorator")
387 if type(m) in (type, MetaHasTraits):
388 if type(m) in (type, MetaHasTraits):
388 # If we're given an uninstantiated class
389 # If we're given an uninstantiated class
389 m = m(shell=self.shell)
390 m = m(shell=self.shell)
390
391
391 # Now that we have an instance, we can register it and update the
392 # Now that we have an instance, we can register it and update the
392 # table of callables
393 # table of callables
393 self.registry[m.__class__.__name__] = m
394 self.registry[m.__class__.__name__] = m
394 for mtype in magic_kinds:
395 for mtype in magic_kinds:
395 self.magics[mtype].update(m.magics[mtype])
396 self.magics[mtype].update(m.magics[mtype])
396
397
397 def register_function(self, func, magic_kind='line', magic_name=None):
398 def register_function(self, func, magic_kind='line', magic_name=None):
398 """Expose a standalone function as magic function for IPython.
399 """Expose a standalone function as magic function for IPython.
399
400
400 This will create an IPython magic (line, cell or both) from a
401 This will create an IPython magic (line, cell or both) from a
401 standalone function. The functions should have the following
402 standalone function. The functions should have the following
402 signatures:
403 signatures:
403
404
404 * For line magics: `def f(line)`
405 * For line magics: `def f(line)`
405 * For cell magics: `def f(line, cell)`
406 * For cell magics: `def f(line, cell)`
406 * For a function that does both: `def f(line, cell=None)`
407 * For a function that does both: `def f(line, cell=None)`
407
408
408 In the latter case, the function will be called with `cell==None` when
409 In the latter case, the function will be called with `cell==None` when
409 invoked as `%f`, and with cell as a string when invoked as `%%f`.
410 invoked as `%f`, and with cell as a string when invoked as `%%f`.
410
411
411 Parameters
412 Parameters
412 ----------
413 ----------
413 func : callable
414 func : callable
414 Function to be registered as a magic.
415 Function to be registered as a magic.
415
416
416 magic_kind : str
417 magic_kind : str
417 Kind of magic, one of 'line', 'cell' or 'line_cell'
418 Kind of magic, one of 'line', 'cell' or 'line_cell'
418
419
419 magic_name : optional str
420 magic_name : optional str
420 If given, the name the magic will have in the IPython namespace. By
421 If given, the name the magic will have in the IPython namespace. By
421 default, the name of the function itself is used.
422 default, the name of the function itself is used.
422 """
423 """
423
424
424 # Create the new method in the user_magics and register it in the
425 # Create the new method in the user_magics and register it in the
425 # global table
426 # global table
426 validate_type(magic_kind)
427 validate_type(magic_kind)
427 magic_name = func.func_name if magic_name is None else magic_name
428 magic_name = func.func_name if magic_name is None else magic_name
428 setattr(self.user_magics, magic_name, func)
429 setattr(self.user_magics, magic_name, func)
429 record_magic(self.magics, magic_kind, magic_name, func)
430 record_magic(self.magics, magic_kind, magic_name, func)
430
431
431 def define_magic(self, name, func):
432 def define_magic(self, name, func):
432 """[Deprecated] Expose own function as magic function for IPython.
433 """[Deprecated] Expose own function as magic function for IPython.
433
434
434 Example::
435 Example::
435
436
436 def foo_impl(self, parameter_s=''):
437 def foo_impl(self, parameter_s=''):
437 'My very own magic!. (Use docstrings, IPython reads them).'
438 'My very own magic!. (Use docstrings, IPython reads them).'
438 print 'Magic function. Passed parameter is between < >:'
439 print 'Magic function. Passed parameter is between < >:'
439 print '<%s>' % parameter_s
440 print '<%s>' % parameter_s
440 print 'The self object is:', self
441 print 'The self object is:', self
441
442
442 ip.define_magic('foo',foo_impl)
443 ip.define_magic('foo',foo_impl)
443 """
444 """
444 meth = types.MethodType(func, self.user_magics)
445 meth = types.MethodType(func, self.user_magics)
445 setattr(self.user_magics, name, meth)
446 setattr(self.user_magics, name, meth)
446 record_magic(self.magics, 'line', name, meth)
447 record_magic(self.magics, 'line', name, meth)
447
448
448 def register_alias(self, alias_name, magic_name, magic_kind='line'):
449 def register_alias(self, alias_name, magic_name, magic_kind='line'):
449 """Register an alias to a magic function.
450 """Register an alias to a magic function.
450
451
451 The alias is an instance of :class:`MagicAlias`, which holds the
452 The alias is an instance of :class:`MagicAlias`, which holds the
452 name and kind of the magic it should call. Binding is done at
453 name and kind of the magic it should call. Binding is done at
453 call time, so if the underlying magic function is changed the alias
454 call time, so if the underlying magic function is changed the alias
454 will call the new function.
455 will call the new function.
455
456
456 Parameters
457 Parameters
457 ----------
458 ----------
458 alias_name : str
459 alias_name : str
459 The name of the magic to be registered.
460 The name of the magic to be registered.
460
461
461 magic_name : str
462 magic_name : str
462 The name of an existing magic.
463 The name of an existing magic.
463
464
464 magic_kind : str
465 magic_kind : str
465 Kind of magic, one of 'line' or 'cell'
466 Kind of magic, one of 'line' or 'cell'
466 """
467 """
467
468
468 # `validate_type` is too permissive, as it allows 'line_cell'
469 # `validate_type` is too permissive, as it allows 'line_cell'
469 # which we do not handle.
470 # which we do not handle.
470 if magic_kind not in magic_kinds:
471 if magic_kind not in magic_kinds:
471 raise ValueError('magic_kind must be one of %s, %s given' %
472 raise ValueError('magic_kind must be one of %s, %s given' %
472 magic_kinds, magic_kind)
473 magic_kinds, magic_kind)
473
474
474 alias = MagicAlias(self.shell, magic_name, magic_kind)
475 alias = MagicAlias(self.shell, magic_name, magic_kind)
475 setattr(self.user_magics, alias_name, alias)
476 setattr(self.user_magics, alias_name, alias)
476 record_magic(self.magics, magic_kind, alias_name, alias)
477 record_magic(self.magics, magic_kind, alias_name, alias)
477
478
478 # Key base class that provides the central functionality for magics.
479 # Key base class that provides the central functionality for magics.
479
480
480
481
481 class Magics(Configurable):
482 class Magics(Configurable):
482 """Base class for implementing magic functions.
483 """Base class for implementing magic functions.
483
484
484 Shell functions which can be reached as %function_name. All magic
485 Shell functions which can be reached as %function_name. All magic
485 functions should accept a string, which they can parse for their own
486 functions should accept a string, which they can parse for their own
486 needs. This can make some functions easier to type, eg `%cd ../`
487 needs. This can make some functions easier to type, eg `%cd ../`
487 vs. `%cd("../")`
488 vs. `%cd("../")`
488
489
489 Classes providing magic functions need to subclass this class, and they
490 Classes providing magic functions need to subclass this class, and they
490 MUST:
491 MUST:
491
492
492 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
493 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
493 individual methods as magic functions, AND
494 individual methods as magic functions, AND
494
495
495 - Use the class decorator `@magics_class` to ensure that the magic
496 - Use the class decorator `@magics_class` to ensure that the magic
496 methods are properly registered at the instance level upon instance
497 methods are properly registered at the instance level upon instance
497 initialization.
498 initialization.
498
499
499 See :mod:`magic_functions` for examples of actual implementation classes.
500 See :mod:`magic_functions` for examples of actual implementation classes.
500 """
501 """
501 # Dict holding all command-line options for each magic.
502 # Dict holding all command-line options for each magic.
502 options_table = None
503 options_table = None
503 # Dict for the mapping of magic names to methods, set by class decorator
504 # Dict for the mapping of magic names to methods, set by class decorator
504 magics = None
505 magics = None
505 # Flag to check that the class decorator was properly applied
506 # Flag to check that the class decorator was properly applied
506 registered = False
507 registered = False
507 # Instance of IPython shell
508 # Instance of IPython shell
508 shell = None
509 shell = None
509
510
510 def __init__(self, shell=None, **kwargs):
511 def __init__(self, shell=None, **kwargs):
511 if not(self.__class__.registered):
512 if not(self.__class__.registered):
512 raise ValueError('Magics subclass without registration - '
513 raise ValueError('Magics subclass without registration - '
513 'did you forget to apply @magics_class?')
514 'did you forget to apply @magics_class?')
514 if shell is not None:
515 if shell is not None:
515 if hasattr(shell, 'configurables'):
516 if hasattr(shell, 'configurables'):
516 shell.configurables.append(self)
517 shell.configurables.append(self)
517 if hasattr(shell, 'config'):
518 if hasattr(shell, 'config'):
518 kwargs.setdefault('parent', shell)
519 kwargs.setdefault('parent', shell)
519 kwargs['shell'] = shell
520 kwargs['shell'] = shell
520
521
521 self.shell = shell
522 self.shell = shell
522 self.options_table = {}
523 self.options_table = {}
523 # The method decorators are run when the instance doesn't exist yet, so
524 # The method decorators are run when the instance doesn't exist yet, so
524 # they can only record the names of the methods they are supposed to
525 # they can only record the names of the methods they are supposed to
525 # grab. Only now, that the instance exists, can we create the proper
526 # grab. Only now, that the instance exists, can we create the proper
526 # mapping to bound methods. So we read the info off the original names
527 # mapping to bound methods. So we read the info off the original names
527 # table and replace each method name by the actual bound method.
528 # table and replace each method name by the actual bound method.
528 # But we mustn't clobber the *class* mapping, in case of multiple instances.
529 # But we mustn't clobber the *class* mapping, in case of multiple instances.
529 class_magics = self.magics
530 class_magics = self.magics
530 self.magics = {}
531 self.magics = {}
531 for mtype in magic_kinds:
532 for mtype in magic_kinds:
532 tab = self.magics[mtype] = {}
533 tab = self.magics[mtype] = {}
533 cls_tab = class_magics[mtype]
534 cls_tab = class_magics[mtype]
534 for magic_name, meth_name in cls_tab.iteritems():
535 for magic_name, meth_name in cls_tab.iteritems():
535 if isinstance(meth_name, basestring):
536 if isinstance(meth_name, basestring):
536 # it's a method name, grab it
537 # it's a method name, grab it
537 tab[magic_name] = getattr(self, meth_name)
538 tab[magic_name] = getattr(self, meth_name)
538 else:
539 else:
539 # it's the real thing
540 # it's the real thing
540 tab[magic_name] = meth_name
541 tab[magic_name] = meth_name
541 # Configurable **needs** to be initiated at the end or the config
542 # Configurable **needs** to be initiated at the end or the config
542 # magics get screwed up.
543 # magics get screwed up.
543 super(Magics, self).__init__(**kwargs)
544 super(Magics, self).__init__(**kwargs)
544
545
545 def arg_err(self,func):
546 def arg_err(self,func):
546 """Print docstring if incorrect arguments were passed"""
547 """Print docstring if incorrect arguments were passed"""
547 print 'Error in arguments:'
548 print('Error in arguments:')
548 print oinspect.getdoc(func)
549 print(oinspect.getdoc(func))
549
550
550 def format_latex(self, strng):
551 def format_latex(self, strng):
551 """Format a string for latex inclusion."""
552 """Format a string for latex inclusion."""
552
553
553 # Characters that need to be escaped for latex:
554 # Characters that need to be escaped for latex:
554 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
555 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
555 # Magic command names as headers:
556 # Magic command names as headers:
556 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
557 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
557 re.MULTILINE)
558 re.MULTILINE)
558 # Magic commands
559 # Magic commands
559 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
560 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
560 re.MULTILINE)
561 re.MULTILINE)
561 # Paragraph continue
562 # Paragraph continue
562 par_re = re.compile(r'\\$',re.MULTILINE)
563 par_re = re.compile(r'\\$',re.MULTILINE)
563
564
564 # The "\n" symbol
565 # The "\n" symbol
565 newline_re = re.compile(r'\\n')
566 newline_re = re.compile(r'\\n')
566
567
567 # Now build the string for output:
568 # Now build the string for output:
568 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
569 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
569 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
570 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
570 strng)
571 strng)
571 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
572 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
572 strng = par_re.sub(r'\\\\',strng)
573 strng = par_re.sub(r'\\\\',strng)
573 strng = escape_re.sub(r'\\\1',strng)
574 strng = escape_re.sub(r'\\\1',strng)
574 strng = newline_re.sub(r'\\textbackslash{}n',strng)
575 strng = newline_re.sub(r'\\textbackslash{}n',strng)
575 return strng
576 return strng
576
577
577 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
578 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
578 """Parse options passed to an argument string.
579 """Parse options passed to an argument string.
579
580
580 The interface is similar to that of getopt(), but it returns back a
581 The interface is similar to that of getopt(), but it returns back a
581 Struct with the options as keys and the stripped argument string still
582 Struct with the options as keys and the stripped argument string still
582 as a string.
583 as a string.
583
584
584 arg_str is quoted as a true sys.argv vector by using shlex.split.
585 arg_str is quoted as a true sys.argv vector by using shlex.split.
585 This allows us to easily expand variables, glob files, quote
586 This allows us to easily expand variables, glob files, quote
586 arguments, etc.
587 arguments, etc.
587
588
588 Options:
589 Options:
589 -mode: default 'string'. If given as 'list', the argument string is
590 -mode: default 'string'. If given as 'list', the argument string is
590 returned as a list (split on whitespace) instead of a string.
591 returned as a list (split on whitespace) instead of a string.
591
592
592 -list_all: put all option values in lists. Normally only options
593 -list_all: put all option values in lists. Normally only options
593 appearing more than once are put in a list.
594 appearing more than once are put in a list.
594
595
595 -posix (True): whether to split the input line in POSIX mode or not,
596 -posix (True): whether to split the input line in POSIX mode or not,
596 as per the conventions outlined in the shlex module from the
597 as per the conventions outlined in the shlex module from the
597 standard library."""
598 standard library."""
598
599
599 # inject default options at the beginning of the input line
600 # inject default options at the beginning of the input line
600 caller = sys._getframe(1).f_code.co_name
601 caller = sys._getframe(1).f_code.co_name
601 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
602 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
602
603
603 mode = kw.get('mode','string')
604 mode = kw.get('mode','string')
604 if mode not in ['string','list']:
605 if mode not in ['string','list']:
605 raise ValueError('incorrect mode given: %s' % mode)
606 raise ValueError('incorrect mode given: %s' % mode)
606 # Get options
607 # Get options
607 list_all = kw.get('list_all',0)
608 list_all = kw.get('list_all',0)
608 posix = kw.get('posix', os.name == 'posix')
609 posix = kw.get('posix', os.name == 'posix')
609 strict = kw.get('strict', True)
610 strict = kw.get('strict', True)
610
611
611 # Check if we have more than one argument to warrant extra processing:
612 # Check if we have more than one argument to warrant extra processing:
612 odict = {} # Dictionary with options
613 odict = {} # Dictionary with options
613 args = arg_str.split()
614 args = arg_str.split()
614 if len(args) >= 1:
615 if len(args) >= 1:
615 # If the list of inputs only has 0 or 1 thing in it, there's no
616 # If the list of inputs only has 0 or 1 thing in it, there's no
616 # need to look for options
617 # need to look for options
617 argv = arg_split(arg_str, posix, strict)
618 argv = arg_split(arg_str, posix, strict)
618 # Do regular option processing
619 # Do regular option processing
619 try:
620 try:
620 opts,args = getopt(argv, opt_str, long_opts)
621 opts,args = getopt(argv, opt_str, long_opts)
621 except GetoptError as e:
622 except GetoptError as e:
622 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
623 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
623 " ".join(long_opts)))
624 " ".join(long_opts)))
624 for o,a in opts:
625 for o,a in opts:
625 if o.startswith('--'):
626 if o.startswith('--'):
626 o = o[2:]
627 o = o[2:]
627 else:
628 else:
628 o = o[1:]
629 o = o[1:]
629 try:
630 try:
630 odict[o].append(a)
631 odict[o].append(a)
631 except AttributeError:
632 except AttributeError:
632 odict[o] = [odict[o],a]
633 odict[o] = [odict[o],a]
633 except KeyError:
634 except KeyError:
634 if list_all:
635 if list_all:
635 odict[o] = [a]
636 odict[o] = [a]
636 else:
637 else:
637 odict[o] = a
638 odict[o] = a
638
639
639 # Prepare opts,args for return
640 # Prepare opts,args for return
640 opts = Struct(odict)
641 opts = Struct(odict)
641 if mode == 'string':
642 if mode == 'string':
642 args = ' '.join(args)
643 args = ' '.join(args)
643
644
644 return opts,args
645 return opts,args
645
646
646 def default_option(self, fn, optstr):
647 def default_option(self, fn, optstr):
647 """Make an entry in the options_table for fn, with value optstr"""
648 """Make an entry in the options_table for fn, with value optstr"""
648
649
649 if fn not in self.lsmagic():
650 if fn not in self.lsmagic():
650 error("%s is not a magic function" % fn)
651 error("%s is not a magic function" % fn)
651 self.options_table[fn] = optstr
652 self.options_table[fn] = optstr
652
653
653
654
654 class MagicAlias(object):
655 class MagicAlias(object):
655 """An alias to another magic function.
656 """An alias to another magic function.
656
657
657 An alias is determined by its magic name and magic kind. Lookup
658 An alias is determined by its magic name and magic kind. Lookup
658 is done at call time, so if the underlying magic changes the alias
659 is done at call time, so if the underlying magic changes the alias
659 will call the new function.
660 will call the new function.
660
661
661 Use the :meth:`MagicsManager.register_alias` method or the
662 Use the :meth:`MagicsManager.register_alias` method or the
662 `%alias_magic` magic function to create and register a new alias.
663 `%alias_magic` magic function to create and register a new alias.
663 """
664 """
664 def __init__(self, shell, magic_name, magic_kind):
665 def __init__(self, shell, magic_name, magic_kind):
665 self.shell = shell
666 self.shell = shell
666 self.magic_name = magic_name
667 self.magic_name = magic_name
667 self.magic_kind = magic_kind
668 self.magic_kind = magic_kind
668
669
669 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
670 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
670 self.__doc__ = "Alias for `%s`." % self.pretty_target
671 self.__doc__ = "Alias for `%s`." % self.pretty_target
671
672
672 self._in_call = False
673 self._in_call = False
673
674
674 def __call__(self, *args, **kwargs):
675 def __call__(self, *args, **kwargs):
675 """Call the magic alias."""
676 """Call the magic alias."""
676 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
677 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
677 if fn is None:
678 if fn is None:
678 raise UsageError("Magic `%s` not found." % self.pretty_target)
679 raise UsageError("Magic `%s` not found." % self.pretty_target)
679
680
680 # Protect against infinite recursion.
681 # Protect against infinite recursion.
681 if self._in_call:
682 if self._in_call:
682 raise UsageError("Infinite recursion detected; "
683 raise UsageError("Infinite recursion detected; "
683 "magic aliases cannot call themselves.")
684 "magic aliases cannot call themselves.")
684 self._in_call = True
685 self._in_call = True
685 try:
686 try:
686 return fn(*args, **kwargs)
687 return fn(*args, **kwargs)
687 finally:
688 finally:
688 self._in_call = False
689 self._in_call = False
@@ -1,128 +1,129 b''
1 """Implementation of magic functions that control various automatic behaviors.
1 """Implementation of magic functions that control various automatic behaviors.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Our own packages
16 # Our own packages
16 from IPython.core.magic import Bunch, Magics, magics_class, line_magic
17 from IPython.core.magic import Bunch, Magics, magics_class, line_magic
17 from IPython.testing.skipdoctest import skip_doctest
18 from IPython.testing.skipdoctest import skip_doctest
18 from IPython.utils.warn import error
19 from IPython.utils.warn import error
19
20
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21 # Magic implementation classes
22 # Magic implementation classes
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23
24
24 @magics_class
25 @magics_class
25 class AutoMagics(Magics):
26 class AutoMagics(Magics):
26 """Magics that control various autoX behaviors."""
27 """Magics that control various autoX behaviors."""
27
28
28 def __init__(self, shell):
29 def __init__(self, shell):
29 super(AutoMagics, self).__init__(shell)
30 super(AutoMagics, self).__init__(shell)
30 # namespace for holding state we may need
31 # namespace for holding state we may need
31 self._magic_state = Bunch()
32 self._magic_state = Bunch()
32
33
33 @line_magic
34 @line_magic
34 def automagic(self, parameter_s=''):
35 def automagic(self, parameter_s=''):
35 """Make magic functions callable without having to type the initial %.
36 """Make magic functions callable without having to type the initial %.
36
37
37 Without argumentsl toggles on/off (when off, you must call it as
38 Without argumentsl toggles on/off (when off, you must call it as
38 %automagic, of course). With arguments it sets the value, and you can
39 %automagic, of course). With arguments it sets the value, and you can
39 use any of (case insensitive):
40 use any of (case insensitive):
40
41
41 - on, 1, True: to activate
42 - on, 1, True: to activate
42
43
43 - off, 0, False: to deactivate.
44 - off, 0, False: to deactivate.
44
45
45 Note that magic functions have lowest priority, so if there's a
46 Note that magic functions have lowest priority, so if there's a
46 variable whose name collides with that of a magic fn, automagic won't
47 variable whose name collides with that of a magic fn, automagic won't
47 work for that function (you get the variable instead). However, if you
48 work for that function (you get the variable instead). However, if you
48 delete the variable (del var), the previously shadowed magic function
49 delete the variable (del var), the previously shadowed magic function
49 becomes visible to automagic again."""
50 becomes visible to automagic again."""
50
51
51 arg = parameter_s.lower()
52 arg = parameter_s.lower()
52 mman = self.shell.magics_manager
53 mman = self.shell.magics_manager
53 if arg in ('on', '1', 'true'):
54 if arg in ('on', '1', 'true'):
54 val = True
55 val = True
55 elif arg in ('off', '0', 'false'):
56 elif arg in ('off', '0', 'false'):
56 val = False
57 val = False
57 else:
58 else:
58 val = not mman.auto_magic
59 val = not mman.auto_magic
59 mman.auto_magic = val
60 mman.auto_magic = val
60 print '\n' + self.shell.magics_manager.auto_status()
61 print('\n' + self.shell.magics_manager.auto_status())
61
62
62 @skip_doctest
63 @skip_doctest
63 @line_magic
64 @line_magic
64 def autocall(self, parameter_s=''):
65 def autocall(self, parameter_s=''):
65 """Make functions callable without having to type parentheses.
66 """Make functions callable without having to type parentheses.
66
67
67 Usage:
68 Usage:
68
69
69 %autocall [mode]
70 %autocall [mode]
70
71
71 The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
72 The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
72 value is toggled on and off (remembering the previous state).
73 value is toggled on and off (remembering the previous state).
73
74
74 In more detail, these values mean:
75 In more detail, these values mean:
75
76
76 0 -> fully disabled
77 0 -> fully disabled
77
78
78 1 -> active, but do not apply if there are no arguments on the line.
79 1 -> active, but do not apply if there are no arguments on the line.
79
80
80 In this mode, you get::
81 In this mode, you get::
81
82
82 In [1]: callable
83 In [1]: callable
83 Out[1]: <built-in function callable>
84 Out[1]: <built-in function callable>
84
85
85 In [2]: callable 'hello'
86 In [2]: callable 'hello'
86 ------> callable('hello')
87 ------> callable('hello')
87 Out[2]: False
88 Out[2]: False
88
89
89 2 -> Active always. Even if no arguments are present, the callable
90 2 -> Active always. Even if no arguments are present, the callable
90 object is called::
91 object is called::
91
92
92 In [2]: float
93 In [2]: float
93 ------> float()
94 ------> float()
94 Out[2]: 0.0
95 Out[2]: 0.0
95
96
96 Note that even with autocall off, you can still use '/' at the start of
97 Note that even with autocall off, you can still use '/' at the start of
97 a line to treat the first argument on the command line as a function
98 a line to treat the first argument on the command line as a function
98 and add parentheses to it::
99 and add parentheses to it::
99
100
100 In [8]: /str 43
101 In [8]: /str 43
101 ------> str(43)
102 ------> str(43)
102 Out[8]: '43'
103 Out[8]: '43'
103
104
104 # all-random (note for auto-testing)
105 # all-random (note for auto-testing)
105 """
106 """
106
107
107 if parameter_s:
108 if parameter_s:
108 arg = int(parameter_s)
109 arg = int(parameter_s)
109 else:
110 else:
110 arg = 'toggle'
111 arg = 'toggle'
111
112
112 if not arg in (0, 1, 2, 'toggle'):
113 if not arg in (0, 1, 2, 'toggle'):
113 error('Valid modes: (0->Off, 1->Smart, 2->Full')
114 error('Valid modes: (0->Off, 1->Smart, 2->Full')
114 return
115 return
115
116
116 if arg in (0, 1, 2):
117 if arg in (0, 1, 2):
117 self.shell.autocall = arg
118 self.shell.autocall = arg
118 else: # toggle
119 else: # toggle
119 if self.shell.autocall:
120 if self.shell.autocall:
120 self._magic_state.autocall_save = self.shell.autocall
121 self._magic_state.autocall_save = self.shell.autocall
121 self.shell.autocall = 0
122 self.shell.autocall = 0
122 else:
123 else:
123 try:
124 try:
124 self.shell.autocall = self._magic_state.autocall_save
125 self.shell.autocall = self._magic_state.autocall_save
125 except AttributeError:
126 except AttributeError:
126 self.shell.autocall = self._magic_state.autocall_save = 1
127 self.shell.autocall = self._magic_state.autocall_save = 1
127
128
128 print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall]
129 print("Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall])
@@ -1,690 +1,691 b''
1 """Implementation of code management magic functions.
1 """Implementation of code management magic functions.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Stdlib
16 # Stdlib
16 import inspect
17 import inspect
17 import io
18 import io
18 import os
19 import os
19 import re
20 import re
20 import sys
21 import sys
21 import ast
22 import ast
22 from itertools import chain
23 from itertools import chain
23
24
24 # Our own packages
25 # Our own packages
25 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
26 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
26 from IPython.core.macro import Macro
27 from IPython.core.macro import Macro
27 from IPython.core.magic import Magics, magics_class, line_magic
28 from IPython.core.magic import Magics, magics_class, line_magic
28 from IPython.core.oinspect import find_file, find_source_lines
29 from IPython.core.oinspect import find_file, find_source_lines
29 from IPython.testing.skipdoctest import skip_doctest
30 from IPython.testing.skipdoctest import skip_doctest
30 from IPython.utils import py3compat
31 from IPython.utils import py3compat
31 from IPython.utils.contexts import preserve_keys
32 from IPython.utils.contexts import preserve_keys
32 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.path import get_py_filename, unquote_filename
33 from IPython.utils.warn import warn, error
34 from IPython.utils.warn import warn, error
34 from IPython.utils.text import get_text_list
35 from IPython.utils.text import get_text_list
35
36
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37 # Magic implementation classes
38 # Magic implementation classes
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39
40
40 # Used for exception handling in magic_edit
41 # Used for exception handling in magic_edit
41 class MacroToEdit(ValueError): pass
42 class MacroToEdit(ValueError): pass
42
43
43 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
44 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
44
45
45 # To match, e.g. 8-10 1:5 :10 3-
46 # To match, e.g. 8-10 1:5 :10 3-
46 range_re = re.compile(r"""
47 range_re = re.compile(r"""
47 (?P<start>\d+)?
48 (?P<start>\d+)?
48 ((?P<sep>[\-:])
49 ((?P<sep>[\-:])
49 (?P<end>\d+)?)?
50 (?P<end>\d+)?)?
50 $""", re.VERBOSE)
51 $""", re.VERBOSE)
51
52
52
53
53 def extract_code_ranges(ranges_str):
54 def extract_code_ranges(ranges_str):
54 """Turn a string of range for %%load into 2-tuples of (start, stop)
55 """Turn a string of range for %%load into 2-tuples of (start, stop)
55 ready to use as a slice of the content splitted by lines.
56 ready to use as a slice of the content splitted by lines.
56
57
57 Examples
58 Examples
58 --------
59 --------
59 list(extract_input_ranges("5-10 2"))
60 list(extract_input_ranges("5-10 2"))
60 [(4, 10), (1, 2)]
61 [(4, 10), (1, 2)]
61 """
62 """
62 for range_str in ranges_str.split():
63 for range_str in ranges_str.split():
63 rmatch = range_re.match(range_str)
64 rmatch = range_re.match(range_str)
64 if not rmatch:
65 if not rmatch:
65 continue
66 continue
66 sep = rmatch.group("sep")
67 sep = rmatch.group("sep")
67 start = rmatch.group("start")
68 start = rmatch.group("start")
68 end = rmatch.group("end")
69 end = rmatch.group("end")
69
70
70 if sep == '-':
71 if sep == '-':
71 start = int(start) - 1 if start else None
72 start = int(start) - 1 if start else None
72 end = int(end) if end else None
73 end = int(end) if end else None
73 elif sep == ':':
74 elif sep == ':':
74 start = int(start) - 1 if start else None
75 start = int(start) - 1 if start else None
75 end = int(end) - 1 if end else None
76 end = int(end) - 1 if end else None
76 else:
77 else:
77 end = int(start)
78 end = int(start)
78 start = int(start) - 1
79 start = int(start) - 1
79 yield (start, end)
80 yield (start, end)
80
81
81
82
82 @skip_doctest
83 @skip_doctest
83 def extract_symbols(code, symbols):
84 def extract_symbols(code, symbols):
84 """
85 """
85 Return a tuple (blocks, not_found)
86 Return a tuple (blocks, not_found)
86 where ``blocks`` is a list of code fragments
87 where ``blocks`` is a list of code fragments
87 for each symbol parsed from code, and ``not_found`` are
88 for each symbol parsed from code, and ``not_found`` are
88 symbols not found in the code.
89 symbols not found in the code.
89
90
90 For example::
91 For example::
91
92
92 >>> code = '''a = 10
93 >>> code = '''a = 10
93
94
94 def b(): return 42
95 def b(): return 42
95
96
96 class A: pass'''
97 class A: pass'''
97
98
98 >>> extract_symbols(code, 'A,b,z')
99 >>> extract_symbols(code, 'A,b,z')
99 (["class A: pass", "def b(): return 42"], ['z'])
100 (["class A: pass", "def b(): return 42"], ['z'])
100 """
101 """
101 symbols = symbols.split(',')
102 symbols = symbols.split(',')
102
103
103 # this will raise SyntaxError if code isn't valid Python
104 # this will raise SyntaxError if code isn't valid Python
104 py_code = ast.parse(code)
105 py_code = ast.parse(code)
105
106
106 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
107 code = code.split('\n')
108 code = code.split('\n')
108
109
109 symbols_lines = {}
110 symbols_lines = {}
110
111
111 # we already know the start_lineno of each symbol (marks).
112 # we already know the start_lineno of each symbol (marks).
112 # To find each end_lineno, we traverse in reverse order until each
113 # To find each end_lineno, we traverse in reverse order until each
113 # non-blank line
114 # non-blank line
114 end = len(code)
115 end = len(code)
115 for name, start in reversed(marks):
116 for name, start in reversed(marks):
116 while not code[end - 1].strip():
117 while not code[end - 1].strip():
117 end -= 1
118 end -= 1
118 if name:
119 if name:
119 symbols_lines[name] = (start - 1, end)
120 symbols_lines[name] = (start - 1, end)
120 end = start - 1
121 end = start - 1
121
122
122 # Now symbols_lines is a map
123 # Now symbols_lines is a map
123 # {'symbol_name': (start_lineno, end_lineno), ...}
124 # {'symbol_name': (start_lineno, end_lineno), ...}
124
125
125 # fill a list with chunks of codes for each requested symbol
126 # fill a list with chunks of codes for each requested symbol
126 blocks = []
127 blocks = []
127 not_found = []
128 not_found = []
128 for symbol in symbols:
129 for symbol in symbols:
129 if symbol in symbols_lines:
130 if symbol in symbols_lines:
130 start, end = symbols_lines[symbol]
131 start, end = symbols_lines[symbol]
131 blocks.append('\n'.join(code[start:end]) + '\n')
132 blocks.append('\n'.join(code[start:end]) + '\n')
132 else:
133 else:
133 not_found.append(symbol)
134 not_found.append(symbol)
134
135
135 return blocks, not_found
136 return blocks, not_found
136
137
137
138
138 class InteractivelyDefined(Exception):
139 class InteractivelyDefined(Exception):
139 """Exception for interactively defined variable in magic_edit"""
140 """Exception for interactively defined variable in magic_edit"""
140 def __init__(self, index):
141 def __init__(self, index):
141 self.index = index
142 self.index = index
142
143
143
144
144 @magics_class
145 @magics_class
145 class CodeMagics(Magics):
146 class CodeMagics(Magics):
146 """Magics related to code management (loading, saving, editing, ...)."""
147 """Magics related to code management (loading, saving, editing, ...)."""
147
148
148 @line_magic
149 @line_magic
149 def save(self, parameter_s=''):
150 def save(self, parameter_s=''):
150 """Save a set of lines or a macro to a given filename.
151 """Save a set of lines or a macro to a given filename.
151
152
152 Usage:\\
153 Usage:\\
153 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
154 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
154
155
155 Options:
156 Options:
156
157
157 -r: use 'raw' input. By default, the 'processed' history is used,
158 -r: use 'raw' input. By default, the 'processed' history is used,
158 so that magics are loaded in their transformed version to valid
159 so that magics are loaded in their transformed version to valid
159 Python. If this option is given, the raw input as typed as the
160 Python. If this option is given, the raw input as typed as the
160 command line is used instead.
161 command line is used instead.
161
162
162 -f: force overwrite. If file exists, %save will prompt for overwrite
163 -f: force overwrite. If file exists, %save will prompt for overwrite
163 unless -f is given.
164 unless -f is given.
164
165
165 -a: append to the file instead of overwriting it.
166 -a: append to the file instead of overwriting it.
166
167
167 This function uses the same syntax as %history for input ranges,
168 This function uses the same syntax as %history for input ranges,
168 then saves the lines to the filename you specify.
169 then saves the lines to the filename you specify.
169
170
170 It adds a '.py' extension to the file if you don't do so yourself, and
171 It adds a '.py' extension to the file if you don't do so yourself, and
171 it asks for confirmation before overwriting existing files.
172 it asks for confirmation before overwriting existing files.
172
173
173 If `-r` option is used, the default extension is `.ipy`.
174 If `-r` option is used, the default extension is `.ipy`.
174 """
175 """
175
176
176 opts,args = self.parse_options(parameter_s,'fra',mode='list')
177 opts,args = self.parse_options(parameter_s,'fra',mode='list')
177 if not args:
178 if not args:
178 raise UsageError('Missing filename.')
179 raise UsageError('Missing filename.')
179 raw = 'r' in opts
180 raw = 'r' in opts
180 force = 'f' in opts
181 force = 'f' in opts
181 append = 'a' in opts
182 append = 'a' in opts
182 mode = 'a' if append else 'w'
183 mode = 'a' if append else 'w'
183 ext = u'.ipy' if raw else u'.py'
184 ext = u'.ipy' if raw else u'.py'
184 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
185 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
185 if not fname.endswith((u'.py',u'.ipy')):
186 if not fname.endswith((u'.py',u'.ipy')):
186 fname += ext
187 fname += ext
187 file_exists = os.path.isfile(fname)
188 file_exists = os.path.isfile(fname)
188 if file_exists and not force and not append:
189 if file_exists and not force and not append:
189 try:
190 try:
190 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
191 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
191 except StdinNotImplementedError:
192 except StdinNotImplementedError:
192 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
193 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
193 return
194 return
194 if not overwrite :
195 if not overwrite :
195 print 'Operation cancelled.'
196 print('Operation cancelled.')
196 return
197 return
197 try:
198 try:
198 cmds = self.shell.find_user_code(codefrom,raw)
199 cmds = self.shell.find_user_code(codefrom,raw)
199 except (TypeError, ValueError) as e:
200 except (TypeError, ValueError) as e:
200 print e.args[0]
201 print(e.args[0])
201 return
202 return
202 out = py3compat.cast_unicode(cmds)
203 out = py3compat.cast_unicode(cmds)
203 with io.open(fname, mode, encoding="utf-8") as f:
204 with io.open(fname, mode, encoding="utf-8") as f:
204 if not file_exists or not append:
205 if not file_exists or not append:
205 f.write(u"# coding: utf-8\n")
206 f.write(u"# coding: utf-8\n")
206 f.write(out)
207 f.write(out)
207 # make sure we end on a newline
208 # make sure we end on a newline
208 if not out.endswith(u'\n'):
209 if not out.endswith(u'\n'):
209 f.write(u'\n')
210 f.write(u'\n')
210 print 'The following commands were written to file `%s`:' % fname
211 print('The following commands were written to file `%s`:' % fname)
211 print cmds
212 print(cmds)
212
213
213 @line_magic
214 @line_magic
214 def pastebin(self, parameter_s=''):
215 def pastebin(self, parameter_s=''):
215 """Upload code to Github's Gist paste bin, returning the URL.
216 """Upload code to Github's Gist paste bin, returning the URL.
216
217
217 Usage:\\
218 Usage:\\
218 %pastebin [-d "Custom description"] 1-7
219 %pastebin [-d "Custom description"] 1-7
219
220
220 The argument can be an input history range, a filename, or the name of a
221 The argument can be an input history range, a filename, or the name of a
221 string or macro.
222 string or macro.
222
223
223 Options:
224 Options:
224
225
225 -d: Pass a custom description for the gist. The default will say
226 -d: Pass a custom description for the gist. The default will say
226 "Pasted from IPython".
227 "Pasted from IPython".
227 """
228 """
228 opts, args = self.parse_options(parameter_s, 'd:')
229 opts, args = self.parse_options(parameter_s, 'd:')
229
230
230 try:
231 try:
231 code = self.shell.find_user_code(args)
232 code = self.shell.find_user_code(args)
232 except (ValueError, TypeError) as e:
233 except (ValueError, TypeError) as e:
233 print e.args[0]
234 print(e.args[0])
234 return
235 return
235
236
236 from urllib2 import urlopen # Deferred import
237 from urllib2 import urlopen # Deferred import
237 import json
238 import json
238 post_data = json.dumps({
239 post_data = json.dumps({
239 "description": opts.get('d', "Pasted from IPython"),
240 "description": opts.get('d', "Pasted from IPython"),
240 "public": True,
241 "public": True,
241 "files": {
242 "files": {
242 "file1.py": {
243 "file1.py": {
243 "content": code
244 "content": code
244 }
245 }
245 }
246 }
246 }).encode('utf-8')
247 }).encode('utf-8')
247
248
248 response = urlopen("https://api.github.com/gists", post_data)
249 response = urlopen("https://api.github.com/gists", post_data)
249 response_data = json.loads(response.read().decode('utf-8'))
250 response_data = json.loads(response.read().decode('utf-8'))
250 return response_data['html_url']
251 return response_data['html_url']
251
252
252 @line_magic
253 @line_magic
253 def loadpy(self, arg_s):
254 def loadpy(self, arg_s):
254 """Alias of `%load`
255 """Alias of `%load`
255
256
256 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
257 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
257 extension. So it has been renamed simply into %load. You can look at
258 extension. So it has been renamed simply into %load. You can look at
258 `%load`'s docstring for more info.
259 `%load`'s docstring for more info.
259 """
260 """
260 self.load(arg_s)
261 self.load(arg_s)
261
262
262 @line_magic
263 @line_magic
263 def load(self, arg_s):
264 def load(self, arg_s):
264 """Load code into the current frontend.
265 """Load code into the current frontend.
265
266
266 Usage:\\
267 Usage:\\
267 %load [options] source
268 %load [options] source
268
269
269 where source can be a filename, URL, input history range or macro
270 where source can be a filename, URL, input history range or macro
270
271
271 Options:
272 Options:
272 --------
273 --------
273 -r <lines>: Specify lines or ranges of lines to load from the source.
274 -r <lines>: Specify lines or ranges of lines to load from the source.
274 Ranges could be specified as x-y (x..y) or in python-style x:y
275 Ranges could be specified as x-y (x..y) or in python-style x:y
275 (x..(y-1)). Both limits x and y can be left blank (meaning the
276 (x..(y-1)). Both limits x and y can be left blank (meaning the
276 beginning and end of the file, respectively).
277 beginning and end of the file, respectively).
277
278
278 -s <symbols>: Specify function or classes to load from python source.
279 -s <symbols>: Specify function or classes to load from python source.
279
280
280 -y : Don't ask confirmation for loading source above 200 000 characters.
281 -y : Don't ask confirmation for loading source above 200 000 characters.
281
282
282 This magic command can either take a local filename, a URL, an history
283 This magic command can either take a local filename, a URL, an history
283 range (see %history) or a macro as argument, it will prompt for
284 range (see %history) or a macro as argument, it will prompt for
284 confirmation before loading source with more than 200 000 characters, unless
285 confirmation before loading source with more than 200 000 characters, unless
285 -y flag is passed or if the frontend does not support raw_input::
286 -y flag is passed or if the frontend does not support raw_input::
286
287
287 %load myscript.py
288 %load myscript.py
288 %load 7-27
289 %load 7-27
289 %load myMacro
290 %load myMacro
290 %load http://www.example.com/myscript.py
291 %load http://www.example.com/myscript.py
291 %load -r 5-10 myscript.py
292 %load -r 5-10 myscript.py
292 %load -r 10-20,30,40: foo.py
293 %load -r 10-20,30,40: foo.py
293 %load -s MyClass,wonder_function myscript.py
294 %load -s MyClass,wonder_function myscript.py
294 """
295 """
295 opts,args = self.parse_options(arg_s,'ys:r:')
296 opts,args = self.parse_options(arg_s,'ys:r:')
296
297
297 if not args:
298 if not args:
298 raise UsageError('Missing filename, URL, input history range, '
299 raise UsageError('Missing filename, URL, input history range, '
299 'or macro.')
300 'or macro.')
300
301
301 contents = self.shell.find_user_code(args)
302 contents = self.shell.find_user_code(args)
302
303
303 if 's' in opts:
304 if 's' in opts:
304 try:
305 try:
305 blocks, not_found = extract_symbols(contents, opts['s'])
306 blocks, not_found = extract_symbols(contents, opts['s'])
306 except SyntaxError:
307 except SyntaxError:
307 # non python code
308 # non python code
308 error("Unable to parse the input as valid Python code")
309 error("Unable to parse the input as valid Python code")
309 return
310 return
310
311
311 if len(not_found) == 1:
312 if len(not_found) == 1:
312 warn('The symbol `%s` was not found' % not_found[0])
313 warn('The symbol `%s` was not found' % not_found[0])
313 elif len(not_found) > 1:
314 elif len(not_found) > 1:
314 warn('The symbols %s were not found' % get_text_list(not_found,
315 warn('The symbols %s were not found' % get_text_list(not_found,
315 wrap_item_with='`')
316 wrap_item_with='`')
316 )
317 )
317
318
318 contents = '\n'.join(blocks)
319 contents = '\n'.join(blocks)
319
320
320 if 'r' in opts:
321 if 'r' in opts:
321 ranges = opts['r'].replace(',', ' ')
322 ranges = opts['r'].replace(',', ' ')
322 lines = contents.split('\n')
323 lines = contents.split('\n')
323 slices = extract_code_ranges(ranges)
324 slices = extract_code_ranges(ranges)
324 contents = [lines[slice(*slc)] for slc in slices]
325 contents = [lines[slice(*slc)] for slc in slices]
325 contents = '\n'.join(chain.from_iterable(contents))
326 contents = '\n'.join(chain.from_iterable(contents))
326
327
327 l = len(contents)
328 l = len(contents)
328
329
329 # 200 000 is ~ 2500 full 80 caracter lines
330 # 200 000 is ~ 2500 full 80 caracter lines
330 # so in average, more than 5000 lines
331 # so in average, more than 5000 lines
331 if l > 200000 and 'y' not in opts:
332 if l > 200000 and 'y' not in opts:
332 try:
333 try:
333 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
334 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
334 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
335 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
335 except StdinNotImplementedError:
336 except StdinNotImplementedError:
336 #asume yes if raw input not implemented
337 #asume yes if raw input not implemented
337 ans = True
338 ans = True
338
339
339 if ans is False :
340 if ans is False :
340 print 'Operation cancelled.'
341 print('Operation cancelled.')
341 return
342 return
342
343
343 self.shell.set_next_input(contents)
344 self.shell.set_next_input(contents)
344
345
345 @staticmethod
346 @staticmethod
346 def _find_edit_target(shell, args, opts, last_call):
347 def _find_edit_target(shell, args, opts, last_call):
347 """Utility method used by magic_edit to find what to edit."""
348 """Utility method used by magic_edit to find what to edit."""
348
349
349 def make_filename(arg):
350 def make_filename(arg):
350 "Make a filename from the given args"
351 "Make a filename from the given args"
351 arg = unquote_filename(arg)
352 arg = unquote_filename(arg)
352 try:
353 try:
353 filename = get_py_filename(arg)
354 filename = get_py_filename(arg)
354 except IOError:
355 except IOError:
355 # If it ends with .py but doesn't already exist, assume we want
356 # If it ends with .py but doesn't already exist, assume we want
356 # a new file.
357 # a new file.
357 if arg.endswith('.py'):
358 if arg.endswith('.py'):
358 filename = arg
359 filename = arg
359 else:
360 else:
360 filename = None
361 filename = None
361 return filename
362 return filename
362
363
363 # Set a few locals from the options for convenience:
364 # Set a few locals from the options for convenience:
364 opts_prev = 'p' in opts
365 opts_prev = 'p' in opts
365 opts_raw = 'r' in opts
366 opts_raw = 'r' in opts
366
367
367 # custom exceptions
368 # custom exceptions
368 class DataIsObject(Exception): pass
369 class DataIsObject(Exception): pass
369
370
370 # Default line number value
371 # Default line number value
371 lineno = opts.get('n',None)
372 lineno = opts.get('n',None)
372
373
373 if opts_prev:
374 if opts_prev:
374 args = '_%s' % last_call[0]
375 args = '_%s' % last_call[0]
375 if args not in shell.user_ns:
376 if args not in shell.user_ns:
376 args = last_call[1]
377 args = last_call[1]
377
378
378 # by default this is done with temp files, except when the given
379 # by default this is done with temp files, except when the given
379 # arg is a filename
380 # arg is a filename
380 use_temp = True
381 use_temp = True
381
382
382 data = ''
383 data = ''
383
384
384 # First, see if the arguments should be a filename.
385 # First, see if the arguments should be a filename.
385 filename = make_filename(args)
386 filename = make_filename(args)
386 if filename:
387 if filename:
387 use_temp = False
388 use_temp = False
388 elif args:
389 elif args:
389 # Mode where user specifies ranges of lines, like in %macro.
390 # Mode where user specifies ranges of lines, like in %macro.
390 data = shell.extract_input_lines(args, opts_raw)
391 data = shell.extract_input_lines(args, opts_raw)
391 if not data:
392 if not data:
392 try:
393 try:
393 # Load the parameter given as a variable. If not a string,
394 # Load the parameter given as a variable. If not a string,
394 # process it as an object instead (below)
395 # process it as an object instead (below)
395
396
396 #print '*** args',args,'type',type(args) # dbg
397 #print '*** args',args,'type',type(args) # dbg
397 data = eval(args, shell.user_ns)
398 data = eval(args, shell.user_ns)
398 if not isinstance(data, basestring):
399 if not isinstance(data, basestring):
399 raise DataIsObject
400 raise DataIsObject
400
401
401 except (NameError,SyntaxError):
402 except (NameError,SyntaxError):
402 # given argument is not a variable, try as a filename
403 # given argument is not a variable, try as a filename
403 filename = make_filename(args)
404 filename = make_filename(args)
404 if filename is None:
405 if filename is None:
405 warn("Argument given (%s) can't be found as a variable "
406 warn("Argument given (%s) can't be found as a variable "
406 "or as a filename." % args)
407 "or as a filename." % args)
407 return (None, None, None)
408 return (None, None, None)
408 use_temp = False
409 use_temp = False
409
410
410 except DataIsObject:
411 except DataIsObject:
411 # macros have a special edit function
412 # macros have a special edit function
412 if isinstance(data, Macro):
413 if isinstance(data, Macro):
413 raise MacroToEdit(data)
414 raise MacroToEdit(data)
414
415
415 # For objects, try to edit the file where they are defined
416 # For objects, try to edit the file where they are defined
416 filename = find_file(data)
417 filename = find_file(data)
417 if filename:
418 if filename:
418 if 'fakemodule' in filename.lower() and \
419 if 'fakemodule' in filename.lower() and \
419 inspect.isclass(data):
420 inspect.isclass(data):
420 # class created by %edit? Try to find source
421 # class created by %edit? Try to find source
421 # by looking for method definitions instead, the
422 # by looking for method definitions instead, the
422 # __module__ in those classes is FakeModule.
423 # __module__ in those classes is FakeModule.
423 attrs = [getattr(data, aname) for aname in dir(data)]
424 attrs = [getattr(data, aname) for aname in dir(data)]
424 for attr in attrs:
425 for attr in attrs:
425 if not inspect.ismethod(attr):
426 if not inspect.ismethod(attr):
426 continue
427 continue
427 filename = find_file(attr)
428 filename = find_file(attr)
428 if filename and \
429 if filename and \
429 'fakemodule' not in filename.lower():
430 'fakemodule' not in filename.lower():
430 # change the attribute to be the edit
431 # change the attribute to be the edit
431 # target instead
432 # target instead
432 data = attr
433 data = attr
433 break
434 break
434
435
435 m = ipython_input_pat.match(os.path.basename(filename))
436 m = ipython_input_pat.match(os.path.basename(filename))
436 if m:
437 if m:
437 raise InteractivelyDefined(int(m.groups()[0]))
438 raise InteractivelyDefined(int(m.groups()[0]))
438
439
439 datafile = 1
440 datafile = 1
440 if filename is None:
441 if filename is None:
441 filename = make_filename(args)
442 filename = make_filename(args)
442 datafile = 1
443 datafile = 1
443 if filename is not None:
444 if filename is not None:
444 # only warn about this if we get a real name
445 # only warn about this if we get a real name
445 warn('Could not find file where `%s` is defined.\n'
446 warn('Could not find file where `%s` is defined.\n'
446 'Opening a file named `%s`' % (args, filename))
447 'Opening a file named `%s`' % (args, filename))
447 # Now, make sure we can actually read the source (if it was
448 # Now, make sure we can actually read the source (if it was
448 # in a temp file it's gone by now).
449 # in a temp file it's gone by now).
449 if datafile:
450 if datafile:
450 if lineno is None:
451 if lineno is None:
451 lineno = find_source_lines(data)
452 lineno = find_source_lines(data)
452 if lineno is None:
453 if lineno is None:
453 filename = make_filename(args)
454 filename = make_filename(args)
454 if filename is None:
455 if filename is None:
455 warn('The file where `%s` was defined '
456 warn('The file where `%s` was defined '
456 'cannot be read or found.' % data)
457 'cannot be read or found.' % data)
457 return (None, None, None)
458 return (None, None, None)
458 use_temp = False
459 use_temp = False
459
460
460 if use_temp:
461 if use_temp:
461 filename = shell.mktempfile(data)
462 filename = shell.mktempfile(data)
462 print 'IPython will make a temporary file named:',filename
463 print('IPython will make a temporary file named:',filename)
463
464
464 # use last_call to remember the state of the previous call, but don't
465 # use last_call to remember the state of the previous call, but don't
465 # let it be clobbered by successive '-p' calls.
466 # let it be clobbered by successive '-p' calls.
466 try:
467 try:
467 last_call[0] = shell.displayhook.prompt_count
468 last_call[0] = shell.displayhook.prompt_count
468 if not opts_prev:
469 if not opts_prev:
469 last_call[1] = args
470 last_call[1] = args
470 except:
471 except:
471 pass
472 pass
472
473
473
474
474 return filename, lineno, use_temp
475 return filename, lineno, use_temp
475
476
476 def _edit_macro(self,mname,macro):
477 def _edit_macro(self,mname,macro):
477 """open an editor with the macro data in a file"""
478 """open an editor with the macro data in a file"""
478 filename = self.shell.mktempfile(macro.value)
479 filename = self.shell.mktempfile(macro.value)
479 self.shell.hooks.editor(filename)
480 self.shell.hooks.editor(filename)
480
481
481 # and make a new macro object, to replace the old one
482 # and make a new macro object, to replace the old one
482 with open(filename) as mfile:
483 with open(filename) as mfile:
483 mvalue = mfile.read()
484 mvalue = mfile.read()
484 self.shell.user_ns[mname] = Macro(mvalue)
485 self.shell.user_ns[mname] = Macro(mvalue)
485
486
486 @skip_doctest
487 @skip_doctest
487 @line_magic
488 @line_magic
488 def edit(self, parameter_s='',last_call=['','']):
489 def edit(self, parameter_s='',last_call=['','']):
489 """Bring up an editor and execute the resulting code.
490 """Bring up an editor and execute the resulting code.
490
491
491 Usage:
492 Usage:
492 %edit [options] [args]
493 %edit [options] [args]
493
494
494 %edit runs IPython's editor hook. The default version of this hook is
495 %edit runs IPython's editor hook. The default version of this hook is
495 set to call the editor specified by your $EDITOR environment variable.
496 set to call the editor specified by your $EDITOR environment variable.
496 If this isn't found, it will default to vi under Linux/Unix and to
497 If this isn't found, it will default to vi under Linux/Unix and to
497 notepad under Windows. See the end of this docstring for how to change
498 notepad under Windows. See the end of this docstring for how to change
498 the editor hook.
499 the editor hook.
499
500
500 You can also set the value of this editor via the
501 You can also set the value of this editor via the
501 ``TerminalInteractiveShell.editor`` option in your configuration file.
502 ``TerminalInteractiveShell.editor`` option in your configuration file.
502 This is useful if you wish to use a different editor from your typical
503 This is useful if you wish to use a different editor from your typical
503 default with IPython (and for Windows users who typically don't set
504 default with IPython (and for Windows users who typically don't set
504 environment variables).
505 environment variables).
505
506
506 This command allows you to conveniently edit multi-line code right in
507 This command allows you to conveniently edit multi-line code right in
507 your IPython session.
508 your IPython session.
508
509
509 If called without arguments, %edit opens up an empty editor with a
510 If called without arguments, %edit opens up an empty editor with a
510 temporary file and will execute the contents of this file when you
511 temporary file and will execute the contents of this file when you
511 close it (don't forget to save it!).
512 close it (don't forget to save it!).
512
513
513
514
514 Options:
515 Options:
515
516
516 -n <number>: open the editor at a specified line number. By default,
517 -n <number>: open the editor at a specified line number. By default,
517 the IPython editor hook uses the unix syntax 'editor +N filename', but
518 the IPython editor hook uses the unix syntax 'editor +N filename', but
518 you can configure this by providing your own modified hook if your
519 you can configure this by providing your own modified hook if your
519 favorite editor supports line-number specifications with a different
520 favorite editor supports line-number specifications with a different
520 syntax.
521 syntax.
521
522
522 -p: this will call the editor with the same data as the previous time
523 -p: this will call the editor with the same data as the previous time
523 it was used, regardless of how long ago (in your current session) it
524 it was used, regardless of how long ago (in your current session) it
524 was.
525 was.
525
526
526 -r: use 'raw' input. This option only applies to input taken from the
527 -r: use 'raw' input. This option only applies to input taken from the
527 user's history. By default, the 'processed' history is used, so that
528 user's history. By default, the 'processed' history is used, so that
528 magics are loaded in their transformed version to valid Python. If
529 magics are loaded in their transformed version to valid Python. If
529 this option is given, the raw input as typed as the command line is
530 this option is given, the raw input as typed as the command line is
530 used instead. When you exit the editor, it will be executed by
531 used instead. When you exit the editor, it will be executed by
531 IPython's own processor.
532 IPython's own processor.
532
533
533 -x: do not execute the edited code immediately upon exit. This is
534 -x: do not execute the edited code immediately upon exit. This is
534 mainly useful if you are editing programs which need to be called with
535 mainly useful if you are editing programs which need to be called with
535 command line arguments, which you can then do using %run.
536 command line arguments, which you can then do using %run.
536
537
537
538
538 Arguments:
539 Arguments:
539
540
540 If arguments are given, the following possibilities exist:
541 If arguments are given, the following possibilities exist:
541
542
542 - If the argument is a filename, IPython will load that into the
543 - If the argument is a filename, IPython will load that into the
543 editor. It will execute its contents with execfile() when you exit,
544 editor. It will execute its contents with execfile() when you exit,
544 loading any code in the file into your interactive namespace.
545 loading any code in the file into your interactive namespace.
545
546
546 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
547 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
547 The syntax is the same as in the %history magic.
548 The syntax is the same as in the %history magic.
548
549
549 - If the argument is a string variable, its contents are loaded
550 - If the argument is a string variable, its contents are loaded
550 into the editor. You can thus edit any string which contains
551 into the editor. You can thus edit any string which contains
551 python code (including the result of previous edits).
552 python code (including the result of previous edits).
552
553
553 - If the argument is the name of an object (other than a string),
554 - If the argument is the name of an object (other than a string),
554 IPython will try to locate the file where it was defined and open the
555 IPython will try to locate the file where it was defined and open the
555 editor at the point where it is defined. You can use `%edit function`
556 editor at the point where it is defined. You can use `%edit function`
556 to load an editor exactly at the point where 'function' is defined,
557 to load an editor exactly at the point where 'function' is defined,
557 edit it and have the file be executed automatically.
558 edit it and have the file be executed automatically.
558
559
559 - If the object is a macro (see %macro for details), this opens up your
560 - If the object is a macro (see %macro for details), this opens up your
560 specified editor with a temporary file containing the macro's data.
561 specified editor with a temporary file containing the macro's data.
561 Upon exit, the macro is reloaded with the contents of the file.
562 Upon exit, the macro is reloaded with the contents of the file.
562
563
563 Note: opening at an exact line is only supported under Unix, and some
564 Note: opening at an exact line is only supported under Unix, and some
564 editors (like kedit and gedit up to Gnome 2.8) do not understand the
565 editors (like kedit and gedit up to Gnome 2.8) do not understand the
565 '+NUMBER' parameter necessary for this feature. Good editors like
566 '+NUMBER' parameter necessary for this feature. Good editors like
566 (X)Emacs, vi, jed, pico and joe all do.
567 (X)Emacs, vi, jed, pico and joe all do.
567
568
568 After executing your code, %edit will return as output the code you
569 After executing your code, %edit will return as output the code you
569 typed in the editor (except when it was an existing file). This way
570 typed in the editor (except when it was an existing file). This way
570 you can reload the code in further invocations of %edit as a variable,
571 you can reload the code in further invocations of %edit as a variable,
571 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
572 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
572 the output.
573 the output.
573
574
574 Note that %edit is also available through the alias %ed.
575 Note that %edit is also available through the alias %ed.
575
576
576 This is an example of creating a simple function inside the editor and
577 This is an example of creating a simple function inside the editor and
577 then modifying it. First, start up the editor::
578 then modifying it. First, start up the editor::
578
579
579 In [1]: edit
580 In [1]: edit
580 Editing... done. Executing edited code...
581 Editing... done. Executing edited code...
581 Out[1]: 'def foo():\\n print "foo() was defined in an editing
582 Out[1]: 'def foo():\\n print "foo() was defined in an editing
582 session"\\n'
583 session"\\n'
583
584
584 We can then call the function foo()::
585 We can then call the function foo()::
585
586
586 In [2]: foo()
587 In [2]: foo()
587 foo() was defined in an editing session
588 foo() was defined in an editing session
588
589
589 Now we edit foo. IPython automatically loads the editor with the
590 Now we edit foo. IPython automatically loads the editor with the
590 (temporary) file where foo() was previously defined::
591 (temporary) file where foo() was previously defined::
591
592
592 In [3]: edit foo
593 In [3]: edit foo
593 Editing... done. Executing edited code...
594 Editing... done. Executing edited code...
594
595
595 And if we call foo() again we get the modified version::
596 And if we call foo() again we get the modified version::
596
597
597 In [4]: foo()
598 In [4]: foo()
598 foo() has now been changed!
599 foo() has now been changed!
599
600
600 Here is an example of how to edit a code snippet successive
601 Here is an example of how to edit a code snippet successive
601 times. First we call the editor::
602 times. First we call the editor::
602
603
603 In [5]: edit
604 In [5]: edit
604 Editing... done. Executing edited code...
605 Editing... done. Executing edited code...
605 hello
606 hello
606 Out[5]: "print 'hello'\\n"
607 Out[5]: "print 'hello'\\n"
607
608
608 Now we call it again with the previous output (stored in _)::
609 Now we call it again with the previous output (stored in _)::
609
610
610 In [6]: edit _
611 In [6]: edit _
611 Editing... done. Executing edited code...
612 Editing... done. Executing edited code...
612 hello world
613 hello world
613 Out[6]: "print 'hello world'\\n"
614 Out[6]: "print 'hello world'\\n"
614
615
615 Now we call it with the output #8 (stored in _8, also as Out[8])::
616 Now we call it with the output #8 (stored in _8, also as Out[8])::
616
617
617 In [7]: edit _8
618 In [7]: edit _8
618 Editing... done. Executing edited code...
619 Editing... done. Executing edited code...
619 hello again
620 hello again
620 Out[7]: "print 'hello again'\\n"
621 Out[7]: "print 'hello again'\\n"
621
622
622
623
623 Changing the default editor hook:
624 Changing the default editor hook:
624
625
625 If you wish to write your own editor hook, you can put it in a
626 If you wish to write your own editor hook, you can put it in a
626 configuration file which you load at startup time. The default hook
627 configuration file which you load at startup time. The default hook
627 is defined in the IPython.core.hooks module, and you can use that as a
628 is defined in the IPython.core.hooks module, and you can use that as a
628 starting example for further modifications. That file also has
629 starting example for further modifications. That file also has
629 general instructions on how to set a new hook for use once you've
630 general instructions on how to set a new hook for use once you've
630 defined it."""
631 defined it."""
631 opts,args = self.parse_options(parameter_s,'prxn:')
632 opts,args = self.parse_options(parameter_s,'prxn:')
632
633
633 try:
634 try:
634 filename, lineno, is_temp = self._find_edit_target(self.shell,
635 filename, lineno, is_temp = self._find_edit_target(self.shell,
635 args, opts, last_call)
636 args, opts, last_call)
636 except MacroToEdit as e:
637 except MacroToEdit as e:
637 self._edit_macro(args, e.args[0])
638 self._edit_macro(args, e.args[0])
638 return
639 return
639 except InteractivelyDefined as e:
640 except InteractivelyDefined as e:
640 print "Editing In[%i]" % e.index
641 print("Editing In[%i]" % e.index)
641 args = str(e.index)
642 args = str(e.index)
642 filename, lineno, is_temp = self._find_edit_target(self.shell,
643 filename, lineno, is_temp = self._find_edit_target(self.shell,
643 args, opts, last_call)
644 args, opts, last_call)
644 if filename is None:
645 if filename is None:
645 # nothing was found, warnings have already been issued,
646 # nothing was found, warnings have already been issued,
646 # just give up.
647 # just give up.
647 return
648 return
648
649
649 # do actual editing here
650 # do actual editing here
650 print 'Editing...',
651 print('Editing...', end=' ')
651 sys.stdout.flush()
652 sys.stdout.flush()
652 try:
653 try:
653 # Quote filenames that may have spaces in them
654 # Quote filenames that may have spaces in them
654 if ' ' in filename:
655 if ' ' in filename:
655 filename = "'%s'" % filename
656 filename = "'%s'" % filename
656 self.shell.hooks.editor(filename,lineno)
657 self.shell.hooks.editor(filename,lineno)
657 except TryNext:
658 except TryNext:
658 warn('Could not open editor')
659 warn('Could not open editor')
659 return
660 return
660
661
661 # XXX TODO: should this be generalized for all string vars?
662 # XXX TODO: should this be generalized for all string vars?
662 # For now, this is special-cased to blocks created by cpaste
663 # For now, this is special-cased to blocks created by cpaste
663 if args.strip() == 'pasted_block':
664 if args.strip() == 'pasted_block':
664 with open(filename, 'r') as f:
665 with open(filename, 'r') as f:
665 self.shell.user_ns['pasted_block'] = f.read()
666 self.shell.user_ns['pasted_block'] = f.read()
666
667
667 if 'x' in opts: # -x prevents actual execution
668 if 'x' in opts: # -x prevents actual execution
668 print
669 print()
669 else:
670 else:
670 print 'done. Executing edited code...'
671 print('done. Executing edited code...')
671 with preserve_keys(self.shell.user_ns, '__file__'):
672 with preserve_keys(self.shell.user_ns, '__file__'):
672 if not is_temp:
673 if not is_temp:
673 self.shell.user_ns['__file__'] = filename
674 self.shell.user_ns['__file__'] = filename
674 if 'r' in opts: # Untranslated IPython code
675 if 'r' in opts: # Untranslated IPython code
675 with open(filename, 'r') as f:
676 with open(filename, 'r') as f:
676 source = f.read()
677 source = f.read()
677 self.shell.run_cell(source, store_history=False)
678 self.shell.run_cell(source, store_history=False)
678 else:
679 else:
679 self.shell.safe_execfile(filename, self.shell.user_ns,
680 self.shell.safe_execfile(filename, self.shell.user_ns,
680 self.shell.user_ns)
681 self.shell.user_ns)
681
682
682 if is_temp:
683 if is_temp:
683 try:
684 try:
684 return open(filename).read()
685 return open(filename).read()
685 except IOError as msg:
686 except IOError as msg:
686 if msg.filename == filename:
687 if msg.filename == filename:
687 warn('File not found. Did you forget to save?')
688 warn('File not found. Did you forget to save?')
688 return
689 return
689 else:
690 else:
690 self.shell.showtraceback()
691 self.shell.showtraceback()
@@ -1,158 +1,159 b''
1 """Implementation of configuration-related magic functions.
1 """Implementation of configuration-related magic functions.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Stdlib
16 # Stdlib
16 import re
17 import re
17
18
18 # Our own packages
19 # Our own packages
19 from IPython.core.error import UsageError
20 from IPython.core.error import UsageError
20 from IPython.core.magic import Magics, magics_class, line_magic
21 from IPython.core.magic import Magics, magics_class, line_magic
21 from IPython.utils.warn import error
22 from IPython.utils.warn import error
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Magic implementation classes
25 # Magic implementation classes
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27 reg = re.compile('^\w+\.\w+$')
28 reg = re.compile('^\w+\.\w+$')
28 @magics_class
29 @magics_class
29 class ConfigMagics(Magics):
30 class ConfigMagics(Magics):
30
31
31 def __init__(self, shell):
32 def __init__(self, shell):
32 super(ConfigMagics, self).__init__(shell)
33 super(ConfigMagics, self).__init__(shell)
33 self.configurables = []
34 self.configurables = []
34
35
35 @line_magic
36 @line_magic
36 def config(self, s):
37 def config(self, s):
37 """configure IPython
38 """configure IPython
38
39
39 %config Class[.trait=value]
40 %config Class[.trait=value]
40
41
41 This magic exposes most of the IPython config system. Any
42 This magic exposes most of the IPython config system. Any
42 Configurable class should be able to be configured with the simple
43 Configurable class should be able to be configured with the simple
43 line::
44 line::
44
45
45 %config Class.trait=value
46 %config Class.trait=value
46
47
47 Where `value` will be resolved in the user's namespace, if it is an
48 Where `value` will be resolved in the user's namespace, if it is an
48 expression or variable name.
49 expression or variable name.
49
50
50 Examples
51 Examples
51 --------
52 --------
52
53
53 To see what classes are available for config, pass no arguments::
54 To see what classes are available for config, pass no arguments::
54
55
55 In [1]: %config
56 In [1]: %config
56 Available objects for config:
57 Available objects for config:
57 TerminalInteractiveShell
58 TerminalInteractiveShell
58 HistoryManager
59 HistoryManager
59 PrefilterManager
60 PrefilterManager
60 AliasManager
61 AliasManager
61 IPCompleter
62 IPCompleter
62 PromptManager
63 PromptManager
63 DisplayFormatter
64 DisplayFormatter
64
65
65 To view what is configurable on a given class, just pass the class
66 To view what is configurable on a given class, just pass the class
66 name::
67 name::
67
68
68 In [2]: %config IPCompleter
69 In [2]: %config IPCompleter
69 IPCompleter options
70 IPCompleter options
70 -----------------
71 -----------------
71 IPCompleter.omit__names=<Enum>
72 IPCompleter.omit__names=<Enum>
72 Current: 2
73 Current: 2
73 Choices: (0, 1, 2)
74 Choices: (0, 1, 2)
74 Instruct the completer to omit private method names
75 Instruct the completer to omit private method names
75 Specifically, when completing on ``object.<tab>``.
76 Specifically, when completing on ``object.<tab>``.
76 When 2 [default]: all names that start with '_' will be excluded.
77 When 2 [default]: all names that start with '_' will be excluded.
77 When 1: all 'magic' names (``__foo__``) will be excluded.
78 When 1: all 'magic' names (``__foo__``) will be excluded.
78 When 0: nothing will be excluded.
79 When 0: nothing will be excluded.
79 IPCompleter.merge_completions=<CBool>
80 IPCompleter.merge_completions=<CBool>
80 Current: True
81 Current: True
81 Whether to merge completion results into a single list
82 Whether to merge completion results into a single list
82 If False, only the completion results from the first non-empty
83 If False, only the completion results from the first non-empty
83 completer will be returned.
84 completer will be returned.
84 IPCompleter.limit_to__all__=<CBool>
85 IPCompleter.limit_to__all__=<CBool>
85 Current: False
86 Current: False
86 Instruct the completer to use __all__ for the completion
87 Instruct the completer to use __all__ for the completion
87 Specifically, when completing on ``object.<tab>``.
88 Specifically, when completing on ``object.<tab>``.
88 When True: only those names in obj.__all__ will be included.
89 When True: only those names in obj.__all__ will be included.
89 When False [default]: the __all__ attribute is ignored
90 When False [default]: the __all__ attribute is ignored
90 IPCompleter.greedy=<CBool>
91 IPCompleter.greedy=<CBool>
91 Current: False
92 Current: False
92 Activate greedy completion
93 Activate greedy completion
93 This will enable completion on elements of lists, results of
94 This will enable completion on elements of lists, results of
94 function calls, etc., but can be unsafe because the code is
95 function calls, etc., but can be unsafe because the code is
95 actually evaluated on TAB.
96 actually evaluated on TAB.
96
97
97 but the real use is in setting values::
98 but the real use is in setting values::
98
99
99 In [3]: %config IPCompleter.greedy = True
100 In [3]: %config IPCompleter.greedy = True
100
101
101 and these values are read from the user_ns if they are variables::
102 and these values are read from the user_ns if they are variables::
102
103
103 In [4]: feeling_greedy=False
104 In [4]: feeling_greedy=False
104
105
105 In [5]: %config IPCompleter.greedy = feeling_greedy
106 In [5]: %config IPCompleter.greedy = feeling_greedy
106
107
107 """
108 """
108 from IPython.config.loader import Config
109 from IPython.config.loader import Config
109 # some IPython objects are Configurable, but do not yet have
110 # some IPython objects are Configurable, but do not yet have
110 # any configurable traits. Exclude them from the effects of
111 # any configurable traits. Exclude them from the effects of
111 # this magic, as their presence is just noise:
112 # this magic, as their presence is just noise:
112 configurables = [ c for c in self.shell.configurables
113 configurables = [ c for c in self.shell.configurables
113 if c.__class__.class_traits(config=True) ]
114 if c.__class__.class_traits(config=True) ]
114 classnames = [ c.__class__.__name__ for c in configurables ]
115 classnames = [ c.__class__.__name__ for c in configurables ]
115
116
116 line = s.strip()
117 line = s.strip()
117 if not line:
118 if not line:
118 # print available configurable names
119 # print available configurable names
119 print "Available objects for config:"
120 print("Available objects for config:")
120 for name in classnames:
121 for name in classnames:
121 print " ", name
122 print(" ", name)
122 return
123 return
123 elif line in classnames:
124 elif line in classnames:
124 # `%config TerminalInteractiveShell` will print trait info for
125 # `%config TerminalInteractiveShell` will print trait info for
125 # TerminalInteractiveShell
126 # TerminalInteractiveShell
126 c = configurables[classnames.index(line)]
127 c = configurables[classnames.index(line)]
127 cls = c.__class__
128 cls = c.__class__
128 help = cls.class_get_help(c)
129 help = cls.class_get_help(c)
129 # strip leading '--' from cl-args:
130 # strip leading '--' from cl-args:
130 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
131 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
131 print help
132 print(help)
132 return
133 return
133 elif reg.match(line):
134 elif reg.match(line):
134 cls, attr = line.split('.')
135 cls, attr = line.split('.')
135 return getattr(configurables[classnames.index(cls)],attr)
136 return getattr(configurables[classnames.index(cls)],attr)
136 elif '=' not in line:
137 elif '=' not in line:
137 msg = "Invalid config statement: %r, "\
138 msg = "Invalid config statement: %r, "\
138 "should be `Class.trait = value`."
139 "should be `Class.trait = value`."
139
140
140 ll = line.lower()
141 ll = line.lower()
141 for classname in classnames:
142 for classname in classnames:
142 if ll == classname.lower():
143 if ll == classname.lower():
143 msg = msg + '\nDid you mean %s (note the case)?' % classname
144 msg = msg + '\nDid you mean %s (note the case)?' % classname
144 break
145 break
145
146
146 raise UsageError( msg % line)
147 raise UsageError( msg % line)
147
148
148 # otherwise, assume we are setting configurables.
149 # otherwise, assume we are setting configurables.
149 # leave quotes on args when splitting, because we want
150 # leave quotes on args when splitting, because we want
150 # unquoted args to eval in user_ns
151 # unquoted args to eval in user_ns
151 cfg = Config()
152 cfg = Config()
152 exec "cfg."+line in locals(), self.shell.user_ns
153 exec "cfg."+line in locals(), self.shell.user_ns
153
154
154 for configurable in configurables:
155 for configurable in configurables:
155 try:
156 try:
156 configurable.update_config(cfg)
157 configurable.update_config(cfg)
157 except Exception as e:
158 except Exception as e:
158 error(e)
159 error(e)
@@ -1,45 +1,46 b''
1 """Deprecated Magic functions.
1 """Deprecated Magic functions.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Our own packages
16 # Our own packages
16 from IPython.core.magic import Magics, magics_class, line_magic
17 from IPython.core.magic import Magics, magics_class, line_magic
17
18
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 # Magic implementation classes
20 # Magic implementation classes
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21
22
22 @magics_class
23 @magics_class
23 class DeprecatedMagics(Magics):
24 class DeprecatedMagics(Magics):
24 """Magics slated for later removal."""
25 """Magics slated for later removal."""
25
26
26 @line_magic
27 @line_magic
27 def install_profiles(self, parameter_s=''):
28 def install_profiles(self, parameter_s=''):
28 """%install_profiles has been deprecated."""
29 """%install_profiles has been deprecated."""
29 print '\n'.join([
30 print('\n'.join([
30 "%install_profiles has been deprecated.",
31 "%install_profiles has been deprecated.",
31 "Use `ipython profile list` to view available profiles.",
32 "Use `ipython profile list` to view available profiles.",
32 "Requesting a profile with `ipython profile create <name>`",
33 "Requesting a profile with `ipython profile create <name>`",
33 "or `ipython --profile=<name>` will start with the bundled",
34 "or `ipython --profile=<name>` will start with the bundled",
34 "profile of that name if it exists."
35 "profile of that name if it exists."
35 ])
36 ]))
36
37
37 @line_magic
38 @line_magic
38 def install_default_config(self, parameter_s=''):
39 def install_default_config(self, parameter_s=''):
39 """%install_default_config has been deprecated."""
40 """%install_default_config has been deprecated."""
40 print '\n'.join([
41 print('\n'.join([
41 "%install_default_config has been deprecated.",
42 "%install_default_config has been deprecated.",
42 "Use `ipython profile create <name>` to initialize a profile",
43 "Use `ipython profile create <name>` to initialize a profile",
43 "with the default config files.",
44 "with the default config files.",
44 "Add `--reset` to overwrite already existing config files with defaults."
45 "Add `--reset` to overwrite already existing config files with defaults."
45 ])
46 ]))
@@ -1,1287 +1,1288 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Implementation of execution-related magic functions.
2 """Implementation of execution-related magic functions.
3 """
3 """
4 from __future__ import print_function
4 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
5 # Copyright (c) 2012 The IPython Development Team.
6 # Copyright (c) 2012 The IPython Development Team.
6 #
7 #
7 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
8 #
9 #
9 # 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.
10 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
11
12
12 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
13 # Imports
14 # Imports
14 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
15
16
16 # Stdlib
17 # Stdlib
17 import __builtin__ as builtin_mod
18 import __builtin__ as builtin_mod
18 import ast
19 import ast
19 import bdb
20 import bdb
20 import os
21 import os
21 import sys
22 import sys
22 import time
23 import time
23 from StringIO import StringIO
24 from StringIO import StringIO
24
25
25 # cProfile was added in Python2.5
26 # cProfile was added in Python2.5
26 try:
27 try:
27 import cProfile as profile
28 import cProfile as profile
28 import pstats
29 import pstats
29 except ImportError:
30 except ImportError:
30 # profile isn't bundled by default in Debian for license reasons
31 # profile isn't bundled by default in Debian for license reasons
31 try:
32 try:
32 import profile, pstats
33 import profile, pstats
33 except ImportError:
34 except ImportError:
34 profile = pstats = None
35 profile = pstats = None
35
36
36 # Our own packages
37 # Our own packages
37 from IPython.core import debugger, oinspect
38 from IPython.core import debugger, oinspect
38 from IPython.core import magic_arguments
39 from IPython.core import magic_arguments
39 from IPython.core import page
40 from IPython.core import page
40 from IPython.core.error import UsageError
41 from IPython.core.error import UsageError
41 from IPython.core.macro import Macro
42 from IPython.core.macro import Macro
42 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
43 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
43 line_cell_magic, on_off, needs_local_scope)
44 line_cell_magic, on_off, needs_local_scope)
44 from IPython.testing.skipdoctest import skip_doctest
45 from IPython.testing.skipdoctest import skip_doctest
45 from IPython.utils import py3compat
46 from IPython.utils import py3compat
46 from IPython.utils.contexts import preserve_keys
47 from IPython.utils.contexts import preserve_keys
47 from IPython.utils.io import capture_output
48 from IPython.utils.io import capture_output
48 from IPython.utils.ipstruct import Struct
49 from IPython.utils.ipstruct import Struct
49 from IPython.utils.module_paths import find_mod
50 from IPython.utils.module_paths import find_mod
50 from IPython.utils.path import get_py_filename, unquote_filename, shellglob
51 from IPython.utils.path import get_py_filename, unquote_filename, shellglob
51 from IPython.utils.timing import clock, clock2
52 from IPython.utils.timing import clock, clock2
52 from IPython.utils.warn import warn, error
53 from IPython.utils.warn import warn, error
53
54
54
55
55 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
56 # Magic implementation classes
57 # Magic implementation classes
57 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
58
59
59
60
60 class TimeitResult(object):
61 class TimeitResult(object):
61 """
62 """
62 Object returned by the timeit magic with info about the run.
63 Object returned by the timeit magic with info about the run.
63
64
64 Contain the following attributes :
65 Contain the following attributes :
65
66
66 loops: (int) number of loop done per measurement
67 loops: (int) number of loop done per measurement
67 repeat: (int) number of time the mesurement has been repeated
68 repeat: (int) number of time the mesurement has been repeated
68 best: (float) best execusion time / number
69 best: (float) best execusion time / number
69 all_runs: (list of float) execusion time of each run (in s)
70 all_runs: (list of float) execusion time of each run (in s)
70 compile_time: (float) time of statement compilation (s)
71 compile_time: (float) time of statement compilation (s)
71
72
72 """
73 """
73
74
74 def __init__(self, loops, repeat, best, all_runs, compile_time, precision):
75 def __init__(self, loops, repeat, best, all_runs, compile_time, precision):
75 self.loops = loops
76 self.loops = loops
76 self.repeat = repeat
77 self.repeat = repeat
77 self.best = best
78 self.best = best
78 self.all_runs = all_runs
79 self.all_runs = all_runs
79 self.compile_time = compile_time
80 self.compile_time = compile_time
80 self._precision = precision
81 self._precision = precision
81
82
82 def _repr_pretty_(self, p , cycle):
83 def _repr_pretty_(self, p , cycle):
83 unic = u"%d loops, best of %d: %s per loop" % (self.loops, self.repeat,
84 unic = u"%d loops, best of %d: %s per loop" % (self.loops, self.repeat,
84 _format_time(self.best, self._precision))
85 _format_time(self.best, self._precision))
85 p.text(u'<TimeitResult : '+unic+u'>')
86 p.text(u'<TimeitResult : '+unic+u'>')
86
87
87
88
88
89
89
90
90 @magics_class
91 @magics_class
91 class ExecutionMagics(Magics):
92 class ExecutionMagics(Magics):
92 """Magics related to code execution, debugging, profiling, etc.
93 """Magics related to code execution, debugging, profiling, etc.
93
94
94 """
95 """
95
96
96 def __init__(self, shell):
97 def __init__(self, shell):
97 super(ExecutionMagics, self).__init__(shell)
98 super(ExecutionMagics, self).__init__(shell)
98 if profile is None:
99 if profile is None:
99 self.prun = self.profile_missing_notice
100 self.prun = self.profile_missing_notice
100 # Default execution function used to actually run user code.
101 # Default execution function used to actually run user code.
101 self.default_runner = None
102 self.default_runner = None
102
103
103 def profile_missing_notice(self, *args, **kwargs):
104 def profile_missing_notice(self, *args, **kwargs):
104 error("""\
105 error("""\
105 The profile module could not be found. It has been removed from the standard
106 The profile module could not be found. It has been removed from the standard
106 python packages because of its non-free license. To use profiling, install the
107 python packages because of its non-free license. To use profiling, install the
107 python-profiler package from non-free.""")
108 python-profiler package from non-free.""")
108
109
109 @skip_doctest
110 @skip_doctest
110 @line_cell_magic
111 @line_cell_magic
111 def prun(self, parameter_s='', cell=None):
112 def prun(self, parameter_s='', cell=None):
112
113
113 """Run a statement through the python code profiler.
114 """Run a statement through the python code profiler.
114
115
115 Usage, in line mode:
116 Usage, in line mode:
116 %prun [options] statement
117 %prun [options] statement
117
118
118 Usage, in cell mode:
119 Usage, in cell mode:
119 %%prun [options] [statement]
120 %%prun [options] [statement]
120 code...
121 code...
121 code...
122 code...
122
123
123 In cell mode, the additional code lines are appended to the (possibly
124 In cell mode, the additional code lines are appended to the (possibly
124 empty) statement in the first line. Cell mode allows you to easily
125 empty) statement in the first line. Cell mode allows you to easily
125 profile multiline blocks without having to put them in a separate
126 profile multiline blocks without having to put them in a separate
126 function.
127 function.
127
128
128 The given statement (which doesn't require quote marks) is run via the
129 The given statement (which doesn't require quote marks) is run via the
129 python profiler in a manner similar to the profile.run() function.
130 python profiler in a manner similar to the profile.run() function.
130 Namespaces are internally managed to work correctly; profile.run
131 Namespaces are internally managed to work correctly; profile.run
131 cannot be used in IPython because it makes certain assumptions about
132 cannot be used in IPython because it makes certain assumptions about
132 namespaces which do not hold under IPython.
133 namespaces which do not hold under IPython.
133
134
134 Options:
135 Options:
135
136
136 -l <limit>
137 -l <limit>
137 you can place restrictions on what or how much of the
138 you can place restrictions on what or how much of the
138 profile gets printed. The limit value can be:
139 profile gets printed. The limit value can be:
139
140
140 * A string: only information for function names containing this string
141 * A string: only information for function names containing this string
141 is printed.
142 is printed.
142
143
143 * An integer: only these many lines are printed.
144 * An integer: only these many lines are printed.
144
145
145 * A float (between 0 and 1): this fraction of the report is printed
146 * A float (between 0 and 1): this fraction of the report is printed
146 (for example, use a limit of 0.4 to see the topmost 40% only).
147 (for example, use a limit of 0.4 to see the topmost 40% only).
147
148
148 You can combine several limits with repeated use of the option. For
149 You can combine several limits with repeated use of the option. For
149 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
150 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
150 information about class constructors.
151 information about class constructors.
151
152
152 -r
153 -r
153 return the pstats.Stats object generated by the profiling. This
154 return the pstats.Stats object generated by the profiling. This
154 object has all the information about the profile in it, and you can
155 object has all the information about the profile in it, and you can
155 later use it for further analysis or in other functions.
156 later use it for further analysis or in other functions.
156
157
157 -s <key>
158 -s <key>
158 sort profile by given key. You can provide more than one key
159 sort profile by given key. You can provide more than one key
159 by using the option several times: '-s key1 -s key2 -s key3...'. The
160 by using the option several times: '-s key1 -s key2 -s key3...'. The
160 default sorting key is 'time'.
161 default sorting key is 'time'.
161
162
162 The following is copied verbatim from the profile documentation
163 The following is copied verbatim from the profile documentation
163 referenced below:
164 referenced below:
164
165
165 When more than one key is provided, additional keys are used as
166 When more than one key is provided, additional keys are used as
166 secondary criteria when the there is equality in all keys selected
167 secondary criteria when the there is equality in all keys selected
167 before them.
168 before them.
168
169
169 Abbreviations can be used for any key names, as long as the
170 Abbreviations can be used for any key names, as long as the
170 abbreviation is unambiguous. The following are the keys currently
171 abbreviation is unambiguous. The following are the keys currently
171 defined:
172 defined:
172
173
173 ============ =====================
174 ============ =====================
174 Valid Arg Meaning
175 Valid Arg Meaning
175 ============ =====================
176 ============ =====================
176 "calls" call count
177 "calls" call count
177 "cumulative" cumulative time
178 "cumulative" cumulative time
178 "file" file name
179 "file" file name
179 "module" file name
180 "module" file name
180 "pcalls" primitive call count
181 "pcalls" primitive call count
181 "line" line number
182 "line" line number
182 "name" function name
183 "name" function name
183 "nfl" name/file/line
184 "nfl" name/file/line
184 "stdname" standard name
185 "stdname" standard name
185 "time" internal time
186 "time" internal time
186 ============ =====================
187 ============ =====================
187
188
188 Note that all sorts on statistics are in descending order (placing
189 Note that all sorts on statistics are in descending order (placing
189 most time consuming items first), where as name, file, and line number
190 most time consuming items first), where as name, file, and line number
190 searches are in ascending order (i.e., alphabetical). The subtle
191 searches are in ascending order (i.e., alphabetical). The subtle
191 distinction between "nfl" and "stdname" is that the standard name is a
192 distinction between "nfl" and "stdname" is that the standard name is a
192 sort of the name as printed, which means that the embedded line
193 sort of the name as printed, which means that the embedded line
193 numbers get compared in an odd way. For example, lines 3, 20, and 40
194 numbers get compared in an odd way. For example, lines 3, 20, and 40
194 would (if the file names were the same) appear in the string order
195 would (if the file names were the same) appear in the string order
195 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
196 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
196 line numbers. In fact, sort_stats("nfl") is the same as
197 line numbers. In fact, sort_stats("nfl") is the same as
197 sort_stats("name", "file", "line").
198 sort_stats("name", "file", "line").
198
199
199 -T <filename>
200 -T <filename>
200 save profile results as shown on screen to a text
201 save profile results as shown on screen to a text
201 file. The profile is still shown on screen.
202 file. The profile is still shown on screen.
202
203
203 -D <filename>
204 -D <filename>
204 save (via dump_stats) profile statistics to given
205 save (via dump_stats) profile statistics to given
205 filename. This data is in a format understood by the pstats module, and
206 filename. This data is in a format understood by the pstats module, and
206 is generated by a call to the dump_stats() method of profile
207 is generated by a call to the dump_stats() method of profile
207 objects. The profile is still shown on screen.
208 objects. The profile is still shown on screen.
208
209
209 -q
210 -q
210 suppress output to the pager. Best used with -T and/or -D above.
211 suppress output to the pager. Best used with -T and/or -D above.
211
212
212 If you want to run complete programs under the profiler's control, use
213 If you want to run complete programs under the profiler's control, use
213 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
214 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
214 contains profiler specific options as described here.
215 contains profiler specific options as described here.
215
216
216 You can read the complete documentation for the profile module with::
217 You can read the complete documentation for the profile module with::
217
218
218 In [1]: import profile; profile.help()
219 In [1]: import profile; profile.help()
219 """
220 """
220 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
221 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
221 list_all=True, posix=False)
222 list_all=True, posix=False)
222 if cell is not None:
223 if cell is not None:
223 arg_str += '\n' + cell
224 arg_str += '\n' + cell
224 arg_str = self.shell.input_splitter.transform_cell(arg_str)
225 arg_str = self.shell.input_splitter.transform_cell(arg_str)
225 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
226 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
226
227
227 def _run_with_profiler(self, code, opts, namespace):
228 def _run_with_profiler(self, code, opts, namespace):
228 """
229 """
229 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
230 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
230
231
231 Parameters
232 Parameters
232 ----------
233 ----------
233 code : str
234 code : str
234 Code to be executed.
235 Code to be executed.
235 opts : Struct
236 opts : Struct
236 Options parsed by `self.parse_options`.
237 Options parsed by `self.parse_options`.
237 namespace : dict
238 namespace : dict
238 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
239 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
239
240
240 """
241 """
241
242
242 # Fill default values for unspecified options:
243 # Fill default values for unspecified options:
243 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
244 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
244
245
245 prof = profile.Profile()
246 prof = profile.Profile()
246 try:
247 try:
247 prof = prof.runctx(code, namespace, namespace)
248 prof = prof.runctx(code, namespace, namespace)
248 sys_exit = ''
249 sys_exit = ''
249 except SystemExit:
250 except SystemExit:
250 sys_exit = """*** SystemExit exception caught in code being profiled."""
251 sys_exit = """*** SystemExit exception caught in code being profiled."""
251
252
252 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
253 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
253
254
254 lims = opts.l
255 lims = opts.l
255 if lims:
256 if lims:
256 lims = [] # rebuild lims with ints/floats/strings
257 lims = [] # rebuild lims with ints/floats/strings
257 for lim in opts.l:
258 for lim in opts.l:
258 try:
259 try:
259 lims.append(int(lim))
260 lims.append(int(lim))
260 except ValueError:
261 except ValueError:
261 try:
262 try:
262 lims.append(float(lim))
263 lims.append(float(lim))
263 except ValueError:
264 except ValueError:
264 lims.append(lim)
265 lims.append(lim)
265
266
266 # Trap output.
267 # Trap output.
267 stdout_trap = StringIO()
268 stdout_trap = StringIO()
268 stats_stream = stats.stream
269 stats_stream = stats.stream
269 try:
270 try:
270 stats.stream = stdout_trap
271 stats.stream = stdout_trap
271 stats.print_stats(*lims)
272 stats.print_stats(*lims)
272 finally:
273 finally:
273 stats.stream = stats_stream
274 stats.stream = stats_stream
274
275
275 output = stdout_trap.getvalue()
276 output = stdout_trap.getvalue()
276 output = output.rstrip()
277 output = output.rstrip()
277
278
278 if 'q' not in opts:
279 if 'q' not in opts:
279 page.page(output)
280 page.page(output)
280 print sys_exit,
281 print(sys_exit, end=' ')
281
282
282 dump_file = opts.D[0]
283 dump_file = opts.D[0]
283 text_file = opts.T[0]
284 text_file = opts.T[0]
284 if dump_file:
285 if dump_file:
285 dump_file = unquote_filename(dump_file)
286 dump_file = unquote_filename(dump_file)
286 prof.dump_stats(dump_file)
287 prof.dump_stats(dump_file)
287 print '\n*** Profile stats marshalled to file',\
288 print('\n*** Profile stats marshalled to file',\
288 repr(dump_file)+'.',sys_exit
289 repr(dump_file)+'.',sys_exit)
289 if text_file:
290 if text_file:
290 text_file = unquote_filename(text_file)
291 text_file = unquote_filename(text_file)
291 pfile = open(text_file,'w')
292 pfile = open(text_file,'w')
292 pfile.write(output)
293 pfile.write(output)
293 pfile.close()
294 pfile.close()
294 print '\n*** Profile printout saved to text file',\
295 print('\n*** Profile printout saved to text file',\
295 repr(text_file)+'.',sys_exit
296 repr(text_file)+'.',sys_exit)
296
297
297 if 'r' in opts:
298 if 'r' in opts:
298 return stats
299 return stats
299 else:
300 else:
300 return None
301 return None
301
302
302 @line_magic
303 @line_magic
303 def pdb(self, parameter_s=''):
304 def pdb(self, parameter_s=''):
304 """Control the automatic calling of the pdb interactive debugger.
305 """Control the automatic calling of the pdb interactive debugger.
305
306
306 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
307 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
307 argument it works as a toggle.
308 argument it works as a toggle.
308
309
309 When an exception is triggered, IPython can optionally call the
310 When an exception is triggered, IPython can optionally call the
310 interactive pdb debugger after the traceback printout. %pdb toggles
311 interactive pdb debugger after the traceback printout. %pdb toggles
311 this feature on and off.
312 this feature on and off.
312
313
313 The initial state of this feature is set in your configuration
314 The initial state of this feature is set in your configuration
314 file (the option is ``InteractiveShell.pdb``).
315 file (the option is ``InteractiveShell.pdb``).
315
316
316 If you want to just activate the debugger AFTER an exception has fired,
317 If you want to just activate the debugger AFTER an exception has fired,
317 without having to type '%pdb on' and rerunning your code, you can use
318 without having to type '%pdb on' and rerunning your code, you can use
318 the %debug magic."""
319 the %debug magic."""
319
320
320 par = parameter_s.strip().lower()
321 par = parameter_s.strip().lower()
321
322
322 if par:
323 if par:
323 try:
324 try:
324 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
325 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
325 except KeyError:
326 except KeyError:
326 print ('Incorrect argument. Use on/1, off/0, '
327 print ('Incorrect argument. Use on/1, off/0, '
327 'or nothing for a toggle.')
328 'or nothing for a toggle.')
328 return
329 return
329 else:
330 else:
330 # toggle
331 # toggle
331 new_pdb = not self.shell.call_pdb
332 new_pdb = not self.shell.call_pdb
332
333
333 # set on the shell
334 # set on the shell
334 self.shell.call_pdb = new_pdb
335 self.shell.call_pdb = new_pdb
335 print 'Automatic pdb calling has been turned',on_off(new_pdb)
336 print('Automatic pdb calling has been turned',on_off(new_pdb))
336
337
337 @skip_doctest
338 @skip_doctest
338 @magic_arguments.magic_arguments()
339 @magic_arguments.magic_arguments()
339 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
340 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
340 help="""
341 help="""
341 Set break point at LINE in FILE.
342 Set break point at LINE in FILE.
342 """
343 """
343 )
344 )
344 @magic_arguments.argument('statement', nargs='*',
345 @magic_arguments.argument('statement', nargs='*',
345 help="""
346 help="""
346 Code to run in debugger.
347 Code to run in debugger.
347 You can omit this in cell magic mode.
348 You can omit this in cell magic mode.
348 """
349 """
349 )
350 )
350 @line_cell_magic
351 @line_cell_magic
351 def debug(self, line='', cell=None):
352 def debug(self, line='', cell=None):
352 """Activate the interactive debugger.
353 """Activate the interactive debugger.
353
354
354 This magic command support two ways of activating debugger.
355 This magic command support two ways of activating debugger.
355 One is to activate debugger before executing code. This way, you
356 One is to activate debugger before executing code. This way, you
356 can set a break point, to step through the code from the point.
357 can set a break point, to step through the code from the point.
357 You can use this mode by giving statements to execute and optionally
358 You can use this mode by giving statements to execute and optionally
358 a breakpoint.
359 a breakpoint.
359
360
360 The other one is to activate debugger in post-mortem mode. You can
361 The other one is to activate debugger in post-mortem mode. You can
361 activate this mode simply running %debug without any argument.
362 activate this mode simply running %debug without any argument.
362 If an exception has just occurred, this lets you inspect its stack
363 If an exception has just occurred, this lets you inspect its stack
363 frames interactively. Note that this will always work only on the last
364 frames interactively. Note that this will always work only on the last
364 traceback that occurred, so you must call this quickly after an
365 traceback that occurred, so you must call this quickly after an
365 exception that you wish to inspect has fired, because if another one
366 exception that you wish to inspect has fired, because if another one
366 occurs, it clobbers the previous one.
367 occurs, it clobbers the previous one.
367
368
368 If you want IPython to automatically do this on every exception, see
369 If you want IPython to automatically do this on every exception, see
369 the %pdb magic for more details.
370 the %pdb magic for more details.
370 """
371 """
371 args = magic_arguments.parse_argstring(self.debug, line)
372 args = magic_arguments.parse_argstring(self.debug, line)
372
373
373 if not (args.breakpoint or args.statement or cell):
374 if not (args.breakpoint or args.statement or cell):
374 self._debug_post_mortem()
375 self._debug_post_mortem()
375 else:
376 else:
376 code = "\n".join(args.statement)
377 code = "\n".join(args.statement)
377 if cell:
378 if cell:
378 code += "\n" + cell
379 code += "\n" + cell
379 self._debug_exec(code, args.breakpoint)
380 self._debug_exec(code, args.breakpoint)
380
381
381 def _debug_post_mortem(self):
382 def _debug_post_mortem(self):
382 self.shell.debugger(force=True)
383 self.shell.debugger(force=True)
383
384
384 def _debug_exec(self, code, breakpoint):
385 def _debug_exec(self, code, breakpoint):
385 if breakpoint:
386 if breakpoint:
386 (filename, bp_line) = breakpoint.split(':', 1)
387 (filename, bp_line) = breakpoint.split(':', 1)
387 bp_line = int(bp_line)
388 bp_line = int(bp_line)
388 else:
389 else:
389 (filename, bp_line) = (None, None)
390 (filename, bp_line) = (None, None)
390 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
391 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
391
392
392 @line_magic
393 @line_magic
393 def tb(self, s):
394 def tb(self, s):
394 """Print the last traceback with the currently active exception mode.
395 """Print the last traceback with the currently active exception mode.
395
396
396 See %xmode for changing exception reporting modes."""
397 See %xmode for changing exception reporting modes."""
397 self.shell.showtraceback()
398 self.shell.showtraceback()
398
399
399 @skip_doctest
400 @skip_doctest
400 @line_magic
401 @line_magic
401 def run(self, parameter_s='', runner=None,
402 def run(self, parameter_s='', runner=None,
402 file_finder=get_py_filename):
403 file_finder=get_py_filename):
403 """Run the named file inside IPython as a program.
404 """Run the named file inside IPython as a program.
404
405
405 Usage::
406 Usage::
406
407
407 %run [-n -i -e -G]
408 %run [-n -i -e -G]
408 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
409 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
409 ( -m mod | file ) [args]
410 ( -m mod | file ) [args]
410
411
411 Parameters after the filename are passed as command-line arguments to
412 Parameters after the filename are passed as command-line arguments to
412 the program (put in sys.argv). Then, control returns to IPython's
413 the program (put in sys.argv). Then, control returns to IPython's
413 prompt.
414 prompt.
414
415
415 This is similar to running at a system prompt ``python file args``,
416 This is similar to running at a system prompt ``python file args``,
416 but with the advantage of giving you IPython's tracebacks, and of
417 but with the advantage of giving you IPython's tracebacks, and of
417 loading all variables into your interactive namespace for further use
418 loading all variables into your interactive namespace for further use
418 (unless -p is used, see below).
419 (unless -p is used, see below).
419
420
420 The file is executed in a namespace initially consisting only of
421 The file is executed in a namespace initially consisting only of
421 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
422 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
422 sees its environment as if it were being run as a stand-alone program
423 sees its environment as if it were being run as a stand-alone program
423 (except for sharing global objects such as previously imported
424 (except for sharing global objects such as previously imported
424 modules). But after execution, the IPython interactive namespace gets
425 modules). But after execution, the IPython interactive namespace gets
425 updated with all variables defined in the program (except for __name__
426 updated with all variables defined in the program (except for __name__
426 and sys.argv). This allows for very convenient loading of code for
427 and sys.argv). This allows for very convenient loading of code for
427 interactive work, while giving each program a 'clean sheet' to run in.
428 interactive work, while giving each program a 'clean sheet' to run in.
428
429
429 Arguments are expanded using shell-like glob match. Patterns
430 Arguments are expanded using shell-like glob match. Patterns
430 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
431 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
431 tilde '~' will be expanded into user's home directory. Unlike
432 tilde '~' will be expanded into user's home directory. Unlike
432 real shells, quotation does not suppress expansions. Use
433 real shells, quotation does not suppress expansions. Use
433 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
434 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
434 To completely disable these expansions, you can use -G flag.
435 To completely disable these expansions, you can use -G flag.
435
436
436 Options:
437 Options:
437
438
438 -n
439 -n
439 __name__ is NOT set to '__main__', but to the running file's name
440 __name__ is NOT set to '__main__', but to the running file's name
440 without extension (as python does under import). This allows running
441 without extension (as python does under import). This allows running
441 scripts and reloading the definitions in them without calling code
442 scripts and reloading the definitions in them without calling code
442 protected by an ``if __name__ == "__main__"`` clause.
443 protected by an ``if __name__ == "__main__"`` clause.
443
444
444 -i
445 -i
445 run the file in IPython's namespace instead of an empty one. This
446 run the file in IPython's namespace instead of an empty one. This
446 is useful if you are experimenting with code written in a text editor
447 is useful if you are experimenting with code written in a text editor
447 which depends on variables defined interactively.
448 which depends on variables defined interactively.
448
449
449 -e
450 -e
450 ignore sys.exit() calls or SystemExit exceptions in the script
451 ignore sys.exit() calls or SystemExit exceptions in the script
451 being run. This is particularly useful if IPython is being used to
452 being run. This is particularly useful if IPython is being used to
452 run unittests, which always exit with a sys.exit() call. In such
453 run unittests, which always exit with a sys.exit() call. In such
453 cases you are interested in the output of the test results, not in
454 cases you are interested in the output of the test results, not in
454 seeing a traceback of the unittest module.
455 seeing a traceback of the unittest module.
455
456
456 -t
457 -t
457 print timing information at the end of the run. IPython will give
458 print timing information at the end of the run. IPython will give
458 you an estimated CPU time consumption for your script, which under
459 you an estimated CPU time consumption for your script, which under
459 Unix uses the resource module to avoid the wraparound problems of
460 Unix uses the resource module to avoid the wraparound problems of
460 time.clock(). Under Unix, an estimate of time spent on system tasks
461 time.clock(). Under Unix, an estimate of time spent on system tasks
461 is also given (for Windows platforms this is reported as 0.0).
462 is also given (for Windows platforms this is reported as 0.0).
462
463
463 If -t is given, an additional ``-N<N>`` option can be given, where <N>
464 If -t is given, an additional ``-N<N>`` option can be given, where <N>
464 must be an integer indicating how many times you want the script to
465 must be an integer indicating how many times you want the script to
465 run. The final timing report will include total and per run results.
466 run. The final timing report will include total and per run results.
466
467
467 For example (testing the script uniq_stable.py)::
468 For example (testing the script uniq_stable.py)::
468
469
469 In [1]: run -t uniq_stable
470 In [1]: run -t uniq_stable
470
471
471 IPython CPU timings (estimated):
472 IPython CPU timings (estimated):
472 User : 0.19597 s.
473 User : 0.19597 s.
473 System: 0.0 s.
474 System: 0.0 s.
474
475
475 In [2]: run -t -N5 uniq_stable
476 In [2]: run -t -N5 uniq_stable
476
477
477 IPython CPU timings (estimated):
478 IPython CPU timings (estimated):
478 Total runs performed: 5
479 Total runs performed: 5
479 Times : Total Per run
480 Times : Total Per run
480 User : 0.910862 s, 0.1821724 s.
481 User : 0.910862 s, 0.1821724 s.
481 System: 0.0 s, 0.0 s.
482 System: 0.0 s, 0.0 s.
482
483
483 -d
484 -d
484 run your program under the control of pdb, the Python debugger.
485 run your program under the control of pdb, the Python debugger.
485 This allows you to execute your program step by step, watch variables,
486 This allows you to execute your program step by step, watch variables,
486 etc. Internally, what IPython does is similar to calling::
487 etc. Internally, what IPython does is similar to calling::
487
488
488 pdb.run('execfile("YOURFILENAME")')
489 pdb.run('execfile("YOURFILENAME")')
489
490
490 with a breakpoint set on line 1 of your file. You can change the line
491 with a breakpoint set on line 1 of your file. You can change the line
491 number for this automatic breakpoint to be <N> by using the -bN option
492 number for this automatic breakpoint to be <N> by using the -bN option
492 (where N must be an integer). For example::
493 (where N must be an integer). For example::
493
494
494 %run -d -b40 myscript
495 %run -d -b40 myscript
495
496
496 will set the first breakpoint at line 40 in myscript.py. Note that
497 will set the first breakpoint at line 40 in myscript.py. Note that
497 the first breakpoint must be set on a line which actually does
498 the first breakpoint must be set on a line which actually does
498 something (not a comment or docstring) for it to stop execution.
499 something (not a comment or docstring) for it to stop execution.
499
500
500 Or you can specify a breakpoint in a different file::
501 Or you can specify a breakpoint in a different file::
501
502
502 %run -d -b myotherfile.py:20 myscript
503 %run -d -b myotherfile.py:20 myscript
503
504
504 When the pdb debugger starts, you will see a (Pdb) prompt. You must
505 When the pdb debugger starts, you will see a (Pdb) prompt. You must
505 first enter 'c' (without quotes) to start execution up to the first
506 first enter 'c' (without quotes) to start execution up to the first
506 breakpoint.
507 breakpoint.
507
508
508 Entering 'help' gives information about the use of the debugger. You
509 Entering 'help' gives information about the use of the debugger. You
509 can easily see pdb's full documentation with "import pdb;pdb.help()"
510 can easily see pdb's full documentation with "import pdb;pdb.help()"
510 at a prompt.
511 at a prompt.
511
512
512 -p
513 -p
513 run program under the control of the Python profiler module (which
514 run program under the control of the Python profiler module (which
514 prints a detailed report of execution times, function calls, etc).
515 prints a detailed report of execution times, function calls, etc).
515
516
516 You can pass other options after -p which affect the behavior of the
517 You can pass other options after -p which affect the behavior of the
517 profiler itself. See the docs for %prun for details.
518 profiler itself. See the docs for %prun for details.
518
519
519 In this mode, the program's variables do NOT propagate back to the
520 In this mode, the program's variables do NOT propagate back to the
520 IPython interactive namespace (because they remain in the namespace
521 IPython interactive namespace (because they remain in the namespace
521 where the profiler executes them).
522 where the profiler executes them).
522
523
523 Internally this triggers a call to %prun, see its documentation for
524 Internally this triggers a call to %prun, see its documentation for
524 details on the options available specifically for profiling.
525 details on the options available specifically for profiling.
525
526
526 There is one special usage for which the text above doesn't apply:
527 There is one special usage for which the text above doesn't apply:
527 if the filename ends with .ipy, the file is run as ipython script,
528 if the filename ends with .ipy, the file is run as ipython script,
528 just as if the commands were written on IPython prompt.
529 just as if the commands were written on IPython prompt.
529
530
530 -m
531 -m
531 specify module name to load instead of script path. Similar to
532 specify module name to load instead of script path. Similar to
532 the -m option for the python interpreter. Use this option last if you
533 the -m option for the python interpreter. Use this option last if you
533 want to combine with other %run options. Unlike the python interpreter
534 want to combine with other %run options. Unlike the python interpreter
534 only source modules are allowed no .pyc or .pyo files.
535 only source modules are allowed no .pyc or .pyo files.
535 For example::
536 For example::
536
537
537 %run -m example
538 %run -m example
538
539
539 will run the example module.
540 will run the example module.
540
541
541 -G
542 -G
542 disable shell-like glob expansion of arguments.
543 disable shell-like glob expansion of arguments.
543
544
544 """
545 """
545
546
546 # get arguments and set sys.argv for program to be run.
547 # get arguments and set sys.argv for program to be run.
547 opts, arg_lst = self.parse_options(parameter_s,
548 opts, arg_lst = self.parse_options(parameter_s,
548 'nidtN:b:pD:l:rs:T:em:G',
549 'nidtN:b:pD:l:rs:T:em:G',
549 mode='list', list_all=1)
550 mode='list', list_all=1)
550 if "m" in opts:
551 if "m" in opts:
551 modulename = opts["m"][0]
552 modulename = opts["m"][0]
552 modpath = find_mod(modulename)
553 modpath = find_mod(modulename)
553 if modpath is None:
554 if modpath is None:
554 warn('%r is not a valid modulename on sys.path'%modulename)
555 warn('%r is not a valid modulename on sys.path'%modulename)
555 return
556 return
556 arg_lst = [modpath] + arg_lst
557 arg_lst = [modpath] + arg_lst
557 try:
558 try:
558 filename = file_finder(arg_lst[0])
559 filename = file_finder(arg_lst[0])
559 except IndexError:
560 except IndexError:
560 warn('you must provide at least a filename.')
561 warn('you must provide at least a filename.')
561 print '\n%run:\n', oinspect.getdoc(self.run)
562 print('\n%run:\n', oinspect.getdoc(self.run))
562 return
563 return
563 except IOError as e:
564 except IOError as e:
564 try:
565 try:
565 msg = str(e)
566 msg = str(e)
566 except UnicodeError:
567 except UnicodeError:
567 msg = e.message
568 msg = e.message
568 error(msg)
569 error(msg)
569 return
570 return
570
571
571 if filename.lower().endswith('.ipy'):
572 if filename.lower().endswith('.ipy'):
572 with preserve_keys(self.shell.user_ns, '__file__'):
573 with preserve_keys(self.shell.user_ns, '__file__'):
573 self.shell.user_ns['__file__'] = filename
574 self.shell.user_ns['__file__'] = filename
574 self.shell.safe_execfile_ipy(filename)
575 self.shell.safe_execfile_ipy(filename)
575 return
576 return
576
577
577 # Control the response to exit() calls made by the script being run
578 # Control the response to exit() calls made by the script being run
578 exit_ignore = 'e' in opts
579 exit_ignore = 'e' in opts
579
580
580 # Make sure that the running script gets a proper sys.argv as if it
581 # Make sure that the running script gets a proper sys.argv as if it
581 # were run from a system shell.
582 # were run from a system shell.
582 save_argv = sys.argv # save it for later restoring
583 save_argv = sys.argv # save it for later restoring
583
584
584 if 'G' in opts:
585 if 'G' in opts:
585 args = arg_lst[1:]
586 args = arg_lst[1:]
586 else:
587 else:
587 # tilde and glob expansion
588 # tilde and glob expansion
588 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
589 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
589
590
590 sys.argv = [filename] + args # put in the proper filename
591 sys.argv = [filename] + args # put in the proper filename
591 # protect sys.argv from potential unicode strings on Python 2:
592 # protect sys.argv from potential unicode strings on Python 2:
592 if not py3compat.PY3:
593 if not py3compat.PY3:
593 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
594 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
594
595
595 if 'i' in opts:
596 if 'i' in opts:
596 # Run in user's interactive namespace
597 # Run in user's interactive namespace
597 prog_ns = self.shell.user_ns
598 prog_ns = self.shell.user_ns
598 __name__save = self.shell.user_ns['__name__']
599 __name__save = self.shell.user_ns['__name__']
599 prog_ns['__name__'] = '__main__'
600 prog_ns['__name__'] = '__main__'
600 main_mod = self.shell.user_module
601 main_mod = self.shell.user_module
601
602
602 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
603 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
603 # set the __file__ global in the script's namespace
604 # set the __file__ global in the script's namespace
604 # TK: Is this necessary in interactive mode?
605 # TK: Is this necessary in interactive mode?
605 prog_ns['__file__'] = filename
606 prog_ns['__file__'] = filename
606 else:
607 else:
607 # Run in a fresh, empty namespace
608 # Run in a fresh, empty namespace
608 if 'n' in opts:
609 if 'n' in opts:
609 name = os.path.splitext(os.path.basename(filename))[0]
610 name = os.path.splitext(os.path.basename(filename))[0]
610 else:
611 else:
611 name = '__main__'
612 name = '__main__'
612
613
613 # The shell MUST hold a reference to prog_ns so after %run
614 # The shell MUST hold a reference to prog_ns so after %run
614 # exits, the python deletion mechanism doesn't zero it out
615 # exits, the python deletion mechanism doesn't zero it out
615 # (leaving dangling references). See interactiveshell for details
616 # (leaving dangling references). See interactiveshell for details
616 main_mod = self.shell.new_main_mod(filename, name)
617 main_mod = self.shell.new_main_mod(filename, name)
617 prog_ns = main_mod.__dict__
618 prog_ns = main_mod.__dict__
618
619
619 # pickle fix. See interactiveshell for an explanation. But we need to
620 # pickle fix. See interactiveshell for an explanation. But we need to
620 # make sure that, if we overwrite __main__, we replace it at the end
621 # make sure that, if we overwrite __main__, we replace it at the end
621 main_mod_name = prog_ns['__name__']
622 main_mod_name = prog_ns['__name__']
622
623
623 if main_mod_name == '__main__':
624 if main_mod_name == '__main__':
624 restore_main = sys.modules['__main__']
625 restore_main = sys.modules['__main__']
625 else:
626 else:
626 restore_main = False
627 restore_main = False
627
628
628 # This needs to be undone at the end to prevent holding references to
629 # This needs to be undone at the end to prevent holding references to
629 # every single object ever created.
630 # every single object ever created.
630 sys.modules[main_mod_name] = main_mod
631 sys.modules[main_mod_name] = main_mod
631
632
632 if 'p' in opts or 'd' in opts:
633 if 'p' in opts or 'd' in opts:
633 if 'm' in opts:
634 if 'm' in opts:
634 code = 'run_module(modulename, prog_ns)'
635 code = 'run_module(modulename, prog_ns)'
635 code_ns = {
636 code_ns = {
636 'run_module': self.shell.safe_run_module,
637 'run_module': self.shell.safe_run_module,
637 'prog_ns': prog_ns,
638 'prog_ns': prog_ns,
638 'modulename': modulename,
639 'modulename': modulename,
639 }
640 }
640 else:
641 else:
641 code = 'execfile(filename, prog_ns)'
642 code = 'execfile(filename, prog_ns)'
642 code_ns = {
643 code_ns = {
643 'execfile': self.shell.safe_execfile,
644 'execfile': self.shell.safe_execfile,
644 'prog_ns': prog_ns,
645 'prog_ns': prog_ns,
645 'filename': get_py_filename(filename),
646 'filename': get_py_filename(filename),
646 }
647 }
647
648
648 try:
649 try:
649 stats = None
650 stats = None
650 with self.shell.readline_no_record:
651 with self.shell.readline_no_record:
651 if 'p' in opts:
652 if 'p' in opts:
652 stats = self._run_with_profiler(code, opts, code_ns)
653 stats = self._run_with_profiler(code, opts, code_ns)
653 else:
654 else:
654 if 'd' in opts:
655 if 'd' in opts:
655 bp_file, bp_line = parse_breakpoint(
656 bp_file, bp_line = parse_breakpoint(
656 opts.get('b', ['1'])[0], filename)
657 opts.get('b', ['1'])[0], filename)
657 self._run_with_debugger(
658 self._run_with_debugger(
658 code, code_ns, filename, bp_line, bp_file)
659 code, code_ns, filename, bp_line, bp_file)
659 else:
660 else:
660 if 'm' in opts:
661 if 'm' in opts:
661 def run():
662 def run():
662 self.shell.safe_run_module(modulename, prog_ns)
663 self.shell.safe_run_module(modulename, prog_ns)
663 else:
664 else:
664 if runner is None:
665 if runner is None:
665 runner = self.default_runner
666 runner = self.default_runner
666 if runner is None:
667 if runner is None:
667 runner = self.shell.safe_execfile
668 runner = self.shell.safe_execfile
668
669
669 def run():
670 def run():
670 runner(filename, prog_ns, prog_ns,
671 runner(filename, prog_ns, prog_ns,
671 exit_ignore=exit_ignore)
672 exit_ignore=exit_ignore)
672
673
673 if 't' in opts:
674 if 't' in opts:
674 # timed execution
675 # timed execution
675 try:
676 try:
676 nruns = int(opts['N'][0])
677 nruns = int(opts['N'][0])
677 if nruns < 1:
678 if nruns < 1:
678 error('Number of runs must be >=1')
679 error('Number of runs must be >=1')
679 return
680 return
680 except (KeyError):
681 except (KeyError):
681 nruns = 1
682 nruns = 1
682 self._run_with_timing(run, nruns)
683 self._run_with_timing(run, nruns)
683 else:
684 else:
684 # regular execution
685 # regular execution
685 run()
686 run()
686
687
687 if 'i' in opts:
688 if 'i' in opts:
688 self.shell.user_ns['__name__'] = __name__save
689 self.shell.user_ns['__name__'] = __name__save
689 else:
690 else:
690 # update IPython interactive namespace
691 # update IPython interactive namespace
691
692
692 # Some forms of read errors on the file may mean the
693 # Some forms of read errors on the file may mean the
693 # __name__ key was never set; using pop we don't have to
694 # __name__ key was never set; using pop we don't have to
694 # worry about a possible KeyError.
695 # worry about a possible KeyError.
695 prog_ns.pop('__name__', None)
696 prog_ns.pop('__name__', None)
696
697
697 with preserve_keys(self.shell.user_ns, '__file__'):
698 with preserve_keys(self.shell.user_ns, '__file__'):
698 self.shell.user_ns.update(prog_ns)
699 self.shell.user_ns.update(prog_ns)
699 finally:
700 finally:
700 # It's a bit of a mystery why, but __builtins__ can change from
701 # It's a bit of a mystery why, but __builtins__ can change from
701 # being a module to becoming a dict missing some key data after
702 # being a module to becoming a dict missing some key data after
702 # %run. As best I can see, this is NOT something IPython is doing
703 # %run. As best I can see, this is NOT something IPython is doing
703 # at all, and similar problems have been reported before:
704 # at all, and similar problems have been reported before:
704 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
705 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
705 # Since this seems to be done by the interpreter itself, the best
706 # Since this seems to be done by the interpreter itself, the best
706 # we can do is to at least restore __builtins__ for the user on
707 # we can do is to at least restore __builtins__ for the user on
707 # exit.
708 # exit.
708 self.shell.user_ns['__builtins__'] = builtin_mod
709 self.shell.user_ns['__builtins__'] = builtin_mod
709
710
710 # Ensure key global structures are restored
711 # Ensure key global structures are restored
711 sys.argv = save_argv
712 sys.argv = save_argv
712 if restore_main:
713 if restore_main:
713 sys.modules['__main__'] = restore_main
714 sys.modules['__main__'] = restore_main
714 else:
715 else:
715 # Remove from sys.modules the reference to main_mod we'd
716 # Remove from sys.modules the reference to main_mod we'd
716 # added. Otherwise it will trap references to objects
717 # added. Otherwise it will trap references to objects
717 # contained therein.
718 # contained therein.
718 del sys.modules[main_mod_name]
719 del sys.modules[main_mod_name]
719
720
720 return stats
721 return stats
721
722
722 def _run_with_debugger(self, code, code_ns, filename=None,
723 def _run_with_debugger(self, code, code_ns, filename=None,
723 bp_line=None, bp_file=None):
724 bp_line=None, bp_file=None):
724 """
725 """
725 Run `code` in debugger with a break point.
726 Run `code` in debugger with a break point.
726
727
727 Parameters
728 Parameters
728 ----------
729 ----------
729 code : str
730 code : str
730 Code to execute.
731 Code to execute.
731 code_ns : dict
732 code_ns : dict
732 A namespace in which `code` is executed.
733 A namespace in which `code` is executed.
733 filename : str
734 filename : str
734 `code` is ran as if it is in `filename`.
735 `code` is ran as if it is in `filename`.
735 bp_line : int, optional
736 bp_line : int, optional
736 Line number of the break point.
737 Line number of the break point.
737 bp_file : str, optional
738 bp_file : str, optional
738 Path to the file in which break point is specified.
739 Path to the file in which break point is specified.
739 `filename` is used if not given.
740 `filename` is used if not given.
740
741
741 Raises
742 Raises
742 ------
743 ------
743 UsageError
744 UsageError
744 If the break point given by `bp_line` is not valid.
745 If the break point given by `bp_line` is not valid.
745
746
746 """
747 """
747 deb = debugger.Pdb(self.shell.colors)
748 deb = debugger.Pdb(self.shell.colors)
748 # reset Breakpoint state, which is moronically kept
749 # reset Breakpoint state, which is moronically kept
749 # in a class
750 # in a class
750 bdb.Breakpoint.next = 1
751 bdb.Breakpoint.next = 1
751 bdb.Breakpoint.bplist = {}
752 bdb.Breakpoint.bplist = {}
752 bdb.Breakpoint.bpbynumber = [None]
753 bdb.Breakpoint.bpbynumber = [None]
753 if bp_line is not None:
754 if bp_line is not None:
754 # Set an initial breakpoint to stop execution
755 # Set an initial breakpoint to stop execution
755 maxtries = 10
756 maxtries = 10
756 bp_file = bp_file or filename
757 bp_file = bp_file or filename
757 checkline = deb.checkline(bp_file, bp_line)
758 checkline = deb.checkline(bp_file, bp_line)
758 if not checkline:
759 if not checkline:
759 for bp in range(bp_line + 1, bp_line + maxtries + 1):
760 for bp in range(bp_line + 1, bp_line + maxtries + 1):
760 if deb.checkline(bp_file, bp):
761 if deb.checkline(bp_file, bp):
761 break
762 break
762 else:
763 else:
763 msg = ("\nI failed to find a valid line to set "
764 msg = ("\nI failed to find a valid line to set "
764 "a breakpoint\n"
765 "a breakpoint\n"
765 "after trying up to line: %s.\n"
766 "after trying up to line: %s.\n"
766 "Please set a valid breakpoint manually "
767 "Please set a valid breakpoint manually "
767 "with the -b option." % bp)
768 "with the -b option." % bp)
768 raise UsageError(msg)
769 raise UsageError(msg)
769 # if we find a good linenumber, set the breakpoint
770 # if we find a good linenumber, set the breakpoint
770 deb.do_break('%s:%s' % (bp_file, bp_line))
771 deb.do_break('%s:%s' % (bp_file, bp_line))
771
772
772 if filename:
773 if filename:
773 # Mimic Pdb._runscript(...)
774 # Mimic Pdb._runscript(...)
774 deb._wait_for_mainpyfile = True
775 deb._wait_for_mainpyfile = True
775 deb.mainpyfile = deb.canonic(filename)
776 deb.mainpyfile = deb.canonic(filename)
776
777
777 # Start file run
778 # Start file run
778 print "NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt
779 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
779 try:
780 try:
780 if filename:
781 if filename:
781 # save filename so it can be used by methods on the deb object
782 # save filename so it can be used by methods on the deb object
782 deb._exec_filename = filename
783 deb._exec_filename = filename
783 deb.run(code, code_ns)
784 deb.run(code, code_ns)
784
785
785 except:
786 except:
786 etype, value, tb = sys.exc_info()
787 etype, value, tb = sys.exc_info()
787 # Skip three frames in the traceback: the %run one,
788 # Skip three frames in the traceback: the %run one,
788 # one inside bdb.py, and the command-line typed by the
789 # one inside bdb.py, and the command-line typed by the
789 # user (run by exec in pdb itself).
790 # user (run by exec in pdb itself).
790 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
791 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
791
792
792 @staticmethod
793 @staticmethod
793 def _run_with_timing(run, nruns):
794 def _run_with_timing(run, nruns):
794 """
795 """
795 Run function `run` and print timing information.
796 Run function `run` and print timing information.
796
797
797 Parameters
798 Parameters
798 ----------
799 ----------
799 run : callable
800 run : callable
800 Any callable object which takes no argument.
801 Any callable object which takes no argument.
801 nruns : int
802 nruns : int
802 Number of times to execute `run`.
803 Number of times to execute `run`.
803
804
804 """
805 """
805 twall0 = time.time()
806 twall0 = time.time()
806 if nruns == 1:
807 if nruns == 1:
807 t0 = clock2()
808 t0 = clock2()
808 run()
809 run()
809 t1 = clock2()
810 t1 = clock2()
810 t_usr = t1[0] - t0[0]
811 t_usr = t1[0] - t0[0]
811 t_sys = t1[1] - t0[1]
812 t_sys = t1[1] - t0[1]
812 print "\nIPython CPU timings (estimated):"
813 print("\nIPython CPU timings (estimated):")
813 print " User : %10.2f s." % t_usr
814 print(" User : %10.2f s." % t_usr)
814 print " System : %10.2f s." % t_sys
815 print(" System : %10.2f s." % t_sys)
815 else:
816 else:
816 runs = range(nruns)
817 runs = range(nruns)
817 t0 = clock2()
818 t0 = clock2()
818 for nr in runs:
819 for nr in runs:
819 run()
820 run()
820 t1 = clock2()
821 t1 = clock2()
821 t_usr = t1[0] - t0[0]
822 t_usr = t1[0] - t0[0]
822 t_sys = t1[1] - t0[1]
823 t_sys = t1[1] - t0[1]
823 print "\nIPython CPU timings (estimated):"
824 print("\nIPython CPU timings (estimated):")
824 print "Total runs performed:", nruns
825 print("Total runs performed:", nruns)
825 print " Times : %10s %10s" % ('Total', 'Per run')
826 print(" Times : %10s %10s" % ('Total', 'Per run'))
826 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
827 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
827 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
828 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
828 twall1 = time.time()
829 twall1 = time.time()
829 print "Wall time: %10.2f s." % (twall1 - twall0)
830 print("Wall time: %10.2f s." % (twall1 - twall0))
830
831
831 @skip_doctest
832 @skip_doctest
832 @line_cell_magic
833 @line_cell_magic
833 def timeit(self, line='', cell=None):
834 def timeit(self, line='', cell=None):
834 """Time execution of a Python statement or expression
835 """Time execution of a Python statement or expression
835
836
836 Usage, in line mode:
837 Usage, in line mode:
837 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
838 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
838 or in cell mode:
839 or in cell mode:
839 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
840 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
840 code
841 code
841 code...
842 code...
842
843
843 Time execution of a Python statement or expression using the timeit
844 Time execution of a Python statement or expression using the timeit
844 module. This function can be used both as a line and cell magic:
845 module. This function can be used both as a line and cell magic:
845
846
846 - In line mode you can time a single-line statement (though multiple
847 - In line mode you can time a single-line statement (though multiple
847 ones can be chained with using semicolons).
848 ones can be chained with using semicolons).
848
849
849 - In cell mode, the statement in the first line is used as setup code
850 - In cell mode, the statement in the first line is used as setup code
850 (executed but not timed) and the body of the cell is timed. The cell
851 (executed but not timed) and the body of the cell is timed. The cell
851 body has access to any variables created in the setup code.
852 body has access to any variables created in the setup code.
852
853
853 Options:
854 Options:
854 -n<N>: execute the given statement <N> times in a loop. If this value
855 -n<N>: execute the given statement <N> times in a loop. If this value
855 is not given, a fitting value is chosen.
856 is not given, a fitting value is chosen.
856
857
857 -r<R>: repeat the loop iteration <R> times and take the best result.
858 -r<R>: repeat the loop iteration <R> times and take the best result.
858 Default: 3
859 Default: 3
859
860
860 -t: use time.time to measure the time, which is the default on Unix.
861 -t: use time.time to measure the time, which is the default on Unix.
861 This function measures wall time.
862 This function measures wall time.
862
863
863 -c: use time.clock to measure the time, which is the default on
864 -c: use time.clock to measure the time, which is the default on
864 Windows and measures wall time. On Unix, resource.getrusage is used
865 Windows and measures wall time. On Unix, resource.getrusage is used
865 instead and returns the CPU user time.
866 instead and returns the CPU user time.
866
867
867 -p<P>: use a precision of <P> digits to display the timing result.
868 -p<P>: use a precision of <P> digits to display the timing result.
868 Default: 3
869 Default: 3
869
870
870 -q: Quiet, do not print result.
871 -q: Quiet, do not print result.
871
872
872 -o: return a TimeitResult that can be stored in a variable to inspect
873 -o: return a TimeitResult that can be stored in a variable to inspect
873 the result in more details.
874 the result in more details.
874
875
875
876
876 Examples
877 Examples
877 --------
878 --------
878 ::
879 ::
879
880
880 In [1]: %timeit pass
881 In [1]: %timeit pass
881 10000000 loops, best of 3: 53.3 ns per loop
882 10000000 loops, best of 3: 53.3 ns per loop
882
883
883 In [2]: u = None
884 In [2]: u = None
884
885
885 In [3]: %timeit u is None
886 In [3]: %timeit u is None
886 10000000 loops, best of 3: 184 ns per loop
887 10000000 loops, best of 3: 184 ns per loop
887
888
888 In [4]: %timeit -r 4 u == None
889 In [4]: %timeit -r 4 u == None
889 1000000 loops, best of 4: 242 ns per loop
890 1000000 loops, best of 4: 242 ns per loop
890
891
891 In [5]: import time
892 In [5]: import time
892
893
893 In [6]: %timeit -n1 time.sleep(2)
894 In [6]: %timeit -n1 time.sleep(2)
894 1 loops, best of 3: 2 s per loop
895 1 loops, best of 3: 2 s per loop
895
896
896
897
897 The times reported by %timeit will be slightly higher than those
898 The times reported by %timeit will be slightly higher than those
898 reported by the timeit.py script when variables are accessed. This is
899 reported by the timeit.py script when variables are accessed. This is
899 due to the fact that %timeit executes the statement in the namespace
900 due to the fact that %timeit executes the statement in the namespace
900 of the shell, compared with timeit.py, which uses a single setup
901 of the shell, compared with timeit.py, which uses a single setup
901 statement to import function or create variables. Generally, the bias
902 statement to import function or create variables. Generally, the bias
902 does not matter as long as results from timeit.py are not mixed with
903 does not matter as long as results from timeit.py are not mixed with
903 those from %timeit."""
904 those from %timeit."""
904
905
905 import timeit
906 import timeit
906
907
907 opts, stmt = self.parse_options(line,'n:r:tcp:qo',
908 opts, stmt = self.parse_options(line,'n:r:tcp:qo',
908 posix=False, strict=False)
909 posix=False, strict=False)
909 if stmt == "" and cell is None:
910 if stmt == "" and cell is None:
910 return
911 return
911
912
912 timefunc = timeit.default_timer
913 timefunc = timeit.default_timer
913 number = int(getattr(opts, "n", 0))
914 number = int(getattr(opts, "n", 0))
914 repeat = int(getattr(opts, "r", timeit.default_repeat))
915 repeat = int(getattr(opts, "r", timeit.default_repeat))
915 precision = int(getattr(opts, "p", 3))
916 precision = int(getattr(opts, "p", 3))
916 quiet = 'q' in opts
917 quiet = 'q' in opts
917 return_result = 'o' in opts
918 return_result = 'o' in opts
918 if hasattr(opts, "t"):
919 if hasattr(opts, "t"):
919 timefunc = time.time
920 timefunc = time.time
920 if hasattr(opts, "c"):
921 if hasattr(opts, "c"):
921 timefunc = clock
922 timefunc = clock
922
923
923 timer = timeit.Timer(timer=timefunc)
924 timer = timeit.Timer(timer=timefunc)
924 # this code has tight coupling to the inner workings of timeit.Timer,
925 # this code has tight coupling to the inner workings of timeit.Timer,
925 # but is there a better way to achieve that the code stmt has access
926 # but is there a better way to achieve that the code stmt has access
926 # to the shell namespace?
927 # to the shell namespace?
927 transform = self.shell.input_splitter.transform_cell
928 transform = self.shell.input_splitter.transform_cell
928
929
929 if cell is None:
930 if cell is None:
930 # called as line magic
931 # called as line magic
931 ast_setup = ast.parse("pass")
932 ast_setup = ast.parse("pass")
932 ast_stmt = ast.parse(transform(stmt))
933 ast_stmt = ast.parse(transform(stmt))
933 else:
934 else:
934 ast_setup = ast.parse(transform(stmt))
935 ast_setup = ast.parse(transform(stmt))
935 ast_stmt = ast.parse(transform(cell))
936 ast_stmt = ast.parse(transform(cell))
936
937
937 ast_setup = self.shell.transform_ast(ast_setup)
938 ast_setup = self.shell.transform_ast(ast_setup)
938 ast_stmt = self.shell.transform_ast(ast_stmt)
939 ast_stmt = self.shell.transform_ast(ast_stmt)
939
940
940 # This codestring is taken from timeit.template - we fill it in as an
941 # This codestring is taken from timeit.template - we fill it in as an
941 # AST, so that we can apply our AST transformations to the user code
942 # AST, so that we can apply our AST transformations to the user code
942 # without affecting the timing code.
943 # without affecting the timing code.
943 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
944 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
944 ' setup\n'
945 ' setup\n'
945 ' _t0 = _timer()\n'
946 ' _t0 = _timer()\n'
946 ' for _i in _it:\n'
947 ' for _i in _it:\n'
947 ' stmt\n'
948 ' stmt\n'
948 ' _t1 = _timer()\n'
949 ' _t1 = _timer()\n'
949 ' return _t1 - _t0\n')
950 ' return _t1 - _t0\n')
950
951
951 class TimeitTemplateFiller(ast.NodeTransformer):
952 class TimeitTemplateFiller(ast.NodeTransformer):
952 "This is quite tightly tied to the template definition above."
953 "This is quite tightly tied to the template definition above."
953 def visit_FunctionDef(self, node):
954 def visit_FunctionDef(self, node):
954 "Fill in the setup statement"
955 "Fill in the setup statement"
955 self.generic_visit(node)
956 self.generic_visit(node)
956 if node.name == "inner":
957 if node.name == "inner":
957 node.body[:1] = ast_setup.body
958 node.body[:1] = ast_setup.body
958
959
959 return node
960 return node
960
961
961 def visit_For(self, node):
962 def visit_For(self, node):
962 "Fill in the statement to be timed"
963 "Fill in the statement to be timed"
963 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
964 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
964 node.body = ast_stmt.body
965 node.body = ast_stmt.body
965 return node
966 return node
966
967
967 timeit_ast = TimeitTemplateFiller().visit(timeit_ast_template)
968 timeit_ast = TimeitTemplateFiller().visit(timeit_ast_template)
968 timeit_ast = ast.fix_missing_locations(timeit_ast)
969 timeit_ast = ast.fix_missing_locations(timeit_ast)
969
970
970 # Track compilation time so it can be reported if too long
971 # Track compilation time so it can be reported if too long
971 # Minimum time above which compilation time will be reported
972 # Minimum time above which compilation time will be reported
972 tc_min = 0.1
973 tc_min = 0.1
973
974
974 t0 = clock()
975 t0 = clock()
975 code = compile(timeit_ast, "<magic-timeit>", "exec")
976 code = compile(timeit_ast, "<magic-timeit>", "exec")
976 tc = clock()-t0
977 tc = clock()-t0
977
978
978 ns = {}
979 ns = {}
979 exec code in self.shell.user_ns, ns
980 exec code in self.shell.user_ns, ns
980 timer.inner = ns["inner"]
981 timer.inner = ns["inner"]
981
982
982 if number == 0:
983 if number == 0:
983 # determine number so that 0.2 <= total time < 2.0
984 # determine number so that 0.2 <= total time < 2.0
984 number = 1
985 number = 1
985 for _ in range(1, 10):
986 for _ in range(1, 10):
986 if timer.timeit(number) >= 0.2:
987 if timer.timeit(number) >= 0.2:
987 break
988 break
988 number *= 10
989 number *= 10
989 all_runs = timer.repeat(repeat, number)
990 all_runs = timer.repeat(repeat, number)
990 best = min(all_runs) / number
991 best = min(all_runs) / number
991 if not quiet :
992 if not quiet :
992 print u"%d loops, best of %d: %s per loop" % (number, repeat,
993 print(u"%d loops, best of %d: %s per loop" % (number, repeat,
993 _format_time(best, precision))
994 _format_time(best, precision)))
994 if tc > tc_min:
995 if tc > tc_min:
995 print "Compiler time: %.2f s" % tc
996 print("Compiler time: %.2f s" % tc)
996 if return_result:
997 if return_result:
997 return TimeitResult(number, repeat, best, all_runs, tc, precision)
998 return TimeitResult(number, repeat, best, all_runs, tc, precision)
998
999
999 @skip_doctest
1000 @skip_doctest
1000 @needs_local_scope
1001 @needs_local_scope
1001 @line_cell_magic
1002 @line_cell_magic
1002 def time(self,line='', cell=None, local_ns=None):
1003 def time(self,line='', cell=None, local_ns=None):
1003 """Time execution of a Python statement or expression.
1004 """Time execution of a Python statement or expression.
1004
1005
1005 The CPU and wall clock times are printed, and the value of the
1006 The CPU and wall clock times are printed, and the value of the
1006 expression (if any) is returned. Note that under Win32, system time
1007 expression (if any) is returned. Note that under Win32, system time
1007 is always reported as 0, since it can not be measured.
1008 is always reported as 0, since it can not be measured.
1008
1009
1009 This function can be used both as a line and cell magic:
1010 This function can be used both as a line and cell magic:
1010
1011
1011 - In line mode you can time a single-line statement (though multiple
1012 - In line mode you can time a single-line statement (though multiple
1012 ones can be chained with using semicolons).
1013 ones can be chained with using semicolons).
1013
1014
1014 - In cell mode, you can time the cell body (a directly
1015 - In cell mode, you can time the cell body (a directly
1015 following statement raises an error).
1016 following statement raises an error).
1016
1017
1017 This function provides very basic timing functionality. Use the timeit
1018 This function provides very basic timing functionality. Use the timeit
1018 magic for more controll over the measurement.
1019 magic for more controll over the measurement.
1019
1020
1020 Examples
1021 Examples
1021 --------
1022 --------
1022 ::
1023 ::
1023
1024
1024 In [1]: %time 2**128
1025 In [1]: %time 2**128
1025 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1026 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1026 Wall time: 0.00
1027 Wall time: 0.00
1027 Out[1]: 340282366920938463463374607431768211456L
1028 Out[1]: 340282366920938463463374607431768211456L
1028
1029
1029 In [2]: n = 1000000
1030 In [2]: n = 1000000
1030
1031
1031 In [3]: %time sum(range(n))
1032 In [3]: %time sum(range(n))
1032 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1033 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1033 Wall time: 1.37
1034 Wall time: 1.37
1034 Out[3]: 499999500000L
1035 Out[3]: 499999500000L
1035
1036
1036 In [4]: %time print 'hello world'
1037 In [4]: %time print 'hello world'
1037 hello world
1038 hello world
1038 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1039 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1039 Wall time: 0.00
1040 Wall time: 0.00
1040
1041
1041 Note that the time needed by Python to compile the given expression
1042 Note that the time needed by Python to compile the given expression
1042 will be reported if it is more than 0.1s. In this example, the
1043 will be reported if it is more than 0.1s. In this example, the
1043 actual exponentiation is done by Python at compilation time, so while
1044 actual exponentiation is done by Python at compilation time, so while
1044 the expression can take a noticeable amount of time to compute, that
1045 the expression can take a noticeable amount of time to compute, that
1045 time is purely due to the compilation:
1046 time is purely due to the compilation:
1046
1047
1047 In [5]: %time 3**9999;
1048 In [5]: %time 3**9999;
1048 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1049 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1049 Wall time: 0.00 s
1050 Wall time: 0.00 s
1050
1051
1051 In [6]: %time 3**999999;
1052 In [6]: %time 3**999999;
1052 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1053 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1053 Wall time: 0.00 s
1054 Wall time: 0.00 s
1054 Compiler : 0.78 s
1055 Compiler : 0.78 s
1055 """
1056 """
1056
1057
1057 # fail immediately if the given expression can't be compiled
1058 # fail immediately if the given expression can't be compiled
1058
1059
1059 if line and cell:
1060 if line and cell:
1060 raise UsageError("Can't use statement directly after '%%time'!")
1061 raise UsageError("Can't use statement directly after '%%time'!")
1061
1062
1062 if cell:
1063 if cell:
1063 expr = self.shell.input_transformer_manager.transform_cell(cell)
1064 expr = self.shell.input_transformer_manager.transform_cell(cell)
1064 else:
1065 else:
1065 expr = self.shell.input_transformer_manager.transform_cell(line)
1066 expr = self.shell.input_transformer_manager.transform_cell(line)
1066
1067
1067 # Minimum time above which parse time will be reported
1068 # Minimum time above which parse time will be reported
1068 tp_min = 0.1
1069 tp_min = 0.1
1069
1070
1070 t0 = clock()
1071 t0 = clock()
1071 expr_ast = ast.parse(expr)
1072 expr_ast = ast.parse(expr)
1072 tp = clock()-t0
1073 tp = clock()-t0
1073
1074
1074 # Apply AST transformations
1075 # Apply AST transformations
1075 expr_ast = self.shell.transform_ast(expr_ast)
1076 expr_ast = self.shell.transform_ast(expr_ast)
1076
1077
1077 # Minimum time above which compilation time will be reported
1078 # Minimum time above which compilation time will be reported
1078 tc_min = 0.1
1079 tc_min = 0.1
1079
1080
1080 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1081 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1081 mode = 'eval'
1082 mode = 'eval'
1082 source = '<timed eval>'
1083 source = '<timed eval>'
1083 expr_ast = ast.Expression(expr_ast.body[0].value)
1084 expr_ast = ast.Expression(expr_ast.body[0].value)
1084 else:
1085 else:
1085 mode = 'exec'
1086 mode = 'exec'
1086 source = '<timed exec>'
1087 source = '<timed exec>'
1087 t0 = clock()
1088 t0 = clock()
1088 code = compile(expr_ast, source, mode)
1089 code = compile(expr_ast, source, mode)
1089 tc = clock()-t0
1090 tc = clock()-t0
1090
1091
1091 # skew measurement as little as possible
1092 # skew measurement as little as possible
1092 glob = self.shell.user_ns
1093 glob = self.shell.user_ns
1093 wtime = time.time
1094 wtime = time.time
1094 # time execution
1095 # time execution
1095 wall_st = wtime()
1096 wall_st = wtime()
1096 if mode=='eval':
1097 if mode=='eval':
1097 st = clock2()
1098 st = clock2()
1098 out = eval(code, glob, local_ns)
1099 out = eval(code, glob, local_ns)
1099 end = clock2()
1100 end = clock2()
1100 else:
1101 else:
1101 st = clock2()
1102 st = clock2()
1102 exec code in glob, local_ns
1103 exec code in glob, local_ns
1103 end = clock2()
1104 end = clock2()
1104 out = None
1105 out = None
1105 wall_end = wtime()
1106 wall_end = wtime()
1106 # Compute actual times and report
1107 # Compute actual times and report
1107 wall_time = wall_end-wall_st
1108 wall_time = wall_end-wall_st
1108 cpu_user = end[0]-st[0]
1109 cpu_user = end[0]-st[0]
1109 cpu_sys = end[1]-st[1]
1110 cpu_sys = end[1]-st[1]
1110 cpu_tot = cpu_user+cpu_sys
1111 cpu_tot = cpu_user+cpu_sys
1111 # On windows cpu_sys is always zero, so no new information to the next print
1112 # On windows cpu_sys is always zero, so no new information to the next print
1112 if sys.platform != 'win32':
1113 if sys.platform != 'win32':
1113 print "CPU times: user %s, sys: %s, total: %s" % \
1114 print("CPU times: user %s, sys: %s, total: %s" % \
1114 (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot))
1115 (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot)))
1115 print "Wall time: %s" % _format_time(wall_time)
1116 print("Wall time: %s" % _format_time(wall_time))
1116 if tc > tc_min:
1117 if tc > tc_min:
1117 print "Compiler : %s" % _format_time(tc)
1118 print("Compiler : %s" % _format_time(tc))
1118 if tp > tp_min:
1119 if tp > tp_min:
1119 print "Parser : %s" % _format_time(tp)
1120 print("Parser : %s" % _format_time(tp))
1120 return out
1121 return out
1121
1122
1122 @skip_doctest
1123 @skip_doctest
1123 @line_magic
1124 @line_magic
1124 def macro(self, parameter_s=''):
1125 def macro(self, parameter_s=''):
1125 """Define a macro for future re-execution. It accepts ranges of history,
1126 """Define a macro for future re-execution. It accepts ranges of history,
1126 filenames or string objects.
1127 filenames or string objects.
1127
1128
1128 Usage:\\
1129 Usage:\\
1129 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1130 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1130
1131
1131 Options:
1132 Options:
1132
1133
1133 -r: use 'raw' input. By default, the 'processed' history is used,
1134 -r: use 'raw' input. By default, the 'processed' history is used,
1134 so that magics are loaded in their transformed version to valid
1135 so that magics are loaded in their transformed version to valid
1135 Python. If this option is given, the raw input as typed at the
1136 Python. If this option is given, the raw input as typed at the
1136 command line is used instead.
1137 command line is used instead.
1137
1138
1138 -q: quiet macro definition. By default, a tag line is printed
1139 -q: quiet macro definition. By default, a tag line is printed
1139 to indicate the macro has been created, and then the contents of
1140 to indicate the macro has been created, and then the contents of
1140 the macro are printed. If this option is given, then no printout
1141 the macro are printed. If this option is given, then no printout
1141 is produced once the macro is created.
1142 is produced once the macro is created.
1142
1143
1143 This will define a global variable called `name` which is a string
1144 This will define a global variable called `name` which is a string
1144 made of joining the slices and lines you specify (n1,n2,... numbers
1145 made of joining the slices and lines you specify (n1,n2,... numbers
1145 above) from your input history into a single string. This variable
1146 above) from your input history into a single string. This variable
1146 acts like an automatic function which re-executes those lines as if
1147 acts like an automatic function which re-executes those lines as if
1147 you had typed them. You just type 'name' at the prompt and the code
1148 you had typed them. You just type 'name' at the prompt and the code
1148 executes.
1149 executes.
1149
1150
1150 The syntax for indicating input ranges is described in %history.
1151 The syntax for indicating input ranges is described in %history.
1151
1152
1152 Note: as a 'hidden' feature, you can also use traditional python slice
1153 Note: as a 'hidden' feature, you can also use traditional python slice
1153 notation, where N:M means numbers N through M-1.
1154 notation, where N:M means numbers N through M-1.
1154
1155
1155 For example, if your history contains (print using %hist -n )::
1156 For example, if your history contains (print using %hist -n )::
1156
1157
1157 44: x=1
1158 44: x=1
1158 45: y=3
1159 45: y=3
1159 46: z=x+y
1160 46: z=x+y
1160 47: print x
1161 47: print x
1161 48: a=5
1162 48: a=5
1162 49: print 'x',x,'y',y
1163 49: print 'x',x,'y',y
1163
1164
1164 you can create a macro with lines 44 through 47 (included) and line 49
1165 you can create a macro with lines 44 through 47 (included) and line 49
1165 called my_macro with::
1166 called my_macro with::
1166
1167
1167 In [55]: %macro my_macro 44-47 49
1168 In [55]: %macro my_macro 44-47 49
1168
1169
1169 Now, typing `my_macro` (without quotes) will re-execute all this code
1170 Now, typing `my_macro` (without quotes) will re-execute all this code
1170 in one pass.
1171 in one pass.
1171
1172
1172 You don't need to give the line-numbers in order, and any given line
1173 You don't need to give the line-numbers in order, and any given line
1173 number can appear multiple times. You can assemble macros with any
1174 number can appear multiple times. You can assemble macros with any
1174 lines from your input history in any order.
1175 lines from your input history in any order.
1175
1176
1176 The macro is a simple object which holds its value in an attribute,
1177 The macro is a simple object which holds its value in an attribute,
1177 but IPython's display system checks for macros and executes them as
1178 but IPython's display system checks for macros and executes them as
1178 code instead of printing them when you type their name.
1179 code instead of printing them when you type their name.
1179
1180
1180 You can view a macro's contents by explicitly printing it with::
1181 You can view a macro's contents by explicitly printing it with::
1181
1182
1182 print macro_name
1183 print macro_name
1183
1184
1184 """
1185 """
1185 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1186 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1186 if not args: # List existing macros
1187 if not args: # List existing macros
1187 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
1188 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
1188 isinstance(v, Macro))
1189 isinstance(v, Macro))
1189 if len(args) == 1:
1190 if len(args) == 1:
1190 raise UsageError(
1191 raise UsageError(
1191 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1192 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1192 name, codefrom = args[0], " ".join(args[1:])
1193 name, codefrom = args[0], " ".join(args[1:])
1193
1194
1194 #print 'rng',ranges # dbg
1195 #print 'rng',ranges # dbg
1195 try:
1196 try:
1196 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1197 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1197 except (ValueError, TypeError) as e:
1198 except (ValueError, TypeError) as e:
1198 print e.args[0]
1199 print(e.args[0])
1199 return
1200 return
1200 macro = Macro(lines)
1201 macro = Macro(lines)
1201 self.shell.define_macro(name, macro)
1202 self.shell.define_macro(name, macro)
1202 if not ( 'q' in opts) :
1203 if not ( 'q' in opts) :
1203 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
1204 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1204 print '=== Macro contents: ==='
1205 print('=== Macro contents: ===')
1205 print macro,
1206 print(macro, end=' ')
1206
1207
1207 @magic_arguments.magic_arguments()
1208 @magic_arguments.magic_arguments()
1208 @magic_arguments.argument('output', type=str, default='', nargs='?',
1209 @magic_arguments.argument('output', type=str, default='', nargs='?',
1209 help="""The name of the variable in which to store output.
1210 help="""The name of the variable in which to store output.
1210 This is a utils.io.CapturedIO object with stdout/err attributes
1211 This is a utils.io.CapturedIO object with stdout/err attributes
1211 for the text of the captured output.
1212 for the text of the captured output.
1212
1213
1213 CapturedOutput also has a show() method for displaying the output,
1214 CapturedOutput also has a show() method for displaying the output,
1214 and __call__ as well, so you can use that to quickly display the
1215 and __call__ as well, so you can use that to quickly display the
1215 output.
1216 output.
1216
1217
1217 If unspecified, captured output is discarded.
1218 If unspecified, captured output is discarded.
1218 """
1219 """
1219 )
1220 )
1220 @magic_arguments.argument('--no-stderr', action="store_true",
1221 @magic_arguments.argument('--no-stderr', action="store_true",
1221 help="""Don't capture stderr."""
1222 help="""Don't capture stderr."""
1222 )
1223 )
1223 @magic_arguments.argument('--no-stdout', action="store_true",
1224 @magic_arguments.argument('--no-stdout', action="store_true",
1224 help="""Don't capture stdout."""
1225 help="""Don't capture stdout."""
1225 )
1226 )
1226 @magic_arguments.argument('--no-display', action="store_true",
1227 @magic_arguments.argument('--no-display', action="store_true",
1227 help="""Don't capture IPython's rich display."""
1228 help="""Don't capture IPython's rich display."""
1228 )
1229 )
1229 @cell_magic
1230 @cell_magic
1230 def capture(self, line, cell):
1231 def capture(self, line, cell):
1231 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1232 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1232 args = magic_arguments.parse_argstring(self.capture, line)
1233 args = magic_arguments.parse_argstring(self.capture, line)
1233 out = not args.no_stdout
1234 out = not args.no_stdout
1234 err = not args.no_stderr
1235 err = not args.no_stderr
1235 disp = not args.no_display
1236 disp = not args.no_display
1236 with capture_output(out, err, disp) as io:
1237 with capture_output(out, err, disp) as io:
1237 self.shell.run_cell(cell)
1238 self.shell.run_cell(cell)
1238 if args.output:
1239 if args.output:
1239 self.shell.user_ns[args.output] = io
1240 self.shell.user_ns[args.output] = io
1240
1241
1241 def parse_breakpoint(text, current_file):
1242 def parse_breakpoint(text, current_file):
1242 '''Returns (file, line) for file:line and (current_file, line) for line'''
1243 '''Returns (file, line) for file:line and (current_file, line) for line'''
1243 colon = text.find(':')
1244 colon = text.find(':')
1244 if colon == -1:
1245 if colon == -1:
1245 return current_file, int(text)
1246 return current_file, int(text)
1246 else:
1247 else:
1247 return text[:colon], int(text[colon+1:])
1248 return text[:colon], int(text[colon+1:])
1248
1249
1249 def _format_time(timespan, precision=3):
1250 def _format_time(timespan, precision=3):
1250 """Formats the timespan in a human readable form"""
1251 """Formats the timespan in a human readable form"""
1251 import math
1252 import math
1252
1253
1253 if timespan >= 60.0:
1254 if timespan >= 60.0:
1254 # we have more than a minute, format that in a human readable form
1255 # we have more than a minute, format that in a human readable form
1255 # Idea from http://snipplr.com/view/5713/
1256 # Idea from http://snipplr.com/view/5713/
1256 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1257 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1257 time = []
1258 time = []
1258 leftover = timespan
1259 leftover = timespan
1259 for suffix, length in parts:
1260 for suffix, length in parts:
1260 value = int(leftover / length)
1261 value = int(leftover / length)
1261 if value > 0:
1262 if value > 0:
1262 leftover = leftover % length
1263 leftover = leftover % length
1263 time.append(u'%s%s' % (str(value), suffix))
1264 time.append(u'%s%s' % (str(value), suffix))
1264 if leftover < 1:
1265 if leftover < 1:
1265 break
1266 break
1266 return " ".join(time)
1267 return " ".join(time)
1267
1268
1268
1269
1269 # Unfortunately the unicode 'micro' symbol can cause problems in
1270 # Unfortunately the unicode 'micro' symbol can cause problems in
1270 # certain terminals.
1271 # certain terminals.
1271 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1272 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1272 # Try to prevent crashes by being more secure than it needs to
1273 # Try to prevent crashes by being more secure than it needs to
1273 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1274 # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set.
1274 units = [u"s", u"ms",u'us',"ns"] # the save value
1275 units = [u"s", u"ms",u'us',"ns"] # the save value
1275 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1276 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1276 try:
1277 try:
1277 u'\xb5'.encode(sys.stdout.encoding)
1278 u'\xb5'.encode(sys.stdout.encoding)
1278 units = [u"s", u"ms",u'\xb5s',"ns"]
1279 units = [u"s", u"ms",u'\xb5s',"ns"]
1279 except:
1280 except:
1280 pass
1281 pass
1281 scaling = [1, 1e3, 1e6, 1e9]
1282 scaling = [1, 1e3, 1e6, 1e9]
1282
1283
1283 if timespan > 0.0:
1284 if timespan > 0.0:
1284 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1285 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1285 else:
1286 else:
1286 order = 3
1287 order = 3
1287 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
1288 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,92 +1,93 b''
1 """Implementation of magic functions for the extension machinery.
1 """Implementation of magic functions for the extension machinery.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Stdlib
16 # Stdlib
16 import os
17 import os
17
18
18 # Our own packages
19 # Our own packages
19 from IPython.core.error import UsageError
20 from IPython.core.error import UsageError
20 from IPython.core.magic import Magics, magics_class, line_magic
21 from IPython.core.magic import Magics, magics_class, line_magic
21
22
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23 # Magic implementation classes
24 # Magic implementation classes
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
25
26
26 @magics_class
27 @magics_class
27 class ExtensionMagics(Magics):
28 class ExtensionMagics(Magics):
28 """Magics to manage the IPython extensions system."""
29 """Magics to manage the IPython extensions system."""
29
30
30 @line_magic
31 @line_magic
31 def install_ext(self, parameter_s=''):
32 def install_ext(self, parameter_s=''):
32 """Download and install an extension from a URL, e.g.::
33 """Download and install an extension from a URL, e.g.::
33
34
34 %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py
35 %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py
35
36
36 The URL should point to an importable Python module - either a .py file
37 The URL should point to an importable Python module - either a .py file
37 or a .zip file.
38 or a .zip file.
38
39
39 Parameters:
40 Parameters:
40
41
41 -n filename : Specify a name for the file, rather than taking it from
42 -n filename : Specify a name for the file, rather than taking it from
42 the URL.
43 the URL.
43 """
44 """
44 opts, args = self.parse_options(parameter_s, 'n:')
45 opts, args = self.parse_options(parameter_s, 'n:')
45 try:
46 try:
46 filename = self.shell.extension_manager.install_extension(args,
47 filename = self.shell.extension_manager.install_extension(args,
47 opts.get('n'))
48 opts.get('n'))
48 except ValueError as e:
49 except ValueError as e:
49 print e
50 print(e)
50 return
51 return
51
52
52 filename = os.path.basename(filename)
53 filename = os.path.basename(filename)
53 print "Installed %s. To use it, type:" % filename
54 print("Installed %s. To use it, type:" % filename)
54 print " %%load_ext %s" % os.path.splitext(filename)[0]
55 print(" %%load_ext %s" % os.path.splitext(filename)[0])
55
56
56
57
57 @line_magic
58 @line_magic
58 def load_ext(self, module_str):
59 def load_ext(self, module_str):
59 """Load an IPython extension by its module name."""
60 """Load an IPython extension by its module name."""
60 if not module_str:
61 if not module_str:
61 raise UsageError('Missing module name.')
62 raise UsageError('Missing module name.')
62 res = self.shell.extension_manager.load_extension(module_str)
63 res = self.shell.extension_manager.load_extension(module_str)
63
64
64 if res == 'already loaded':
65 if res == 'already loaded':
65 print "The %s extension is already loaded. To reload it, use:" % module_str
66 print("The %s extension is already loaded. To reload it, use:" % module_str)
66 print " %reload_ext", module_str
67 print(" %reload_ext", module_str)
67 elif res == 'no load function':
68 elif res == 'no load function':
68 print "The %s module is not an IPython extension." % module_str
69 print("The %s module is not an IPython extension." % module_str)
69
70
70 @line_magic
71 @line_magic
71 def unload_ext(self, module_str):
72 def unload_ext(self, module_str):
72 """Unload an IPython extension by its module name.
73 """Unload an IPython extension by its module name.
73
74
74 Not all extensions can be unloaded, only those which define an
75 Not all extensions can be unloaded, only those which define an
75 ``unload_ipython_extension`` function.
76 ``unload_ipython_extension`` function.
76 """
77 """
77 if not module_str:
78 if not module_str:
78 raise UsageError('Missing module name.')
79 raise UsageError('Missing module name.')
79
80
80 res = self.shell.extension_manager.unload_extension(module_str)
81 res = self.shell.extension_manager.unload_extension(module_str)
81
82
82 if res == 'no unload function':
83 if res == 'no unload function':
83 print "The %s extension doesn't define how to unload it." % module_str
84 print("The %s extension doesn't define how to unload it." % module_str)
84 elif res == "not loaded":
85 elif res == "not loaded":
85 print "The %s extension is not loaded." % module_str
86 print("The %s extension is not loaded." % module_str)
86
87
87 @line_magic
88 @line_magic
88 def reload_ext(self, module_str):
89 def reload_ext(self, module_str):
89 """Reload an IPython extension by its module name."""
90 """Reload an IPython extension by its module name."""
90 if not module_str:
91 if not module_str:
91 raise UsageError('Missing module name.')
92 raise UsageError('Missing module name.')
92 self.shell.extension_manager.reload_extension(module_str)
93 self.shell.extension_manager.reload_extension(module_str)
@@ -1,704 +1,705 b''
1 """Implementation of namespace-related magic functions.
1 """Implementation of namespace-related magic functions.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Stdlib
16 # Stdlib
16 import gc
17 import gc
17 import re
18 import re
18 import sys
19 import sys
19
20
20 # Our own packages
21 # Our own packages
21 from IPython.core import page
22 from IPython.core import page
22 from IPython.core.error import StdinNotImplementedError, UsageError
23 from IPython.core.error import StdinNotImplementedError, UsageError
23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.testing.skipdoctest import skip_doctest
25 from IPython.utils.encoding import DEFAULT_ENCODING
26 from IPython.utils.encoding import DEFAULT_ENCODING
26 from IPython.utils.openpy import read_py_file
27 from IPython.utils.openpy import read_py_file
27 from IPython.utils.path import get_py_filename
28 from IPython.utils.path import get_py_filename
28
29
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30 # Magic implementation classes
31 # Magic implementation classes
31 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
32
33
33 @magics_class
34 @magics_class
34 class NamespaceMagics(Magics):
35 class NamespaceMagics(Magics):
35 """Magics to manage various aspects of the user's namespace.
36 """Magics to manage various aspects of the user's namespace.
36
37
37 These include listing variables, introspecting into them, etc.
38 These include listing variables, introspecting into them, etc.
38 """
39 """
39
40
40 @line_magic
41 @line_magic
41 def pinfo(self, parameter_s='', namespaces=None):
42 def pinfo(self, parameter_s='', namespaces=None):
42 """Provide detailed information about an object.
43 """Provide detailed information about an object.
43
44
44 '%pinfo object' is just a synonym for object? or ?object."""
45 '%pinfo object' is just a synonym for object? or ?object."""
45
46
46 #print 'pinfo par: <%s>' % parameter_s # dbg
47 #print 'pinfo par: <%s>' % parameter_s # dbg
47 # detail_level: 0 -> obj? , 1 -> obj??
48 # detail_level: 0 -> obj? , 1 -> obj??
48 detail_level = 0
49 detail_level = 0
49 # We need to detect if we got called as 'pinfo pinfo foo', which can
50 # We need to detect if we got called as 'pinfo pinfo foo', which can
50 # happen if the user types 'pinfo foo?' at the cmd line.
51 # happen if the user types 'pinfo foo?' at the cmd line.
51 pinfo,qmark1,oname,qmark2 = \
52 pinfo,qmark1,oname,qmark2 = \
52 re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
53 re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
53 if pinfo or qmark1 or qmark2:
54 if pinfo or qmark1 or qmark2:
54 detail_level = 1
55 detail_level = 1
55 if "*" in oname:
56 if "*" in oname:
56 self.psearch(oname)
57 self.psearch(oname)
57 else:
58 else:
58 self.shell._inspect('pinfo', oname, detail_level=detail_level,
59 self.shell._inspect('pinfo', oname, detail_level=detail_level,
59 namespaces=namespaces)
60 namespaces=namespaces)
60
61
61 @line_magic
62 @line_magic
62 def pinfo2(self, parameter_s='', namespaces=None):
63 def pinfo2(self, parameter_s='', namespaces=None):
63 """Provide extra detailed information about an object.
64 """Provide extra detailed information about an object.
64
65
65 '%pinfo2 object' is just a synonym for object?? or ??object."""
66 '%pinfo2 object' is just a synonym for object?? or ??object."""
66 self.shell._inspect('pinfo', parameter_s, detail_level=1,
67 self.shell._inspect('pinfo', parameter_s, detail_level=1,
67 namespaces=namespaces)
68 namespaces=namespaces)
68
69
69 @skip_doctest
70 @skip_doctest
70 @line_magic
71 @line_magic
71 def pdef(self, parameter_s='', namespaces=None):
72 def pdef(self, parameter_s='', namespaces=None):
72 """Print the call signature for any callable object.
73 """Print the call signature for any callable object.
73
74
74 If the object is a class, print the constructor information.
75 If the object is a class, print the constructor information.
75
76
76 Examples
77 Examples
77 --------
78 --------
78 ::
79 ::
79
80
80 In [3]: %pdef urllib.urlopen
81 In [3]: %pdef urllib.urlopen
81 urllib.urlopen(url, data=None, proxies=None)
82 urllib.urlopen(url, data=None, proxies=None)
82 """
83 """
83 self.shell._inspect('pdef',parameter_s, namespaces)
84 self.shell._inspect('pdef',parameter_s, namespaces)
84
85
85 @line_magic
86 @line_magic
86 def pdoc(self, parameter_s='', namespaces=None):
87 def pdoc(self, parameter_s='', namespaces=None):
87 """Print the docstring for an object.
88 """Print the docstring for an object.
88
89
89 If the given object is a class, it will print both the class and the
90 If the given object is a class, it will print both the class and the
90 constructor docstrings."""
91 constructor docstrings."""
91 self.shell._inspect('pdoc',parameter_s, namespaces)
92 self.shell._inspect('pdoc',parameter_s, namespaces)
92
93
93 @line_magic
94 @line_magic
94 def psource(self, parameter_s='', namespaces=None):
95 def psource(self, parameter_s='', namespaces=None):
95 """Print (or run through pager) the source code for an object."""
96 """Print (or run through pager) the source code for an object."""
96 if not parameter_s:
97 if not parameter_s:
97 raise UsageError('Missing object name.')
98 raise UsageError('Missing object name.')
98 self.shell._inspect('psource',parameter_s, namespaces)
99 self.shell._inspect('psource',parameter_s, namespaces)
99
100
100 @line_magic
101 @line_magic
101 def pfile(self, parameter_s='', namespaces=None):
102 def pfile(self, parameter_s='', namespaces=None):
102 """Print (or run through pager) the file where an object is defined.
103 """Print (or run through pager) the file where an object is defined.
103
104
104 The file opens at the line where the object definition begins. IPython
105 The file opens at the line where the object definition begins. IPython
105 will honor the environment variable PAGER if set, and otherwise will
106 will honor the environment variable PAGER if set, and otherwise will
106 do its best to print the file in a convenient form.
107 do its best to print the file in a convenient form.
107
108
108 If the given argument is not an object currently defined, IPython will
109 If the given argument is not an object currently defined, IPython will
109 try to interpret it as a filename (automatically adding a .py extension
110 try to interpret it as a filename (automatically adding a .py extension
110 if needed). You can thus use %pfile as a syntax highlighting code
111 if needed). You can thus use %pfile as a syntax highlighting code
111 viewer."""
112 viewer."""
112
113
113 # first interpret argument as an object name
114 # first interpret argument as an object name
114 out = self.shell._inspect('pfile',parameter_s, namespaces)
115 out = self.shell._inspect('pfile',parameter_s, namespaces)
115 # if not, try the input as a filename
116 # if not, try the input as a filename
116 if out == 'not found':
117 if out == 'not found':
117 try:
118 try:
118 filename = get_py_filename(parameter_s)
119 filename = get_py_filename(parameter_s)
119 except IOError as msg:
120 except IOError as msg:
120 print msg
121 print(msg)
121 return
122 return
122 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
123 page.page(self.shell.pycolorize(read_py_file(filename, skip_encoding_cookie=False)))
123
124
124 @line_magic
125 @line_magic
125 def psearch(self, parameter_s=''):
126 def psearch(self, parameter_s=''):
126 """Search for object in namespaces by wildcard.
127 """Search for object in namespaces by wildcard.
127
128
128 %psearch [options] PATTERN [OBJECT TYPE]
129 %psearch [options] PATTERN [OBJECT TYPE]
129
130
130 Note: ? can be used as a synonym for %psearch, at the beginning or at
131 Note: ? can be used as a synonym for %psearch, at the beginning or at
131 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
132 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
132 rest of the command line must be unchanged (options come first), so
133 rest of the command line must be unchanged (options come first), so
133 for example the following forms are equivalent
134 for example the following forms are equivalent
134
135
135 %psearch -i a* function
136 %psearch -i a* function
136 -i a* function?
137 -i a* function?
137 ?-i a* function
138 ?-i a* function
138
139
139 Arguments:
140 Arguments:
140
141
141 PATTERN
142 PATTERN
142
143
143 where PATTERN is a string containing * as a wildcard similar to its
144 where PATTERN is a string containing * as a wildcard similar to its
144 use in a shell. The pattern is matched in all namespaces on the
145 use in a shell. The pattern is matched in all namespaces on the
145 search path. By default objects starting with a single _ are not
146 search path. By default objects starting with a single _ are not
146 matched, many IPython generated objects have a single
147 matched, many IPython generated objects have a single
147 underscore. The default is case insensitive matching. Matching is
148 underscore. The default is case insensitive matching. Matching is
148 also done on the attributes of objects and not only on the objects
149 also done on the attributes of objects and not only on the objects
149 in a module.
150 in a module.
150
151
151 [OBJECT TYPE]
152 [OBJECT TYPE]
152
153
153 Is the name of a python type from the types module. The name is
154 Is the name of a python type from the types module. The name is
154 given in lowercase without the ending type, ex. StringType is
155 given in lowercase without the ending type, ex. StringType is
155 written string. By adding a type here only objects matching the
156 written string. By adding a type here only objects matching the
156 given type are matched. Using all here makes the pattern match all
157 given type are matched. Using all here makes the pattern match all
157 types (this is the default).
158 types (this is the default).
158
159
159 Options:
160 Options:
160
161
161 -a: makes the pattern match even objects whose names start with a
162 -a: makes the pattern match even objects whose names start with a
162 single underscore. These names are normally omitted from the
163 single underscore. These names are normally omitted from the
163 search.
164 search.
164
165
165 -i/-c: make the pattern case insensitive/sensitive. If neither of
166 -i/-c: make the pattern case insensitive/sensitive. If neither of
166 these options are given, the default is read from your configuration
167 these options are given, the default is read from your configuration
167 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
168 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
168 If this option is not specified in your configuration file, IPython's
169 If this option is not specified in your configuration file, IPython's
169 internal default is to do a case sensitive search.
170 internal default is to do a case sensitive search.
170
171
171 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
172 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
172 specify can be searched in any of the following namespaces:
173 specify can be searched in any of the following namespaces:
173 'builtin', 'user', 'user_global','internal', 'alias', where
174 'builtin', 'user', 'user_global','internal', 'alias', where
174 'builtin' and 'user' are the search defaults. Note that you should
175 'builtin' and 'user' are the search defaults. Note that you should
175 not use quotes when specifying namespaces.
176 not use quotes when specifying namespaces.
176
177
177 'Builtin' contains the python module builtin, 'user' contains all
178 'Builtin' contains the python module builtin, 'user' contains all
178 user data, 'alias' only contain the shell aliases and no python
179 user data, 'alias' only contain the shell aliases and no python
179 objects, 'internal' contains objects used by IPython. The
180 objects, 'internal' contains objects used by IPython. The
180 'user_global' namespace is only used by embedded IPython instances,
181 'user_global' namespace is only used by embedded IPython instances,
181 and it contains module-level globals. You can add namespaces to the
182 and it contains module-level globals. You can add namespaces to the
182 search with -s or exclude them with -e (these options can be given
183 search with -s or exclude them with -e (these options can be given
183 more than once).
184 more than once).
184
185
185 Examples
186 Examples
186 --------
187 --------
187 ::
188 ::
188
189
189 %psearch a* -> objects beginning with an a
190 %psearch a* -> objects beginning with an a
190 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
191 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
191 %psearch a* function -> all functions beginning with an a
192 %psearch a* function -> all functions beginning with an a
192 %psearch re.e* -> objects beginning with an e in module re
193 %psearch re.e* -> objects beginning with an e in module re
193 %psearch r*.e* -> objects that start with e in modules starting in r
194 %psearch r*.e* -> objects that start with e in modules starting in r
194 %psearch r*.* string -> all strings in modules beginning with r
195 %psearch r*.* string -> all strings in modules beginning with r
195
196
196 Case sensitive search::
197 Case sensitive search::
197
198
198 %psearch -c a* list all object beginning with lower case a
199 %psearch -c a* list all object beginning with lower case a
199
200
200 Show objects beginning with a single _::
201 Show objects beginning with a single _::
201
202
202 %psearch -a _* list objects beginning with a single underscore
203 %psearch -a _* list objects beginning with a single underscore
203 """
204 """
204 try:
205 try:
205 parameter_s.encode('ascii')
206 parameter_s.encode('ascii')
206 except UnicodeEncodeError:
207 except UnicodeEncodeError:
207 print 'Python identifiers can only contain ascii characters.'
208 print('Python identifiers can only contain ascii characters.')
208 return
209 return
209
210
210 # default namespaces to be searched
211 # default namespaces to be searched
211 def_search = ['user_local', 'user_global', 'builtin']
212 def_search = ['user_local', 'user_global', 'builtin']
212
213
213 # Process options/args
214 # Process options/args
214 opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True)
215 opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True)
215 opt = opts.get
216 opt = opts.get
216 shell = self.shell
217 shell = self.shell
217 psearch = shell.inspector.psearch
218 psearch = shell.inspector.psearch
218
219
219 # select case options
220 # select case options
220 if 'i' in opts:
221 if 'i' in opts:
221 ignore_case = True
222 ignore_case = True
222 elif 'c' in opts:
223 elif 'c' in opts:
223 ignore_case = False
224 ignore_case = False
224 else:
225 else:
225 ignore_case = not shell.wildcards_case_sensitive
226 ignore_case = not shell.wildcards_case_sensitive
226
227
227 # Build list of namespaces to search from user options
228 # Build list of namespaces to search from user options
228 def_search.extend(opt('s',[]))
229 def_search.extend(opt('s',[]))
229 ns_exclude = ns_exclude=opt('e',[])
230 ns_exclude = ns_exclude=opt('e',[])
230 ns_search = [nm for nm in def_search if nm not in ns_exclude]
231 ns_search = [nm for nm in def_search if nm not in ns_exclude]
231
232
232 # Call the actual search
233 # Call the actual search
233 try:
234 try:
234 psearch(args,shell.ns_table,ns_search,
235 psearch(args,shell.ns_table,ns_search,
235 show_all=opt('a'),ignore_case=ignore_case)
236 show_all=opt('a'),ignore_case=ignore_case)
236 except:
237 except:
237 shell.showtraceback()
238 shell.showtraceback()
238
239
239 @skip_doctest
240 @skip_doctest
240 @line_magic
241 @line_magic
241 def who_ls(self, parameter_s=''):
242 def who_ls(self, parameter_s=''):
242 """Return a sorted list of all interactive variables.
243 """Return a sorted list of all interactive variables.
243
244
244 If arguments are given, only variables of types matching these
245 If arguments are given, only variables of types matching these
245 arguments are returned.
246 arguments are returned.
246
247
247 Examples
248 Examples
248 --------
249 --------
249
250
250 Define two variables and list them with who_ls::
251 Define two variables and list them with who_ls::
251
252
252 In [1]: alpha = 123
253 In [1]: alpha = 123
253
254
254 In [2]: beta = 'test'
255 In [2]: beta = 'test'
255
256
256 In [3]: %who_ls
257 In [3]: %who_ls
257 Out[3]: ['alpha', 'beta']
258 Out[3]: ['alpha', 'beta']
258
259
259 In [4]: %who_ls int
260 In [4]: %who_ls int
260 Out[4]: ['alpha']
261 Out[4]: ['alpha']
261
262
262 In [5]: %who_ls str
263 In [5]: %who_ls str
263 Out[5]: ['beta']
264 Out[5]: ['beta']
264 """
265 """
265
266
266 user_ns = self.shell.user_ns
267 user_ns = self.shell.user_ns
267 user_ns_hidden = self.shell.user_ns_hidden
268 user_ns_hidden = self.shell.user_ns_hidden
268 nonmatching = object() # This can never be in user_ns
269 nonmatching = object() # This can never be in user_ns
269 out = [ i for i in user_ns
270 out = [ i for i in user_ns
270 if not i.startswith('_') \
271 if not i.startswith('_') \
271 and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
272 and (user_ns[i] is not user_ns_hidden.get(i, nonmatching)) ]
272
273
273 typelist = parameter_s.split()
274 typelist = parameter_s.split()
274 if typelist:
275 if typelist:
275 typeset = set(typelist)
276 typeset = set(typelist)
276 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
277 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
277
278
278 out.sort()
279 out.sort()
279 return out
280 return out
280
281
281 @skip_doctest
282 @skip_doctest
282 @line_magic
283 @line_magic
283 def who(self, parameter_s=''):
284 def who(self, parameter_s=''):
284 """Print all interactive variables, with some minimal formatting.
285 """Print all interactive variables, with some minimal formatting.
285
286
286 If any arguments are given, only variables whose type matches one of
287 If any arguments are given, only variables whose type matches one of
287 these are printed. For example::
288 these are printed. For example::
288
289
289 %who function str
290 %who function str
290
291
291 will only list functions and strings, excluding all other types of
292 will only list functions and strings, excluding all other types of
292 variables. To find the proper type names, simply use type(var) at a
293 variables. To find the proper type names, simply use type(var) at a
293 command line to see how python prints type names. For example:
294 command line to see how python prints type names. For example:
294
295
295 ::
296 ::
296
297
297 In [1]: type('hello')\\
298 In [1]: type('hello')\\
298 Out[1]: <type 'str'>
299 Out[1]: <type 'str'>
299
300
300 indicates that the type name for strings is 'str'.
301 indicates that the type name for strings is 'str'.
301
302
302 ``%who`` always excludes executed names loaded through your configuration
303 ``%who`` always excludes executed names loaded through your configuration
303 file and things which are internal to IPython.
304 file and things which are internal to IPython.
304
305
305 This is deliberate, as typically you may load many modules and the
306 This is deliberate, as typically you may load many modules and the
306 purpose of %who is to show you only what you've manually defined.
307 purpose of %who is to show you only what you've manually defined.
307
308
308 Examples
309 Examples
309 --------
310 --------
310
311
311 Define two variables and list them with who::
312 Define two variables and list them with who::
312
313
313 In [1]: alpha = 123
314 In [1]: alpha = 123
314
315
315 In [2]: beta = 'test'
316 In [2]: beta = 'test'
316
317
317 In [3]: %who
318 In [3]: %who
318 alpha beta
319 alpha beta
319
320
320 In [4]: %who int
321 In [4]: %who int
321 alpha
322 alpha
322
323
323 In [5]: %who str
324 In [5]: %who str
324 beta
325 beta
325 """
326 """
326
327
327 varlist = self.who_ls(parameter_s)
328 varlist = self.who_ls(parameter_s)
328 if not varlist:
329 if not varlist:
329 if parameter_s:
330 if parameter_s:
330 print 'No variables match your requested type.'
331 print('No variables match your requested type.')
331 else:
332 else:
332 print 'Interactive namespace is empty.'
333 print('Interactive namespace is empty.')
333 return
334 return
334
335
335 # if we have variables, move on...
336 # if we have variables, move on...
336 count = 0
337 count = 0
337 for i in varlist:
338 for i in varlist:
338 print i+'\t',
339 print(i+'\t', end=' ')
339 count += 1
340 count += 1
340 if count > 8:
341 if count > 8:
341 count = 0
342 count = 0
342 print
343 print()
343 print
344 print()
344
345
345 @skip_doctest
346 @skip_doctest
346 @line_magic
347 @line_magic
347 def whos(self, parameter_s=''):
348 def whos(self, parameter_s=''):
348 """Like %who, but gives some extra information about each variable.
349 """Like %who, but gives some extra information about each variable.
349
350
350 The same type filtering of %who can be applied here.
351 The same type filtering of %who can be applied here.
351
352
352 For all variables, the type is printed. Additionally it prints:
353 For all variables, the type is printed. Additionally it prints:
353
354
354 - For {},[],(): their length.
355 - For {},[],(): their length.
355
356
356 - For numpy arrays, a summary with shape, number of
357 - For numpy arrays, a summary with shape, number of
357 elements, typecode and size in memory.
358 elements, typecode and size in memory.
358
359
359 - Everything else: a string representation, snipping their middle if
360 - Everything else: a string representation, snipping their middle if
360 too long.
361 too long.
361
362
362 Examples
363 Examples
363 --------
364 --------
364
365
365 Define two variables and list them with whos::
366 Define two variables and list them with whos::
366
367
367 In [1]: alpha = 123
368 In [1]: alpha = 123
368
369
369 In [2]: beta = 'test'
370 In [2]: beta = 'test'
370
371
371 In [3]: %whos
372 In [3]: %whos
372 Variable Type Data/Info
373 Variable Type Data/Info
373 --------------------------------
374 --------------------------------
374 alpha int 123
375 alpha int 123
375 beta str test
376 beta str test
376 """
377 """
377
378
378 varnames = self.who_ls(parameter_s)
379 varnames = self.who_ls(parameter_s)
379 if not varnames:
380 if not varnames:
380 if parameter_s:
381 if parameter_s:
381 print 'No variables match your requested type.'
382 print('No variables match your requested type.')
382 else:
383 else:
383 print 'Interactive namespace is empty.'
384 print('Interactive namespace is empty.')
384 return
385 return
385
386
386 # if we have variables, move on...
387 # if we have variables, move on...
387
388
388 # for these types, show len() instead of data:
389 # for these types, show len() instead of data:
389 seq_types = ['dict', 'list', 'tuple']
390 seq_types = ['dict', 'list', 'tuple']
390
391
391 # for numpy arrays, display summary info
392 # for numpy arrays, display summary info
392 ndarray_type = None
393 ndarray_type = None
393 if 'numpy' in sys.modules:
394 if 'numpy' in sys.modules:
394 try:
395 try:
395 from numpy import ndarray
396 from numpy import ndarray
396 except ImportError:
397 except ImportError:
397 pass
398 pass
398 else:
399 else:
399 ndarray_type = ndarray.__name__
400 ndarray_type = ndarray.__name__
400
401
401 # Find all variable names and types so we can figure out column sizes
402 # Find all variable names and types so we can figure out column sizes
402 def get_vars(i):
403 def get_vars(i):
403 return self.shell.user_ns[i]
404 return self.shell.user_ns[i]
404
405
405 # some types are well known and can be shorter
406 # some types are well known and can be shorter
406 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
407 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
407 def type_name(v):
408 def type_name(v):
408 tn = type(v).__name__
409 tn = type(v).__name__
409 return abbrevs.get(tn,tn)
410 return abbrevs.get(tn,tn)
410
411
411 varlist = map(get_vars,varnames)
412 varlist = map(get_vars,varnames)
412
413
413 typelist = []
414 typelist = []
414 for vv in varlist:
415 for vv in varlist:
415 tt = type_name(vv)
416 tt = type_name(vv)
416
417
417 if tt=='instance':
418 if tt=='instance':
418 typelist.append( abbrevs.get(str(vv.__class__),
419 typelist.append( abbrevs.get(str(vv.__class__),
419 str(vv.__class__)))
420 str(vv.__class__)))
420 else:
421 else:
421 typelist.append(tt)
422 typelist.append(tt)
422
423
423 # column labels and # of spaces as separator
424 # column labels and # of spaces as separator
424 varlabel = 'Variable'
425 varlabel = 'Variable'
425 typelabel = 'Type'
426 typelabel = 'Type'
426 datalabel = 'Data/Info'
427 datalabel = 'Data/Info'
427 colsep = 3
428 colsep = 3
428 # variable format strings
429 # variable format strings
429 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
430 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
430 aformat = "%s: %s elems, type `%s`, %s bytes"
431 aformat = "%s: %s elems, type `%s`, %s bytes"
431 # find the size of the columns to format the output nicely
432 # find the size of the columns to format the output nicely
432 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
433 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
433 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
434 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
434 # table header
435 # table header
435 print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
436 print(varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
436 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1)
437 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1))
437 # and the table itself
438 # and the table itself
438 kb = 1024
439 kb = 1024
439 Mb = 1048576 # kb**2
440 Mb = 1048576 # kb**2
440 for vname,var,vtype in zip(varnames,varlist,typelist):
441 for vname,var,vtype in zip(varnames,varlist,typelist):
441 print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth),
442 print(vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth), end=' ')
442 if vtype in seq_types:
443 if vtype in seq_types:
443 print "n="+str(len(var))
444 print("n="+str(len(var)))
444 elif vtype == ndarray_type:
445 elif vtype == ndarray_type:
445 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
446 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
446 if vtype==ndarray_type:
447 if vtype==ndarray_type:
447 # numpy
448 # numpy
448 vsize = var.size
449 vsize = var.size
449 vbytes = vsize*var.itemsize
450 vbytes = vsize*var.itemsize
450 vdtype = var.dtype
451 vdtype = var.dtype
451
452
452 if vbytes < 100000:
453 if vbytes < 100000:
453 print aformat % (vshape, vsize, vdtype, vbytes)
454 print(aformat % (vshape, vsize, vdtype, vbytes))
454 else:
455 else:
455 print aformat % (vshape, vsize, vdtype, vbytes),
456 print(aformat % (vshape, vsize, vdtype, vbytes), end=' ')
456 if vbytes < Mb:
457 if vbytes < Mb:
457 print '(%s kb)' % (vbytes/kb,)
458 print('(%s kb)' % (vbytes/kb,))
458 else:
459 else:
459 print '(%s Mb)' % (vbytes/Mb,)
460 print('(%s Mb)' % (vbytes/Mb,))
460 else:
461 else:
461 try:
462 try:
462 vstr = str(var)
463 vstr = str(var)
463 except UnicodeEncodeError:
464 except UnicodeEncodeError:
464 vstr = unicode(var).encode(DEFAULT_ENCODING,
465 vstr = unicode(var).encode(DEFAULT_ENCODING,
465 'backslashreplace')
466 'backslashreplace')
466 except:
467 except:
467 vstr = "<object with id %d (str() failed)>" % id(var)
468 vstr = "<object with id %d (str() failed)>" % id(var)
468 vstr = vstr.replace('\n', '\\n')
469 vstr = vstr.replace('\n', '\\n')
469 if len(vstr) < 50:
470 if len(vstr) < 50:
470 print vstr
471 print(vstr)
471 else:
472 else:
472 print vstr[:25] + "<...>" + vstr[-25:]
473 print(vstr[:25] + "<...>" + vstr[-25:])
473
474
474 @line_magic
475 @line_magic
475 def reset(self, parameter_s=''):
476 def reset(self, parameter_s=''):
476 """Resets the namespace by removing all names defined by the user, if
477 """Resets the namespace by removing all names defined by the user, if
477 called without arguments, or by removing some types of objects, such
478 called without arguments, or by removing some types of objects, such
478 as everything currently in IPython's In[] and Out[] containers (see
479 as everything currently in IPython's In[] and Out[] containers (see
479 the parameters for details).
480 the parameters for details).
480
481
481 Parameters
482 Parameters
482 ----------
483 ----------
483 -f : force reset without asking for confirmation.
484 -f : force reset without asking for confirmation.
484
485
485 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
486 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
486 References to objects may be kept. By default (without this option),
487 References to objects may be kept. By default (without this option),
487 we do a 'hard' reset, giving you a new session and removing all
488 we do a 'hard' reset, giving you a new session and removing all
488 references to objects from the current session.
489 references to objects from the current session.
489
490
490 in : reset input history
491 in : reset input history
491
492
492 out : reset output history
493 out : reset output history
493
494
494 dhist : reset directory history
495 dhist : reset directory history
495
496
496 array : reset only variables that are NumPy arrays
497 array : reset only variables that are NumPy arrays
497
498
498 See Also
499 See Also
499 --------
500 --------
500 magic_reset_selective : invoked as ``%reset_selective``
501 magic_reset_selective : invoked as ``%reset_selective``
501
502
502 Examples
503 Examples
503 --------
504 --------
504 ::
505 ::
505
506
506 In [6]: a = 1
507 In [6]: a = 1
507
508
508 In [7]: a
509 In [7]: a
509 Out[7]: 1
510 Out[7]: 1
510
511
511 In [8]: 'a' in _ip.user_ns
512 In [8]: 'a' in _ip.user_ns
512 Out[8]: True
513 Out[8]: True
513
514
514 In [9]: %reset -f
515 In [9]: %reset -f
515
516
516 In [1]: 'a' in _ip.user_ns
517 In [1]: 'a' in _ip.user_ns
517 Out[1]: False
518 Out[1]: False
518
519
519 In [2]: %reset -f in
520 In [2]: %reset -f in
520 Flushing input history
521 Flushing input history
521
522
522 In [3]: %reset -f dhist in
523 In [3]: %reset -f dhist in
523 Flushing directory history
524 Flushing directory history
524 Flushing input history
525 Flushing input history
525
526
526 Notes
527 Notes
527 -----
528 -----
528 Calling this magic from clients that do not implement standard input,
529 Calling this magic from clients that do not implement standard input,
529 such as the ipython notebook interface, will reset the namespace
530 such as the ipython notebook interface, will reset the namespace
530 without confirmation.
531 without confirmation.
531 """
532 """
532 opts, args = self.parse_options(parameter_s,'sf', mode='list')
533 opts, args = self.parse_options(parameter_s,'sf', mode='list')
533 if 'f' in opts:
534 if 'f' in opts:
534 ans = True
535 ans = True
535 else:
536 else:
536 try:
537 try:
537 ans = self.shell.ask_yes_no(
538 ans = self.shell.ask_yes_no(
538 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
539 "Once deleted, variables cannot be recovered. Proceed (y/[n])?",
539 default='n')
540 default='n')
540 except StdinNotImplementedError:
541 except StdinNotImplementedError:
541 ans = True
542 ans = True
542 if not ans:
543 if not ans:
543 print 'Nothing done.'
544 print('Nothing done.')
544 return
545 return
545
546
546 if 's' in opts: # Soft reset
547 if 's' in opts: # Soft reset
547 user_ns = self.shell.user_ns
548 user_ns = self.shell.user_ns
548 for i in self.who_ls():
549 for i in self.who_ls():
549 del(user_ns[i])
550 del(user_ns[i])
550 elif len(args) == 0: # Hard reset
551 elif len(args) == 0: # Hard reset
551 self.shell.reset(new_session = False)
552 self.shell.reset(new_session = False)
552
553
553 # reset in/out/dhist/array: previously extensinions/clearcmd.py
554 # reset in/out/dhist/array: previously extensinions/clearcmd.py
554 ip = self.shell
555 ip = self.shell
555 user_ns = self.shell.user_ns # local lookup, heavily used
556 user_ns = self.shell.user_ns # local lookup, heavily used
556
557
557 for target in args:
558 for target in args:
558 target = target.lower() # make matches case insensitive
559 target = target.lower() # make matches case insensitive
559 if target == 'out':
560 if target == 'out':
560 print "Flushing output cache (%d entries)" % len(user_ns['_oh'])
561 print("Flushing output cache (%d entries)" % len(user_ns['_oh']))
561 self.shell.displayhook.flush()
562 self.shell.displayhook.flush()
562
563
563 elif target == 'in':
564 elif target == 'in':
564 print "Flushing input history"
565 print("Flushing input history")
565 pc = self.shell.displayhook.prompt_count + 1
566 pc = self.shell.displayhook.prompt_count + 1
566 for n in range(1, pc):
567 for n in range(1, pc):
567 key = '_i'+repr(n)
568 key = '_i'+repr(n)
568 user_ns.pop(key,None)
569 user_ns.pop(key,None)
569 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
570 user_ns.update(dict(_i=u'',_ii=u'',_iii=u''))
570 hm = ip.history_manager
571 hm = ip.history_manager
571 # don't delete these, as %save and %macro depending on the
572 # don't delete these, as %save and %macro depending on the
572 # length of these lists to be preserved
573 # length of these lists to be preserved
573 hm.input_hist_parsed[:] = [''] * pc
574 hm.input_hist_parsed[:] = [''] * pc
574 hm.input_hist_raw[:] = [''] * pc
575 hm.input_hist_raw[:] = [''] * pc
575 # hm has internal machinery for _i,_ii,_iii, clear it out
576 # hm has internal machinery for _i,_ii,_iii, clear it out
576 hm._i = hm._ii = hm._iii = hm._i00 = u''
577 hm._i = hm._ii = hm._iii = hm._i00 = u''
577
578
578 elif target == 'array':
579 elif target == 'array':
579 # Support cleaning up numpy arrays
580 # Support cleaning up numpy arrays
580 try:
581 try:
581 from numpy import ndarray
582 from numpy import ndarray
582 # This must be done with items and not iteritems because
583 # This must be done with items and not iteritems because
583 # we're going to modify the dict in-place.
584 # we're going to modify the dict in-place.
584 for x,val in user_ns.items():
585 for x,val in user_ns.items():
585 if isinstance(val,ndarray):
586 if isinstance(val,ndarray):
586 del user_ns[x]
587 del user_ns[x]
587 except ImportError:
588 except ImportError:
588 print "reset array only works if Numpy is available."
589 print("reset array only works if Numpy is available.")
589
590
590 elif target == 'dhist':
591 elif target == 'dhist':
591 print "Flushing directory history"
592 print("Flushing directory history")
592 del user_ns['_dh'][:]
593 del user_ns['_dh'][:]
593
594
594 else:
595 else:
595 print "Don't know how to reset ",
596 print("Don't know how to reset ", end=' ')
596 print target + ", please run `%reset?` for details"
597 print(target + ", please run `%reset?` for details")
597
598
598 gc.collect()
599 gc.collect()
599
600
600 @line_magic
601 @line_magic
601 def reset_selective(self, parameter_s=''):
602 def reset_selective(self, parameter_s=''):
602 """Resets the namespace by removing names defined by the user.
603 """Resets the namespace by removing names defined by the user.
603
604
604 Input/Output history are left around in case you need them.
605 Input/Output history are left around in case you need them.
605
606
606 %reset_selective [-f] regex
607 %reset_selective [-f] regex
607
608
608 No action is taken if regex is not included
609 No action is taken if regex is not included
609
610
610 Options
611 Options
611 -f : force reset without asking for confirmation.
612 -f : force reset without asking for confirmation.
612
613
613 See Also
614 See Also
614 --------
615 --------
615 magic_reset : invoked as ``%reset``
616 magic_reset : invoked as ``%reset``
616
617
617 Examples
618 Examples
618 --------
619 --------
619
620
620 We first fully reset the namespace so your output looks identical to
621 We first fully reset the namespace so your output looks identical to
621 this example for pedagogical reasons; in practice you do not need a
622 this example for pedagogical reasons; in practice you do not need a
622 full reset::
623 full reset::
623
624
624 In [1]: %reset -f
625 In [1]: %reset -f
625
626
626 Now, with a clean namespace we can make a few variables and use
627 Now, with a clean namespace we can make a few variables and use
627 ``%reset_selective`` to only delete names that match our regexp::
628 ``%reset_selective`` to only delete names that match our regexp::
628
629
629 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
630 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
630
631
631 In [3]: who_ls
632 In [3]: who_ls
632 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
633 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
633
634
634 In [4]: %reset_selective -f b[2-3]m
635 In [4]: %reset_selective -f b[2-3]m
635
636
636 In [5]: who_ls
637 In [5]: who_ls
637 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
638 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
638
639
639 In [6]: %reset_selective -f d
640 In [6]: %reset_selective -f d
640
641
641 In [7]: who_ls
642 In [7]: who_ls
642 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
643 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
643
644
644 In [8]: %reset_selective -f c
645 In [8]: %reset_selective -f c
645
646
646 In [9]: who_ls
647 In [9]: who_ls
647 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
648 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
648
649
649 In [10]: %reset_selective -f b
650 In [10]: %reset_selective -f b
650
651
651 In [11]: who_ls
652 In [11]: who_ls
652 Out[11]: ['a']
653 Out[11]: ['a']
653
654
654 Notes
655 Notes
655 -----
656 -----
656 Calling this magic from clients that do not implement standard input,
657 Calling this magic from clients that do not implement standard input,
657 such as the ipython notebook interface, will reset the namespace
658 such as the ipython notebook interface, will reset the namespace
658 without confirmation.
659 without confirmation.
659 """
660 """
660
661
661 opts, regex = self.parse_options(parameter_s,'f')
662 opts, regex = self.parse_options(parameter_s,'f')
662
663
663 if 'f' in opts:
664 if 'f' in opts:
664 ans = True
665 ans = True
665 else:
666 else:
666 try:
667 try:
667 ans = self.shell.ask_yes_no(
668 ans = self.shell.ask_yes_no(
668 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
669 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
669 default='n')
670 default='n')
670 except StdinNotImplementedError:
671 except StdinNotImplementedError:
671 ans = True
672 ans = True
672 if not ans:
673 if not ans:
673 print 'Nothing done.'
674 print('Nothing done.')
674 return
675 return
675 user_ns = self.shell.user_ns
676 user_ns = self.shell.user_ns
676 if not regex:
677 if not regex:
677 print 'No regex pattern specified. Nothing done.'
678 print('No regex pattern specified. Nothing done.')
678 return
679 return
679 else:
680 else:
680 try:
681 try:
681 m = re.compile(regex)
682 m = re.compile(regex)
682 except TypeError:
683 except TypeError:
683 raise TypeError('regex must be a string or compiled pattern')
684 raise TypeError('regex must be a string or compiled pattern')
684 for i in self.who_ls():
685 for i in self.who_ls():
685 if m.search(i):
686 if m.search(i):
686 del(user_ns[i])
687 del(user_ns[i])
687
688
688 @line_magic
689 @line_magic
689 def xdel(self, parameter_s=''):
690 def xdel(self, parameter_s=''):
690 """Delete a variable, trying to clear it from anywhere that
691 """Delete a variable, trying to clear it from anywhere that
691 IPython's machinery has references to it. By default, this uses
692 IPython's machinery has references to it. By default, this uses
692 the identity of the named object in the user namespace to remove
693 the identity of the named object in the user namespace to remove
693 references held under other names. The object is also removed
694 references held under other names. The object is also removed
694 from the output history.
695 from the output history.
695
696
696 Options
697 Options
697 -n : Delete the specified name from all namespaces, without
698 -n : Delete the specified name from all namespaces, without
698 checking their identity.
699 checking their identity.
699 """
700 """
700 opts, varname = self.parse_options(parameter_s,'n')
701 opts, varname = self.parse_options(parameter_s,'n')
701 try:
702 try:
702 self.shell.del_var(varname, ('n' in opts))
703 self.shell.del_var(varname, ('n' in opts))
703 except (NameError, ValueError) as e:
704 except (NameError, ValueError) as e:
704 print type(e).__name__ +": "+ str(e)
705 print(type(e).__name__ +": "+ str(e))
@@ -1,738 +1,739 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 from __future__ import print_function
6 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
7 # Copyright (c) 2012 The IPython Development Team.
8 # Copyright (c) 2012 The IPython Development Team.
8 #
9 #
9 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
10 #
11 #
11 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
13
14
14 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
15 # Imports
16 # Imports
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17
18
18 # Stdlib
19 # Stdlib
19 import io
20 import io
20 import os
21 import os
21 import re
22 import re
22 import sys
23 import sys
23 from pprint import pformat
24 from pprint import pformat
24
25
25 # Our own packages
26 # Our own packages
26 from IPython.core import magic_arguments
27 from IPython.core import magic_arguments
27 from IPython.core import oinspect
28 from IPython.core import oinspect
28 from IPython.core import page
29 from IPython.core import page
29 from IPython.core.alias import AliasError, Alias
30 from IPython.core.alias import AliasError, Alias
30 from IPython.core.error import UsageError
31 from IPython.core.error import UsageError
31 from IPython.core.magic import (
32 from IPython.core.magic import (
32 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
33 )
34 )
34 from IPython.testing.skipdoctest import skip_doctest
35 from IPython.testing.skipdoctest import skip_doctest
35 from IPython.utils.openpy import source_to_unicode
36 from IPython.utils.openpy import source_to_unicode
36 from IPython.utils.path import unquote_filename
37 from IPython.utils.path import unquote_filename
37 from IPython.utils.process import abbrev_cwd
38 from IPython.utils.process import abbrev_cwd
38 from IPython.utils.terminal import set_term_title
39 from IPython.utils.terminal import set_term_title
39
40
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41 # Magic implementation classes
42 # Magic implementation classes
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43 @magics_class
44 @magics_class
44 class OSMagics(Magics):
45 class OSMagics(Magics):
45 """Magics to interact with the underlying OS (shell-type functionality).
46 """Magics to interact with the underlying OS (shell-type functionality).
46 """
47 """
47
48
48 @skip_doctest
49 @skip_doctest
49 @line_magic
50 @line_magic
50 def alias(self, parameter_s=''):
51 def alias(self, parameter_s=''):
51 """Define an alias for a system command.
52 """Define an alias for a system command.
52
53
53 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
54 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
54
55
55 Then, typing 'alias_name params' will execute the system command 'cmd
56 Then, typing 'alias_name params' will execute the system command 'cmd
56 params' (from your underlying operating system).
57 params' (from your underlying operating system).
57
58
58 Aliases have lower precedence than magic functions and Python normal
59 Aliases have lower precedence than magic functions and Python normal
59 variables, so if 'foo' is both a Python variable and an alias, the
60 variables, so if 'foo' is both a Python variable and an alias, the
60 alias can not be executed until 'del foo' removes the Python variable.
61 alias can not be executed until 'del foo' removes the Python variable.
61
62
62 You can use the %l specifier in an alias definition to represent the
63 You can use the %l specifier in an alias definition to represent the
63 whole line when the alias is called. For example::
64 whole line when the alias is called. For example::
64
65
65 In [2]: alias bracket echo "Input in brackets: <%l>"
66 In [2]: alias bracket echo "Input in brackets: <%l>"
66 In [3]: bracket hello world
67 In [3]: bracket hello world
67 Input in brackets: <hello world>
68 Input in brackets: <hello world>
68
69
69 You can also define aliases with parameters using %s specifiers (one
70 You can also define aliases with parameters using %s specifiers (one
70 per parameter)::
71 per parameter)::
71
72
72 In [1]: alias parts echo first %s second %s
73 In [1]: alias parts echo first %s second %s
73 In [2]: %parts A B
74 In [2]: %parts A B
74 first A second B
75 first A second B
75 In [3]: %parts A
76 In [3]: %parts A
76 Incorrect number of arguments: 2 expected.
77 Incorrect number of arguments: 2 expected.
77 parts is an alias to: 'echo first %s second %s'
78 parts is an alias to: 'echo first %s second %s'
78
79
79 Note that %l and %s are mutually exclusive. You can only use one or
80 Note that %l and %s are mutually exclusive. You can only use one or
80 the other in your aliases.
81 the other in your aliases.
81
82
82 Aliases expand Python variables just like system calls using ! or !!
83 Aliases expand Python variables just like system calls using ! or !!
83 do: all expressions prefixed with '$' get expanded. For details of
84 do: all expressions prefixed with '$' get expanded. For details of
84 the semantic rules, see PEP-215:
85 the semantic rules, see PEP-215:
85 http://www.python.org/peps/pep-0215.html. This is the library used by
86 http://www.python.org/peps/pep-0215.html. This is the library used by
86 IPython for variable expansion. If you want to access a true shell
87 IPython for variable expansion. If you want to access a true shell
87 variable, an extra $ is necessary to prevent its expansion by
88 variable, an extra $ is necessary to prevent its expansion by
88 IPython::
89 IPython::
89
90
90 In [6]: alias show echo
91 In [6]: alias show echo
91 In [7]: PATH='A Python string'
92 In [7]: PATH='A Python string'
92 In [8]: show $PATH
93 In [8]: show $PATH
93 A Python string
94 A Python string
94 In [9]: show $$PATH
95 In [9]: show $$PATH
95 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
96 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
96
97
97 You can use the alias facility to acess all of $PATH. See the %rehash
98 You can use the alias facility to acess all of $PATH. See the %rehash
98 and %rehashx functions, which automatically create aliases for the
99 and %rehashx functions, which automatically create aliases for the
99 contents of your $PATH.
100 contents of your $PATH.
100
101
101 If called with no parameters, %alias prints the current alias table."""
102 If called with no parameters, %alias prints the current alias table."""
102
103
103 par = parameter_s.strip()
104 par = parameter_s.strip()
104 if not par:
105 if not par:
105 aliases = sorted(self.shell.alias_manager.aliases)
106 aliases = sorted(self.shell.alias_manager.aliases)
106 # stored = self.shell.db.get('stored_aliases', {} )
107 # stored = self.shell.db.get('stored_aliases', {} )
107 # for k, v in stored:
108 # for k, v in stored:
108 # atab.append(k, v[0])
109 # atab.append(k, v[0])
109
110
110 print "Total number of aliases:", len(aliases)
111 print("Total number of aliases:", len(aliases))
111 sys.stdout.flush()
112 sys.stdout.flush()
112 return aliases
113 return aliases
113
114
114 # Now try to define a new one
115 # Now try to define a new one
115 try:
116 try:
116 alias,cmd = par.split(None, 1)
117 alias,cmd = par.split(None, 1)
117 except TypeError:
118 except TypeError:
118 print(oinspect.getdoc(self.alias))
119 print((oinspect.getdoc(self.alias)))
119 return
120 return
120
121
121 try:
122 try:
122 self.shell.alias_manager.define_alias(alias, cmd)
123 self.shell.alias_manager.define_alias(alias, cmd)
123 except AliasError as e:
124 except AliasError as e:
124 print(e)
125 print(e)
125 # end magic_alias
126 # end magic_alias
126
127
127 @line_magic
128 @line_magic
128 def unalias(self, parameter_s=''):
129 def unalias(self, parameter_s=''):
129 """Remove an alias"""
130 """Remove an alias"""
130
131
131 aname = parameter_s.strip()
132 aname = parameter_s.strip()
132 try:
133 try:
133 self.shell.alias_manager.undefine_alias(aname)
134 self.shell.alias_manager.undefine_alias(aname)
134 except ValueError as e:
135 except ValueError as e:
135 print(e)
136 print(e)
136 return
137 return
137
138
138 stored = self.shell.db.get('stored_aliases', {} )
139 stored = self.shell.db.get('stored_aliases', {} )
139 if aname in stored:
140 if aname in stored:
140 print "Removing %stored alias",aname
141 print("Removing %stored alias",aname)
141 del stored[aname]
142 del stored[aname]
142 self.shell.db['stored_aliases'] = stored
143 self.shell.db['stored_aliases'] = stored
143
144
144 @line_magic
145 @line_magic
145 def rehashx(self, parameter_s=''):
146 def rehashx(self, parameter_s=''):
146 """Update the alias table with all executable files in $PATH.
147 """Update the alias table with all executable files in $PATH.
147
148
148 This version explicitly checks that every entry in $PATH is a file
149 This version explicitly checks that every entry in $PATH is a file
149 with execute access (os.X_OK), so it is much slower than %rehash.
150 with execute access (os.X_OK), so it is much slower than %rehash.
150
151
151 Under Windows, it checks executability as a match against a
152 Under Windows, it checks executability as a match against a
152 '|'-separated string of extensions, stored in the IPython config
153 '|'-separated string of extensions, stored in the IPython config
153 variable win_exec_ext. This defaults to 'exe|com|bat'.
154 variable win_exec_ext. This defaults to 'exe|com|bat'.
154
155
155 This function also resets the root module cache of module completer,
156 This function also resets the root module cache of module completer,
156 used on slow filesystems.
157 used on slow filesystems.
157 """
158 """
158 from IPython.core.alias import InvalidAliasError
159 from IPython.core.alias import InvalidAliasError
159
160
160 # for the benefit of module completer in ipy_completers.py
161 # for the benefit of module completer in ipy_completers.py
161 del self.shell.db['rootmodules_cache']
162 del self.shell.db['rootmodules_cache']
162
163
163 path = [os.path.abspath(os.path.expanduser(p)) for p in
164 path = [os.path.abspath(os.path.expanduser(p)) for p in
164 os.environ.get('PATH','').split(os.pathsep)]
165 os.environ.get('PATH','').split(os.pathsep)]
165 path = filter(os.path.isdir,path)
166 path = filter(os.path.isdir,path)
166
167
167 syscmdlist = []
168 syscmdlist = []
168 # Now define isexec in a cross platform manner.
169 # Now define isexec in a cross platform manner.
169 if os.name == 'posix':
170 if os.name == 'posix':
170 isexec = lambda fname:os.path.isfile(fname) and \
171 isexec = lambda fname:os.path.isfile(fname) and \
171 os.access(fname,os.X_OK)
172 os.access(fname,os.X_OK)
172 else:
173 else:
173 try:
174 try:
174 winext = os.environ['pathext'].replace(';','|').replace('.','')
175 winext = os.environ['pathext'].replace(';','|').replace('.','')
175 except KeyError:
176 except KeyError:
176 winext = 'exe|com|bat|py'
177 winext = 'exe|com|bat|py'
177 if 'py' not in winext:
178 if 'py' not in winext:
178 winext += '|py'
179 winext += '|py'
179 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
180 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
180 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
181 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
181 savedir = os.getcwdu()
182 savedir = os.getcwdu()
182
183
183 # Now walk the paths looking for executables to alias.
184 # Now walk the paths looking for executables to alias.
184 try:
185 try:
185 # write the whole loop for posix/Windows so we don't have an if in
186 # write the whole loop for posix/Windows so we don't have an if in
186 # the innermost part
187 # the innermost part
187 if os.name == 'posix':
188 if os.name == 'posix':
188 for pdir in path:
189 for pdir in path:
189 os.chdir(pdir)
190 os.chdir(pdir)
190 for ff in os.listdir(pdir):
191 for ff in os.listdir(pdir):
191 if isexec(ff):
192 if isexec(ff):
192 try:
193 try:
193 # Removes dots from the name since ipython
194 # Removes dots from the name since ipython
194 # will assume names with dots to be python.
195 # will assume names with dots to be python.
195 if not self.shell.alias_manager.is_alias(ff):
196 if not self.shell.alias_manager.is_alias(ff):
196 self.shell.alias_manager.define_alias(
197 self.shell.alias_manager.define_alias(
197 ff.replace('.',''), ff)
198 ff.replace('.',''), ff)
198 except InvalidAliasError:
199 except InvalidAliasError:
199 pass
200 pass
200 else:
201 else:
201 syscmdlist.append(ff)
202 syscmdlist.append(ff)
202 else:
203 else:
203 no_alias = Alias.blacklist
204 no_alias = Alias.blacklist
204 for pdir in path:
205 for pdir in path:
205 os.chdir(pdir)
206 os.chdir(pdir)
206 for ff in os.listdir(pdir):
207 for ff in os.listdir(pdir):
207 base, ext = os.path.splitext(ff)
208 base, ext = os.path.splitext(ff)
208 if isexec(ff) and base.lower() not in no_alias:
209 if isexec(ff) and base.lower() not in no_alias:
209 if ext.lower() == '.exe':
210 if ext.lower() == '.exe':
210 ff = base
211 ff = base
211 try:
212 try:
212 # Removes dots from the name since ipython
213 # Removes dots from the name since ipython
213 # will assume names with dots to be python.
214 # will assume names with dots to be python.
214 self.shell.alias_manager.define_alias(
215 self.shell.alias_manager.define_alias(
215 base.lower().replace('.',''), ff)
216 base.lower().replace('.',''), ff)
216 except InvalidAliasError:
217 except InvalidAliasError:
217 pass
218 pass
218 syscmdlist.append(ff)
219 syscmdlist.append(ff)
219 self.shell.db['syscmdlist'] = syscmdlist
220 self.shell.db['syscmdlist'] = syscmdlist
220 finally:
221 finally:
221 os.chdir(savedir)
222 os.chdir(savedir)
222
223
223 @skip_doctest
224 @skip_doctest
224 @line_magic
225 @line_magic
225 def pwd(self, parameter_s=''):
226 def pwd(self, parameter_s=''):
226 """Return the current working directory path.
227 """Return the current working directory path.
227
228
228 Examples
229 Examples
229 --------
230 --------
230 ::
231 ::
231
232
232 In [9]: pwd
233 In [9]: pwd
233 Out[9]: '/home/tsuser/sprint/ipython'
234 Out[9]: '/home/tsuser/sprint/ipython'
234 """
235 """
235 return os.getcwdu()
236 return os.getcwdu()
236
237
237 @skip_doctest
238 @skip_doctest
238 @line_magic
239 @line_magic
239 def cd(self, parameter_s=''):
240 def cd(self, parameter_s=''):
240 """Change the current working directory.
241 """Change the current working directory.
241
242
242 This command automatically maintains an internal list of directories
243 This command automatically maintains an internal list of directories
243 you visit during your IPython session, in the variable _dh. The
244 you visit during your IPython session, in the variable _dh. The
244 command %dhist shows this history nicely formatted. You can also
245 command %dhist shows this history nicely formatted. You can also
245 do 'cd -<tab>' to see directory history conveniently.
246 do 'cd -<tab>' to see directory history conveniently.
246
247
247 Usage:
248 Usage:
248
249
249 cd 'dir': changes to directory 'dir'.
250 cd 'dir': changes to directory 'dir'.
250
251
251 cd -: changes to the last visited directory.
252 cd -: changes to the last visited directory.
252
253
253 cd -<n>: changes to the n-th directory in the directory history.
254 cd -<n>: changes to the n-th directory in the directory history.
254
255
255 cd --foo: change to directory that matches 'foo' in history
256 cd --foo: change to directory that matches 'foo' in history
256
257
257 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
258 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
258 (note: cd <bookmark_name> is enough if there is no
259 (note: cd <bookmark_name> is enough if there is no
259 directory <bookmark_name>, but a bookmark with the name exists.)
260 directory <bookmark_name>, but a bookmark with the name exists.)
260 'cd -b <tab>' allows you to tab-complete bookmark names.
261 'cd -b <tab>' allows you to tab-complete bookmark names.
261
262
262 Options:
263 Options:
263
264
264 -q: quiet. Do not print the working directory after the cd command is
265 -q: quiet. Do not print the working directory after the cd command is
265 executed. By default IPython's cd command does print this directory,
266 executed. By default IPython's cd command does print this directory,
266 since the default prompts do not display path information.
267 since the default prompts do not display path information.
267
268
268 Note that !cd doesn't work for this purpose because the shell where
269 Note that !cd doesn't work for this purpose because the shell where
269 !command runs is immediately discarded after executing 'command'.
270 !command runs is immediately discarded after executing 'command'.
270
271
271 Examples
272 Examples
272 --------
273 --------
273 ::
274 ::
274
275
275 In [10]: cd parent/child
276 In [10]: cd parent/child
276 /home/tsuser/parent/child
277 /home/tsuser/parent/child
277 """
278 """
278
279
279 oldcwd = os.getcwdu()
280 oldcwd = os.getcwdu()
280 numcd = re.match(r'(-)(\d+)$',parameter_s)
281 numcd = re.match(r'(-)(\d+)$',parameter_s)
281 # jump in directory history by number
282 # jump in directory history by number
282 if numcd:
283 if numcd:
283 nn = int(numcd.group(2))
284 nn = int(numcd.group(2))
284 try:
285 try:
285 ps = self.shell.user_ns['_dh'][nn]
286 ps = self.shell.user_ns['_dh'][nn]
286 except IndexError:
287 except IndexError:
287 print 'The requested directory does not exist in history.'
288 print('The requested directory does not exist in history.')
288 return
289 return
289 else:
290 else:
290 opts = {}
291 opts = {}
291 elif parameter_s.startswith('--'):
292 elif parameter_s.startswith('--'):
292 ps = None
293 ps = None
293 fallback = None
294 fallback = None
294 pat = parameter_s[2:]
295 pat = parameter_s[2:]
295 dh = self.shell.user_ns['_dh']
296 dh = self.shell.user_ns['_dh']
296 # first search only by basename (last component)
297 # first search only by basename (last component)
297 for ent in reversed(dh):
298 for ent in reversed(dh):
298 if pat in os.path.basename(ent) and os.path.isdir(ent):
299 if pat in os.path.basename(ent) and os.path.isdir(ent):
299 ps = ent
300 ps = ent
300 break
301 break
301
302
302 if fallback is None and pat in ent and os.path.isdir(ent):
303 if fallback is None and pat in ent and os.path.isdir(ent):
303 fallback = ent
304 fallback = ent
304
305
305 # if we have no last part match, pick the first full path match
306 # if we have no last part match, pick the first full path match
306 if ps is None:
307 if ps is None:
307 ps = fallback
308 ps = fallback
308
309
309 if ps is None:
310 if ps is None:
310 print "No matching entry in directory history"
311 print("No matching entry in directory history")
311 return
312 return
312 else:
313 else:
313 opts = {}
314 opts = {}
314
315
315
316
316 else:
317 else:
317 #turn all non-space-escaping backslashes to slashes,
318 #turn all non-space-escaping backslashes to slashes,
318 # for c:\windows\directory\names\
319 # for c:\windows\directory\names\
319 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
320 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
320 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
321 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
321 # jump to previous
322 # jump to previous
322 if ps == '-':
323 if ps == '-':
323 try:
324 try:
324 ps = self.shell.user_ns['_dh'][-2]
325 ps = self.shell.user_ns['_dh'][-2]
325 except IndexError:
326 except IndexError:
326 raise UsageError('%cd -: No previous directory to change to.')
327 raise UsageError('%cd -: No previous directory to change to.')
327 # jump to bookmark if needed
328 # jump to bookmark if needed
328 else:
329 else:
329 if not os.path.isdir(ps) or 'b' in opts:
330 if not os.path.isdir(ps) or 'b' in opts:
330 bkms = self.shell.db.get('bookmarks', {})
331 bkms = self.shell.db.get('bookmarks', {})
331
332
332 if ps in bkms:
333 if ps in bkms:
333 target = bkms[ps]
334 target = bkms[ps]
334 print '(bookmark:%s) -> %s' % (ps, target)
335 print('(bookmark:%s) -> %s' % (ps, target))
335 ps = target
336 ps = target
336 else:
337 else:
337 if 'b' in opts:
338 if 'b' in opts:
338 raise UsageError("Bookmark '%s' not found. "
339 raise UsageError("Bookmark '%s' not found. "
339 "Use '%%bookmark -l' to see your bookmarks." % ps)
340 "Use '%%bookmark -l' to see your bookmarks." % ps)
340
341
341 # strip extra quotes on Windows, because os.chdir doesn't like them
342 # strip extra quotes on Windows, because os.chdir doesn't like them
342 ps = unquote_filename(ps)
343 ps = unquote_filename(ps)
343 # at this point ps should point to the target dir
344 # at this point ps should point to the target dir
344 if ps:
345 if ps:
345 try:
346 try:
346 os.chdir(os.path.expanduser(ps))
347 os.chdir(os.path.expanduser(ps))
347 if hasattr(self.shell, 'term_title') and self.shell.term_title:
348 if hasattr(self.shell, 'term_title') and self.shell.term_title:
348 set_term_title('IPython: ' + abbrev_cwd())
349 set_term_title('IPython: ' + abbrev_cwd())
349 except OSError:
350 except OSError:
350 print sys.exc_info()[1]
351 print(sys.exc_info()[1])
351 else:
352 else:
352 cwd = os.getcwdu()
353 cwd = os.getcwdu()
353 dhist = self.shell.user_ns['_dh']
354 dhist = self.shell.user_ns['_dh']
354 if oldcwd != cwd:
355 if oldcwd != cwd:
355 dhist.append(cwd)
356 dhist.append(cwd)
356 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
357 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
357
358
358 else:
359 else:
359 os.chdir(self.shell.home_dir)
360 os.chdir(self.shell.home_dir)
360 if hasattr(self.shell, 'term_title') and self.shell.term_title:
361 if hasattr(self.shell, 'term_title') and self.shell.term_title:
361 set_term_title('IPython: ' + '~')
362 set_term_title('IPython: ' + '~')
362 cwd = os.getcwdu()
363 cwd = os.getcwdu()
363 dhist = self.shell.user_ns['_dh']
364 dhist = self.shell.user_ns['_dh']
364
365
365 if oldcwd != cwd:
366 if oldcwd != cwd:
366 dhist.append(cwd)
367 dhist.append(cwd)
367 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
368 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
368 if not 'q' in opts and self.shell.user_ns['_dh']:
369 if not 'q' in opts and self.shell.user_ns['_dh']:
369 print self.shell.user_ns['_dh'][-1]
370 print(self.shell.user_ns['_dh'][-1])
370
371
371
372
372 @line_magic
373 @line_magic
373 def env(self, parameter_s=''):
374 def env(self, parameter_s=''):
374 """List environment variables."""
375 """List environment variables."""
375
376
376 return dict(os.environ)
377 return dict(os.environ)
377
378
378 @line_magic
379 @line_magic
379 def pushd(self, parameter_s=''):
380 def pushd(self, parameter_s=''):
380 """Place the current dir on stack and change directory.
381 """Place the current dir on stack and change directory.
381
382
382 Usage:\\
383 Usage:\\
383 %pushd ['dirname']
384 %pushd ['dirname']
384 """
385 """
385
386
386 dir_s = self.shell.dir_stack
387 dir_s = self.shell.dir_stack
387 tgt = os.path.expanduser(unquote_filename(parameter_s))
388 tgt = os.path.expanduser(unquote_filename(parameter_s))
388 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
389 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
389 if tgt:
390 if tgt:
390 self.cd(parameter_s)
391 self.cd(parameter_s)
391 dir_s.insert(0,cwd)
392 dir_s.insert(0,cwd)
392 return self.shell.magic('dirs')
393 return self.shell.magic('dirs')
393
394
394 @line_magic
395 @line_magic
395 def popd(self, parameter_s=''):
396 def popd(self, parameter_s=''):
396 """Change to directory popped off the top of the stack.
397 """Change to directory popped off the top of the stack.
397 """
398 """
398 if not self.shell.dir_stack:
399 if not self.shell.dir_stack:
399 raise UsageError("%popd on empty stack")
400 raise UsageError("%popd on empty stack")
400 top = self.shell.dir_stack.pop(0)
401 top = self.shell.dir_stack.pop(0)
401 self.cd(top)
402 self.cd(top)
402 print "popd ->",top
403 print("popd ->",top)
403
404
404 @line_magic
405 @line_magic
405 def dirs(self, parameter_s=''):
406 def dirs(self, parameter_s=''):
406 """Return the current directory stack."""
407 """Return the current directory stack."""
407
408
408 return self.shell.dir_stack
409 return self.shell.dir_stack
409
410
410 @line_magic
411 @line_magic
411 def dhist(self, parameter_s=''):
412 def dhist(self, parameter_s=''):
412 """Print your history of visited directories.
413 """Print your history of visited directories.
413
414
414 %dhist -> print full history\\
415 %dhist -> print full history\\
415 %dhist n -> print last n entries only\\
416 %dhist n -> print last n entries only\\
416 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
417 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
417
418
418 This history is automatically maintained by the %cd command, and
419 This history is automatically maintained by the %cd command, and
419 always available as the global list variable _dh. You can use %cd -<n>
420 always available as the global list variable _dh. You can use %cd -<n>
420 to go to directory number <n>.
421 to go to directory number <n>.
421
422
422 Note that most of time, you should view directory history by entering
423 Note that most of time, you should view directory history by entering
423 cd -<TAB>.
424 cd -<TAB>.
424
425
425 """
426 """
426
427
427 dh = self.shell.user_ns['_dh']
428 dh = self.shell.user_ns['_dh']
428 if parameter_s:
429 if parameter_s:
429 try:
430 try:
430 args = map(int,parameter_s.split())
431 args = map(int,parameter_s.split())
431 except:
432 except:
432 self.arg_err(self.dhist)
433 self.arg_err(self.dhist)
433 return
434 return
434 if len(args) == 1:
435 if len(args) == 1:
435 ini,fin = max(len(dh)-(args[0]),0),len(dh)
436 ini,fin = max(len(dh)-(args[0]),0),len(dh)
436 elif len(args) == 2:
437 elif len(args) == 2:
437 ini,fin = args
438 ini,fin = args
438 fin = min(fin, len(dh))
439 fin = min(fin, len(dh))
439 else:
440 else:
440 self.arg_err(self.dhist)
441 self.arg_err(self.dhist)
441 return
442 return
442 else:
443 else:
443 ini,fin = 0,len(dh)
444 ini,fin = 0,len(dh)
444 print 'Directory history (kept in _dh)'
445 print('Directory history (kept in _dh)')
445 for i in range(ini, fin):
446 for i in range(ini, fin):
446 print "%d: %s" % (i, dh[i])
447 print("%d: %s" % (i, dh[i]))
447
448
448 @skip_doctest
449 @skip_doctest
449 @line_magic
450 @line_magic
450 def sc(self, parameter_s=''):
451 def sc(self, parameter_s=''):
451 """Shell capture - run shell command and capture output (DEPRECATED use !).
452 """Shell capture - run shell command and capture output (DEPRECATED use !).
452
453
453 DEPRECATED. Suboptimal, retained for backwards compatibility.
454 DEPRECATED. Suboptimal, retained for backwards compatibility.
454
455
455 You should use the form 'var = !command' instead. Example:
456 You should use the form 'var = !command' instead. Example:
456
457
457 "%sc -l myfiles = ls ~" should now be written as
458 "%sc -l myfiles = ls ~" should now be written as
458
459
459 "myfiles = !ls ~"
460 "myfiles = !ls ~"
460
461
461 myfiles.s, myfiles.l and myfiles.n still apply as documented
462 myfiles.s, myfiles.l and myfiles.n still apply as documented
462 below.
463 below.
463
464
464 --
465 --
465 %sc [options] varname=command
466 %sc [options] varname=command
466
467
467 IPython will run the given command using commands.getoutput(), and
468 IPython will run the given command using commands.getoutput(), and
468 will then update the user's interactive namespace with a variable
469 will then update the user's interactive namespace with a variable
469 called varname, containing the value of the call. Your command can
470 called varname, containing the value of the call. Your command can
470 contain shell wildcards, pipes, etc.
471 contain shell wildcards, pipes, etc.
471
472
472 The '=' sign in the syntax is mandatory, and the variable name you
473 The '=' sign in the syntax is mandatory, and the variable name you
473 supply must follow Python's standard conventions for valid names.
474 supply must follow Python's standard conventions for valid names.
474
475
475 (A special format without variable name exists for internal use)
476 (A special format without variable name exists for internal use)
476
477
477 Options:
478 Options:
478
479
479 -l: list output. Split the output on newlines into a list before
480 -l: list output. Split the output on newlines into a list before
480 assigning it to the given variable. By default the output is stored
481 assigning it to the given variable. By default the output is stored
481 as a single string.
482 as a single string.
482
483
483 -v: verbose. Print the contents of the variable.
484 -v: verbose. Print the contents of the variable.
484
485
485 In most cases you should not need to split as a list, because the
486 In most cases you should not need to split as a list, because the
486 returned value is a special type of string which can automatically
487 returned value is a special type of string which can automatically
487 provide its contents either as a list (split on newlines) or as a
488 provide its contents either as a list (split on newlines) or as a
488 space-separated string. These are convenient, respectively, either
489 space-separated string. These are convenient, respectively, either
489 for sequential processing or to be passed to a shell command.
490 for sequential processing or to be passed to a shell command.
490
491
491 For example::
492 For example::
492
493
493 # Capture into variable a
494 # Capture into variable a
494 In [1]: sc a=ls *py
495 In [1]: sc a=ls *py
495
496
496 # a is a string with embedded newlines
497 # a is a string with embedded newlines
497 In [2]: a
498 In [2]: a
498 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
499 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
499
500
500 # which can be seen as a list:
501 # which can be seen as a list:
501 In [3]: a.l
502 In [3]: a.l
502 Out[3]: ['setup.py', 'win32_manual_post_install.py']
503 Out[3]: ['setup.py', 'win32_manual_post_install.py']
503
504
504 # or as a whitespace-separated string:
505 # or as a whitespace-separated string:
505 In [4]: a.s
506 In [4]: a.s
506 Out[4]: 'setup.py win32_manual_post_install.py'
507 Out[4]: 'setup.py win32_manual_post_install.py'
507
508
508 # a.s is useful to pass as a single command line:
509 # a.s is useful to pass as a single command line:
509 In [5]: !wc -l $a.s
510 In [5]: !wc -l $a.s
510 146 setup.py
511 146 setup.py
511 130 win32_manual_post_install.py
512 130 win32_manual_post_install.py
512 276 total
513 276 total
513
514
514 # while the list form is useful to loop over:
515 # while the list form is useful to loop over:
515 In [6]: for f in a.l:
516 In [6]: for f in a.l:
516 ...: !wc -l $f
517 ...: !wc -l $f
517 ...:
518 ...:
518 146 setup.py
519 146 setup.py
519 130 win32_manual_post_install.py
520 130 win32_manual_post_install.py
520
521
521 Similarly, the lists returned by the -l option are also special, in
522 Similarly, the lists returned by the -l option are also special, in
522 the sense that you can equally invoke the .s attribute on them to
523 the sense that you can equally invoke the .s attribute on them to
523 automatically get a whitespace-separated string from their contents::
524 automatically get a whitespace-separated string from their contents::
524
525
525 In [7]: sc -l b=ls *py
526 In [7]: sc -l b=ls *py
526
527
527 In [8]: b
528 In [8]: b
528 Out[8]: ['setup.py', 'win32_manual_post_install.py']
529 Out[8]: ['setup.py', 'win32_manual_post_install.py']
529
530
530 In [9]: b.s
531 In [9]: b.s
531 Out[9]: 'setup.py win32_manual_post_install.py'
532 Out[9]: 'setup.py win32_manual_post_install.py'
532
533
533 In summary, both the lists and strings used for output capture have
534 In summary, both the lists and strings used for output capture have
534 the following special attributes::
535 the following special attributes::
535
536
536 .l (or .list) : value as list.
537 .l (or .list) : value as list.
537 .n (or .nlstr): value as newline-separated string.
538 .n (or .nlstr): value as newline-separated string.
538 .s (or .spstr): value as space-separated string.
539 .s (or .spstr): value as space-separated string.
539 """
540 """
540
541
541 opts,args = self.parse_options(parameter_s, 'lv')
542 opts,args = self.parse_options(parameter_s, 'lv')
542 # Try to get a variable name and command to run
543 # Try to get a variable name and command to run
543 try:
544 try:
544 # the variable name must be obtained from the parse_options
545 # the variable name must be obtained from the parse_options
545 # output, which uses shlex.split to strip options out.
546 # output, which uses shlex.split to strip options out.
546 var,_ = args.split('=', 1)
547 var,_ = args.split('=', 1)
547 var = var.strip()
548 var = var.strip()
548 # But the command has to be extracted from the original input
549 # But the command has to be extracted from the original input
549 # parameter_s, not on what parse_options returns, to avoid the
550 # parameter_s, not on what parse_options returns, to avoid the
550 # quote stripping which shlex.split performs on it.
551 # quote stripping which shlex.split performs on it.
551 _,cmd = parameter_s.split('=', 1)
552 _,cmd = parameter_s.split('=', 1)
552 except ValueError:
553 except ValueError:
553 var,cmd = '',''
554 var,cmd = '',''
554 # If all looks ok, proceed
555 # If all looks ok, proceed
555 split = 'l' in opts
556 split = 'l' in opts
556 out = self.shell.getoutput(cmd, split=split)
557 out = self.shell.getoutput(cmd, split=split)
557 if 'v' in opts:
558 if 'v' in opts:
558 print '%s ==\n%s' % (var, pformat(out))
559 print('%s ==\n%s' % (var, pformat(out)))
559 if var:
560 if var:
560 self.shell.user_ns.update({var:out})
561 self.shell.user_ns.update({var:out})
561 else:
562 else:
562 return out
563 return out
563
564
564 @line_cell_magic
565 @line_cell_magic
565 def sx(self, line='', cell=None):
566 def sx(self, line='', cell=None):
566 """Shell execute - run shell command and capture output (!! is short-hand).
567 """Shell execute - run shell command and capture output (!! is short-hand).
567
568
568 %sx command
569 %sx command
569
570
570 IPython will run the given command using commands.getoutput(), and
571 IPython will run the given command using commands.getoutput(), and
571 return the result formatted as a list (split on '\\n'). Since the
572 return the result formatted as a list (split on '\\n'). Since the
572 output is _returned_, it will be stored in ipython's regular output
573 output is _returned_, it will be stored in ipython's regular output
573 cache Out[N] and in the '_N' automatic variables.
574 cache Out[N] and in the '_N' automatic variables.
574
575
575 Notes:
576 Notes:
576
577
577 1) If an input line begins with '!!', then %sx is automatically
578 1) If an input line begins with '!!', then %sx is automatically
578 invoked. That is, while::
579 invoked. That is, while::
579
580
580 !ls
581 !ls
581
582
582 causes ipython to simply issue system('ls'), typing::
583 causes ipython to simply issue system('ls'), typing::
583
584
584 !!ls
585 !!ls
585
586
586 is a shorthand equivalent to::
587 is a shorthand equivalent to::
587
588
588 %sx ls
589 %sx ls
589
590
590 2) %sx differs from %sc in that %sx automatically splits into a list,
591 2) %sx differs from %sc in that %sx automatically splits into a list,
591 like '%sc -l'. The reason for this is to make it as easy as possible
592 like '%sc -l'. The reason for this is to make it as easy as possible
592 to process line-oriented shell output via further python commands.
593 to process line-oriented shell output via further python commands.
593 %sc is meant to provide much finer control, but requires more
594 %sc is meant to provide much finer control, but requires more
594 typing.
595 typing.
595
596
596 3) Just like %sc -l, this is a list with special attributes:
597 3) Just like %sc -l, this is a list with special attributes:
597 ::
598 ::
598
599
599 .l (or .list) : value as list.
600 .l (or .list) : value as list.
600 .n (or .nlstr): value as newline-separated string.
601 .n (or .nlstr): value as newline-separated string.
601 .s (or .spstr): value as whitespace-separated string.
602 .s (or .spstr): value as whitespace-separated string.
602
603
603 This is very useful when trying to use such lists as arguments to
604 This is very useful when trying to use such lists as arguments to
604 system commands."""
605 system commands."""
605
606
606 if cell is None:
607 if cell is None:
607 # line magic
608 # line magic
608 return self.shell.getoutput(line)
609 return self.shell.getoutput(line)
609 else:
610 else:
610 opts,args = self.parse_options(line, '', 'out=')
611 opts,args = self.parse_options(line, '', 'out=')
611 output = self.shell.getoutput(cell)
612 output = self.shell.getoutput(cell)
612 out_name = opts.get('out', opts.get('o'))
613 out_name = opts.get('out', opts.get('o'))
613 if out_name:
614 if out_name:
614 self.shell.user_ns[out_name] = output
615 self.shell.user_ns[out_name] = output
615 else:
616 else:
616 return output
617 return output
617
618
618 system = line_cell_magic('system')(sx)
619 system = line_cell_magic('system')(sx)
619 bang = cell_magic('!')(sx)
620 bang = cell_magic('!')(sx)
620
621
621 @line_magic
622 @line_magic
622 def bookmark(self, parameter_s=''):
623 def bookmark(self, parameter_s=''):
623 """Manage IPython's bookmark system.
624 """Manage IPython's bookmark system.
624
625
625 %bookmark <name> - set bookmark to current dir
626 %bookmark <name> - set bookmark to current dir
626 %bookmark <name> <dir> - set bookmark to <dir>
627 %bookmark <name> <dir> - set bookmark to <dir>
627 %bookmark -l - list all bookmarks
628 %bookmark -l - list all bookmarks
628 %bookmark -d <name> - remove bookmark
629 %bookmark -d <name> - remove bookmark
629 %bookmark -r - remove all bookmarks
630 %bookmark -r - remove all bookmarks
630
631
631 You can later on access a bookmarked folder with::
632 You can later on access a bookmarked folder with::
632
633
633 %cd -b <name>
634 %cd -b <name>
634
635
635 or simply '%cd <name>' if there is no directory called <name> AND
636 or simply '%cd <name>' if there is no directory called <name> AND
636 there is such a bookmark defined.
637 there is such a bookmark defined.
637
638
638 Your bookmarks persist through IPython sessions, but they are
639 Your bookmarks persist through IPython sessions, but they are
639 associated with each profile."""
640 associated with each profile."""
640
641
641 opts,args = self.parse_options(parameter_s,'drl',mode='list')
642 opts,args = self.parse_options(parameter_s,'drl',mode='list')
642 if len(args) > 2:
643 if len(args) > 2:
643 raise UsageError("%bookmark: too many arguments")
644 raise UsageError("%bookmark: too many arguments")
644
645
645 bkms = self.shell.db.get('bookmarks',{})
646 bkms = self.shell.db.get('bookmarks',{})
646
647
647 if 'd' in opts:
648 if 'd' in opts:
648 try:
649 try:
649 todel = args[0]
650 todel = args[0]
650 except IndexError:
651 except IndexError:
651 raise UsageError(
652 raise UsageError(
652 "%bookmark -d: must provide a bookmark to delete")
653 "%bookmark -d: must provide a bookmark to delete")
653 else:
654 else:
654 try:
655 try:
655 del bkms[todel]
656 del bkms[todel]
656 except KeyError:
657 except KeyError:
657 raise UsageError(
658 raise UsageError(
658 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
659 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
659
660
660 elif 'r' in opts:
661 elif 'r' in opts:
661 bkms = {}
662 bkms = {}
662 elif 'l' in opts:
663 elif 'l' in opts:
663 bks = bkms.keys()
664 bks = bkms.keys()
664 bks.sort()
665 bks.sort()
665 if bks:
666 if bks:
666 size = max(map(len, bks))
667 size = max(map(len, bks))
667 else:
668 else:
668 size = 0
669 size = 0
669 fmt = '%-'+str(size)+'s -> %s'
670 fmt = '%-'+str(size)+'s -> %s'
670 print 'Current bookmarks:'
671 print('Current bookmarks:')
671 for bk in bks:
672 for bk in bks:
672 print fmt % (bk, bkms[bk])
673 print(fmt % (bk, bkms[bk]))
673 else:
674 else:
674 if not args:
675 if not args:
675 raise UsageError("%bookmark: You must specify the bookmark name")
676 raise UsageError("%bookmark: You must specify the bookmark name")
676 elif len(args)==1:
677 elif len(args)==1:
677 bkms[args[0]] = os.getcwdu()
678 bkms[args[0]] = os.getcwdu()
678 elif len(args)==2:
679 elif len(args)==2:
679 bkms[args[0]] = args[1]
680 bkms[args[0]] = args[1]
680 self.shell.db['bookmarks'] = bkms
681 self.shell.db['bookmarks'] = bkms
681
682
682 @line_magic
683 @line_magic
683 def pycat(self, parameter_s=''):
684 def pycat(self, parameter_s=''):
684 """Show a syntax-highlighted file through a pager.
685 """Show a syntax-highlighted file through a pager.
685
686
686 This magic is similar to the cat utility, but it will assume the file
687 This magic is similar to the cat utility, but it will assume the file
687 to be Python source and will show it with syntax highlighting.
688 to be Python source and will show it with syntax highlighting.
688
689
689 This magic command can either take a local filename, an url,
690 This magic command can either take a local filename, an url,
690 an history range (see %history) or a macro as argument ::
691 an history range (see %history) or a macro as argument ::
691
692
692 %pycat myscript.py
693 %pycat myscript.py
693 %pycat 7-27
694 %pycat 7-27
694 %pycat myMacro
695 %pycat myMacro
695 %pycat http://www.example.com/myscript.py
696 %pycat http://www.example.com/myscript.py
696 """
697 """
697 if not parameter_s:
698 if not parameter_s:
698 raise UsageError('Missing filename, URL, input history range, '
699 raise UsageError('Missing filename, URL, input history range, '
699 'or macro.')
700 'or macro.')
700
701
701 try :
702 try :
702 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
703 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
703 except (ValueError, IOError):
704 except (ValueError, IOError):
704 print "Error: no such file, variable, URL, history range or macro"
705 print("Error: no such file, variable, URL, history range or macro")
705 return
706 return
706
707
707 page.page(self.shell.pycolorize(source_to_unicode(cont)))
708 page.page(self.shell.pycolorize(source_to_unicode(cont)))
708
709
709 @magic_arguments.magic_arguments()
710 @magic_arguments.magic_arguments()
710 @magic_arguments.argument(
711 @magic_arguments.argument(
711 '-a', '--append', action='store_true', default=False,
712 '-a', '--append', action='store_true', default=False,
712 help='Append contents of the cell to an existing file. '
713 help='Append contents of the cell to an existing file. '
713 'The file will be created if it does not exist.'
714 'The file will be created if it does not exist.'
714 )
715 )
715 @magic_arguments.argument(
716 @magic_arguments.argument(
716 'filename', type=unicode,
717 'filename', type=unicode,
717 help='file to write'
718 help='file to write'
718 )
719 )
719 @cell_magic
720 @cell_magic
720 def writefile(self, line, cell):
721 def writefile(self, line, cell):
721 """Write the contents of the cell to a file.
722 """Write the contents of the cell to a file.
722
723
723 The file will be overwritten unless the -a (--append) flag is specified.
724 The file will be overwritten unless the -a (--append) flag is specified.
724 """
725 """
725 args = magic_arguments.parse_argstring(self.writefile, line)
726 args = magic_arguments.parse_argstring(self.writefile, line)
726 filename = os.path.expanduser(unquote_filename(args.filename))
727 filename = os.path.expanduser(unquote_filename(args.filename))
727
728
728 if os.path.exists(filename):
729 if os.path.exists(filename):
729 if args.append:
730 if args.append:
730 print "Appending to %s" % filename
731 print("Appending to %s" % filename)
731 else:
732 else:
732 print "Overwriting %s" % filename
733 print("Overwriting %s" % filename)
733 else:
734 else:
734 print "Writing %s" % filename
735 print("Writing %s" % filename)
735
736
736 mode = 'a' if args.append else 'w'
737 mode = 'a' if args.append else 'w'
737 with io.open(filename, mode, encoding='utf-8') as f:
738 with io.open(filename, mode, encoding='utf-8') as f:
738 f.write(cell)
739 f.write(cell)
@@ -1,143 +1,144 b''
1 """Implementation of magic functions for matplotlib/pylab support.
1 """Implementation of magic functions for matplotlib/pylab support.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 # Our own packages
16 # Our own packages
16 from IPython.config.application import Application
17 from IPython.config.application import Application
17 from IPython.core import magic_arguments
18 from IPython.core import magic_arguments
18 from IPython.core.magic import Magics, magics_class, line_magic
19 from IPython.core.magic import Magics, magics_class, line_magic
19 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.utils.warn import warn
21 from IPython.utils.warn import warn
21 from IPython.core.pylabtools import backends
22 from IPython.core.pylabtools import backends
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Magic implementation classes
25 # Magic implementation classes
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27 magic_gui_arg = magic_arguments.argument(
28 magic_gui_arg = magic_arguments.argument(
28 'gui', nargs='?',
29 'gui', nargs='?',
29 help="""Name of the matplotlib backend to use %s.
30 help="""Name of the matplotlib backend to use %s.
30 If given, the corresponding matplotlib backend is used,
31 If given, the corresponding matplotlib backend is used,
31 otherwise it will be matplotlib's default
32 otherwise it will be matplotlib's default
32 (which you can set in your matplotlib config file).
33 (which you can set in your matplotlib config file).
33 """ % str(tuple(sorted(backends.keys())))
34 """ % str(tuple(sorted(backends.keys())))
34 )
35 )
35
36
36
37
37 @magics_class
38 @magics_class
38 class PylabMagics(Magics):
39 class PylabMagics(Magics):
39 """Magics related to matplotlib's pylab support"""
40 """Magics related to matplotlib's pylab support"""
40
41
41 @skip_doctest
42 @skip_doctest
42 @line_magic
43 @line_magic
43 @magic_arguments.magic_arguments()
44 @magic_arguments.magic_arguments()
44 @magic_gui_arg
45 @magic_gui_arg
45 def matplotlib(self, line=''):
46 def matplotlib(self, line=''):
46 """Set up matplotlib to work interactively.
47 """Set up matplotlib to work interactively.
47
48
48 This function lets you activate matplotlib interactive support
49 This function lets you activate matplotlib interactive support
49 at any point during an IPython session.
50 at any point during an IPython session.
50 It does not import anything into the interactive namespace.
51 It does not import anything into the interactive namespace.
51
52
52 If you are using the inline matplotlib backend for embedded figures,
53 If you are using the inline matplotlib backend for embedded figures,
53 you can adjust its behavior via the %config magic::
54 you can adjust its behavior via the %config magic::
54
55
55 # enable SVG figures, necessary for SVG+XHTML export in the qtconsole
56 # enable SVG figures, necessary for SVG+XHTML export in the qtconsole
56 In [1]: %config InlineBackend.figure_format = 'svg'
57 In [1]: %config InlineBackend.figure_format = 'svg'
57
58
58 # change the behavior of closing all figures at the end of each
59 # change the behavior of closing all figures at the end of each
59 # execution (cell), or allowing reuse of active figures across
60 # execution (cell), or allowing reuse of active figures across
60 # cells:
61 # cells:
61 In [2]: %config InlineBackend.close_figures = False
62 In [2]: %config InlineBackend.close_figures = False
62
63
63 Examples
64 Examples
64 --------
65 --------
65 In this case, where the MPL default is TkAgg::
66 In this case, where the MPL default is TkAgg::
66
67
67 In [2]: %matplotlib
68 In [2]: %matplotlib
68 Using matplotlib backend: TkAgg
69 Using matplotlib backend: TkAgg
69
70
70 But you can explicitly request a different backend::
71 But you can explicitly request a different backend::
71
72
72 In [3]: %matplotlib qt
73 In [3]: %matplotlib qt
73 """
74 """
74 args = magic_arguments.parse_argstring(self.matplotlib, line)
75 args = magic_arguments.parse_argstring(self.matplotlib, line)
75 gui, backend = self.shell.enable_matplotlib(args.gui)
76 gui, backend = self.shell.enable_matplotlib(args.gui)
76 self._show_matplotlib_backend(args.gui, backend)
77 self._show_matplotlib_backend(args.gui, backend)
77
78
78 @skip_doctest
79 @skip_doctest
79 @line_magic
80 @line_magic
80 @magic_arguments.magic_arguments()
81 @magic_arguments.magic_arguments()
81 @magic_arguments.argument(
82 @magic_arguments.argument(
82 '--no-import-all', action='store_true', default=None,
83 '--no-import-all', action='store_true', default=None,
83 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
84 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
84
85
85 You can govern the default behavior of this flag with the
86 You can govern the default behavior of this flag with the
86 InteractiveShellApp.pylab_import_all configurable.
87 InteractiveShellApp.pylab_import_all configurable.
87 """
88 """
88 )
89 )
89 @magic_gui_arg
90 @magic_gui_arg
90 def pylab(self, line=''):
91 def pylab(self, line=''):
91 """Load numpy and matplotlib to work interactively.
92 """Load numpy and matplotlib to work interactively.
92
93
93 This function lets you activate pylab (matplotlib, numpy and
94 This function lets you activate pylab (matplotlib, numpy and
94 interactive support) at any point during an IPython session.
95 interactive support) at any point during an IPython session.
95
96
96 %pylab makes the following imports::
97 %pylab makes the following imports::
97
98
98 import numpy
99 import numpy
99 import matplotlib
100 import matplotlib
100 from matplotlib import pylab, mlab, pyplot
101 from matplotlib import pylab, mlab, pyplot
101 np = numpy
102 np = numpy
102 plt = pyplot
103 plt = pyplot
103
104
104 from IPython.display import display
105 from IPython.display import display
105 from IPython.core.pylabtools import figsize, getfigs
106 from IPython.core.pylabtools import figsize, getfigs
106
107
107 from pylab import *
108 from pylab import *
108 from numpy import *
109 from numpy import *
109
110
110 If you pass `--no-import-all`, the last two `*` imports will be excluded.
111 If you pass `--no-import-all`, the last two `*` imports will be excluded.
111
112
112 See the %matplotlib magic for more details about activating matplotlib
113 See the %matplotlib magic for more details about activating matplotlib
113 without affecting the interactive namespace.
114 without affecting the interactive namespace.
114 """
115 """
115 args = magic_arguments.parse_argstring(self.pylab, line)
116 args = magic_arguments.parse_argstring(self.pylab, line)
116 if args.no_import_all is None:
117 if args.no_import_all is None:
117 # get default from Application
118 # get default from Application
118 if Application.initialized():
119 if Application.initialized():
119 app = Application.instance()
120 app = Application.instance()
120 try:
121 try:
121 import_all = app.pylab_import_all
122 import_all = app.pylab_import_all
122 except AttributeError:
123 except AttributeError:
123 import_all = True
124 import_all = True
124 else:
125 else:
125 # nothing specified, no app - default True
126 # nothing specified, no app - default True
126 import_all = True
127 import_all = True
127 else:
128 else:
128 # invert no-import flag
129 # invert no-import flag
129 import_all = not args.no_import_all
130 import_all = not args.no_import_all
130
131
131 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
132 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
132 self._show_matplotlib_backend(args.gui, backend)
133 self._show_matplotlib_backend(args.gui, backend)
133 print ("Populating the interactive namespace from numpy and matplotlib")
134 print ("Populating the interactive namespace from numpy and matplotlib")
134 if clobbered:
135 if clobbered:
135 warn("pylab import has clobbered these variables: %s" % clobbered +
136 warn("pylab import has clobbered these variables: %s" % clobbered +
136 "\n`%pylab --no-import-all` prevents importing * from pylab and numpy"
137 "\n`%pylab --no-import-all` prevents importing * from pylab and numpy"
137 )
138 )
138
139
139 def _show_matplotlib_backend(self, gui, backend):
140 def _show_matplotlib_backend(self, gui, backend):
140 """show matplotlib message backend message"""
141 """show matplotlib message backend message"""
141 if not gui or gui == 'auto':
142 if not gui or gui == 'auto':
142 print ("Using matplotlib backend: %s" % backend)
143 print(("Using matplotlib backend: %s" % backend))
143
144
@@ -1,279 +1,280 b''
1 """Magic functions for running cells in various scripts."""
1 """Magic functions for running cells in various scripts."""
2 from __future__ import print_function
2 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
3 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
4 #
5 #
5 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
6 #
7 #
7 # 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.
8 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
9
10
10 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
11 # Imports
12 # Imports
12 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
13
14
14 # Stdlib
15 # Stdlib
15 import errno
16 import errno
16 import os
17 import os
17 import sys
18 import sys
18 import signal
19 import signal
19 import time
20 import time
20 from subprocess import Popen, PIPE
21 from subprocess import Popen, PIPE
21 import atexit
22 import atexit
22
23
23 # Our own packages
24 # Our own packages
24 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
25 from IPython.core import magic_arguments
26 from IPython.core import magic_arguments
26 from IPython.core.magic import (
27 from IPython.core.magic import (
27 Magics, magics_class, line_magic, cell_magic
28 Magics, magics_class, line_magic, cell_magic
28 )
29 )
29 from IPython.lib.backgroundjobs import BackgroundJobManager
30 from IPython.lib.backgroundjobs import BackgroundJobManager
30 from IPython.utils import py3compat
31 from IPython.utils import py3compat
31 from IPython.utils.process import arg_split
32 from IPython.utils.process import arg_split
32 from IPython.utils.traitlets import List, Dict
33 from IPython.utils.traitlets import List, Dict
33
34
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35 # Magic implementation classes
36 # Magic implementation classes
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37
38
38 def script_args(f):
39 def script_args(f):
39 """single decorator for adding script args"""
40 """single decorator for adding script args"""
40 args = [
41 args = [
41 magic_arguments.argument(
42 magic_arguments.argument(
42 '--out', type=str,
43 '--out', type=str,
43 help="""The variable in which to store stdout from the script.
44 help="""The variable in which to store stdout from the script.
44 If the script is backgrounded, this will be the stdout *pipe*,
45 If the script is backgrounded, this will be the stdout *pipe*,
45 instead of the stderr text itself.
46 instead of the stderr text itself.
46 """
47 """
47 ),
48 ),
48 magic_arguments.argument(
49 magic_arguments.argument(
49 '--err', type=str,
50 '--err', type=str,
50 help="""The variable in which to store stderr from the script.
51 help="""The variable in which to store stderr from the script.
51 If the script is backgrounded, this will be the stderr *pipe*,
52 If the script is backgrounded, this will be the stderr *pipe*,
52 instead of the stderr text itself.
53 instead of the stderr text itself.
53 """
54 """
54 ),
55 ),
55 magic_arguments.argument(
56 magic_arguments.argument(
56 '--bg', action="store_true",
57 '--bg', action="store_true",
57 help="""Whether to run the script in the background.
58 help="""Whether to run the script in the background.
58 If given, the only way to see the output of the command is
59 If given, the only way to see the output of the command is
59 with --out/err.
60 with --out/err.
60 """
61 """
61 ),
62 ),
62 magic_arguments.argument(
63 magic_arguments.argument(
63 '--proc', type=str,
64 '--proc', type=str,
64 help="""The variable in which to store Popen instance.
65 help="""The variable in which to store Popen instance.
65 This is used only when --bg option is given.
66 This is used only when --bg option is given.
66 """
67 """
67 ),
68 ),
68 ]
69 ]
69 for arg in args:
70 for arg in args:
70 f = arg(f)
71 f = arg(f)
71 return f
72 return f
72
73
73 @magics_class
74 @magics_class
74 class ScriptMagics(Magics):
75 class ScriptMagics(Magics):
75 """Magics for talking to scripts
76 """Magics for talking to scripts
76
77
77 This defines a base `%%script` cell magic for running a cell
78 This defines a base `%%script` cell magic for running a cell
78 with a program in a subprocess, and registers a few top-level
79 with a program in a subprocess, and registers a few top-level
79 magics that call %%script with common interpreters.
80 magics that call %%script with common interpreters.
80 """
81 """
81 script_magics = List(config=True,
82 script_magics = List(config=True,
82 help="""Extra script cell magics to define
83 help="""Extra script cell magics to define
83
84
84 This generates simple wrappers of `%%script foo` as `%%foo`.
85 This generates simple wrappers of `%%script foo` as `%%foo`.
85
86
86 If you want to add script magics that aren't on your path,
87 If you want to add script magics that aren't on your path,
87 specify them in script_paths
88 specify them in script_paths
88 """,
89 """,
89 )
90 )
90 def _script_magics_default(self):
91 def _script_magics_default(self):
91 """default to a common list of programs"""
92 """default to a common list of programs"""
92
93
93 defaults = [
94 defaults = [
94 'sh',
95 'sh',
95 'bash',
96 'bash',
96 'perl',
97 'perl',
97 'ruby',
98 'ruby',
98 'python',
99 'python',
99 'python3',
100 'python3',
100 'pypy',
101 'pypy',
101 ]
102 ]
102 if os.name == 'nt':
103 if os.name == 'nt':
103 defaults.extend([
104 defaults.extend([
104 'cmd',
105 'cmd',
105 'powershell',
106 'powershell',
106 ])
107 ])
107
108
108 return defaults
109 return defaults
109
110
110 script_paths = Dict(config=True,
111 script_paths = Dict(config=True,
111 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
112 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
112
113
113 Only necessary for items in script_magics where the default path will not
114 Only necessary for items in script_magics where the default path will not
114 find the right interpreter.
115 find the right interpreter.
115 """
116 """
116 )
117 )
117
118
118 def __init__(self, shell=None):
119 def __init__(self, shell=None):
119 super(ScriptMagics, self).__init__(shell=shell)
120 super(ScriptMagics, self).__init__(shell=shell)
120 self._generate_script_magics()
121 self._generate_script_magics()
121 self.job_manager = BackgroundJobManager()
122 self.job_manager = BackgroundJobManager()
122 self.bg_processes = []
123 self.bg_processes = []
123 atexit.register(self.kill_bg_processes)
124 atexit.register(self.kill_bg_processes)
124
125
125 def __del__(self):
126 def __del__(self):
126 self.kill_bg_processes()
127 self.kill_bg_processes()
127
128
128 def _generate_script_magics(self):
129 def _generate_script_magics(self):
129 cell_magics = self.magics['cell']
130 cell_magics = self.magics['cell']
130 for name in self.script_magics:
131 for name in self.script_magics:
131 cell_magics[name] = self._make_script_magic(name)
132 cell_magics[name] = self._make_script_magic(name)
132
133
133 def _make_script_magic(self, name):
134 def _make_script_magic(self, name):
134 """make a named magic, that calls %%script with a particular program"""
135 """make a named magic, that calls %%script with a particular program"""
135 # expand to explicit path if necessary:
136 # expand to explicit path if necessary:
136 script = self.script_paths.get(name, name)
137 script = self.script_paths.get(name, name)
137
138
138 @magic_arguments.magic_arguments()
139 @magic_arguments.magic_arguments()
139 @script_args
140 @script_args
140 def named_script_magic(line, cell):
141 def named_script_magic(line, cell):
141 # if line, add it as cl-flags
142 # if line, add it as cl-flags
142 if line:
143 if line:
143 line = "%s %s" % (script, line)
144 line = "%s %s" % (script, line)
144 else:
145 else:
145 line = script
146 line = script
146 return self.shebang(line, cell)
147 return self.shebang(line, cell)
147
148
148 # write a basic docstring:
149 # write a basic docstring:
149 named_script_magic.__doc__ = \
150 named_script_magic.__doc__ = \
150 """%%{name} script magic
151 """%%{name} script magic
151
152
152 Run cells with {script} in a subprocess.
153 Run cells with {script} in a subprocess.
153
154
154 This is a shortcut for `%%script {script}`
155 This is a shortcut for `%%script {script}`
155 """.format(**locals())
156 """.format(**locals())
156
157
157 return named_script_magic
158 return named_script_magic
158
159
159 @magic_arguments.magic_arguments()
160 @magic_arguments.magic_arguments()
160 @script_args
161 @script_args
161 @cell_magic("script")
162 @cell_magic("script")
162 def shebang(self, line, cell):
163 def shebang(self, line, cell):
163 """Run a cell via a shell command
164 """Run a cell via a shell command
164
165
165 The `%%script` line is like the #! line of script,
166 The `%%script` line is like the #! line of script,
166 specifying a program (bash, perl, ruby, etc.) with which to run.
167 specifying a program (bash, perl, ruby, etc.) with which to run.
167
168
168 The rest of the cell is run by that program.
169 The rest of the cell is run by that program.
169
170
170 Examples
171 Examples
171 --------
172 --------
172 ::
173 ::
173
174
174 In [1]: %%script bash
175 In [1]: %%script bash
175 ...: for i in 1 2 3; do
176 ...: for i in 1 2 3; do
176 ...: echo $i
177 ...: echo $i
177 ...: done
178 ...: done
178 1
179 1
179 2
180 2
180 3
181 3
181 """
182 """
182 argv = arg_split(line, posix = not sys.platform.startswith('win'))
183 argv = arg_split(line, posix = not sys.platform.startswith('win'))
183 args, cmd = self.shebang.parser.parse_known_args(argv)
184 args, cmd = self.shebang.parser.parse_known_args(argv)
184
185
185 try:
186 try:
186 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
187 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
187 except OSError as e:
188 except OSError as e:
188 if e.errno == errno.ENOENT:
189 if e.errno == errno.ENOENT:
189 print "Couldn't find program: %r" % cmd[0]
190 print("Couldn't find program: %r" % cmd[0])
190 return
191 return
191 else:
192 else:
192 raise
193 raise
193
194
194 cell = cell.encode('utf8', 'replace')
195 cell = cell.encode('utf8', 'replace')
195 if args.bg:
196 if args.bg:
196 self.bg_processes.append(p)
197 self.bg_processes.append(p)
197 self._gc_bg_processes()
198 self._gc_bg_processes()
198 if args.out:
199 if args.out:
199 self.shell.user_ns[args.out] = p.stdout
200 self.shell.user_ns[args.out] = p.stdout
200 if args.err:
201 if args.err:
201 self.shell.user_ns[args.err] = p.stderr
202 self.shell.user_ns[args.err] = p.stderr
202 self.job_manager.new(self._run_script, p, cell, daemon=True)
203 self.job_manager.new(self._run_script, p, cell, daemon=True)
203 if args.proc:
204 if args.proc:
204 self.shell.user_ns[args.proc] = p
205 self.shell.user_ns[args.proc] = p
205 return
206 return
206
207
207 try:
208 try:
208 out, err = p.communicate(cell)
209 out, err = p.communicate(cell)
209 except KeyboardInterrupt:
210 except KeyboardInterrupt:
210 try:
211 try:
211 p.send_signal(signal.SIGINT)
212 p.send_signal(signal.SIGINT)
212 time.sleep(0.1)
213 time.sleep(0.1)
213 if p.poll() is not None:
214 if p.poll() is not None:
214 print "Process is interrupted."
215 print("Process is interrupted.")
215 return
216 return
216 p.terminate()
217 p.terminate()
217 time.sleep(0.1)
218 time.sleep(0.1)
218 if p.poll() is not None:
219 if p.poll() is not None:
219 print "Process is terminated."
220 print("Process is terminated.")
220 return
221 return
221 p.kill()
222 p.kill()
222 print "Process is killed."
223 print("Process is killed.")
223 except OSError:
224 except OSError:
224 pass
225 pass
225 except Exception as e:
226 except Exception as e:
226 print "Error while terminating subprocess (pid=%i): %s" \
227 print("Error while terminating subprocess (pid=%i): %s" \
227 % (p.pid, e)
228 % (p.pid, e))
228 return
229 return
229 out = py3compat.bytes_to_str(out)
230 out = py3compat.bytes_to_str(out)
230 err = py3compat.bytes_to_str(err)
231 err = py3compat.bytes_to_str(err)
231 if args.out:
232 if args.out:
232 self.shell.user_ns[args.out] = out
233 self.shell.user_ns[args.out] = out
233 else:
234 else:
234 sys.stdout.write(out)
235 sys.stdout.write(out)
235 sys.stdout.flush()
236 sys.stdout.flush()
236 if args.err:
237 if args.err:
237 self.shell.user_ns[args.err] = err
238 self.shell.user_ns[args.err] = err
238 else:
239 else:
239 sys.stderr.write(err)
240 sys.stderr.write(err)
240 sys.stderr.flush()
241 sys.stderr.flush()
241
242
242 def _run_script(self, p, cell):
243 def _run_script(self, p, cell):
243 """callback for running the script in the background"""
244 """callback for running the script in the background"""
244 p.stdin.write(cell)
245 p.stdin.write(cell)
245 p.stdin.close()
246 p.stdin.close()
246 p.wait()
247 p.wait()
247
248
248 @line_magic("killbgscripts")
249 @line_magic("killbgscripts")
249 def killbgscripts(self, _nouse_=''):
250 def killbgscripts(self, _nouse_=''):
250 """Kill all BG processes started by %%script and its family."""
251 """Kill all BG processes started by %%script and its family."""
251 self.kill_bg_processes()
252 self.kill_bg_processes()
252 print "All background processes were killed."
253 print("All background processes were killed.")
253
254
254 def kill_bg_processes(self):
255 def kill_bg_processes(self):
255 """Kill all BG processes which are still running."""
256 """Kill all BG processes which are still running."""
256 for p in self.bg_processes:
257 for p in self.bg_processes:
257 if p.poll() is None:
258 if p.poll() is None:
258 try:
259 try:
259 p.send_signal(signal.SIGINT)
260 p.send_signal(signal.SIGINT)
260 except:
261 except:
261 pass
262 pass
262 time.sleep(0.1)
263 time.sleep(0.1)
263 for p in self.bg_processes:
264 for p in self.bg_processes:
264 if p.poll() is None:
265 if p.poll() is None:
265 try:
266 try:
266 p.terminate()
267 p.terminate()
267 except:
268 except:
268 pass
269 pass
269 time.sleep(0.1)
270 time.sleep(0.1)
270 for p in self.bg_processes:
271 for p in self.bg_processes:
271 if p.poll() is None:
272 if p.poll() is None:
272 try:
273 try:
273 p.kill()
274 p.kill()
274 except:
275 except:
275 pass
276 pass
276 self._gc_bg_processes()
277 self._gc_bg_processes()
277
278
278 def _gc_bg_processes(self):
279 def _gc_bg_processes(self):
279 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,313 +1,314 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 from __future__ import print_function
12
13
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008 The IPython Development Team
15 #
16 #
16 # 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
17 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19
20
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21 # Imports
22 # Imports
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23
24
24 import os
25 import os
25
26
26 from IPython.config.application import Application
27 from IPython.config.application import Application
27 from IPython.core.application import (
28 from IPython.core.application import (
28 BaseIPythonApplication, base_flags
29 BaseIPythonApplication, base_flags
29 )
30 )
30 from IPython.core.profiledir import ProfileDir
31 from IPython.core.profiledir import ProfileDir
31 from IPython.utils.importstring import import_item
32 from IPython.utils.importstring import import_item
32 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
33 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
33 from IPython.utils.traitlets import Unicode, Bool, Dict
34 from IPython.utils.traitlets import Unicode, Bool, Dict
34
35
35 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
36 # Constants
37 # Constants
37 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
38
39
39 create_help = """Create an IPython profile by name
40 create_help = """Create an IPython profile by name
40
41
41 Create an ipython profile directory by its name or
42 Create an ipython profile directory by its name or
42 profile directory path. Profile directories contain
43 profile directory path. Profile directories contain
43 configuration, log and security related files and are named
44 configuration, log and security related files and are named
44 using the convention 'profile_<name>'. By default they are
45 using the convention 'profile_<name>'. By default they are
45 located in your ipython directory. Once created, you will
46 located in your ipython directory. Once created, you will
46 can edit the configuration files in the profile
47 can edit the configuration files in the profile
47 directory to configure IPython. Most users will create a
48 directory to configure IPython. Most users will create a
48 profile directory by name,
49 profile directory by name,
49 `ipython profile create myprofile`, which will put the directory
50 `ipython profile create myprofile`, which will put the directory
50 in `<ipython_dir>/profile_myprofile`.
51 in `<ipython_dir>/profile_myprofile`.
51 """
52 """
52 list_help = """List available IPython profiles
53 list_help = """List available IPython profiles
53
54
54 List all available profiles, by profile location, that can
55 List all available profiles, by profile location, that can
55 be found in the current working directly or in the ipython
56 be found in the current working directly or in the ipython
56 directory. Profile directories are named using the convention
57 directory. Profile directories are named using the convention
57 'profile_<profile>'.
58 'profile_<profile>'.
58 """
59 """
59 profile_help = """Manage IPython profiles
60 profile_help = """Manage IPython profiles
60
61
61 Profile directories contain
62 Profile directories contain
62 configuration, log and security related files and are named
63 configuration, log and security related files and are named
63 using the convention 'profile_<name>'. By default they are
64 using the convention 'profile_<name>'. By default they are
64 located in your ipython directory. You can create profiles
65 located in your ipython directory. You can create profiles
65 with `ipython profile create <name>`, or see the profiles you
66 with `ipython profile create <name>`, or see the profiles you
66 already have with `ipython profile list`
67 already have with `ipython profile list`
67
68
68 To get started configuring IPython, simply do:
69 To get started configuring IPython, simply do:
69
70
70 $> ipython profile create
71 $> ipython profile create
71
72
72 and IPython will create the default profile in <ipython_dir>/profile_default,
73 and IPython will create the default profile in <ipython_dir>/profile_default,
73 where you can edit ipython_config.py to start configuring IPython.
74 where you can edit ipython_config.py to start configuring IPython.
74
75
75 """
76 """
76
77
77 _list_examples = "ipython profile list # list all profiles"
78 _list_examples = "ipython profile list # list all profiles"
78
79
79 _create_examples = """
80 _create_examples = """
80 ipython profile create foo # create profile foo w/ default config files
81 ipython profile create foo # create profile foo w/ default config files
81 ipython profile create foo --reset # restage default config files over current
82 ipython profile create foo --reset # restage default config files over current
82 ipython profile create foo --parallel # also stage parallel config files
83 ipython profile create foo --parallel # also stage parallel config files
83 """
84 """
84
85
85 _main_examples = """
86 _main_examples = """
86 ipython profile create -h # show the help string for the create subcommand
87 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
88 ipython profile list -h # show the help string for the list subcommand
88
89
89 ipython locate profile foo # print the path to the directory for profile 'foo'
90 ipython locate profile foo # print the path to the directory for profile 'foo'
90 """
91 """
91
92
92 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
93 # Profile Application Class (for `ipython profile` subcommand)
94 # Profile Application Class (for `ipython profile` subcommand)
94 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
95
96
96
97
97 def list_profiles_in(path):
98 def list_profiles_in(path):
98 """list profiles in a given root directory"""
99 """list profiles in a given root directory"""
99 files = os.listdir(path)
100 files = os.listdir(path)
100 profiles = []
101 profiles = []
101 for f in files:
102 for f in files:
102 try:
103 try:
103 full_path = os.path.join(path, f)
104 full_path = os.path.join(path, f)
104 except UnicodeError:
105 except UnicodeError:
105 continue
106 continue
106 if os.path.isdir(full_path) and f.startswith('profile_'):
107 if os.path.isdir(full_path) and f.startswith('profile_'):
107 profiles.append(f.split('_',1)[-1])
108 profiles.append(f.split('_',1)[-1])
108 return profiles
109 return profiles
109
110
110
111
111 def list_bundled_profiles():
112 def list_bundled_profiles():
112 """list profiles that are bundled with IPython."""
113 """list profiles that are bundled with IPython."""
113 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
114 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
114 files = os.listdir(path)
115 files = os.listdir(path)
115 profiles = []
116 profiles = []
116 for profile in files:
117 for profile in files:
117 full_path = os.path.join(path, profile)
118 full_path = os.path.join(path, profile)
118 if os.path.isdir(full_path) and profile != "__pycache__":
119 if os.path.isdir(full_path) and profile != "__pycache__":
119 profiles.append(profile)
120 profiles.append(profile)
120 return profiles
121 return profiles
121
122
122
123
123 class ProfileLocate(BaseIPythonApplication):
124 class ProfileLocate(BaseIPythonApplication):
124 description = """print the path to an IPython profile dir"""
125 description = """print the path to an IPython profile dir"""
125
126
126 def parse_command_line(self, argv=None):
127 def parse_command_line(self, argv=None):
127 super(ProfileLocate, self).parse_command_line(argv)
128 super(ProfileLocate, self).parse_command_line(argv)
128 if self.extra_args:
129 if self.extra_args:
129 self.profile = self.extra_args[0]
130 self.profile = self.extra_args[0]
130
131
131 def start(self):
132 def start(self):
132 print self.profile_dir.location
133 print(self.profile_dir.location)
133
134
134
135
135 class ProfileList(Application):
136 class ProfileList(Application):
136 name = u'ipython-profile'
137 name = u'ipython-profile'
137 description = list_help
138 description = list_help
138 examples = _list_examples
139 examples = _list_examples
139
140
140 aliases = Dict({
141 aliases = Dict({
141 'ipython-dir' : 'ProfileList.ipython_dir',
142 'ipython-dir' : 'ProfileList.ipython_dir',
142 'log-level' : 'Application.log_level',
143 'log-level' : 'Application.log_level',
143 })
144 })
144 flags = Dict(dict(
145 flags = Dict(dict(
145 debug = ({'Application' : {'log_level' : 0}},
146 debug = ({'Application' : {'log_level' : 0}},
146 "Set Application.log_level to 0, maximizing log output."
147 "Set Application.log_level to 0, maximizing log output."
147 )
148 )
148 ))
149 ))
149
150
150 ipython_dir = Unicode(get_ipython_dir(), config=True,
151 ipython_dir = Unicode(get_ipython_dir(), config=True,
151 help="""
152 help="""
152 The name of the IPython directory. This directory is used for logging
153 The name of the IPython directory. This directory is used for logging
153 configuration (through profiles), history storage, etc. The default
154 configuration (through profiles), history storage, etc. The default
154 is usually $HOME/.ipython. This options can also be specified through
155 is usually $HOME/.ipython. This options can also be specified through
155 the environment variable IPYTHONDIR.
156 the environment variable IPYTHONDIR.
156 """
157 """
157 )
158 )
158
159
159
160
160 def _print_profiles(self, profiles):
161 def _print_profiles(self, profiles):
161 """print list of profiles, indented."""
162 """print list of profiles, indented."""
162 for profile in profiles:
163 for profile in profiles:
163 print ' %s' % profile
164 print(' %s' % profile)
164
165
165 def list_profile_dirs(self):
166 def list_profile_dirs(self):
166 profiles = list_bundled_profiles()
167 profiles = list_bundled_profiles()
167 if profiles:
168 if profiles:
168 print
169 print()
169 print "Available profiles in IPython:"
170 print("Available profiles in IPython:")
170 self._print_profiles(profiles)
171 self._print_profiles(profiles)
171 print
172 print()
172 print " The first request for a bundled profile will copy it"
173 print(" The first request for a bundled profile will copy it")
173 print " into your IPython directory (%s)," % self.ipython_dir
174 print(" into your IPython directory (%s)," % self.ipython_dir)
174 print " where you can customize it."
175 print(" where you can customize it.")
175
176
176 profiles = list_profiles_in(self.ipython_dir)
177 profiles = list_profiles_in(self.ipython_dir)
177 if profiles:
178 if profiles:
178 print
179 print()
179 print "Available profiles in %s:" % self.ipython_dir
180 print("Available profiles in %s:" % self.ipython_dir)
180 self._print_profiles(profiles)
181 self._print_profiles(profiles)
181
182
182 profiles = list_profiles_in(os.getcwdu())
183 profiles = list_profiles_in(os.getcwdu())
183 if profiles:
184 if profiles:
184 print
185 print()
185 print "Available profiles in current directory (%s):" % os.getcwdu()
186 print("Available profiles in current directory (%s):" % os.getcwdu())
186 self._print_profiles(profiles)
187 self._print_profiles(profiles)
187
188
188 print
189 print()
189 print "To use any of the above profiles, start IPython with:"
190 print("To use any of the above profiles, start IPython with:")
190 print " ipython --profile=<name>"
191 print(" ipython --profile=<name>")
191 print
192 print()
192
193
193 def start(self):
194 def start(self):
194 self.list_profile_dirs()
195 self.list_profile_dirs()
195
196
196
197
197 create_flags = {}
198 create_flags = {}
198 create_flags.update(base_flags)
199 create_flags.update(base_flags)
199 # don't include '--init' flag, which implies running profile create in other apps
200 # don't include '--init' flag, which implies running profile create in other apps
200 create_flags.pop('init')
201 create_flags.pop('init')
201 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
202 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
202 "reset config files in this profile to the defaults.")
203 "reset config files in this profile to the defaults.")
203 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
204 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
204 "Include the config files for parallel "
205 "Include the config files for parallel "
205 "computing apps (ipengine, ipcontroller, etc.)")
206 "computing apps (ipengine, ipcontroller, etc.)")
206
207
207
208
208 class ProfileCreate(BaseIPythonApplication):
209 class ProfileCreate(BaseIPythonApplication):
209 name = u'ipython-profile'
210 name = u'ipython-profile'
210 description = create_help
211 description = create_help
211 examples = _create_examples
212 examples = _create_examples
212 auto_create = Bool(True, config=False)
213 auto_create = Bool(True, config=False)
213 def _log_format_default(self):
214 def _log_format_default(self):
214 return "[%(name)s] %(message)s"
215 return "[%(name)s] %(message)s"
215
216
216 def _copy_config_files_default(self):
217 def _copy_config_files_default(self):
217 return True
218 return True
218
219
219 parallel = Bool(False, config=True,
220 parallel = Bool(False, config=True,
220 help="whether to include parallel computing config files")
221 help="whether to include parallel computing config files")
221 def _parallel_changed(self, name, old, new):
222 def _parallel_changed(self, name, old, new):
222 parallel_files = [ 'ipcontroller_config.py',
223 parallel_files = [ 'ipcontroller_config.py',
223 'ipengine_config.py',
224 'ipengine_config.py',
224 'ipcluster_config.py'
225 'ipcluster_config.py'
225 ]
226 ]
226 if new:
227 if new:
227 for cf in parallel_files:
228 for cf in parallel_files:
228 self.config_files.append(cf)
229 self.config_files.append(cf)
229 else:
230 else:
230 for cf in parallel_files:
231 for cf in parallel_files:
231 if cf in self.config_files:
232 if cf in self.config_files:
232 self.config_files.remove(cf)
233 self.config_files.remove(cf)
233
234
234 def parse_command_line(self, argv):
235 def parse_command_line(self, argv):
235 super(ProfileCreate, self).parse_command_line(argv)
236 super(ProfileCreate, self).parse_command_line(argv)
236 # accept positional arg as profile name
237 # accept positional arg as profile name
237 if self.extra_args:
238 if self.extra_args:
238 self.profile = self.extra_args[0]
239 self.profile = self.extra_args[0]
239
240
240 flags = Dict(create_flags)
241 flags = Dict(create_flags)
241
242
242 classes = [ProfileDir]
243 classes = [ProfileDir]
243
244
244 def _import_app(self, app_path):
245 def _import_app(self, app_path):
245 """import an app class"""
246 """import an app class"""
246 app = None
247 app = None
247 name = app_path.rsplit('.', 1)[-1]
248 name = app_path.rsplit('.', 1)[-1]
248 try:
249 try:
249 app = import_item(app_path)
250 app = import_item(app_path)
250 except ImportError as e:
251 except ImportError as e:
251 self.log.info("Couldn't import %s, config file will be excluded", name)
252 self.log.info("Couldn't import %s, config file will be excluded", name)
252 except Exception:
253 except Exception:
253 self.log.warn('Unexpected error importing %s', name, exc_info=True)
254 self.log.warn('Unexpected error importing %s', name, exc_info=True)
254 return app
255 return app
255
256
256 def init_config_files(self):
257 def init_config_files(self):
257 super(ProfileCreate, self).init_config_files()
258 super(ProfileCreate, self).init_config_files()
258 # use local imports, since these classes may import from here
259 # use local imports, since these classes may import from here
259 from IPython.terminal.ipapp import TerminalIPythonApp
260 from IPython.terminal.ipapp import TerminalIPythonApp
260 apps = [TerminalIPythonApp]
261 apps = [TerminalIPythonApp]
261 for app_path in (
262 for app_path in (
262 'IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
263 'IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
263 'IPython.html.notebookapp.NotebookApp',
264 'IPython.html.notebookapp.NotebookApp',
264 'IPython.nbconvert.nbconvertapp.NbConvertApp',
265 'IPython.nbconvert.nbconvertapp.NbConvertApp',
265 ):
266 ):
266 app = self._import_app(app_path)
267 app = self._import_app(app_path)
267 if app is not None:
268 if app is not None:
268 apps.append(app)
269 apps.append(app)
269 if self.parallel:
270 if self.parallel:
270 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
271 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
271 from IPython.parallel.apps.ipengineapp import IPEngineApp
272 from IPython.parallel.apps.ipengineapp import IPEngineApp
272 from IPython.parallel.apps.ipclusterapp import IPClusterStart
273 from IPython.parallel.apps.ipclusterapp import IPClusterStart
273 from IPython.parallel.apps.iploggerapp import IPLoggerApp
274 from IPython.parallel.apps.iploggerapp import IPLoggerApp
274 apps.extend([
275 apps.extend([
275 IPControllerApp,
276 IPControllerApp,
276 IPEngineApp,
277 IPEngineApp,
277 IPClusterStart,
278 IPClusterStart,
278 IPLoggerApp,
279 IPLoggerApp,
279 ])
280 ])
280 for App in apps:
281 for App in apps:
281 app = App()
282 app = App()
282 app.config.update(self.config)
283 app.config.update(self.config)
283 app.log = self.log
284 app.log = self.log
284 app.overwrite = self.overwrite
285 app.overwrite = self.overwrite
285 app.copy_config_files=True
286 app.copy_config_files=True
286 app.profile = self.profile
287 app.profile = self.profile
287 app.init_profile_dir()
288 app.init_profile_dir()
288 app.init_config_files()
289 app.init_config_files()
289
290
290 def stage_default_config_file(self):
291 def stage_default_config_file(self):
291 pass
292 pass
292
293
293
294
294 class ProfileApp(Application):
295 class ProfileApp(Application):
295 name = u'ipython-profile'
296 name = u'ipython-profile'
296 description = profile_help
297 description = profile_help
297 examples = _main_examples
298 examples = _main_examples
298
299
299 subcommands = Dict(dict(
300 subcommands = Dict(dict(
300 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
301 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
301 list = (ProfileList, ProfileList.description.splitlines()[0]),
302 list = (ProfileList, ProfileList.description.splitlines()[0]),
302 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
303 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
303 ))
304 ))
304
305
305 def start(self):
306 def start(self):
306 if self.subapp is None:
307 if self.subapp is None:
307 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
308 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
308 print
309 print()
309 self.print_description()
310 self.print_description()
310 self.print_subcommands()
311 self.print_subcommands()
311 self.exit(1)
312 self.exit(1)
312 else:
313 else:
313 return self.subapp.start()
314 return self.subapp.start()
@@ -1,339 +1,340 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 from __future__ import print_function
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009 The IPython Development Team
13 # Copyright (C) 2009 The IPython Development Team
13 #
14 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17
18
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 # Imports
20 # Imports
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21
22
22 import sys
23 import sys
23 from io import BytesIO
24 from io import BytesIO
24
25
25 from IPython.core.display import _pngxy
26 from IPython.core.display import _pngxy
26 from IPython.utils.decorators import flag_calls
27 from IPython.utils.decorators import flag_calls
27
28
28 # If user specifies a GUI, that dictates the backend, otherwise we read the
29 # If user specifies a GUI, that dictates the backend, otherwise we read the
29 # user's mpl default from the mpl rc structure
30 # user's mpl default from the mpl rc structure
30 backends = {'tk': 'TkAgg',
31 backends = {'tk': 'TkAgg',
31 'gtk': 'GTKAgg',
32 'gtk': 'GTKAgg',
32 'wx': 'WXAgg',
33 'wx': 'WXAgg',
33 'qt': 'Qt4Agg', # qt3 not supported
34 'qt': 'Qt4Agg', # qt3 not supported
34 'qt4': 'Qt4Agg',
35 'qt4': 'Qt4Agg',
35 'osx': 'MacOSX',
36 'osx': 'MacOSX',
36 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
37 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
37
38
38 # We also need a reverse backends2guis mapping that will properly choose which
39 # We also need a reverse backends2guis mapping that will properly choose which
39 # GUI support to activate based on the desired matplotlib backend. For the
40 # GUI support to activate based on the desired matplotlib backend. For the
40 # most part it's just a reverse of the above dict, but we also need to add a
41 # most part it's just a reverse of the above dict, but we also need to add a
41 # few others that map to the same GUI manually:
42 # few others that map to the same GUI manually:
42 backend2gui = dict(zip(backends.values(), backends.keys()))
43 backend2gui = dict(zip(backends.values(), backends.keys()))
43 # Our tests expect backend2gui to just return 'qt'
44 # Our tests expect backend2gui to just return 'qt'
44 backend2gui['Qt4Agg'] = 'qt'
45 backend2gui['Qt4Agg'] = 'qt'
45 # In the reverse mapping, there are a few extra valid matplotlib backends that
46 # In the reverse mapping, there are a few extra valid matplotlib backends that
46 # map to the same GUI support
47 # map to the same GUI support
47 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
48 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
48 backend2gui['WX'] = 'wx'
49 backend2gui['WX'] = 'wx'
49 backend2gui['CocoaAgg'] = 'osx'
50 backend2gui['CocoaAgg'] = 'osx'
50
51
51 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
52 # Matplotlib utilities
53 # Matplotlib utilities
53 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
54
55
55
56
56 def getfigs(*fig_nums):
57 def getfigs(*fig_nums):
57 """Get a list of matplotlib figures by figure numbers.
58 """Get a list of matplotlib figures by figure numbers.
58
59
59 If no arguments are given, all available figures are returned. If the
60 If no arguments are given, all available figures are returned. If the
60 argument list contains references to invalid figures, a warning is printed
61 argument list contains references to invalid figures, a warning is printed
61 but the function continues pasting further figures.
62 but the function continues pasting further figures.
62
63
63 Parameters
64 Parameters
64 ----------
65 ----------
65 figs : tuple
66 figs : tuple
66 A tuple of ints giving the figure numbers of the figures to return.
67 A tuple of ints giving the figure numbers of the figures to return.
67 """
68 """
68 from matplotlib._pylab_helpers import Gcf
69 from matplotlib._pylab_helpers import Gcf
69 if not fig_nums:
70 if not fig_nums:
70 fig_managers = Gcf.get_all_fig_managers()
71 fig_managers = Gcf.get_all_fig_managers()
71 return [fm.canvas.figure for fm in fig_managers]
72 return [fm.canvas.figure for fm in fig_managers]
72 else:
73 else:
73 figs = []
74 figs = []
74 for num in fig_nums:
75 for num in fig_nums:
75 f = Gcf.figs.get(num)
76 f = Gcf.figs.get(num)
76 if f is None:
77 if f is None:
77 print('Warning: figure %s not available.' % num)
78 print(('Warning: figure %s not available.' % num))
78 else:
79 else:
79 figs.append(f.canvas.figure)
80 figs.append(f.canvas.figure)
80 return figs
81 return figs
81
82
82
83
83 def figsize(sizex, sizey):
84 def figsize(sizex, sizey):
84 """Set the default figure size to be [sizex, sizey].
85 """Set the default figure size to be [sizex, sizey].
85
86
86 This is just an easy to remember, convenience wrapper that sets::
87 This is just an easy to remember, convenience wrapper that sets::
87
88
88 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
89 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
89 """
90 """
90 import matplotlib
91 import matplotlib
91 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92
93
93
94
94 def print_figure(fig, fmt='png'):
95 def print_figure(fig, fmt='png'):
95 """Convert a figure to svg or png for inline display."""
96 """Convert a figure to svg or png for inline display."""
96 from matplotlib import rcParams
97 from matplotlib import rcParams
97 # When there's an empty figure, we shouldn't return anything, otherwise we
98 # When there's an empty figure, we shouldn't return anything, otherwise we
98 # get big blank areas in the qt console.
99 # get big blank areas in the qt console.
99 if not fig.axes and not fig.lines:
100 if not fig.axes and not fig.lines:
100 return
101 return
101
102
102 fc = fig.get_facecolor()
103 fc = fig.get_facecolor()
103 ec = fig.get_edgecolor()
104 ec = fig.get_edgecolor()
104 bytes_io = BytesIO()
105 bytes_io = BytesIO()
105 dpi = rcParams['savefig.dpi']
106 dpi = rcParams['savefig.dpi']
106 if fmt == 'retina':
107 if fmt == 'retina':
107 dpi = dpi * 2
108 dpi = dpi * 2
108 fmt = 'png'
109 fmt = 'png'
109 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
110 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
110 facecolor=fc, edgecolor=ec, dpi=dpi)
111 facecolor=fc, edgecolor=ec, dpi=dpi)
111 data = bytes_io.getvalue()
112 data = bytes_io.getvalue()
112 return data
113 return data
113
114
114 def retina_figure(fig):
115 def retina_figure(fig):
115 """format a figure as a pixel-doubled (retina) PNG"""
116 """format a figure as a pixel-doubled (retina) PNG"""
116 pngdata = print_figure(fig, fmt='retina')
117 pngdata = print_figure(fig, fmt='retina')
117 w, h = _pngxy(pngdata)
118 w, h = _pngxy(pngdata)
118 metadata = dict(width=w//2, height=h//2)
119 metadata = dict(width=w//2, height=h//2)
119 return pngdata, metadata
120 return pngdata, metadata
120
121
121 # We need a little factory function here to create the closure where
122 # We need a little factory function here to create the closure where
122 # safe_execfile can live.
123 # safe_execfile can live.
123 def mpl_runner(safe_execfile):
124 def mpl_runner(safe_execfile):
124 """Factory to return a matplotlib-enabled runner for %run.
125 """Factory to return a matplotlib-enabled runner for %run.
125
126
126 Parameters
127 Parameters
127 ----------
128 ----------
128 safe_execfile : function
129 safe_execfile : function
129 This must be a function with the same interface as the
130 This must be a function with the same interface as the
130 :meth:`safe_execfile` method of IPython.
131 :meth:`safe_execfile` method of IPython.
131
132
132 Returns
133 Returns
133 -------
134 -------
134 A function suitable for use as the ``runner`` argument of the %run magic
135 A function suitable for use as the ``runner`` argument of the %run magic
135 function.
136 function.
136 """
137 """
137
138
138 def mpl_execfile(fname,*where,**kw):
139 def mpl_execfile(fname,*where,**kw):
139 """matplotlib-aware wrapper around safe_execfile.
140 """matplotlib-aware wrapper around safe_execfile.
140
141
141 Its interface is identical to that of the :func:`execfile` builtin.
142 Its interface is identical to that of the :func:`execfile` builtin.
142
143
143 This is ultimately a call to execfile(), but wrapped in safeties to
144 This is ultimately a call to execfile(), but wrapped in safeties to
144 properly handle interactive rendering."""
145 properly handle interactive rendering."""
145
146
146 import matplotlib
147 import matplotlib
147 import matplotlib.pylab as pylab
148 import matplotlib.pylab as pylab
148
149
149 #print '*** Matplotlib runner ***' # dbg
150 #print '*** Matplotlib runner ***' # dbg
150 # turn off rendering until end of script
151 # turn off rendering until end of script
151 is_interactive = matplotlib.rcParams['interactive']
152 is_interactive = matplotlib.rcParams['interactive']
152 matplotlib.interactive(False)
153 matplotlib.interactive(False)
153 safe_execfile(fname,*where,**kw)
154 safe_execfile(fname,*where,**kw)
154 matplotlib.interactive(is_interactive)
155 matplotlib.interactive(is_interactive)
155 # make rendering call now, if the user tried to do it
156 # make rendering call now, if the user tried to do it
156 if pylab.draw_if_interactive.called:
157 if pylab.draw_if_interactive.called:
157 pylab.draw()
158 pylab.draw()
158 pylab.draw_if_interactive.called = False
159 pylab.draw_if_interactive.called = False
159
160
160 return mpl_execfile
161 return mpl_execfile
161
162
162
163
163 def select_figure_format(shell, fmt):
164 def select_figure_format(shell, fmt):
164 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
165 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
165
166
166 Using this method ensures only one figure format is active at a time.
167 Using this method ensures only one figure format is active at a time.
167 """
168 """
168 from matplotlib.figure import Figure
169 from matplotlib.figure import Figure
169 from IPython.kernel.zmq.pylab import backend_inline
170 from IPython.kernel.zmq.pylab import backend_inline
170
171
171 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
172 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
172 png_formatter = shell.display_formatter.formatters['image/png']
173 png_formatter = shell.display_formatter.formatters['image/png']
173
174
174 if fmt == 'png':
175 if fmt == 'png':
175 svg_formatter.type_printers.pop(Figure, None)
176 svg_formatter.type_printers.pop(Figure, None)
176 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
177 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
177 elif fmt in ('png2x', 'retina'):
178 elif fmt in ('png2x', 'retina'):
178 svg_formatter.type_printers.pop(Figure, None)
179 svg_formatter.type_printers.pop(Figure, None)
179 png_formatter.for_type(Figure, retina_figure)
180 png_formatter.for_type(Figure, retina_figure)
180 elif fmt == 'svg':
181 elif fmt == 'svg':
181 png_formatter.type_printers.pop(Figure, None)
182 png_formatter.type_printers.pop(Figure, None)
182 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
183 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
183 else:
184 else:
184 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
185 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
185
186
186 # set the format to be used in the backend()
187 # set the format to be used in the backend()
187 backend_inline._figure_format = fmt
188 backend_inline._figure_format = fmt
188
189
189 #-----------------------------------------------------------------------------
190 #-----------------------------------------------------------------------------
190 # Code for initializing matplotlib and importing pylab
191 # Code for initializing matplotlib and importing pylab
191 #-----------------------------------------------------------------------------
192 #-----------------------------------------------------------------------------
192
193
193
194
194 def find_gui_and_backend(gui=None, gui_select=None):
195 def find_gui_and_backend(gui=None, gui_select=None):
195 """Given a gui string return the gui and mpl backend.
196 """Given a gui string return the gui and mpl backend.
196
197
197 Parameters
198 Parameters
198 ----------
199 ----------
199 gui : str
200 gui : str
200 Can be one of ('tk','gtk','wx','qt','qt4','inline').
201 Can be one of ('tk','gtk','wx','qt','qt4','inline').
201 gui_select : str
202 gui_select : str
202 Can be one of ('tk','gtk','wx','qt','qt4','inline').
203 Can be one of ('tk','gtk','wx','qt','qt4','inline').
203 This is any gui already selected by the shell.
204 This is any gui already selected by the shell.
204
205
205 Returns
206 Returns
206 -------
207 -------
207 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
208 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
208 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
209 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
209 """
210 """
210
211
211 import matplotlib
212 import matplotlib
212
213
213 if gui and gui != 'auto':
214 if gui and gui != 'auto':
214 # select backend based on requested gui
215 # select backend based on requested gui
215 backend = backends[gui]
216 backend = backends[gui]
216 else:
217 else:
217 # We need to read the backend from the original data structure, *not*
218 # We need to read the backend from the original data structure, *not*
218 # from mpl.rcParams, since a prior invocation of %matplotlib may have
219 # from mpl.rcParams, since a prior invocation of %matplotlib may have
219 # overwritten that.
220 # overwritten that.
220 # WARNING: this assumes matplotlib 1.1 or newer!!
221 # WARNING: this assumes matplotlib 1.1 or newer!!
221 backend = matplotlib.rcParamsOrig['backend']
222 backend = matplotlib.rcParamsOrig['backend']
222 # In this case, we need to find what the appropriate gui selection call
223 # In this case, we need to find what the appropriate gui selection call
223 # should be for IPython, so we can activate inputhook accordingly
224 # should be for IPython, so we can activate inputhook accordingly
224 gui = backend2gui.get(backend, None)
225 gui = backend2gui.get(backend, None)
225
226
226 # If we have already had a gui active, we need it and inline are the
227 # If we have already had a gui active, we need it and inline are the
227 # ones allowed.
228 # ones allowed.
228 if gui_select and gui != gui_select:
229 if gui_select and gui != gui_select:
229 gui = gui_select
230 gui = gui_select
230 backend = backends[gui]
231 backend = backends[gui]
231
232
232 return gui, backend
233 return gui, backend
233
234
234
235
235 def activate_matplotlib(backend):
236 def activate_matplotlib(backend):
236 """Activate the given backend and set interactive to True."""
237 """Activate the given backend and set interactive to True."""
237
238
238 import matplotlib
239 import matplotlib
239 matplotlib.interactive(True)
240 matplotlib.interactive(True)
240
241
241 # Matplotlib had a bug where even switch_backend could not force
242 # Matplotlib had a bug where even switch_backend could not force
242 # the rcParam to update. This needs to be set *before* the module
243 # the rcParam to update. This needs to be set *before* the module
243 # magic of switch_backend().
244 # magic of switch_backend().
244 matplotlib.rcParams['backend'] = backend
245 matplotlib.rcParams['backend'] = backend
245
246
246 import matplotlib.pyplot
247 import matplotlib.pyplot
247 matplotlib.pyplot.switch_backend(backend)
248 matplotlib.pyplot.switch_backend(backend)
248
249
249 # This must be imported last in the matplotlib series, after
250 # This must be imported last in the matplotlib series, after
250 # backend/interactivity choices have been made
251 # backend/interactivity choices have been made
251 import matplotlib.pylab as pylab
252 import matplotlib.pylab as pylab
252
253
253 pylab.show._needmain = False
254 pylab.show._needmain = False
254 # We need to detect at runtime whether show() is called by the user.
255 # We need to detect at runtime whether show() is called by the user.
255 # For this, we wrap it into a decorator which adds a 'called' flag.
256 # For this, we wrap it into a decorator which adds a 'called' flag.
256 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
257 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
257
258
258
259
259 def import_pylab(user_ns, import_all=True):
260 def import_pylab(user_ns, import_all=True):
260 """Populate the namespace with pylab-related values.
261 """Populate the namespace with pylab-related values.
261
262
262 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
263 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
263
264
264 Also imports a few names from IPython (figsize, display, getfigs)
265 Also imports a few names from IPython (figsize, display, getfigs)
265
266
266 """
267 """
267
268
268 # Import numpy as np/pyplot as plt are conventions we're trying to
269 # Import numpy as np/pyplot as plt are conventions we're trying to
269 # somewhat standardize on. Making them available to users by default
270 # somewhat standardize on. Making them available to users by default
270 # will greatly help this.
271 # will greatly help this.
271 s = ("import numpy\n"
272 s = ("import numpy\n"
272 "import matplotlib\n"
273 "import matplotlib\n"
273 "from matplotlib import pylab, mlab, pyplot\n"
274 "from matplotlib import pylab, mlab, pyplot\n"
274 "np = numpy\n"
275 "np = numpy\n"
275 "plt = pyplot\n"
276 "plt = pyplot\n"
276 )
277 )
277 exec s in user_ns
278 exec s in user_ns
278
279
279 if import_all:
280 if import_all:
280 s = ("from matplotlib.pylab import *\n"
281 s = ("from matplotlib.pylab import *\n"
281 "from numpy import *\n")
282 "from numpy import *\n")
282 exec s in user_ns
283 exec s in user_ns
283
284
284 # IPython symbols to add
285 # IPython symbols to add
285 user_ns['figsize'] = figsize
286 user_ns['figsize'] = figsize
286 from IPython.core.display import display
287 from IPython.core.display import display
287 # Add display and getfigs to the user's namespace
288 # Add display and getfigs to the user's namespace
288 user_ns['display'] = display
289 user_ns['display'] = display
289 user_ns['getfigs'] = getfigs
290 user_ns['getfigs'] = getfigs
290
291
291
292
292 def configure_inline_support(shell, backend):
293 def configure_inline_support(shell, backend):
293 """Configure an IPython shell object for matplotlib use.
294 """Configure an IPython shell object for matplotlib use.
294
295
295 Parameters
296 Parameters
296 ----------
297 ----------
297 shell : InteractiveShell instance
298 shell : InteractiveShell instance
298
299
299 backend : matplotlib backend
300 backend : matplotlib backend
300 """
301 """
301 # If using our svg payload backend, register the post-execution
302 # If using our svg payload backend, register the post-execution
302 # function that will pick up the results for display. This can only be
303 # function that will pick up the results for display. This can only be
303 # done with access to the real shell object.
304 # done with access to the real shell object.
304
305
305 # Note: if we can't load the inline backend, then there's no point
306 # Note: if we can't load the inline backend, then there's no point
306 # continuing (such as in terminal-only shells in environments without
307 # continuing (such as in terminal-only shells in environments without
307 # zeromq available).
308 # zeromq available).
308 try:
309 try:
309 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
310 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
310 except ImportError:
311 except ImportError:
311 return
312 return
312 from matplotlib import pyplot
313 from matplotlib import pyplot
313
314
314 cfg = InlineBackend.instance(parent=shell)
315 cfg = InlineBackend.instance(parent=shell)
315 cfg.shell = shell
316 cfg.shell = shell
316 if cfg not in shell.configurables:
317 if cfg not in shell.configurables:
317 shell.configurables.append(cfg)
318 shell.configurables.append(cfg)
318
319
319 if backend == backends['inline']:
320 if backend == backends['inline']:
320 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
321 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
321 shell.register_post_execute(flush_figures)
322 shell.register_post_execute(flush_figures)
322
323
323 # Save rcParams that will be overwrittern
324 # Save rcParams that will be overwrittern
324 shell._saved_rcParams = dict()
325 shell._saved_rcParams = dict()
325 for k in cfg.rc:
326 for k in cfg.rc:
326 shell._saved_rcParams[k] = pyplot.rcParams[k]
327 shell._saved_rcParams[k] = pyplot.rcParams[k]
327 # load inline_rc
328 # load inline_rc
328 pyplot.rcParams.update(cfg.rc)
329 pyplot.rcParams.update(cfg.rc)
329 else:
330 else:
330 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
331 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
331 if flush_figures in shell._post_execute:
332 if flush_figures in shell._post_execute:
332 shell._post_execute.pop(flush_figures)
333 shell._post_execute.pop(flush_figures)
333 if hasattr(shell, '_saved_rcParams'):
334 if hasattr(shell, '_saved_rcParams'):
334 pyplot.rcParams.update(shell._saved_rcParams)
335 pyplot.rcParams.update(shell._saved_rcParams)
335 del shell._saved_rcParams
336 del shell._saved_rcParams
336
337
337 # Setup the default figure format
338 # Setup the default figure format
338 select_figure_format(shell, cfg.figure_format)
339 select_figure_format(shell, cfg.figure_format)
339
340
@@ -1,409 +1,410 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A mixin for :class:`~IPython.core.application.Application` classes that
3 A mixin for :class:`~IPython.core.application.Application` classes that
4 launch InteractiveShell instances, load extensions, etc.
4 launch InteractiveShell instances, load extensions, etc.
5
5
6 Authors
6 Authors
7 -------
7 -------
8
8
9 * Min Ragan-Kelley
9 * Min Ragan-Kelley
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 from __future__ import absolute_import
23 from __future__ import absolute_import
24 from __future__ import print_function
24
25
25 import glob
26 import glob
26 import os
27 import os
27 import sys
28 import sys
28
29
29 from IPython.config.application import boolean_flag
30 from IPython.config.application import boolean_flag
30 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
31 from IPython.config.loader import Config
32 from IPython.config.loader import Config
32 from IPython.core import pylabtools
33 from IPython.core import pylabtools
33 from IPython.utils import py3compat
34 from IPython.utils import py3compat
34 from IPython.utils.contexts import preserve_keys
35 from IPython.utils.contexts import preserve_keys
35 from IPython.utils.path import filefind
36 from IPython.utils.path import filefind
36 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
37 Unicode, Instance, List, Bool, CaselessStrEnum, Dict
38 Unicode, Instance, List, Bool, CaselessStrEnum, Dict
38 )
39 )
39 from IPython.lib.inputhook import guis
40 from IPython.lib.inputhook import guis
40
41
41 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
42 # Aliases and Flags
43 # Aliases and Flags
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44
45
45 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
46 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
46
47
47 backend_keys = sorted(pylabtools.backends.keys())
48 backend_keys = sorted(pylabtools.backends.keys())
48 backend_keys.insert(0, 'auto')
49 backend_keys.insert(0, 'auto')
49
50
50 shell_flags = {}
51 shell_flags = {}
51
52
52 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
53 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
53 addflag('autoindent', 'InteractiveShell.autoindent',
54 addflag('autoindent', 'InteractiveShell.autoindent',
54 'Turn on autoindenting.', 'Turn off autoindenting.'
55 'Turn on autoindenting.', 'Turn off autoindenting.'
55 )
56 )
56 addflag('automagic', 'InteractiveShell.automagic',
57 addflag('automagic', 'InteractiveShell.automagic',
57 """Turn on the auto calling of magic commands. Type %%magic at the
58 """Turn on the auto calling of magic commands. Type %%magic at the
58 IPython prompt for more information.""",
59 IPython prompt for more information.""",
59 'Turn off the auto calling of magic commands.'
60 'Turn off the auto calling of magic commands.'
60 )
61 )
61 addflag('pdb', 'InteractiveShell.pdb',
62 addflag('pdb', 'InteractiveShell.pdb',
62 "Enable auto calling the pdb debugger after every exception.",
63 "Enable auto calling the pdb debugger after every exception.",
63 "Disable auto calling the pdb debugger after every exception."
64 "Disable auto calling the pdb debugger after every exception."
64 )
65 )
65 # pydb flag doesn't do any config, as core.debugger switches on import,
66 # pydb flag doesn't do any config, as core.debugger switches on import,
66 # which is before parsing. This just allows the flag to be passed.
67 # which is before parsing. This just allows the flag to be passed.
67 shell_flags.update(dict(
68 shell_flags.update(dict(
68 pydb = ({},
69 pydb = ({},
69 """Use the third party 'pydb' package as debugger, instead of pdb.
70 """Use the third party 'pydb' package as debugger, instead of pdb.
70 Requires that pydb is installed."""
71 Requires that pydb is installed."""
71 )
72 )
72 ))
73 ))
73 addflag('pprint', 'PlainTextFormatter.pprint',
74 addflag('pprint', 'PlainTextFormatter.pprint',
74 "Enable auto pretty printing of results.",
75 "Enable auto pretty printing of results.",
75 "Disable auto pretty printing of results."
76 "Disable auto pretty printing of results."
76 )
77 )
77 addflag('color-info', 'InteractiveShell.color_info',
78 addflag('color-info', 'InteractiveShell.color_info',
78 """IPython can display information about objects via a set of func-
79 """IPython can display information about objects via a set of func-
79 tions, and optionally can use colors for this, syntax highlighting
80 tions, and optionally can use colors for this, syntax highlighting
80 source code and various other elements. However, because this
81 source code and various other elements. However, because this
81 information is passed through a pager (like 'less') and many pagers get
82 information is passed through a pager (like 'less') and many pagers get
82 confused with color codes, this option is off by default. You can test
83 confused with color codes, this option is off by default. You can test
83 it and turn it on permanently in your ipython_config.py file if it
84 it and turn it on permanently in your ipython_config.py file if it
84 works for you. Test it and turn it on permanently if it works with
85 works for you. Test it and turn it on permanently if it works with
85 your system. The magic function %%color_info allows you to toggle this
86 your system. The magic function %%color_info allows you to toggle this
86 interactively for testing.""",
87 interactively for testing.""",
87 "Disable using colors for info related things."
88 "Disable using colors for info related things."
88 )
89 )
89 addflag('deep-reload', 'InteractiveShell.deep_reload',
90 addflag('deep-reload', 'InteractiveShell.deep_reload',
90 """Enable deep (recursive) reloading by default. IPython can use the
91 """Enable deep (recursive) reloading by default. IPython can use the
91 deep_reload module which reloads changes in modules recursively (it
92 deep_reload module which reloads changes in modules recursively (it
92 replaces the reload() function, so you don't need to change anything to
93 replaces the reload() function, so you don't need to change anything to
93 use it). deep_reload() forces a full reload of modules whose code may
94 use it). deep_reload() forces a full reload of modules whose code may
94 have changed, which the default reload() function does not. When
95 have changed, which the default reload() function does not. When
95 deep_reload is off, IPython will use the normal reload(), but
96 deep_reload is off, IPython will use the normal reload(), but
96 deep_reload will still be available as dreload(). This feature is off
97 deep_reload will still be available as dreload(). This feature is off
97 by default [which means that you have both normal reload() and
98 by default [which means that you have both normal reload() and
98 dreload()].""",
99 dreload()].""",
99 "Disable deep (recursive) reloading by default."
100 "Disable deep (recursive) reloading by default."
100 )
101 )
101 nosep_config = Config()
102 nosep_config = Config()
102 nosep_config.InteractiveShell.separate_in = ''
103 nosep_config.InteractiveShell.separate_in = ''
103 nosep_config.InteractiveShell.separate_out = ''
104 nosep_config.InteractiveShell.separate_out = ''
104 nosep_config.InteractiveShell.separate_out2 = ''
105 nosep_config.InteractiveShell.separate_out2 = ''
105
106
106 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
107 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
107 shell_flags['pylab'] = (
108 shell_flags['pylab'] = (
108 {'InteractiveShellApp' : {'pylab' : 'auto'}},
109 {'InteractiveShellApp' : {'pylab' : 'auto'}},
109 """Pre-load matplotlib and numpy for interactive use with
110 """Pre-load matplotlib and numpy for interactive use with
110 the default matplotlib backend."""
111 the default matplotlib backend."""
111 )
112 )
112 shell_flags['matplotlib'] = (
113 shell_flags['matplotlib'] = (
113 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
114 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
114 """Configure matplotlib for interactive use with
115 """Configure matplotlib for interactive use with
115 the default matplotlib backend."""
116 the default matplotlib backend."""
116 )
117 )
117
118
118 # it's possible we don't want short aliases for *all* of these:
119 # it's possible we don't want short aliases for *all* of these:
119 shell_aliases = dict(
120 shell_aliases = dict(
120 autocall='InteractiveShell.autocall',
121 autocall='InteractiveShell.autocall',
121 colors='InteractiveShell.colors',
122 colors='InteractiveShell.colors',
122 logfile='InteractiveShell.logfile',
123 logfile='InteractiveShell.logfile',
123 logappend='InteractiveShell.logappend',
124 logappend='InteractiveShell.logappend',
124 c='InteractiveShellApp.code_to_run',
125 c='InteractiveShellApp.code_to_run',
125 m='InteractiveShellApp.module_to_run',
126 m='InteractiveShellApp.module_to_run',
126 ext='InteractiveShellApp.extra_extension',
127 ext='InteractiveShellApp.extra_extension',
127 gui='InteractiveShellApp.gui',
128 gui='InteractiveShellApp.gui',
128 pylab='InteractiveShellApp.pylab',
129 pylab='InteractiveShellApp.pylab',
129 matplotlib='InteractiveShellApp.matplotlib',
130 matplotlib='InteractiveShellApp.matplotlib',
130 )
131 )
131 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
132 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
132
133
133 #-----------------------------------------------------------------------------
134 #-----------------------------------------------------------------------------
134 # Main classes and functions
135 # Main classes and functions
135 #-----------------------------------------------------------------------------
136 #-----------------------------------------------------------------------------
136
137
137 class InteractiveShellApp(Configurable):
138 class InteractiveShellApp(Configurable):
138 """A Mixin for applications that start InteractiveShell instances.
139 """A Mixin for applications that start InteractiveShell instances.
139
140
140 Provides configurables for loading extensions and executing files
141 Provides configurables for loading extensions and executing files
141 as part of configuring a Shell environment.
142 as part of configuring a Shell environment.
142
143
143 The following methods should be called by the :meth:`initialize` method
144 The following methods should be called by the :meth:`initialize` method
144 of the subclass:
145 of the subclass:
145
146
146 - :meth:`init_path`
147 - :meth:`init_path`
147 - :meth:`init_shell` (to be implemented by the subclass)
148 - :meth:`init_shell` (to be implemented by the subclass)
148 - :meth:`init_gui_pylab`
149 - :meth:`init_gui_pylab`
149 - :meth:`init_extensions`
150 - :meth:`init_extensions`
150 - :meth:`init_code`
151 - :meth:`init_code`
151 """
152 """
152 extensions = List(Unicode, config=True,
153 extensions = List(Unicode, config=True,
153 help="A list of dotted module names of IPython extensions to load."
154 help="A list of dotted module names of IPython extensions to load."
154 )
155 )
155 extra_extension = Unicode('', config=True,
156 extra_extension = Unicode('', config=True,
156 help="dotted module name of an IPython extension to load."
157 help="dotted module name of an IPython extension to load."
157 )
158 )
158 def _extra_extension_changed(self, name, old, new):
159 def _extra_extension_changed(self, name, old, new):
159 if new:
160 if new:
160 # add to self.extensions
161 # add to self.extensions
161 self.extensions.append(new)
162 self.extensions.append(new)
162
163
163 # Extensions that are always loaded (not configurable)
164 # Extensions that are always loaded (not configurable)
164 default_extensions = List(Unicode, [u'storemagic'], config=False)
165 default_extensions = List(Unicode, [u'storemagic'], config=False)
165
166
166 exec_files = List(Unicode, config=True,
167 exec_files = List(Unicode, config=True,
167 help="""List of files to run at IPython startup."""
168 help="""List of files to run at IPython startup."""
168 )
169 )
169 file_to_run = Unicode('', config=True,
170 file_to_run = Unicode('', config=True,
170 help="""A file to be run""")
171 help="""A file to be run""")
171
172
172 exec_lines = List(Unicode, config=True,
173 exec_lines = List(Unicode, config=True,
173 help="""lines of code to run at IPython startup."""
174 help="""lines of code to run at IPython startup."""
174 )
175 )
175 code_to_run = Unicode('', config=True,
176 code_to_run = Unicode('', config=True,
176 help="Execute the given command string."
177 help="Execute the given command string."
177 )
178 )
178 module_to_run = Unicode('', config=True,
179 module_to_run = Unicode('', config=True,
179 help="Run the module as a script."
180 help="Run the module as a script."
180 )
181 )
181 gui = CaselessStrEnum(gui_keys, config=True,
182 gui = CaselessStrEnum(gui_keys, config=True,
182 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
183 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
183 )
184 )
184 matplotlib = CaselessStrEnum(backend_keys,
185 matplotlib = CaselessStrEnum(backend_keys,
185 config=True,
186 config=True,
186 help="""Configure matplotlib for interactive use with
187 help="""Configure matplotlib for interactive use with
187 the default matplotlib backend."""
188 the default matplotlib backend."""
188 )
189 )
189 pylab = CaselessStrEnum(backend_keys,
190 pylab = CaselessStrEnum(backend_keys,
190 config=True,
191 config=True,
191 help="""Pre-load matplotlib and numpy for interactive use,
192 help="""Pre-load matplotlib and numpy for interactive use,
192 selecting a particular matplotlib backend and loop integration.
193 selecting a particular matplotlib backend and loop integration.
193 """
194 """
194 )
195 )
195 pylab_import_all = Bool(True, config=True,
196 pylab_import_all = Bool(True, config=True,
196 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
197 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
197 and an 'import *' is done from numpy and pylab, when using pylab mode.
198 and an 'import *' is done from numpy and pylab, when using pylab mode.
198
199
199 When False, pylab mode should not import any names into the user namespace.
200 When False, pylab mode should not import any names into the user namespace.
200 """
201 """
201 )
202 )
202 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
203 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
203
204
204 user_ns = Instance(dict, args=None, allow_none=True)
205 user_ns = Instance(dict, args=None, allow_none=True)
205 def _user_ns_changed(self, name, old, new):
206 def _user_ns_changed(self, name, old, new):
206 if self.shell is not None:
207 if self.shell is not None:
207 self.shell.user_ns = new
208 self.shell.user_ns = new
208 self.shell.init_user_ns()
209 self.shell.init_user_ns()
209
210
210 def init_path(self):
211 def init_path(self):
211 """Add current working directory, '', to sys.path"""
212 """Add current working directory, '', to sys.path"""
212 if sys.path[0] != '':
213 if sys.path[0] != '':
213 sys.path.insert(0, '')
214 sys.path.insert(0, '')
214
215
215 def init_shell(self):
216 def init_shell(self):
216 raise NotImplementedError("Override in subclasses")
217 raise NotImplementedError("Override in subclasses")
217
218
218 def init_gui_pylab(self):
219 def init_gui_pylab(self):
219 """Enable GUI event loop integration, taking pylab into account."""
220 """Enable GUI event loop integration, taking pylab into account."""
220 enable = False
221 enable = False
221 shell = self.shell
222 shell = self.shell
222 if self.pylab:
223 if self.pylab:
223 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
224 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
224 key = self.pylab
225 key = self.pylab
225 elif self.matplotlib:
226 elif self.matplotlib:
226 enable = shell.enable_matplotlib
227 enable = shell.enable_matplotlib
227 key = self.matplotlib
228 key = self.matplotlib
228 elif self.gui:
229 elif self.gui:
229 enable = shell.enable_gui
230 enable = shell.enable_gui
230 key = self.gui
231 key = self.gui
231
232
232 if not enable:
233 if not enable:
233 return
234 return
234
235
235 try:
236 try:
236 r = enable(key)
237 r = enable(key)
237 except ImportError:
238 except ImportError:
238 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
239 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
239 self.shell.showtraceback()
240 self.shell.showtraceback()
240 return
241 return
241 except Exception:
242 except Exception:
242 self.log.warn("GUI event loop or pylab initialization failed")
243 self.log.warn("GUI event loop or pylab initialization failed")
243 self.shell.showtraceback()
244 self.shell.showtraceback()
244 return
245 return
245
246
246 if isinstance(r, tuple):
247 if isinstance(r, tuple):
247 gui, backend = r[:2]
248 gui, backend = r[:2]
248 self.log.info("Enabling GUI event loop integration, "
249 self.log.info("Enabling GUI event loop integration, "
249 "eventloop=%s, matplotlib=%s", gui, backend)
250 "eventloop=%s, matplotlib=%s", gui, backend)
250 if key == "auto":
251 if key == "auto":
251 print ("Using matplotlib backend: %s" % backend)
252 print(("Using matplotlib backend: %s" % backend))
252 else:
253 else:
253 gui = r
254 gui = r
254 self.log.info("Enabling GUI event loop integration, "
255 self.log.info("Enabling GUI event loop integration, "
255 "eventloop=%s", gui)
256 "eventloop=%s", gui)
256
257
257 def init_extensions(self):
258 def init_extensions(self):
258 """Load all IPython extensions in IPythonApp.extensions.
259 """Load all IPython extensions in IPythonApp.extensions.
259
260
260 This uses the :meth:`ExtensionManager.load_extensions` to load all
261 This uses the :meth:`ExtensionManager.load_extensions` to load all
261 the extensions listed in ``self.extensions``.
262 the extensions listed in ``self.extensions``.
262 """
263 """
263 try:
264 try:
264 self.log.debug("Loading IPython extensions...")
265 self.log.debug("Loading IPython extensions...")
265 extensions = self.default_extensions + self.extensions
266 extensions = self.default_extensions + self.extensions
266 for ext in extensions:
267 for ext in extensions:
267 try:
268 try:
268 self.log.info("Loading IPython extension: %s" % ext)
269 self.log.info("Loading IPython extension: %s" % ext)
269 self.shell.extension_manager.load_extension(ext)
270 self.shell.extension_manager.load_extension(ext)
270 except:
271 except:
271 self.log.warn("Error in loading extension: %s" % ext +
272 self.log.warn("Error in loading extension: %s" % ext +
272 "\nCheck your config files in %s" % self.profile_dir.location
273 "\nCheck your config files in %s" % self.profile_dir.location
273 )
274 )
274 self.shell.showtraceback()
275 self.shell.showtraceback()
275 except:
276 except:
276 self.log.warn("Unknown error in loading extensions:")
277 self.log.warn("Unknown error in loading extensions:")
277 self.shell.showtraceback()
278 self.shell.showtraceback()
278
279
279 def init_code(self):
280 def init_code(self):
280 """run the pre-flight code, specified via exec_lines"""
281 """run the pre-flight code, specified via exec_lines"""
281 self._run_startup_files()
282 self._run_startup_files()
282 self._run_exec_lines()
283 self._run_exec_lines()
283 self._run_exec_files()
284 self._run_exec_files()
284 self._run_cmd_line_code()
285 self._run_cmd_line_code()
285 self._run_module()
286 self._run_module()
286
287
287 # flush output, so itwon't be attached to the first cell
288 # flush output, so itwon't be attached to the first cell
288 sys.stdout.flush()
289 sys.stdout.flush()
289 sys.stderr.flush()
290 sys.stderr.flush()
290
291
291 # Hide variables defined here from %who etc.
292 # Hide variables defined here from %who etc.
292 self.shell.user_ns_hidden.update(self.shell.user_ns)
293 self.shell.user_ns_hidden.update(self.shell.user_ns)
293
294
294 def _run_exec_lines(self):
295 def _run_exec_lines(self):
295 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
296 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
296 if not self.exec_lines:
297 if not self.exec_lines:
297 return
298 return
298 try:
299 try:
299 self.log.debug("Running code from IPythonApp.exec_lines...")
300 self.log.debug("Running code from IPythonApp.exec_lines...")
300 for line in self.exec_lines:
301 for line in self.exec_lines:
301 try:
302 try:
302 self.log.info("Running code in user namespace: %s" %
303 self.log.info("Running code in user namespace: %s" %
303 line)
304 line)
304 self.shell.run_cell(line, store_history=False)
305 self.shell.run_cell(line, store_history=False)
305 except:
306 except:
306 self.log.warn("Error in executing line in user "
307 self.log.warn("Error in executing line in user "
307 "namespace: %s" % line)
308 "namespace: %s" % line)
308 self.shell.showtraceback()
309 self.shell.showtraceback()
309 except:
310 except:
310 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
311 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
311 self.shell.showtraceback()
312 self.shell.showtraceback()
312
313
313 def _exec_file(self, fname):
314 def _exec_file(self, fname):
314 try:
315 try:
315 full_filename = filefind(fname, [u'.', self.ipython_dir])
316 full_filename = filefind(fname, [u'.', self.ipython_dir])
316 except IOError as e:
317 except IOError as e:
317 self.log.warn("File not found: %r"%fname)
318 self.log.warn("File not found: %r"%fname)
318 return
319 return
319 # Make sure that the running script gets a proper sys.argv as if it
320 # Make sure that the running script gets a proper sys.argv as if it
320 # were run from a system shell.
321 # were run from a system shell.
321 save_argv = sys.argv
322 save_argv = sys.argv
322 sys.argv = [full_filename] + self.extra_args[1:]
323 sys.argv = [full_filename] + self.extra_args[1:]
323 # protect sys.argv from potential unicode strings on Python 2:
324 # protect sys.argv from potential unicode strings on Python 2:
324 if not py3compat.PY3:
325 if not py3compat.PY3:
325 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
326 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
326 try:
327 try:
327 if os.path.isfile(full_filename):
328 if os.path.isfile(full_filename):
328 self.log.info("Running file in user namespace: %s" %
329 self.log.info("Running file in user namespace: %s" %
329 full_filename)
330 full_filename)
330 # Ensure that __file__ is always defined to match Python
331 # Ensure that __file__ is always defined to match Python
331 # behavior.
332 # behavior.
332 with preserve_keys(self.shell.user_ns, '__file__'):
333 with preserve_keys(self.shell.user_ns, '__file__'):
333 self.shell.user_ns['__file__'] = fname
334 self.shell.user_ns['__file__'] = fname
334 if full_filename.endswith('.ipy'):
335 if full_filename.endswith('.ipy'):
335 self.shell.safe_execfile_ipy(full_filename)
336 self.shell.safe_execfile_ipy(full_filename)
336 else:
337 else:
337 # default to python, even without extension
338 # default to python, even without extension
338 self.shell.safe_execfile(full_filename,
339 self.shell.safe_execfile(full_filename,
339 self.shell.user_ns)
340 self.shell.user_ns)
340 finally:
341 finally:
341 sys.argv = save_argv
342 sys.argv = save_argv
342
343
343 def _run_startup_files(self):
344 def _run_startup_files(self):
344 """Run files from profile startup directory"""
345 """Run files from profile startup directory"""
345 startup_dir = self.profile_dir.startup_dir
346 startup_dir = self.profile_dir.startup_dir
346 startup_files = []
347 startup_files = []
347 if os.environ.get('PYTHONSTARTUP', False):
348 if os.environ.get('PYTHONSTARTUP', False):
348 startup_files.append(os.environ['PYTHONSTARTUP'])
349 startup_files.append(os.environ['PYTHONSTARTUP'])
349 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
350 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
350 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
351 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
351 if not startup_files:
352 if not startup_files:
352 return
353 return
353
354
354 self.log.debug("Running startup files from %s...", startup_dir)
355 self.log.debug("Running startup files from %s...", startup_dir)
355 try:
356 try:
356 for fname in sorted(startup_files):
357 for fname in sorted(startup_files):
357 self._exec_file(fname)
358 self._exec_file(fname)
358 except:
359 except:
359 self.log.warn("Unknown error in handling startup files:")
360 self.log.warn("Unknown error in handling startup files:")
360 self.shell.showtraceback()
361 self.shell.showtraceback()
361
362
362 def _run_exec_files(self):
363 def _run_exec_files(self):
363 """Run files from IPythonApp.exec_files"""
364 """Run files from IPythonApp.exec_files"""
364 if not self.exec_files:
365 if not self.exec_files:
365 return
366 return
366
367
367 self.log.debug("Running files in IPythonApp.exec_files...")
368 self.log.debug("Running files in IPythonApp.exec_files...")
368 try:
369 try:
369 for fname in self.exec_files:
370 for fname in self.exec_files:
370 self._exec_file(fname)
371 self._exec_file(fname)
371 except:
372 except:
372 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
373 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
373 self.shell.showtraceback()
374 self.shell.showtraceback()
374
375
375 def _run_cmd_line_code(self):
376 def _run_cmd_line_code(self):
376 """Run code or file specified at the command-line"""
377 """Run code or file specified at the command-line"""
377 if self.code_to_run:
378 if self.code_to_run:
378 line = self.code_to_run
379 line = self.code_to_run
379 try:
380 try:
380 self.log.info("Running code given at command line (c=): %s" %
381 self.log.info("Running code given at command line (c=): %s" %
381 line)
382 line)
382 self.shell.run_cell(line, store_history=False)
383 self.shell.run_cell(line, store_history=False)
383 except:
384 except:
384 self.log.warn("Error in executing line in user namespace: %s" %
385 self.log.warn("Error in executing line in user namespace: %s" %
385 line)
386 line)
386 self.shell.showtraceback()
387 self.shell.showtraceback()
387
388
388 # Like Python itself, ignore the second if the first of these is present
389 # Like Python itself, ignore the second if the first of these is present
389 elif self.file_to_run:
390 elif self.file_to_run:
390 fname = self.file_to_run
391 fname = self.file_to_run
391 try:
392 try:
392 self._exec_file(fname)
393 self._exec_file(fname)
393 except:
394 except:
394 self.log.warn("Error in executing file in user namespace: %s" %
395 self.log.warn("Error in executing file in user namespace: %s" %
395 fname)
396 fname)
396 self.shell.showtraceback()
397 self.shell.showtraceback()
397
398
398 def _run_module(self):
399 def _run_module(self):
399 """Run module specified at the command-line."""
400 """Run module specified at the command-line."""
400 if self.module_to_run:
401 if self.module_to_run:
401 # Make sure that the module gets a proper sys.argv as if it were
402 # Make sure that the module gets a proper sys.argv as if it were
402 # run using `python -m`.
403 # run using `python -m`.
403 save_argv = sys.argv
404 save_argv = sys.argv
404 sys.argv = [sys.executable] + self.extra_args
405 sys.argv = [sys.executable] + self.extra_args
405 try:
406 try:
406 self.shell.safe_run_module(self.module_to_run,
407 self.shell.safe_run_module(self.module_to_run,
407 self.shell.user_ns)
408 self.shell.user_ns)
408 finally:
409 finally:
409 sys.argv = save_argv
410 sys.argv = save_argv
@@ -1,2 +1,3 b''
1 from __future__ import print_function
1 import sys
2 import sys
2 print sys.argv[1:]
3 print(sys.argv[1:])
@@ -1,47 +1,48 b''
1 """Minimal script to reproduce our nasty reference counting bug.
1 """Minimal script to reproduce our nasty reference counting bug.
2
2
3 The problem is related to https://github.com/ipython/ipython/issues/141
3 The problem is related to https://github.com/ipython/ipython/issues/141
4
4
5 The original fix for that appeared to work, but John D. Hunter found a
5 The original fix for that appeared to work, but John D. Hunter found a
6 matplotlib example which, when run twice in a row, would break. The problem
6 matplotlib example which, when run twice in a row, would break. The problem
7 were references held by open figures to internals of Tkinter.
7 were references held by open figures to internals of Tkinter.
8
8
9 This code reproduces the problem that John saw, without matplotlib.
9 This code reproduces the problem that John saw, without matplotlib.
10
10
11 This script is meant to be called by other parts of the test suite that call it
11 This script is meant to be called by other parts of the test suite that call it
12 via %run as if it were executed interactively by the user. As of 2011-05-29,
12 via %run as if it were executed interactively by the user. As of 2011-05-29,
13 test_run.py calls it.
13 test_run.py calls it.
14 """
14 """
15 from __future__ import print_function
15
16
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17 # Module imports
18 # Module imports
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 import sys
20 import sys
20
21
21 from IPython import get_ipython
22 from IPython import get_ipython
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Globals
25 # Globals
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27 # This needs to be here because nose and other test runners will import
28 # This needs to be here because nose and other test runners will import
28 # this module. Importing this module has potential side effects that we
29 # this module. Importing this module has potential side effects that we
29 # want to prevent.
30 # want to prevent.
30 if __name__ == '__main__':
31 if __name__ == '__main__':
31
32
32 ip = get_ipython()
33 ip = get_ipython()
33
34
34 if not '_refbug_cache' in ip.user_ns:
35 if not '_refbug_cache' in ip.user_ns:
35 ip.user_ns['_refbug_cache'] = []
36 ip.user_ns['_refbug_cache'] = []
36
37
37
38
38 aglobal = 'Hello'
39 aglobal = 'Hello'
39 def f():
40 def f():
40 return aglobal
41 return aglobal
41
42
42 cache = ip.user_ns['_refbug_cache']
43 cache = ip.user_ns['_refbug_cache']
43 cache.append(f)
44 cache.append(f)
44
45
45 def call_f():
46 def call_f():
46 for func in cache:
47 for func in cache:
47 print 'lowercased:',func().lower()
48 print('lowercased:',func().lower())
@@ -1,153 +1,154 b''
1 """Tests for debugging machinery.
1 """Tests for debugging machinery.
2 """
2 """
3 from __future__ import print_function
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012, The IPython Development Team.
5 # Copyright (c) 2012, The IPython Development Team.
5 #
6 #
6 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
7 #
8 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Imports
13 # Imports
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 import sys
16 import sys
16
17
17 # third-party
18 # third-party
18 import nose.tools as nt
19 import nose.tools as nt
19
20
20 # Our own
21 # Our own
21 from IPython.core import debugger
22 from IPython.core import debugger
22
23
23 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
24 # Helper classes, from CPython's Pdb test suite
25 # Helper classes, from CPython's Pdb test suite
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26
27
27 class _FakeInput(object):
28 class _FakeInput(object):
28 """
29 """
29 A fake input stream for pdb's interactive debugger. Whenever a
30 A fake input stream for pdb's interactive debugger. Whenever a
30 line is read, print it (to simulate the user typing it), and then
31 line is read, print it (to simulate the user typing it), and then
31 return it. The set of lines to return is specified in the
32 return it. The set of lines to return is specified in the
32 constructor; they should not have trailing newlines.
33 constructor; they should not have trailing newlines.
33 """
34 """
34 def __init__(self, lines):
35 def __init__(self, lines):
35 self.lines = iter(lines)
36 self.lines = iter(lines)
36
37
37 def readline(self):
38 def readline(self):
38 line = next(self.lines)
39 line = next(self.lines)
39 print line
40 print(line)
40 return line+'\n'
41 return line+'\n'
41
42
42 class PdbTestInput(object):
43 class PdbTestInput(object):
43 """Context manager that makes testing Pdb in doctests easier."""
44 """Context manager that makes testing Pdb in doctests easier."""
44
45
45 def __init__(self, input):
46 def __init__(self, input):
46 self.input = input
47 self.input = input
47
48
48 def __enter__(self):
49 def __enter__(self):
49 self.real_stdin = sys.stdin
50 self.real_stdin = sys.stdin
50 sys.stdin = _FakeInput(self.input)
51 sys.stdin = _FakeInput(self.input)
51
52
52 def __exit__(self, *exc):
53 def __exit__(self, *exc):
53 sys.stdin = self.real_stdin
54 sys.stdin = self.real_stdin
54
55
55 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
56 # Tests
57 # Tests
57 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
58
59
59 def test_longer_repr():
60 def test_longer_repr():
60 from repr import repr as trepr
61 from repr import repr as trepr
61
62
62 a = '1234567890'* 7
63 a = '1234567890'* 7
63 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
64 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
64 a_trunc = "'123456789012...8901234567890'"
65 a_trunc = "'123456789012...8901234567890'"
65 nt.assert_equal(trepr(a), a_trunc)
66 nt.assert_equal(trepr(a), a_trunc)
66 # The creation of our tracer modifies the repr module's repr function
67 # The creation of our tracer modifies the repr module's repr function
67 # in-place, since that global is used directly by the stdlib's pdb module.
68 # in-place, since that global is used directly by the stdlib's pdb module.
68 t = debugger.Tracer()
69 t = debugger.Tracer()
69 nt.assert_equal(trepr(a), ar)
70 nt.assert_equal(trepr(a), ar)
70
71
71 def test_ipdb_magics():
72 def test_ipdb_magics():
72 '''Test calling some IPython magics from ipdb.
73 '''Test calling some IPython magics from ipdb.
73
74
74 First, set up some test functions and classes which we can inspect.
75 First, set up some test functions and classes which we can inspect.
75
76
76 >>> class ExampleClass(object):
77 >>> class ExampleClass(object):
77 ... """Docstring for ExampleClass."""
78 ... """Docstring for ExampleClass."""
78 ... def __init__(self):
79 ... def __init__(self):
79 ... """Docstring for ExampleClass.__init__"""
80 ... """Docstring for ExampleClass.__init__"""
80 ... pass
81 ... pass
81 ... def __str__(self):
82 ... def __str__(self):
82 ... return "ExampleClass()"
83 ... return "ExampleClass()"
83
84
84 >>> def example_function(x, y, z="hello"):
85 >>> def example_function(x, y, z="hello"):
85 ... """Docstring for example_function."""
86 ... """Docstring for example_function."""
86 ... pass
87 ... pass
87
88
88 >>> old_trace = sys.gettrace()
89 >>> old_trace = sys.gettrace()
89
90
90 Create a function which triggers ipdb.
91 Create a function which triggers ipdb.
91
92
92 >>> def trigger_ipdb():
93 >>> def trigger_ipdb():
93 ... a = ExampleClass()
94 ... a = ExampleClass()
94 ... debugger.Pdb().set_trace()
95 ... debugger.Pdb().set_trace()
95
96
96 >>> with PdbTestInput([
97 >>> with PdbTestInput([
97 ... 'pdef example_function',
98 ... 'pdef example_function',
98 ... 'pdoc ExampleClass',
99 ... 'pdoc ExampleClass',
99 ... 'pinfo a',
100 ... 'pinfo a',
100 ... 'continue',
101 ... 'continue',
101 ... ]):
102 ... ]):
102 ... trigger_ipdb()
103 ... trigger_ipdb()
103 --Return--
104 --Return--
104 None
105 None
105 > <doctest ...>(3)trigger_ipdb()
106 > <doctest ...>(3)trigger_ipdb()
106 1 def trigger_ipdb():
107 1 def trigger_ipdb():
107 2 a = ExampleClass()
108 2 a = ExampleClass()
108 ----> 3 debugger.Pdb().set_trace()
109 ----> 3 debugger.Pdb().set_trace()
109 <BLANKLINE>
110 <BLANKLINE>
110 ipdb> pdef example_function
111 ipdb> pdef example_function
111 example_function(x, y, z='hello')
112 example_function(x, y, z='hello')
112 ipdb> pdoc ExampleClass
113 ipdb> pdoc ExampleClass
113 Class Docstring:
114 Class Docstring:
114 Docstring for ExampleClass.
115 Docstring for ExampleClass.
115 Constructor Docstring:
116 Constructor Docstring:
116 Docstring for ExampleClass.__init__
117 Docstring for ExampleClass.__init__
117 ipdb> pinfo a
118 ipdb> pinfo a
118 Type: ExampleClass
119 Type: ExampleClass
119 String Form:ExampleClass()
120 String Form:ExampleClass()
120 Namespace: Local...
121 Namespace: Local...
121 Docstring: Docstring for ExampleClass.
122 Docstring: Docstring for ExampleClass.
122 Constructor Docstring:Docstring for ExampleClass.__init__
123 Constructor Docstring:Docstring for ExampleClass.__init__
123 ipdb> continue
124 ipdb> continue
124
125
125 Restore previous trace function, e.g. for coverage.py
126 Restore previous trace function, e.g. for coverage.py
126
127
127 >>> sys.settrace(old_trace)
128 >>> sys.settrace(old_trace)
128 '''
129 '''
129
130
130 def test_ipdb_magics2():
131 def test_ipdb_magics2():
131 '''Test ipdb with a very short function.
132 '''Test ipdb with a very short function.
132
133
133 >>> old_trace = sys.gettrace()
134 >>> old_trace = sys.gettrace()
134
135
135 >>> def bar():
136 >>> def bar():
136 ... pass
137 ... pass
137
138
138 Run ipdb.
139 Run ipdb.
139
140
140 >>> with PdbTestInput([
141 >>> with PdbTestInput([
141 ... 'continue',
142 ... 'continue',
142 ... ]):
143 ... ]):
143 ... debugger.Pdb().runcall(bar)
144 ... debugger.Pdb().runcall(bar)
144 > <doctest ...>(2)bar()
145 > <doctest ...>(2)bar()
145 1 def bar():
146 1 def bar():
146 ----> 2 pass
147 ----> 2 pass
147 <BLANKLINE>
148 <BLANKLINE>
148 ipdb> continue
149 ipdb> continue
149
150
150 Restore previous trace function, e.g. for coverage.py
151 Restore previous trace function, e.g. for coverage.py
151
152
152 >>> sys.settrace(old_trace)
153 >>> sys.settrace(old_trace)
153 '''
154 '''
@@ -1,582 +1,583 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the inputsplitter module.
2 """Tests for the inputsplitter module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Fernando Perez
6 * Fernando Perez
7 * Robert Kern
7 * Robert Kern
8 """
8 """
9 from __future__ import print_function
9 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
11 # Copyright (C) 2010-2011 The IPython Development Team
11 #
12 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
15
16
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17 # Imports
18 # Imports
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 # stdlib
20 # stdlib
20 import unittest
21 import unittest
21 import sys
22 import sys
22
23
23 # Third party
24 # Third party
24 import nose.tools as nt
25 import nose.tools as nt
25
26
26 # Our own
27 # Our own
27 from IPython.core import inputsplitter as isp
28 from IPython.core import inputsplitter as isp
28 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
29 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
29 from IPython.testing import tools as tt
30 from IPython.testing import tools as tt
30 from IPython.utils import py3compat
31 from IPython.utils import py3compat
31
32
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33 # Semi-complete examples (also used as tests)
34 # Semi-complete examples (also used as tests)
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35
36
36 # Note: at the bottom, there's a slightly more complete version of this that
37 # Note: at the bottom, there's a slightly more complete version of this that
37 # can be useful during development of code here.
38 # can be useful during development of code here.
38
39
39 def mini_interactive_loop(input_func):
40 def mini_interactive_loop(input_func):
40 """Minimal example of the logic of an interactive interpreter loop.
41 """Minimal example of the logic of an interactive interpreter loop.
41
42
42 This serves as an example, and it is used by the test system with a fake
43 This serves as an example, and it is used by the test system with a fake
43 raw_input that simulates interactive input."""
44 raw_input that simulates interactive input."""
44
45
45 from IPython.core.inputsplitter import InputSplitter
46 from IPython.core.inputsplitter import InputSplitter
46
47
47 isp = InputSplitter()
48 isp = InputSplitter()
48 # In practice, this input loop would be wrapped in an outside loop to read
49 # In practice, this input loop would be wrapped in an outside loop to read
49 # input indefinitely, until some exit/quit command was issued. Here we
50 # input indefinitely, until some exit/quit command was issued. Here we
50 # only illustrate the basic inner loop.
51 # only illustrate the basic inner loop.
51 while isp.push_accepts_more():
52 while isp.push_accepts_more():
52 indent = ' '*isp.indent_spaces
53 indent = ' '*isp.indent_spaces
53 prompt = '>>> ' + indent
54 prompt = '>>> ' + indent
54 line = indent + input_func(prompt)
55 line = indent + input_func(prompt)
55 isp.push(line)
56 isp.push(line)
56
57
57 # Here we just return input so we can use it in a test suite, but a real
58 # Here we just return input so we can use it in a test suite, but a real
58 # interpreter would instead send it for execution somewhere.
59 # interpreter would instead send it for execution somewhere.
59 src = isp.source_reset()
60 src = isp.source_reset()
60 #print 'Input source was:\n', src # dbg
61 #print 'Input source was:\n', src # dbg
61 return src
62 return src
62
63
63 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
64 # Test utilities, just for local use
65 # Test utilities, just for local use
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66
67
67 def assemble(block):
68 def assemble(block):
68 """Assemble a block into multi-line sub-blocks."""
69 """Assemble a block into multi-line sub-blocks."""
69 return ['\n'.join(sub_block)+'\n' for sub_block in block]
70 return ['\n'.join(sub_block)+'\n' for sub_block in block]
70
71
71
72
72 def pseudo_input(lines):
73 def pseudo_input(lines):
73 """Return a function that acts like raw_input but feeds the input list."""
74 """Return a function that acts like raw_input but feeds the input list."""
74 ilines = iter(lines)
75 ilines = iter(lines)
75 def raw_in(prompt):
76 def raw_in(prompt):
76 try:
77 try:
77 return next(ilines)
78 return next(ilines)
78 except StopIteration:
79 except StopIteration:
79 return ''
80 return ''
80 return raw_in
81 return raw_in
81
82
82 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
83 # Tests
84 # Tests
84 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
85 def test_spaces():
86 def test_spaces():
86 tests = [('', 0),
87 tests = [('', 0),
87 (' ', 1),
88 (' ', 1),
88 ('\n', 0),
89 ('\n', 0),
89 (' \n', 1),
90 (' \n', 1),
90 ('x', 0),
91 ('x', 0),
91 (' x', 1),
92 (' x', 1),
92 (' x',2),
93 (' x',2),
93 (' x',4),
94 (' x',4),
94 # Note: tabs are counted as a single whitespace!
95 # Note: tabs are counted as a single whitespace!
95 ('\tx', 1),
96 ('\tx', 1),
96 ('\t x', 2),
97 ('\t x', 2),
97 ]
98 ]
98 tt.check_pairs(isp.num_ini_spaces, tests)
99 tt.check_pairs(isp.num_ini_spaces, tests)
99
100
100
101
101 def test_remove_comments():
102 def test_remove_comments():
102 tests = [('text', 'text'),
103 tests = [('text', 'text'),
103 ('text # comment', 'text '),
104 ('text # comment', 'text '),
104 ('text # comment\n', 'text \n'),
105 ('text # comment\n', 'text \n'),
105 ('text # comment \n', 'text \n'),
106 ('text # comment \n', 'text \n'),
106 ('line # c \nline\n','line \nline\n'),
107 ('line # c \nline\n','line \nline\n'),
107 ('line # c \nline#c2 \nline\nline #c\n\n',
108 ('line # c \nline#c2 \nline\nline #c\n\n',
108 'line \nline\nline\nline \n\n'),
109 'line \nline\nline\nline \n\n'),
109 ]
110 ]
110 tt.check_pairs(isp.remove_comments, tests)
111 tt.check_pairs(isp.remove_comments, tests)
111
112
112
113
113 def test_get_input_encoding():
114 def test_get_input_encoding():
114 encoding = isp.get_input_encoding()
115 encoding = isp.get_input_encoding()
115 nt.assert_true(isinstance(encoding, basestring))
116 nt.assert_true(isinstance(encoding, basestring))
116 # simple-minded check that at least encoding a simple string works with the
117 # simple-minded check that at least encoding a simple string works with the
117 # encoding we got.
118 # encoding we got.
118 nt.assert_equal(u'test'.encode(encoding), b'test')
119 nt.assert_equal(u'test'.encode(encoding), b'test')
119
120
120
121
121 class NoInputEncodingTestCase(unittest.TestCase):
122 class NoInputEncodingTestCase(unittest.TestCase):
122 def setUp(self):
123 def setUp(self):
123 self.old_stdin = sys.stdin
124 self.old_stdin = sys.stdin
124 class X: pass
125 class X: pass
125 fake_stdin = X()
126 fake_stdin = X()
126 sys.stdin = fake_stdin
127 sys.stdin = fake_stdin
127
128
128 def test(self):
129 def test(self):
129 # Verify that if sys.stdin has no 'encoding' attribute we do the right
130 # Verify that if sys.stdin has no 'encoding' attribute we do the right
130 # thing
131 # thing
131 enc = isp.get_input_encoding()
132 enc = isp.get_input_encoding()
132 self.assertEqual(enc, 'ascii')
133 self.assertEqual(enc, 'ascii')
133
134
134 def tearDown(self):
135 def tearDown(self):
135 sys.stdin = self.old_stdin
136 sys.stdin = self.old_stdin
136
137
137
138
138 class InputSplitterTestCase(unittest.TestCase):
139 class InputSplitterTestCase(unittest.TestCase):
139 def setUp(self):
140 def setUp(self):
140 self.isp = isp.InputSplitter()
141 self.isp = isp.InputSplitter()
141
142
142 def test_reset(self):
143 def test_reset(self):
143 isp = self.isp
144 isp = self.isp
144 isp.push('x=1')
145 isp.push('x=1')
145 isp.reset()
146 isp.reset()
146 self.assertEqual(isp._buffer, [])
147 self.assertEqual(isp._buffer, [])
147 self.assertEqual(isp.indent_spaces, 0)
148 self.assertEqual(isp.indent_spaces, 0)
148 self.assertEqual(isp.source, '')
149 self.assertEqual(isp.source, '')
149 self.assertEqual(isp.code, None)
150 self.assertEqual(isp.code, None)
150 self.assertEqual(isp._is_complete, False)
151 self.assertEqual(isp._is_complete, False)
151
152
152 def test_source(self):
153 def test_source(self):
153 self.isp._store('1')
154 self.isp._store('1')
154 self.isp._store('2')
155 self.isp._store('2')
155 self.assertEqual(self.isp.source, '1\n2\n')
156 self.assertEqual(self.isp.source, '1\n2\n')
156 self.assertTrue(len(self.isp._buffer)>0)
157 self.assertTrue(len(self.isp._buffer)>0)
157 self.assertEqual(self.isp.source_reset(), '1\n2\n')
158 self.assertEqual(self.isp.source_reset(), '1\n2\n')
158 self.assertEqual(self.isp._buffer, [])
159 self.assertEqual(self.isp._buffer, [])
159 self.assertEqual(self.isp.source, '')
160 self.assertEqual(self.isp.source, '')
160
161
161 def test_indent(self):
162 def test_indent(self):
162 isp = self.isp # shorthand
163 isp = self.isp # shorthand
163 isp.push('x=1')
164 isp.push('x=1')
164 self.assertEqual(isp.indent_spaces, 0)
165 self.assertEqual(isp.indent_spaces, 0)
165 isp.push('if 1:\n x=1')
166 isp.push('if 1:\n x=1')
166 self.assertEqual(isp.indent_spaces, 4)
167 self.assertEqual(isp.indent_spaces, 4)
167 isp.push('y=2\n')
168 isp.push('y=2\n')
168 self.assertEqual(isp.indent_spaces, 0)
169 self.assertEqual(isp.indent_spaces, 0)
169
170
170 def test_indent2(self):
171 def test_indent2(self):
171 isp = self.isp
172 isp = self.isp
172 isp.push('if 1:')
173 isp.push('if 1:')
173 self.assertEqual(isp.indent_spaces, 4)
174 self.assertEqual(isp.indent_spaces, 4)
174 isp.push(' x=1')
175 isp.push(' x=1')
175 self.assertEqual(isp.indent_spaces, 4)
176 self.assertEqual(isp.indent_spaces, 4)
176 # Blank lines shouldn't change the indent level
177 # Blank lines shouldn't change the indent level
177 isp.push(' '*2)
178 isp.push(' '*2)
178 self.assertEqual(isp.indent_spaces, 4)
179 self.assertEqual(isp.indent_spaces, 4)
179
180
180 def test_indent3(self):
181 def test_indent3(self):
181 isp = self.isp
182 isp = self.isp
182 # When a multiline statement contains parens or multiline strings, we
183 # When a multiline statement contains parens or multiline strings, we
183 # shouldn't get confused.
184 # shouldn't get confused.
184 isp.push("if 1:")
185 isp.push("if 1:")
185 isp.push(" x = (1+\n 2)")
186 isp.push(" x = (1+\n 2)")
186 self.assertEqual(isp.indent_spaces, 4)
187 self.assertEqual(isp.indent_spaces, 4)
187
188
188 def test_indent4(self):
189 def test_indent4(self):
189 isp = self.isp
190 isp = self.isp
190 # whitespace after ':' should not screw up indent level
191 # whitespace after ':' should not screw up indent level
191 isp.push('if 1: \n x=1')
192 isp.push('if 1: \n x=1')
192 self.assertEqual(isp.indent_spaces, 4)
193 self.assertEqual(isp.indent_spaces, 4)
193 isp.push('y=2\n')
194 isp.push('y=2\n')
194 self.assertEqual(isp.indent_spaces, 0)
195 self.assertEqual(isp.indent_spaces, 0)
195 isp.push('if 1:\t\n x=1')
196 isp.push('if 1:\t\n x=1')
196 self.assertEqual(isp.indent_spaces, 4)
197 self.assertEqual(isp.indent_spaces, 4)
197 isp.push('y=2\n')
198 isp.push('y=2\n')
198 self.assertEqual(isp.indent_spaces, 0)
199 self.assertEqual(isp.indent_spaces, 0)
199
200
200 def test_dedent_pass(self):
201 def test_dedent_pass(self):
201 isp = self.isp # shorthand
202 isp = self.isp # shorthand
202 # should NOT cause dedent
203 # should NOT cause dedent
203 isp.push('if 1:\n passes = 5')
204 isp.push('if 1:\n passes = 5')
204 self.assertEqual(isp.indent_spaces, 4)
205 self.assertEqual(isp.indent_spaces, 4)
205 isp.push('if 1:\n pass')
206 isp.push('if 1:\n pass')
206 self.assertEqual(isp.indent_spaces, 0)
207 self.assertEqual(isp.indent_spaces, 0)
207 isp.push('if 1:\n pass ')
208 isp.push('if 1:\n pass ')
208 self.assertEqual(isp.indent_spaces, 0)
209 self.assertEqual(isp.indent_spaces, 0)
209
210
210 def test_dedent_break(self):
211 def test_dedent_break(self):
211 isp = self.isp # shorthand
212 isp = self.isp # shorthand
212 # should NOT cause dedent
213 # should NOT cause dedent
213 isp.push('while 1:\n breaks = 5')
214 isp.push('while 1:\n breaks = 5')
214 self.assertEqual(isp.indent_spaces, 4)
215 self.assertEqual(isp.indent_spaces, 4)
215 isp.push('while 1:\n break')
216 isp.push('while 1:\n break')
216 self.assertEqual(isp.indent_spaces, 0)
217 self.assertEqual(isp.indent_spaces, 0)
217 isp.push('while 1:\n break ')
218 isp.push('while 1:\n break ')
218 self.assertEqual(isp.indent_spaces, 0)
219 self.assertEqual(isp.indent_spaces, 0)
219
220
220 def test_dedent_continue(self):
221 def test_dedent_continue(self):
221 isp = self.isp # shorthand
222 isp = self.isp # shorthand
222 # should NOT cause dedent
223 # should NOT cause dedent
223 isp.push('while 1:\n continues = 5')
224 isp.push('while 1:\n continues = 5')
224 self.assertEqual(isp.indent_spaces, 4)
225 self.assertEqual(isp.indent_spaces, 4)
225 isp.push('while 1:\n continue')
226 isp.push('while 1:\n continue')
226 self.assertEqual(isp.indent_spaces, 0)
227 self.assertEqual(isp.indent_spaces, 0)
227 isp.push('while 1:\n continue ')
228 isp.push('while 1:\n continue ')
228 self.assertEqual(isp.indent_spaces, 0)
229 self.assertEqual(isp.indent_spaces, 0)
229
230
230 def test_dedent_raise(self):
231 def test_dedent_raise(self):
231 isp = self.isp # shorthand
232 isp = self.isp # shorthand
232 # should NOT cause dedent
233 # should NOT cause dedent
233 isp.push('if 1:\n raised = 4')
234 isp.push('if 1:\n raised = 4')
234 self.assertEqual(isp.indent_spaces, 4)
235 self.assertEqual(isp.indent_spaces, 4)
235 isp.push('if 1:\n raise TypeError()')
236 isp.push('if 1:\n raise TypeError()')
236 self.assertEqual(isp.indent_spaces, 0)
237 self.assertEqual(isp.indent_spaces, 0)
237 isp.push('if 1:\n raise')
238 isp.push('if 1:\n raise')
238 self.assertEqual(isp.indent_spaces, 0)
239 self.assertEqual(isp.indent_spaces, 0)
239 isp.push('if 1:\n raise ')
240 isp.push('if 1:\n raise ')
240 self.assertEqual(isp.indent_spaces, 0)
241 self.assertEqual(isp.indent_spaces, 0)
241
242
242 def test_dedent_return(self):
243 def test_dedent_return(self):
243 isp = self.isp # shorthand
244 isp = self.isp # shorthand
244 # should NOT cause dedent
245 # should NOT cause dedent
245 isp.push('if 1:\n returning = 4')
246 isp.push('if 1:\n returning = 4')
246 self.assertEqual(isp.indent_spaces, 4)
247 self.assertEqual(isp.indent_spaces, 4)
247 isp.push('if 1:\n return 5 + 493')
248 isp.push('if 1:\n return 5 + 493')
248 self.assertEqual(isp.indent_spaces, 0)
249 self.assertEqual(isp.indent_spaces, 0)
249 isp.push('if 1:\n return')
250 isp.push('if 1:\n return')
250 self.assertEqual(isp.indent_spaces, 0)
251 self.assertEqual(isp.indent_spaces, 0)
251 isp.push('if 1:\n return ')
252 isp.push('if 1:\n return ')
252 self.assertEqual(isp.indent_spaces, 0)
253 self.assertEqual(isp.indent_spaces, 0)
253 isp.push('if 1:\n return(0)')
254 isp.push('if 1:\n return(0)')
254 self.assertEqual(isp.indent_spaces, 0)
255 self.assertEqual(isp.indent_spaces, 0)
255
256
256 def test_push(self):
257 def test_push(self):
257 isp = self.isp
258 isp = self.isp
258 self.assertTrue(isp.push('x=1'))
259 self.assertTrue(isp.push('x=1'))
259
260
260 def test_push2(self):
261 def test_push2(self):
261 isp = self.isp
262 isp = self.isp
262 self.assertFalse(isp.push('if 1:'))
263 self.assertFalse(isp.push('if 1:'))
263 for line in [' x=1', '# a comment', ' y=2']:
264 for line in [' x=1', '# a comment', ' y=2']:
264 print(line)
265 print(line)
265 self.assertTrue(isp.push(line))
266 self.assertTrue(isp.push(line))
266
267
267 def test_push3(self):
268 def test_push3(self):
268 isp = self.isp
269 isp = self.isp
269 isp.push('if True:')
270 isp.push('if True:')
270 isp.push(' a = 1')
271 isp.push(' a = 1')
271 self.assertFalse(isp.push('b = [1,'))
272 self.assertFalse(isp.push('b = [1,'))
272
273
273 def test_push_accepts_more(self):
274 def test_push_accepts_more(self):
274 isp = self.isp
275 isp = self.isp
275 isp.push('x=1')
276 isp.push('x=1')
276 self.assertFalse(isp.push_accepts_more())
277 self.assertFalse(isp.push_accepts_more())
277
278
278 def test_push_accepts_more2(self):
279 def test_push_accepts_more2(self):
279 isp = self.isp
280 isp = self.isp
280 isp.push('if 1:')
281 isp.push('if 1:')
281 self.assertTrue(isp.push_accepts_more())
282 self.assertTrue(isp.push_accepts_more())
282 isp.push(' x=1')
283 isp.push(' x=1')
283 self.assertTrue(isp.push_accepts_more())
284 self.assertTrue(isp.push_accepts_more())
284 isp.push('')
285 isp.push('')
285 self.assertFalse(isp.push_accepts_more())
286 self.assertFalse(isp.push_accepts_more())
286
287
287 def test_push_accepts_more3(self):
288 def test_push_accepts_more3(self):
288 isp = self.isp
289 isp = self.isp
289 isp.push("x = (2+\n3)")
290 isp.push("x = (2+\n3)")
290 self.assertFalse(isp.push_accepts_more())
291 self.assertFalse(isp.push_accepts_more())
291
292
292 def test_push_accepts_more4(self):
293 def test_push_accepts_more4(self):
293 isp = self.isp
294 isp = self.isp
294 # When a multiline statement contains parens or multiline strings, we
295 # When a multiline statement contains parens or multiline strings, we
295 # shouldn't get confused.
296 # shouldn't get confused.
296 # FIXME: we should be able to better handle de-dents in statements like
297 # FIXME: we should be able to better handle de-dents in statements like
297 # multiline strings and multiline expressions (continued with \ or
298 # multiline strings and multiline expressions (continued with \ or
298 # parens). Right now we aren't handling the indentation tracking quite
299 # parens). Right now we aren't handling the indentation tracking quite
299 # correctly with this, though in practice it may not be too much of a
300 # correctly with this, though in practice it may not be too much of a
300 # problem. We'll need to see.
301 # problem. We'll need to see.
301 isp.push("if 1:")
302 isp.push("if 1:")
302 isp.push(" x = (2+")
303 isp.push(" x = (2+")
303 isp.push(" 3)")
304 isp.push(" 3)")
304 self.assertTrue(isp.push_accepts_more())
305 self.assertTrue(isp.push_accepts_more())
305 isp.push(" y = 3")
306 isp.push(" y = 3")
306 self.assertTrue(isp.push_accepts_more())
307 self.assertTrue(isp.push_accepts_more())
307 isp.push('')
308 isp.push('')
308 self.assertFalse(isp.push_accepts_more())
309 self.assertFalse(isp.push_accepts_more())
309
310
310 def test_push_accepts_more5(self):
311 def test_push_accepts_more5(self):
311 isp = self.isp
312 isp = self.isp
312 isp.push('try:')
313 isp.push('try:')
313 isp.push(' a = 5')
314 isp.push(' a = 5')
314 isp.push('except:')
315 isp.push('except:')
315 isp.push(' raise')
316 isp.push(' raise')
316 # We want to be able to add an else: block at this point, so it should
317 # We want to be able to add an else: block at this point, so it should
317 # wait for a blank line.
318 # wait for a blank line.
318 self.assertTrue(isp.push_accepts_more())
319 self.assertTrue(isp.push_accepts_more())
319
320
320 def test_continuation(self):
321 def test_continuation(self):
321 isp = self.isp
322 isp = self.isp
322 isp.push("import os, \\")
323 isp.push("import os, \\")
323 self.assertTrue(isp.push_accepts_more())
324 self.assertTrue(isp.push_accepts_more())
324 isp.push("sys")
325 isp.push("sys")
325 self.assertFalse(isp.push_accepts_more())
326 self.assertFalse(isp.push_accepts_more())
326
327
327 def test_syntax_error(self):
328 def test_syntax_error(self):
328 isp = self.isp
329 isp = self.isp
329 # Syntax errors immediately produce a 'ready' block, so the invalid
330 # Syntax errors immediately produce a 'ready' block, so the invalid
330 # Python can be sent to the kernel for evaluation with possible ipython
331 # Python can be sent to the kernel for evaluation with possible ipython
331 # special-syntax conversion.
332 # special-syntax conversion.
332 isp.push('run foo')
333 isp.push('run foo')
333 self.assertFalse(isp.push_accepts_more())
334 self.assertFalse(isp.push_accepts_more())
334
335
335 def test_unicode(self):
336 def test_unicode(self):
336 self.isp.push(u"Pérez")
337 self.isp.push(u"Pérez")
337 self.isp.push(u'\xc3\xa9')
338 self.isp.push(u'\xc3\xa9')
338 self.isp.push(u"u'\xc3\xa9'")
339 self.isp.push(u"u'\xc3\xa9'")
339
340
340 def test_line_continuation(self):
341 def test_line_continuation(self):
341 """ Test issue #2108."""
342 """ Test issue #2108."""
342 isp = self.isp
343 isp = self.isp
343 # A blank line after a line continuation should not accept more
344 # A blank line after a line continuation should not accept more
344 isp.push("1 \\\n\n")
345 isp.push("1 \\\n\n")
345 self.assertFalse(isp.push_accepts_more())
346 self.assertFalse(isp.push_accepts_more())
346 # Whitespace after a \ is a SyntaxError. The only way to test that
347 # Whitespace after a \ is a SyntaxError. The only way to test that
347 # here is to test that push doesn't accept more (as with
348 # here is to test that push doesn't accept more (as with
348 # test_syntax_error() above).
349 # test_syntax_error() above).
349 isp.push(r"1 \ ")
350 isp.push(r"1 \ ")
350 self.assertFalse(isp.push_accepts_more())
351 self.assertFalse(isp.push_accepts_more())
351 # Even if the line is continuable (c.f. the regular Python
352 # Even if the line is continuable (c.f. the regular Python
352 # interpreter)
353 # interpreter)
353 isp.push(r"(1 \ ")
354 isp.push(r"(1 \ ")
354 self.assertFalse(isp.push_accepts_more())
355 self.assertFalse(isp.push_accepts_more())
355
356
356 class InteractiveLoopTestCase(unittest.TestCase):
357 class InteractiveLoopTestCase(unittest.TestCase):
357 """Tests for an interactive loop like a python shell.
358 """Tests for an interactive loop like a python shell.
358 """
359 """
359 def check_ns(self, lines, ns):
360 def check_ns(self, lines, ns):
360 """Validate that the given input lines produce the resulting namespace.
361 """Validate that the given input lines produce the resulting namespace.
361
362
362 Note: the input lines are given exactly as they would be typed in an
363 Note: the input lines are given exactly as they would be typed in an
363 auto-indenting environment, as mini_interactive_loop above already does
364 auto-indenting environment, as mini_interactive_loop above already does
364 auto-indenting and prepends spaces to the input.
365 auto-indenting and prepends spaces to the input.
365 """
366 """
366 src = mini_interactive_loop(pseudo_input(lines))
367 src = mini_interactive_loop(pseudo_input(lines))
367 test_ns = {}
368 test_ns = {}
368 exec src in test_ns
369 exec src in test_ns
369 # We can't check that the provided ns is identical to the test_ns,
370 # We can't check that the provided ns is identical to the test_ns,
370 # because Python fills test_ns with extra keys (copyright, etc). But
371 # because Python fills test_ns with extra keys (copyright, etc). But
371 # we can check that the given dict is *contained* in test_ns
372 # we can check that the given dict is *contained* in test_ns
372 for k,v in ns.iteritems():
373 for k,v in ns.iteritems():
373 self.assertEqual(test_ns[k], v)
374 self.assertEqual(test_ns[k], v)
374
375
375 def test_simple(self):
376 def test_simple(self):
376 self.check_ns(['x=1'], dict(x=1))
377 self.check_ns(['x=1'], dict(x=1))
377
378
378 def test_simple2(self):
379 def test_simple2(self):
379 self.check_ns(['if 1:', 'x=2'], dict(x=2))
380 self.check_ns(['if 1:', 'x=2'], dict(x=2))
380
381
381 def test_xy(self):
382 def test_xy(self):
382 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
383 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
383
384
384 def test_abc(self):
385 def test_abc(self):
385 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
386 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
386
387
387 def test_multi(self):
388 def test_multi(self):
388 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
389 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
389
390
390
391
391 class IPythonInputTestCase(InputSplitterTestCase):
392 class IPythonInputTestCase(InputSplitterTestCase):
392 """By just creating a new class whose .isp is a different instance, we
393 """By just creating a new class whose .isp is a different instance, we
393 re-run the same test battery on the new input splitter.
394 re-run the same test battery on the new input splitter.
394
395
395 In addition, this runs the tests over the syntax and syntax_ml dicts that
396 In addition, this runs the tests over the syntax and syntax_ml dicts that
396 were tested by individual functions, as part of the OO interface.
397 were tested by individual functions, as part of the OO interface.
397
398
398 It also makes some checks on the raw buffer storage.
399 It also makes some checks on the raw buffer storage.
399 """
400 """
400
401
401 def setUp(self):
402 def setUp(self):
402 self.isp = isp.IPythonInputSplitter()
403 self.isp = isp.IPythonInputSplitter()
403
404
404 def test_syntax(self):
405 def test_syntax(self):
405 """Call all single-line syntax tests from the main object"""
406 """Call all single-line syntax tests from the main object"""
406 isp = self.isp
407 isp = self.isp
407 for example in syntax.itervalues():
408 for example in syntax.itervalues():
408 for raw, out_t in example:
409 for raw, out_t in example:
409 if raw.startswith(' '):
410 if raw.startswith(' '):
410 continue
411 continue
411
412
412 isp.push(raw+'\n')
413 isp.push(raw+'\n')
413 out, out_raw = isp.source_raw_reset()
414 out, out_raw = isp.source_raw_reset()
414 self.assertEqual(out.rstrip(), out_t,
415 self.assertEqual(out.rstrip(), out_t,
415 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
416 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
416 self.assertEqual(out_raw.rstrip(), raw.rstrip())
417 self.assertEqual(out_raw.rstrip(), raw.rstrip())
417
418
418 def test_syntax_multiline(self):
419 def test_syntax_multiline(self):
419 isp = self.isp
420 isp = self.isp
420 for example in syntax_ml.itervalues():
421 for example in syntax_ml.itervalues():
421 for line_pairs in example:
422 for line_pairs in example:
422 out_t_parts = []
423 out_t_parts = []
423 raw_parts = []
424 raw_parts = []
424 for lraw, out_t_part in line_pairs:
425 for lraw, out_t_part in line_pairs:
425 if out_t_part is not None:
426 if out_t_part is not None:
426 out_t_parts.append(out_t_part)
427 out_t_parts.append(out_t_part)
427
428
428 if lraw is not None:
429 if lraw is not None:
429 isp.push(lraw)
430 isp.push(lraw)
430 raw_parts.append(lraw)
431 raw_parts.append(lraw)
431
432
432 out, out_raw = isp.source_raw_reset()
433 out, out_raw = isp.source_raw_reset()
433 out_t = '\n'.join(out_t_parts).rstrip()
434 out_t = '\n'.join(out_t_parts).rstrip()
434 raw = '\n'.join(raw_parts).rstrip()
435 raw = '\n'.join(raw_parts).rstrip()
435 self.assertEqual(out.rstrip(), out_t)
436 self.assertEqual(out.rstrip(), out_t)
436 self.assertEqual(out_raw.rstrip(), raw)
437 self.assertEqual(out_raw.rstrip(), raw)
437
438
438 def test_syntax_multiline_cell(self):
439 def test_syntax_multiline_cell(self):
439 isp = self.isp
440 isp = self.isp
440 for example in syntax_ml.itervalues():
441 for example in syntax_ml.itervalues():
441
442
442 out_t_parts = []
443 out_t_parts = []
443 for line_pairs in example:
444 for line_pairs in example:
444 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
445 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
445 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
446 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
446 out = isp.transform_cell(raw)
447 out = isp.transform_cell(raw)
447 # Match ignoring trailing whitespace
448 # Match ignoring trailing whitespace
448 self.assertEqual(out.rstrip(), out_t.rstrip())
449 self.assertEqual(out.rstrip(), out_t.rstrip())
449
450
450 def test_cellmagic_preempt(self):
451 def test_cellmagic_preempt(self):
451 isp = self.isp
452 isp = self.isp
452 for raw, name, line, cell in [
453 for raw, name, line, cell in [
453 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
454 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
454 ("%%cellm \nline\n>>>hi", u'cellm', u'', u'line\n>>>hi'),
455 ("%%cellm \nline\n>>>hi", u'cellm', u'', u'line\n>>>hi'),
455 (">>>%%cellm \nline\n>>>hi", u'cellm', u'', u'line\nhi'),
456 (">>>%%cellm \nline\n>>>hi", u'cellm', u'', u'line\nhi'),
456 ("%%cellm \n>>>hi", u'cellm', u'', u'hi'),
457 ("%%cellm \n>>>hi", u'cellm', u'', u'hi'),
457 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
458 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
458 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
459 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
459 ]:
460 ]:
460 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
461 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
461 name, line, cell
462 name, line, cell
462 )
463 )
463 out = isp.transform_cell(raw)
464 out = isp.transform_cell(raw)
464 self.assertEqual(out.rstrip(), expected.rstrip())
465 self.assertEqual(out.rstrip(), expected.rstrip())
465
466
466
467
467
468
468 #-----------------------------------------------------------------------------
469 #-----------------------------------------------------------------------------
469 # Main - use as a script, mostly for developer experiments
470 # Main - use as a script, mostly for developer experiments
470 #-----------------------------------------------------------------------------
471 #-----------------------------------------------------------------------------
471
472
472 if __name__ == '__main__':
473 if __name__ == '__main__':
473 # A simple demo for interactive experimentation. This code will not get
474 # A simple demo for interactive experimentation. This code will not get
474 # picked up by any test suite.
475 # picked up by any test suite.
475 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
476 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
476
477
477 # configure here the syntax to use, prompt and whether to autoindent
478 # configure here the syntax to use, prompt and whether to autoindent
478 #isp, start_prompt = InputSplitter(), '>>> '
479 #isp, start_prompt = InputSplitter(), '>>> '
479 isp, start_prompt = IPythonInputSplitter(), 'In> '
480 isp, start_prompt = IPythonInputSplitter(), 'In> '
480
481
481 autoindent = True
482 autoindent = True
482 #autoindent = False
483 #autoindent = False
483
484
484 try:
485 try:
485 while True:
486 while True:
486 prompt = start_prompt
487 prompt = start_prompt
487 while isp.push_accepts_more():
488 while isp.push_accepts_more():
488 indent = ' '*isp.indent_spaces
489 indent = ' '*isp.indent_spaces
489 if autoindent:
490 if autoindent:
490 line = indent + raw_input(prompt+indent)
491 line = indent + raw_input(prompt+indent)
491 else:
492 else:
492 line = raw_input(prompt)
493 line = raw_input(prompt)
493 isp.push(line)
494 isp.push(line)
494 prompt = '... '
495 prompt = '... '
495
496
496 # Here we just return input so we can use it in a test suite, but a
497 # Here we just return input so we can use it in a test suite, but a
497 # real interpreter would instead send it for execution somewhere.
498 # real interpreter would instead send it for execution somewhere.
498 #src = isp.source; raise EOFError # dbg
499 #src = isp.source; raise EOFError # dbg
499 src, raw = isp.source_raw_reset()
500 src, raw = isp.source_raw_reset()
500 print 'Input source was:\n', src
501 print('Input source was:\n', src)
501 print 'Raw source was:\n', raw
502 print('Raw source was:\n', raw)
502 except EOFError:
503 except EOFError:
503 print 'Bye'
504 print('Bye')
504
505
505 # Tests for cell magics support
506 # Tests for cell magics support
506
507
507 def test_last_blank():
508 def test_last_blank():
508 nt.assert_false(isp.last_blank(''))
509 nt.assert_false(isp.last_blank(''))
509 nt.assert_false(isp.last_blank('abc'))
510 nt.assert_false(isp.last_blank('abc'))
510 nt.assert_false(isp.last_blank('abc\n'))
511 nt.assert_false(isp.last_blank('abc\n'))
511 nt.assert_false(isp.last_blank('abc\na'))
512 nt.assert_false(isp.last_blank('abc\na'))
512
513
513 nt.assert_true(isp.last_blank('\n'))
514 nt.assert_true(isp.last_blank('\n'))
514 nt.assert_true(isp.last_blank('\n '))
515 nt.assert_true(isp.last_blank('\n '))
515 nt.assert_true(isp.last_blank('abc\n '))
516 nt.assert_true(isp.last_blank('abc\n '))
516 nt.assert_true(isp.last_blank('abc\n\n'))
517 nt.assert_true(isp.last_blank('abc\n\n'))
517 nt.assert_true(isp.last_blank('abc\nd\n\n'))
518 nt.assert_true(isp.last_blank('abc\nd\n\n'))
518 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
519 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
519 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
520 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
520
521
521
522
522 def test_last_two_blanks():
523 def test_last_two_blanks():
523 nt.assert_false(isp.last_two_blanks(''))
524 nt.assert_false(isp.last_two_blanks(''))
524 nt.assert_false(isp.last_two_blanks('abc'))
525 nt.assert_false(isp.last_two_blanks('abc'))
525 nt.assert_false(isp.last_two_blanks('abc\n'))
526 nt.assert_false(isp.last_two_blanks('abc\n'))
526 nt.assert_false(isp.last_two_blanks('abc\n\na'))
527 nt.assert_false(isp.last_two_blanks('abc\n\na'))
527 nt.assert_false(isp.last_two_blanks('abc\n \n'))
528 nt.assert_false(isp.last_two_blanks('abc\n \n'))
528 nt.assert_false(isp.last_two_blanks('abc\n\n'))
529 nt.assert_false(isp.last_two_blanks('abc\n\n'))
529
530
530 nt.assert_true(isp.last_two_blanks('\n\n'))
531 nt.assert_true(isp.last_two_blanks('\n\n'))
531 nt.assert_true(isp.last_two_blanks('\n\n '))
532 nt.assert_true(isp.last_two_blanks('\n\n '))
532 nt.assert_true(isp.last_two_blanks('\n \n'))
533 nt.assert_true(isp.last_two_blanks('\n \n'))
533 nt.assert_true(isp.last_two_blanks('abc\n\n '))
534 nt.assert_true(isp.last_two_blanks('abc\n\n '))
534 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
535 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
535 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
536 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
536 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
537 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
537 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
538 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
538 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
539 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
539 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
540 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
540
541
541
542
542 class CellMagicsCommon(object):
543 class CellMagicsCommon(object):
543
544
544 def test_whole_cell(self):
545 def test_whole_cell(self):
545 src = "%%cellm line\nbody\n"
546 src = "%%cellm line\nbody\n"
546 sp = self.sp
547 sp = self.sp
547 sp.push(src)
548 sp.push(src)
548 out = sp.source_reset()
549 out = sp.source_reset()
549 ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n"
550 ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n"
550 nt.assert_equal(out, py3compat.u_format(ref))
551 nt.assert_equal(out, py3compat.u_format(ref))
551
552
552 def test_cellmagic_help(self):
553 def test_cellmagic_help(self):
553 self.sp.push('%%cellm?')
554 self.sp.push('%%cellm?')
554 nt.assert_false(self.sp.push_accepts_more())
555 nt.assert_false(self.sp.push_accepts_more())
555
556
556 def tearDown(self):
557 def tearDown(self):
557 self.sp.reset()
558 self.sp.reset()
558
559
559
560
560 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
561 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
561 sp = isp.IPythonInputSplitter(line_input_checker=False)
562 sp = isp.IPythonInputSplitter(line_input_checker=False)
562
563
563 def test_incremental(self):
564 def test_incremental(self):
564 sp = self.sp
565 sp = self.sp
565 sp.push('%%cellm firstline\n')
566 sp.push('%%cellm firstline\n')
566 nt.assert_true(sp.push_accepts_more()) #1
567 nt.assert_true(sp.push_accepts_more()) #1
567 sp.push('line2\n')
568 sp.push('line2\n')
568 nt.assert_true(sp.push_accepts_more()) #2
569 nt.assert_true(sp.push_accepts_more()) #2
569 sp.push('\n')
570 sp.push('\n')
570 # This should accept a blank line and carry on until the cell is reset
571 # This should accept a blank line and carry on until the cell is reset
571 nt.assert_true(sp.push_accepts_more()) #3
572 nt.assert_true(sp.push_accepts_more()) #3
572
573
573 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
574 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
574 sp = isp.IPythonInputSplitter(line_input_checker=True)
575 sp = isp.IPythonInputSplitter(line_input_checker=True)
575
576
576 def test_incremental(self):
577 def test_incremental(self):
577 sp = self.sp
578 sp = self.sp
578 sp.push('%%cellm line2\n')
579 sp.push('%%cellm line2\n')
579 nt.assert_true(sp.push_accepts_more()) #1
580 nt.assert_true(sp.push_accepts_more()) #1
580 sp.push('\n')
581 sp.push('\n')
581 # In this case, a blank line should end the cell magic
582 # In this case, a blank line should end the cell magic
582 nt.assert_false(sp.push_accepts_more()) #2
583 nt.assert_false(sp.push_accepts_more()) #2
@@ -1,1266 +1,1267 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
12
13 import sys,ultratb
13 import sys,ultratb
14 sys.excepthook = ultratb.ColorTB()
14 sys.excepthook = ultratb.ColorTB()
15
15
16 * VerboseTB
16 * VerboseTB
17 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
18 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 of useful info when a traceback occurs. Ping originally had it spit out HTML
19 and intended it for CGI programmers, but why should they have all the fun? I
19 and intended it for CGI programmers, but why should they have all the fun? I
20 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 altered it to spit out colored text to the terminal. It's a bit overwhelming,
21 but kind of neat, and maybe useful for long-running programs that you believe
21 but kind of neat, and maybe useful for long-running programs that you believe
22 are bug-free. If a crash *does* occur in that type of program you want details.
22 are bug-free. If a crash *does* occur in that type of program you want details.
23 Give it a shot--you'll love it or you'll hate it.
23 Give it a shot--you'll love it or you'll hate it.
24
24
25 .. note::
25 .. note::
26
26
27 The Verbose mode prints the variables currently visible where the exception
27 The Verbose mode prints the variables currently visible where the exception
28 happened (shortening their strings if too long). This can potentially be
28 happened (shortening their strings if too long). This can potentially be
29 very slow, if you happen to have a huge data structure whose string
29 very slow, if you happen to have a huge data structure whose string
30 representation is complex to compute. Your computer may appear to freeze for
30 representation is complex to compute. Your computer may appear to freeze for
31 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
32 with Ctrl-C (maybe hitting it more than once).
32 with Ctrl-C (maybe hitting it more than once).
33
33
34 If you encounter this kind of situation often, you may want to use the
34 If you encounter this kind of situation often, you may want to use the
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 Verbose_novars mode instead of the regular Verbose, which avoids formatting
36 variables (but otherwise includes the information and context given by
36 variables (but otherwise includes the information and context given by
37 Verbose).
37 Verbose).
38
38
39
39
40 Installation instructions for ColorTB::
40 Installation instructions for ColorTB::
41
41
42 import sys,ultratb
42 import sys,ultratb
43 sys.excepthook = ultratb.VerboseTB()
43 sys.excepthook = ultratb.VerboseTB()
44
44
45 Note: Much of the code in this module was lifted verbatim from the standard
45 Note: Much of the code in this module was lifted verbatim from the standard
46 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
46 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
47
47
48 Color schemes
48 Color schemes
49 -------------
49 -------------
50
50
51 The colors are defined in the class TBTools through the use of the
51 The colors are defined in the class TBTools through the use of the
52 ColorSchemeTable class. Currently the following exist:
52 ColorSchemeTable class. Currently the following exist:
53
53
54 - NoColor: allows all of this module to be used in any terminal (the color
54 - NoColor: allows all of this module to be used in any terminal (the color
55 escapes are just dummy blank strings).
55 escapes are just dummy blank strings).
56
56
57 - Linux: is meant to look good in a terminal like the Linux console (black
57 - Linux: is meant to look good in a terminal like the Linux console (black
58 or very dark background).
58 or very dark background).
59
59
60 - LightBG: similar to Linux but swaps dark/light colors to be more readable
60 - LightBG: similar to Linux but swaps dark/light colors to be more readable
61 in light background terminals.
61 in light background terminals.
62
62
63 You can implement other color schemes easily, the syntax is fairly
63 You can implement other color schemes easily, the syntax is fairly
64 self-explanatory. Please send back new schemes you develop to the author for
64 self-explanatory. Please send back new schemes you develop to the author for
65 possible inclusion in future releases.
65 possible inclusion in future releases.
66
66
67 Inheritance diagram:
67 Inheritance diagram:
68
68
69 .. inheritance-diagram:: IPython.core.ultratb
69 .. inheritance-diagram:: IPython.core.ultratb
70 :parts: 3
70 :parts: 3
71 """
71 """
72
72
73 #*****************************************************************************
73 #*****************************************************************************
74 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
74 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
75 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
75 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
76 #
76 #
77 # Distributed under the terms of the BSD License. The full license is in
77 # Distributed under the terms of the BSD License. The full license is in
78 # the file COPYING, distributed as part of this software.
78 # the file COPYING, distributed as part of this software.
79 #*****************************************************************************
79 #*****************************************************************************
80
80
81 from __future__ import unicode_literals
81 from __future__ import unicode_literals
82 from __future__ import print_function
82
83
83 import inspect
84 import inspect
84 import keyword
85 import keyword
85 import linecache
86 import linecache
86 import os
87 import os
87 import pydoc
88 import pydoc
88 import re
89 import re
89 import sys
90 import sys
90 import time
91 import time
91 import tokenize
92 import tokenize
92 import traceback
93 import traceback
93 import types
94 import types
94
95
95 try: # Python 2
96 try: # Python 2
96 generate_tokens = tokenize.generate_tokens
97 generate_tokens = tokenize.generate_tokens
97 except AttributeError: # Python 3
98 except AttributeError: # Python 3
98 generate_tokens = tokenize.tokenize
99 generate_tokens = tokenize.tokenize
99
100
100 # For purposes of monkeypatching inspect to fix a bug in it.
101 # For purposes of monkeypatching inspect to fix a bug in it.
101 from inspect import getsourcefile, getfile, getmodule,\
102 from inspect import getsourcefile, getfile, getmodule,\
102 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
103 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
103
104
104 # IPython's own modules
105 # IPython's own modules
105 # Modified pdb which doesn't damage IPython's readline handling
106 # Modified pdb which doesn't damage IPython's readline handling
106 from IPython import get_ipython
107 from IPython import get_ipython
107 from IPython.core import debugger
108 from IPython.core import debugger
108 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.display_trap import DisplayTrap
109 from IPython.core.excolors import exception_colors
110 from IPython.core.excolors import exception_colors
110 from IPython.utils import PyColorize
111 from IPython.utils import PyColorize
111 from IPython.utils import io
112 from IPython.utils import io
112 from IPython.utils import openpy
113 from IPython.utils import openpy
113 from IPython.utils import path as util_path
114 from IPython.utils import path as util_path
114 from IPython.utils import py3compat
115 from IPython.utils import py3compat
115 from IPython.utils import ulinecache
116 from IPython.utils import ulinecache
116 from IPython.utils.data import uniq_stable
117 from IPython.utils.data import uniq_stable
117 from IPython.utils.warn import info, error
118 from IPython.utils.warn import info, error
118
119
119 # Globals
120 # Globals
120 # amount of space to put line numbers before verbose tracebacks
121 # amount of space to put line numbers before verbose tracebacks
121 INDENT_SIZE = 8
122 INDENT_SIZE = 8
122
123
123 # Default color scheme. This is used, for example, by the traceback
124 # Default color scheme. This is used, for example, by the traceback
124 # formatter. When running in an actual IPython instance, the user's rc.colors
125 # formatter. When running in an actual IPython instance, the user's rc.colors
125 # value is used, but havinga module global makes this functionality available
126 # value is used, but havinga module global makes this functionality available
126 # to users of ultratb who are NOT running inside ipython.
127 # to users of ultratb who are NOT running inside ipython.
127 DEFAULT_SCHEME = 'NoColor'
128 DEFAULT_SCHEME = 'NoColor'
128
129
129 #---------------------------------------------------------------------------
130 #---------------------------------------------------------------------------
130 # Code begins
131 # Code begins
131
132
132 # Utility functions
133 # Utility functions
133 def inspect_error():
134 def inspect_error():
134 """Print a message about internal inspect errors.
135 """Print a message about internal inspect errors.
135
136
136 These are unfortunately quite common."""
137 These are unfortunately quite common."""
137
138
138 error('Internal Python error in the inspect module.\n'
139 error('Internal Python error in the inspect module.\n'
139 'Below is the traceback from this internal error.\n')
140 'Below is the traceback from this internal error.\n')
140
141
141 # This function is a monkeypatch we apply to the Python inspect module. We have
142 # This function is a monkeypatch we apply to the Python inspect module. We have
142 # now found when it's needed (see discussion on issue gh-1456), and we have a
143 # now found when it's needed (see discussion on issue gh-1456), and we have a
143 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
144 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
144 # the monkeypatch is not applied. TK, Aug 2012.
145 # the monkeypatch is not applied. TK, Aug 2012.
145 def findsource(object):
146 def findsource(object):
146 """Return the entire source file and starting line number for an object.
147 """Return the entire source file and starting line number for an object.
147
148
148 The argument may be a module, class, method, function, traceback, frame,
149 The argument may be a module, class, method, function, traceback, frame,
149 or code object. The source code is returned as a list of all the lines
150 or code object. The source code is returned as a list of all the lines
150 in the file and the line number indexes a line in that list. An IOError
151 in the file and the line number indexes a line in that list. An IOError
151 is raised if the source code cannot be retrieved.
152 is raised if the source code cannot be retrieved.
152
153
153 FIXED version with which we monkeypatch the stdlib to work around a bug."""
154 FIXED version with which we monkeypatch the stdlib to work around a bug."""
154
155
155 file = getsourcefile(object) or getfile(object)
156 file = getsourcefile(object) or getfile(object)
156 # If the object is a frame, then trying to get the globals dict from its
157 # If the object is a frame, then trying to get the globals dict from its
157 # module won't work. Instead, the frame object itself has the globals
158 # module won't work. Instead, the frame object itself has the globals
158 # dictionary.
159 # dictionary.
159 globals_dict = None
160 globals_dict = None
160 if inspect.isframe(object):
161 if inspect.isframe(object):
161 # XXX: can this ever be false?
162 # XXX: can this ever be false?
162 globals_dict = object.f_globals
163 globals_dict = object.f_globals
163 else:
164 else:
164 module = getmodule(object, file)
165 module = getmodule(object, file)
165 if module:
166 if module:
166 globals_dict = module.__dict__
167 globals_dict = module.__dict__
167 lines = linecache.getlines(file, globals_dict)
168 lines = linecache.getlines(file, globals_dict)
168 if not lines:
169 if not lines:
169 raise IOError('could not get source code')
170 raise IOError('could not get source code')
170
171
171 if ismodule(object):
172 if ismodule(object):
172 return lines, 0
173 return lines, 0
173
174
174 if isclass(object):
175 if isclass(object):
175 name = object.__name__
176 name = object.__name__
176 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
177 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
177 # make some effort to find the best matching class definition:
178 # make some effort to find the best matching class definition:
178 # use the one with the least indentation, which is the one
179 # use the one with the least indentation, which is the one
179 # that's most probably not inside a function definition.
180 # that's most probably not inside a function definition.
180 candidates = []
181 candidates = []
181 for i in range(len(lines)):
182 for i in range(len(lines)):
182 match = pat.match(lines[i])
183 match = pat.match(lines[i])
183 if match:
184 if match:
184 # if it's at toplevel, it's already the best one
185 # if it's at toplevel, it's already the best one
185 if lines[i][0] == 'c':
186 if lines[i][0] == 'c':
186 return lines, i
187 return lines, i
187 # else add whitespace to candidate list
188 # else add whitespace to candidate list
188 candidates.append((match.group(1), i))
189 candidates.append((match.group(1), i))
189 if candidates:
190 if candidates:
190 # this will sort by whitespace, and by line number,
191 # this will sort by whitespace, and by line number,
191 # less whitespace first
192 # less whitespace first
192 candidates.sort()
193 candidates.sort()
193 return lines, candidates[0][1]
194 return lines, candidates[0][1]
194 else:
195 else:
195 raise IOError('could not find class definition')
196 raise IOError('could not find class definition')
196
197
197 if ismethod(object):
198 if ismethod(object):
198 object = object.im_func
199 object = object.im_func
199 if isfunction(object):
200 if isfunction(object):
200 object = object.func_code
201 object = object.func_code
201 if istraceback(object):
202 if istraceback(object):
202 object = object.tb_frame
203 object = object.tb_frame
203 if isframe(object):
204 if isframe(object):
204 object = object.f_code
205 object = object.f_code
205 if iscode(object):
206 if iscode(object):
206 if not hasattr(object, 'co_firstlineno'):
207 if not hasattr(object, 'co_firstlineno'):
207 raise IOError('could not find function definition')
208 raise IOError('could not find function definition')
208 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
209 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
209 pmatch = pat.match
210 pmatch = pat.match
210 # fperez - fix: sometimes, co_firstlineno can give a number larger than
211 # fperez - fix: sometimes, co_firstlineno can give a number larger than
211 # the length of lines, which causes an error. Safeguard against that.
212 # the length of lines, which causes an error. Safeguard against that.
212 lnum = min(object.co_firstlineno,len(lines))-1
213 lnum = min(object.co_firstlineno,len(lines))-1
213 while lnum > 0:
214 while lnum > 0:
214 if pmatch(lines[lnum]): break
215 if pmatch(lines[lnum]): break
215 lnum -= 1
216 lnum -= 1
216
217
217 return lines, lnum
218 return lines, lnum
218 raise IOError('could not find code object')
219 raise IOError('could not find code object')
219
220
220 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
221 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
221 inspect.findsource = findsource
222 inspect.findsource = findsource
222
223
223 def fix_frame_records_filenames(records):
224 def fix_frame_records_filenames(records):
224 """Try to fix the filenames in each record from inspect.getinnerframes().
225 """Try to fix the filenames in each record from inspect.getinnerframes().
225
226
226 Particularly, modules loaded from within zip files have useless filenames
227 Particularly, modules loaded from within zip files have useless filenames
227 attached to their code object, and inspect.getinnerframes() just uses it.
228 attached to their code object, and inspect.getinnerframes() just uses it.
228 """
229 """
229 fixed_records = []
230 fixed_records = []
230 for frame, filename, line_no, func_name, lines, index in records:
231 for frame, filename, line_no, func_name, lines, index in records:
231 # Look inside the frame's globals dictionary for __file__, which should
232 # Look inside the frame's globals dictionary for __file__, which should
232 # be better.
233 # be better.
233 better_fn = frame.f_globals.get('__file__', None)
234 better_fn = frame.f_globals.get('__file__', None)
234 if isinstance(better_fn, str):
235 if isinstance(better_fn, str):
235 # Check the type just in case someone did something weird with
236 # Check the type just in case someone did something weird with
236 # __file__. It might also be None if the error occurred during
237 # __file__. It might also be None if the error occurred during
237 # import.
238 # import.
238 filename = better_fn
239 filename = better_fn
239 fixed_records.append((frame, filename, line_no, func_name, lines, index))
240 fixed_records.append((frame, filename, line_no, func_name, lines, index))
240 return fixed_records
241 return fixed_records
241
242
242
243
243 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
244 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
244 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
245 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
245
246
246 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
247 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
247
248
248 # If the error is at the console, don't build any context, since it would
249 # If the error is at the console, don't build any context, since it would
249 # otherwise produce 5 blank lines printed out (there is no file at the
250 # otherwise produce 5 blank lines printed out (there is no file at the
250 # console)
251 # console)
251 rec_check = records[tb_offset:]
252 rec_check = records[tb_offset:]
252 try:
253 try:
253 rname = rec_check[0][1]
254 rname = rec_check[0][1]
254 if rname == '<ipython console>' or rname.endswith('<string>'):
255 if rname == '<ipython console>' or rname.endswith('<string>'):
255 return rec_check
256 return rec_check
256 except IndexError:
257 except IndexError:
257 pass
258 pass
258
259
259 aux = traceback.extract_tb(etb)
260 aux = traceback.extract_tb(etb)
260 assert len(records) == len(aux)
261 assert len(records) == len(aux)
261 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
262 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
262 maybeStart = lnum-1 - context//2
263 maybeStart = lnum-1 - context//2
263 start = max(maybeStart, 0)
264 start = max(maybeStart, 0)
264 end = start + context
265 end = start + context
265 lines = ulinecache.getlines(file)[start:end]
266 lines = ulinecache.getlines(file)[start:end]
266 buf = list(records[i])
267 buf = list(records[i])
267 buf[LNUM_POS] = lnum
268 buf[LNUM_POS] = lnum
268 buf[INDEX_POS] = lnum - 1 - start
269 buf[INDEX_POS] = lnum - 1 - start
269 buf[LINES_POS] = lines
270 buf[LINES_POS] = lines
270 records[i] = tuple(buf)
271 records[i] = tuple(buf)
271 return records[tb_offset:]
272 return records[tb_offset:]
272
273
273 # Helper function -- largely belongs to VerboseTB, but we need the same
274 # Helper function -- largely belongs to VerboseTB, but we need the same
274 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
275 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
275 # can be recognized properly by ipython.el's py-traceback-line-re
276 # can be recognized properly by ipython.el's py-traceback-line-re
276 # (SyntaxErrors have to be treated specially because they have no traceback)
277 # (SyntaxErrors have to be treated specially because they have no traceback)
277
278
278 _parser = PyColorize.Parser()
279 _parser = PyColorize.Parser()
279
280
280 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
281 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
281 numbers_width = INDENT_SIZE - 1
282 numbers_width = INDENT_SIZE - 1
282 res = []
283 res = []
283 i = lnum - index
284 i = lnum - index
284
285
285 # This lets us get fully syntax-highlighted tracebacks.
286 # This lets us get fully syntax-highlighted tracebacks.
286 if scheme is None:
287 if scheme is None:
287 ipinst = get_ipython()
288 ipinst = get_ipython()
288 if ipinst is not None:
289 if ipinst is not None:
289 scheme = ipinst.colors
290 scheme = ipinst.colors
290 else:
291 else:
291 scheme = DEFAULT_SCHEME
292 scheme = DEFAULT_SCHEME
292
293
293 _line_format = _parser.format2
294 _line_format = _parser.format2
294
295
295 for line in lines:
296 for line in lines:
296 line = py3compat.cast_unicode(line)
297 line = py3compat.cast_unicode(line)
297
298
298 new_line, err = _line_format(line, 'str', scheme)
299 new_line, err = _line_format(line, 'str', scheme)
299 if not err: line = new_line
300 if not err: line = new_line
300
301
301 if i == lnum:
302 if i == lnum:
302 # This is the line with the error
303 # This is the line with the error
303 pad = numbers_width - len(str(i))
304 pad = numbers_width - len(str(i))
304 if pad >= 3:
305 if pad >= 3:
305 marker = '-'*(pad-3) + '-> '
306 marker = '-'*(pad-3) + '-> '
306 elif pad == 2:
307 elif pad == 2:
307 marker = '> '
308 marker = '> '
308 elif pad == 1:
309 elif pad == 1:
309 marker = '>'
310 marker = '>'
310 else:
311 else:
311 marker = ''
312 marker = ''
312 num = marker + str(i)
313 num = marker + str(i)
313 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
314 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
314 Colors.line, line, Colors.Normal)
315 Colors.line, line, Colors.Normal)
315 else:
316 else:
316 num = '%*s' % (numbers_width,i)
317 num = '%*s' % (numbers_width,i)
317 line = '%s%s%s %s' %(Colors.lineno, num,
318 line = '%s%s%s %s' %(Colors.lineno, num,
318 Colors.Normal, line)
319 Colors.Normal, line)
319
320
320 res.append(line)
321 res.append(line)
321 if lvals and i == lnum:
322 if lvals and i == lnum:
322 res.append(lvals + '\n')
323 res.append(lvals + '\n')
323 i = i + 1
324 i = i + 1
324 return res
325 return res
325
326
326
327
327 #---------------------------------------------------------------------------
328 #---------------------------------------------------------------------------
328 # Module classes
329 # Module classes
329 class TBTools(object):
330 class TBTools(object):
330 """Basic tools used by all traceback printer classes."""
331 """Basic tools used by all traceback printer classes."""
331
332
332 # Number of frames to skip when reporting tracebacks
333 # Number of frames to skip when reporting tracebacks
333 tb_offset = 0
334 tb_offset = 0
334
335
335 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
336 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
336 # Whether to call the interactive pdb debugger after printing
337 # Whether to call the interactive pdb debugger after printing
337 # tracebacks or not
338 # tracebacks or not
338 self.call_pdb = call_pdb
339 self.call_pdb = call_pdb
339
340
340 # Output stream to write to. Note that we store the original value in
341 # Output stream to write to. Note that we store the original value in
341 # a private attribute and then make the public ostream a property, so
342 # a private attribute and then make the public ostream a property, so
342 # that we can delay accessing io.stdout until runtime. The way
343 # that we can delay accessing io.stdout until runtime. The way
343 # things are written now, the io.stdout object is dynamically managed
344 # things are written now, the io.stdout object is dynamically managed
344 # so a reference to it should NEVER be stored statically. This
345 # so a reference to it should NEVER be stored statically. This
345 # property approach confines this detail to a single location, and all
346 # property approach confines this detail to a single location, and all
346 # subclasses can simply access self.ostream for writing.
347 # subclasses can simply access self.ostream for writing.
347 self._ostream = ostream
348 self._ostream = ostream
348
349
349 # Create color table
350 # Create color table
350 self.color_scheme_table = exception_colors()
351 self.color_scheme_table = exception_colors()
351
352
352 self.set_colors(color_scheme)
353 self.set_colors(color_scheme)
353 self.old_scheme = color_scheme # save initial value for toggles
354 self.old_scheme = color_scheme # save initial value for toggles
354
355
355 if call_pdb:
356 if call_pdb:
356 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
357 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
357 else:
358 else:
358 self.pdb = None
359 self.pdb = None
359
360
360 def _get_ostream(self):
361 def _get_ostream(self):
361 """Output stream that exceptions are written to.
362 """Output stream that exceptions are written to.
362
363
363 Valid values are:
364 Valid values are:
364
365
365 - None: the default, which means that IPython will dynamically resolve
366 - None: the default, which means that IPython will dynamically resolve
366 to io.stdout. This ensures compatibility with most tools, including
367 to io.stdout. This ensures compatibility with most tools, including
367 Windows (where plain stdout doesn't recognize ANSI escapes).
368 Windows (where plain stdout doesn't recognize ANSI escapes).
368
369
369 - Any object with 'write' and 'flush' attributes.
370 - Any object with 'write' and 'flush' attributes.
370 """
371 """
371 return io.stdout if self._ostream is None else self._ostream
372 return io.stdout if self._ostream is None else self._ostream
372
373
373 def _set_ostream(self, val):
374 def _set_ostream(self, val):
374 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
375 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
375 self._ostream = val
376 self._ostream = val
376
377
377 ostream = property(_get_ostream, _set_ostream)
378 ostream = property(_get_ostream, _set_ostream)
378
379
379 def set_colors(self,*args,**kw):
380 def set_colors(self,*args,**kw):
380 """Shorthand access to the color table scheme selector method."""
381 """Shorthand access to the color table scheme selector method."""
381
382
382 # Set own color table
383 # Set own color table
383 self.color_scheme_table.set_active_scheme(*args,**kw)
384 self.color_scheme_table.set_active_scheme(*args,**kw)
384 # for convenience, set Colors to the active scheme
385 # for convenience, set Colors to the active scheme
385 self.Colors = self.color_scheme_table.active_colors
386 self.Colors = self.color_scheme_table.active_colors
386 # Also set colors of debugger
387 # Also set colors of debugger
387 if hasattr(self,'pdb') and self.pdb is not None:
388 if hasattr(self,'pdb') and self.pdb is not None:
388 self.pdb.set_colors(*args,**kw)
389 self.pdb.set_colors(*args,**kw)
389
390
390 def color_toggle(self):
391 def color_toggle(self):
391 """Toggle between the currently active color scheme and NoColor."""
392 """Toggle between the currently active color scheme and NoColor."""
392
393
393 if self.color_scheme_table.active_scheme_name == 'NoColor':
394 if self.color_scheme_table.active_scheme_name == 'NoColor':
394 self.color_scheme_table.set_active_scheme(self.old_scheme)
395 self.color_scheme_table.set_active_scheme(self.old_scheme)
395 self.Colors = self.color_scheme_table.active_colors
396 self.Colors = self.color_scheme_table.active_colors
396 else:
397 else:
397 self.old_scheme = self.color_scheme_table.active_scheme_name
398 self.old_scheme = self.color_scheme_table.active_scheme_name
398 self.color_scheme_table.set_active_scheme('NoColor')
399 self.color_scheme_table.set_active_scheme('NoColor')
399 self.Colors = self.color_scheme_table.active_colors
400 self.Colors = self.color_scheme_table.active_colors
400
401
401 def stb2text(self, stb):
402 def stb2text(self, stb):
402 """Convert a structured traceback (a list) to a string."""
403 """Convert a structured traceback (a list) to a string."""
403 return '\n'.join(stb)
404 return '\n'.join(stb)
404
405
405 def text(self, etype, value, tb, tb_offset=None, context=5):
406 def text(self, etype, value, tb, tb_offset=None, context=5):
406 """Return formatted traceback.
407 """Return formatted traceback.
407
408
408 Subclasses may override this if they add extra arguments.
409 Subclasses may override this if they add extra arguments.
409 """
410 """
410 tb_list = self.structured_traceback(etype, value, tb,
411 tb_list = self.structured_traceback(etype, value, tb,
411 tb_offset, context)
412 tb_offset, context)
412 return self.stb2text(tb_list)
413 return self.stb2text(tb_list)
413
414
414 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
415 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
415 context=5, mode=None):
416 context=5, mode=None):
416 """Return a list of traceback frames.
417 """Return a list of traceback frames.
417
418
418 Must be implemented by each class.
419 Must be implemented by each class.
419 """
420 """
420 raise NotImplementedError()
421 raise NotImplementedError()
421
422
422
423
423 #---------------------------------------------------------------------------
424 #---------------------------------------------------------------------------
424 class ListTB(TBTools):
425 class ListTB(TBTools):
425 """Print traceback information from a traceback list, with optional color.
426 """Print traceback information from a traceback list, with optional color.
426
427
427 Calling requires 3 arguments: (etype, evalue, elist)
428 Calling requires 3 arguments: (etype, evalue, elist)
428 as would be obtained by::
429 as would be obtained by::
429
430
430 etype, evalue, tb = sys.exc_info()
431 etype, evalue, tb = sys.exc_info()
431 if tb:
432 if tb:
432 elist = traceback.extract_tb(tb)
433 elist = traceback.extract_tb(tb)
433 else:
434 else:
434 elist = None
435 elist = None
435
436
436 It can thus be used by programs which need to process the traceback before
437 It can thus be used by programs which need to process the traceback before
437 printing (such as console replacements based on the code module from the
438 printing (such as console replacements based on the code module from the
438 standard library).
439 standard library).
439
440
440 Because they are meant to be called without a full traceback (only a
441 Because they are meant to be called without a full traceback (only a
441 list), instances of this class can't call the interactive pdb debugger."""
442 list), instances of this class can't call the interactive pdb debugger."""
442
443
443 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
444 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
444 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
445 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
445 ostream=ostream)
446 ostream=ostream)
446
447
447 def __call__(self, etype, value, elist):
448 def __call__(self, etype, value, elist):
448 self.ostream.flush()
449 self.ostream.flush()
449 self.ostream.write(self.text(etype, value, elist))
450 self.ostream.write(self.text(etype, value, elist))
450 self.ostream.write('\n')
451 self.ostream.write('\n')
451
452
452 def structured_traceback(self, etype, value, elist, tb_offset=None,
453 def structured_traceback(self, etype, value, elist, tb_offset=None,
453 context=5):
454 context=5):
454 """Return a color formatted string with the traceback info.
455 """Return a color formatted string with the traceback info.
455
456
456 Parameters
457 Parameters
457 ----------
458 ----------
458 etype : exception type
459 etype : exception type
459 Type of the exception raised.
460 Type of the exception raised.
460
461
461 value : object
462 value : object
462 Data stored in the exception
463 Data stored in the exception
463
464
464 elist : list
465 elist : list
465 List of frames, see class docstring for details.
466 List of frames, see class docstring for details.
466
467
467 tb_offset : int, optional
468 tb_offset : int, optional
468 Number of frames in the traceback to skip. If not given, the
469 Number of frames in the traceback to skip. If not given, the
469 instance value is used (set in constructor).
470 instance value is used (set in constructor).
470
471
471 context : int, optional
472 context : int, optional
472 Number of lines of context information to print.
473 Number of lines of context information to print.
473
474
474 Returns
475 Returns
475 -------
476 -------
476 String with formatted exception.
477 String with formatted exception.
477 """
478 """
478 tb_offset = self.tb_offset if tb_offset is None else tb_offset
479 tb_offset = self.tb_offset if tb_offset is None else tb_offset
479 Colors = self.Colors
480 Colors = self.Colors
480 out_list = []
481 out_list = []
481 if elist:
482 if elist:
482
483
483 if tb_offset and len(elist) > tb_offset:
484 if tb_offset and len(elist) > tb_offset:
484 elist = elist[tb_offset:]
485 elist = elist[tb_offset:]
485
486
486 out_list.append('Traceback %s(most recent call last)%s:' %
487 out_list.append('Traceback %s(most recent call last)%s:' %
487 (Colors.normalEm, Colors.Normal) + '\n')
488 (Colors.normalEm, Colors.Normal) + '\n')
488 out_list.extend(self._format_list(elist))
489 out_list.extend(self._format_list(elist))
489 # The exception info should be a single entry in the list.
490 # The exception info should be a single entry in the list.
490 lines = ''.join(self._format_exception_only(etype, value))
491 lines = ''.join(self._format_exception_only(etype, value))
491 out_list.append(lines)
492 out_list.append(lines)
492
493
493 # Note: this code originally read:
494 # Note: this code originally read:
494
495
495 ## for line in lines[:-1]:
496 ## for line in lines[:-1]:
496 ## out_list.append(" "+line)
497 ## out_list.append(" "+line)
497 ## out_list.append(lines[-1])
498 ## out_list.append(lines[-1])
498
499
499 # This means it was indenting everything but the last line by a little
500 # This means it was indenting everything but the last line by a little
500 # bit. I've disabled this for now, but if we see ugliness somewhre we
501 # bit. I've disabled this for now, but if we see ugliness somewhre we
501 # can restore it.
502 # can restore it.
502
503
503 return out_list
504 return out_list
504
505
505 def _format_list(self, extracted_list):
506 def _format_list(self, extracted_list):
506 """Format a list of traceback entry tuples for printing.
507 """Format a list of traceback entry tuples for printing.
507
508
508 Given a list of tuples as returned by extract_tb() or
509 Given a list of tuples as returned by extract_tb() or
509 extract_stack(), return a list of strings ready for printing.
510 extract_stack(), return a list of strings ready for printing.
510 Each string in the resulting list corresponds to the item with the
511 Each string in the resulting list corresponds to the item with the
511 same index in the argument list. Each string ends in a newline;
512 same index in the argument list. Each string ends in a newline;
512 the strings may contain internal newlines as well, for those items
513 the strings may contain internal newlines as well, for those items
513 whose source text line is not None.
514 whose source text line is not None.
514
515
515 Lifted almost verbatim from traceback.py
516 Lifted almost verbatim from traceback.py
516 """
517 """
517
518
518 Colors = self.Colors
519 Colors = self.Colors
519 list = []
520 list = []
520 for filename, lineno, name, line in extracted_list[:-1]:
521 for filename, lineno, name, line in extracted_list[:-1]:
521 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
522 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
522 (Colors.filename, filename, Colors.Normal,
523 (Colors.filename, filename, Colors.Normal,
523 Colors.lineno, lineno, Colors.Normal,
524 Colors.lineno, lineno, Colors.Normal,
524 Colors.name, name, Colors.Normal)
525 Colors.name, name, Colors.Normal)
525 if line:
526 if line:
526 item += ' %s\n' % line.strip()
527 item += ' %s\n' % line.strip()
527 list.append(item)
528 list.append(item)
528 # Emphasize the last entry
529 # Emphasize the last entry
529 filename, lineno, name, line = extracted_list[-1]
530 filename, lineno, name, line = extracted_list[-1]
530 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
531 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
531 (Colors.normalEm,
532 (Colors.normalEm,
532 Colors.filenameEm, filename, Colors.normalEm,
533 Colors.filenameEm, filename, Colors.normalEm,
533 Colors.linenoEm, lineno, Colors.normalEm,
534 Colors.linenoEm, lineno, Colors.normalEm,
534 Colors.nameEm, name, Colors.normalEm,
535 Colors.nameEm, name, Colors.normalEm,
535 Colors.Normal)
536 Colors.Normal)
536 if line:
537 if line:
537 item += '%s %s%s\n' % (Colors.line, line.strip(),
538 item += '%s %s%s\n' % (Colors.line, line.strip(),
538 Colors.Normal)
539 Colors.Normal)
539 list.append(item)
540 list.append(item)
540 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
541 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
541 return list
542 return list
542
543
543 def _format_exception_only(self, etype, value):
544 def _format_exception_only(self, etype, value):
544 """Format the exception part of a traceback.
545 """Format the exception part of a traceback.
545
546
546 The arguments are the exception type and value such as given by
547 The arguments are the exception type and value such as given by
547 sys.exc_info()[:2]. The return value is a list of strings, each ending
548 sys.exc_info()[:2]. The return value is a list of strings, each ending
548 in a newline. Normally, the list contains a single string; however,
549 in a newline. Normally, the list contains a single string; however,
549 for SyntaxError exceptions, it contains several lines that (when
550 for SyntaxError exceptions, it contains several lines that (when
550 printed) display detailed information about where the syntax error
551 printed) display detailed information about where the syntax error
551 occurred. The message indicating which exception occurred is the
552 occurred. The message indicating which exception occurred is the
552 always last string in the list.
553 always last string in the list.
553
554
554 Also lifted nearly verbatim from traceback.py
555 Also lifted nearly verbatim from traceback.py
555 """
556 """
556 have_filedata = False
557 have_filedata = False
557 Colors = self.Colors
558 Colors = self.Colors
558 list = []
559 list = []
559 stype = Colors.excName + etype.__name__ + Colors.Normal
560 stype = Colors.excName + etype.__name__ + Colors.Normal
560 if value is None:
561 if value is None:
561 # Not sure if this can still happen in Python 2.6 and above
562 # Not sure if this can still happen in Python 2.6 and above
562 list.append( py3compat.cast_unicode(stype) + '\n')
563 list.append( py3compat.cast_unicode(stype) + '\n')
563 else:
564 else:
564 if issubclass(etype, SyntaxError):
565 if issubclass(etype, SyntaxError):
565 have_filedata = True
566 have_filedata = True
566 #print 'filename is',filename # dbg
567 #print 'filename is',filename # dbg
567 if not value.filename: value.filename = "<string>"
568 if not value.filename: value.filename = "<string>"
568 if value.lineno:
569 if value.lineno:
569 lineno = value.lineno
570 lineno = value.lineno
570 textline = ulinecache.getline(value.filename, value.lineno)
571 textline = ulinecache.getline(value.filename, value.lineno)
571 else:
572 else:
572 lineno = 'unknown'
573 lineno = 'unknown'
573 textline = ''
574 textline = ''
574 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
575 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
575 (Colors.normalEm,
576 (Colors.normalEm,
576 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
577 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
577 Colors.linenoEm, lineno, Colors.Normal ))
578 Colors.linenoEm, lineno, Colors.Normal ))
578 if textline == '':
579 if textline == '':
579 textline = py3compat.cast_unicode(value.text, "utf-8")
580 textline = py3compat.cast_unicode(value.text, "utf-8")
580
581
581 if textline is not None:
582 if textline is not None:
582 i = 0
583 i = 0
583 while i < len(textline) and textline[i].isspace():
584 while i < len(textline) and textline[i].isspace():
584 i += 1
585 i += 1
585 list.append('%s %s%s\n' % (Colors.line,
586 list.append('%s %s%s\n' % (Colors.line,
586 textline.strip(),
587 textline.strip(),
587 Colors.Normal))
588 Colors.Normal))
588 if value.offset is not None:
589 if value.offset is not None:
589 s = ' '
590 s = ' '
590 for c in textline[i:value.offset-1]:
591 for c in textline[i:value.offset-1]:
591 if c.isspace():
592 if c.isspace():
592 s += c
593 s += c
593 else:
594 else:
594 s += ' '
595 s += ' '
595 list.append('%s%s^%s\n' % (Colors.caret, s,
596 list.append('%s%s^%s\n' % (Colors.caret, s,
596 Colors.Normal) )
597 Colors.Normal) )
597
598
598 try:
599 try:
599 s = value.msg
600 s = value.msg
600 except Exception:
601 except Exception:
601 s = self._some_str(value)
602 s = self._some_str(value)
602 if s:
603 if s:
603 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
604 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
604 Colors.Normal, s))
605 Colors.Normal, s))
605 else:
606 else:
606 list.append('%s\n' % str(stype))
607 list.append('%s\n' % str(stype))
607
608
608 # sync with user hooks
609 # sync with user hooks
609 if have_filedata:
610 if have_filedata:
610 ipinst = get_ipython()
611 ipinst = get_ipython()
611 if ipinst is not None:
612 if ipinst is not None:
612 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
613 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
613
614
614 return list
615 return list
615
616
616 def get_exception_only(self, etype, value):
617 def get_exception_only(self, etype, value):
617 """Only print the exception type and message, without a traceback.
618 """Only print the exception type and message, without a traceback.
618
619
619 Parameters
620 Parameters
620 ----------
621 ----------
621 etype : exception type
622 etype : exception type
622 value : exception value
623 value : exception value
623 """
624 """
624 return ListTB.structured_traceback(self, etype, value, [])
625 return ListTB.structured_traceback(self, etype, value, [])
625
626
626
627
627 def show_exception_only(self, etype, evalue):
628 def show_exception_only(self, etype, evalue):
628 """Only print the exception type and message, without a traceback.
629 """Only print the exception type and message, without a traceback.
629
630
630 Parameters
631 Parameters
631 ----------
632 ----------
632 etype : exception type
633 etype : exception type
633 value : exception value
634 value : exception value
634 """
635 """
635 # This method needs to use __call__ from *this* class, not the one from
636 # This method needs to use __call__ from *this* class, not the one from
636 # a subclass whose signature or behavior may be different
637 # a subclass whose signature or behavior may be different
637 ostream = self.ostream
638 ostream = self.ostream
638 ostream.flush()
639 ostream.flush()
639 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
640 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
640 ostream.flush()
641 ostream.flush()
641
642
642 def _some_str(self, value):
643 def _some_str(self, value):
643 # Lifted from traceback.py
644 # Lifted from traceback.py
644 try:
645 try:
645 return str(value)
646 return str(value)
646 except:
647 except:
647 return '<unprintable %s object>' % type(value).__name__
648 return '<unprintable %s object>' % type(value).__name__
648
649
649 #----------------------------------------------------------------------------
650 #----------------------------------------------------------------------------
650 class VerboseTB(TBTools):
651 class VerboseTB(TBTools):
651 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
652 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
652 of HTML. Requires inspect and pydoc. Crazy, man.
653 of HTML. Requires inspect and pydoc. Crazy, man.
653
654
654 Modified version which optionally strips the topmost entries from the
655 Modified version which optionally strips the topmost entries from the
655 traceback, to be used with alternate interpreters (because their own code
656 traceback, to be used with alternate interpreters (because their own code
656 would appear in the traceback)."""
657 would appear in the traceback)."""
657
658
658 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
659 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
659 tb_offset=0, long_header=False, include_vars=True,
660 tb_offset=0, long_header=False, include_vars=True,
660 check_cache=None):
661 check_cache=None):
661 """Specify traceback offset, headers and color scheme.
662 """Specify traceback offset, headers and color scheme.
662
663
663 Define how many frames to drop from the tracebacks. Calling it with
664 Define how many frames to drop from the tracebacks. Calling it with
664 tb_offset=1 allows use of this handler in interpreters which will have
665 tb_offset=1 allows use of this handler in interpreters which will have
665 their own code at the top of the traceback (VerboseTB will first
666 their own code at the top of the traceback (VerboseTB will first
666 remove that frame before printing the traceback info)."""
667 remove that frame before printing the traceback info)."""
667 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
668 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
668 ostream=ostream)
669 ostream=ostream)
669 self.tb_offset = tb_offset
670 self.tb_offset = tb_offset
670 self.long_header = long_header
671 self.long_header = long_header
671 self.include_vars = include_vars
672 self.include_vars = include_vars
672 # By default we use linecache.checkcache, but the user can provide a
673 # By default we use linecache.checkcache, but the user can provide a
673 # different check_cache implementation. This is used by the IPython
674 # different check_cache implementation. This is used by the IPython
674 # kernel to provide tracebacks for interactive code that is cached,
675 # kernel to provide tracebacks for interactive code that is cached,
675 # by a compiler instance that flushes the linecache but preserves its
676 # by a compiler instance that flushes the linecache but preserves its
676 # own code cache.
677 # own code cache.
677 if check_cache is None:
678 if check_cache is None:
678 check_cache = linecache.checkcache
679 check_cache = linecache.checkcache
679 self.check_cache = check_cache
680 self.check_cache = check_cache
680
681
681 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
682 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
682 context=5):
683 context=5):
683 """Return a nice text document describing the traceback."""
684 """Return a nice text document describing the traceback."""
684
685
685 tb_offset = self.tb_offset if tb_offset is None else tb_offset
686 tb_offset = self.tb_offset if tb_offset is None else tb_offset
686
687
687 # some locals
688 # some locals
688 try:
689 try:
689 etype = etype.__name__
690 etype = etype.__name__
690 except AttributeError:
691 except AttributeError:
691 pass
692 pass
692 Colors = self.Colors # just a shorthand + quicker name lookup
693 Colors = self.Colors # just a shorthand + quicker name lookup
693 ColorsNormal = Colors.Normal # used a lot
694 ColorsNormal = Colors.Normal # used a lot
694 col_scheme = self.color_scheme_table.active_scheme_name
695 col_scheme = self.color_scheme_table.active_scheme_name
695 indent = ' '*INDENT_SIZE
696 indent = ' '*INDENT_SIZE
696 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
697 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
697 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
698 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
698 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
699 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
699
700
700 # some internal-use functions
701 # some internal-use functions
701 def text_repr(value):
702 def text_repr(value):
702 """Hopefully pretty robust repr equivalent."""
703 """Hopefully pretty robust repr equivalent."""
703 # this is pretty horrible but should always return *something*
704 # this is pretty horrible but should always return *something*
704 try:
705 try:
705 return pydoc.text.repr(value)
706 return pydoc.text.repr(value)
706 except KeyboardInterrupt:
707 except KeyboardInterrupt:
707 raise
708 raise
708 except:
709 except:
709 try:
710 try:
710 return repr(value)
711 return repr(value)
711 except KeyboardInterrupt:
712 except KeyboardInterrupt:
712 raise
713 raise
713 except:
714 except:
714 try:
715 try:
715 # all still in an except block so we catch
716 # all still in an except block so we catch
716 # getattr raising
717 # getattr raising
717 name = getattr(value, '__name__', None)
718 name = getattr(value, '__name__', None)
718 if name:
719 if name:
719 # ick, recursion
720 # ick, recursion
720 return text_repr(name)
721 return text_repr(name)
721 klass = getattr(value, '__class__', None)
722 klass = getattr(value, '__class__', None)
722 if klass:
723 if klass:
723 return '%s instance' % text_repr(klass)
724 return '%s instance' % text_repr(klass)
724 except KeyboardInterrupt:
725 except KeyboardInterrupt:
725 raise
726 raise
726 except:
727 except:
727 return 'UNRECOVERABLE REPR FAILURE'
728 return 'UNRECOVERABLE REPR FAILURE'
728 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
729 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
729 def nullrepr(value, repr=text_repr): return ''
730 def nullrepr(value, repr=text_repr): return ''
730
731
731 # meat of the code begins
732 # meat of the code begins
732 try:
733 try:
733 etype = etype.__name__
734 etype = etype.__name__
734 except AttributeError:
735 except AttributeError:
735 pass
736 pass
736
737
737 if self.long_header:
738 if self.long_header:
738 # Header with the exception type, python version, and date
739 # Header with the exception type, python version, and date
739 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
740 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
740 date = time.ctime(time.time())
741 date = time.ctime(time.time())
741
742
742 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
743 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
743 exc, ' '*(75-len(str(etype))-len(pyver)),
744 exc, ' '*(75-len(str(etype))-len(pyver)),
744 pyver, date.rjust(75) )
745 pyver, date.rjust(75) )
745 head += "\nA problem occured executing Python code. Here is the sequence of function"\
746 head += "\nA problem occured executing Python code. Here is the sequence of function"\
746 "\ncalls leading up to the error, with the most recent (innermost) call last."
747 "\ncalls leading up to the error, with the most recent (innermost) call last."
747 else:
748 else:
748 # Simplified header
749 # Simplified header
749 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
750 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
750 'Traceback (most recent call last)'.\
751 'Traceback (most recent call last)'.\
751 rjust(75 - len(str(etype)) ) )
752 rjust(75 - len(str(etype)) ) )
752 frames = []
753 frames = []
753 # Flush cache before calling inspect. This helps alleviate some of the
754 # Flush cache before calling inspect. This helps alleviate some of the
754 # problems with python 2.3's inspect.py.
755 # problems with python 2.3's inspect.py.
755 ##self.check_cache()
756 ##self.check_cache()
756 # Drop topmost frames if requested
757 # Drop topmost frames if requested
757 try:
758 try:
758 # Try the default getinnerframes and Alex's: Alex's fixes some
759 # Try the default getinnerframes and Alex's: Alex's fixes some
759 # problems, but it generates empty tracebacks for console errors
760 # problems, but it generates empty tracebacks for console errors
760 # (5 blanks lines) where none should be returned.
761 # (5 blanks lines) where none should be returned.
761 #records = inspect.getinnerframes(etb, context)[tb_offset:]
762 #records = inspect.getinnerframes(etb, context)[tb_offset:]
762 #print 'python records:', records # dbg
763 #print 'python records:', records # dbg
763 records = _fixed_getinnerframes(etb, context, tb_offset)
764 records = _fixed_getinnerframes(etb, context, tb_offset)
764 #print 'alex records:', records # dbg
765 #print 'alex records:', records # dbg
765 except:
766 except:
766
767
767 # FIXME: I've been getting many crash reports from python 2.3
768 # FIXME: I've been getting many crash reports from python 2.3
768 # users, traceable to inspect.py. If I can find a small test-case
769 # users, traceable to inspect.py. If I can find a small test-case
769 # to reproduce this, I should either write a better workaround or
770 # to reproduce this, I should either write a better workaround or
770 # file a bug report against inspect (if that's the real problem).
771 # file a bug report against inspect (if that's the real problem).
771 # So far, I haven't been able to find an isolated example to
772 # So far, I haven't been able to find an isolated example to
772 # reproduce the problem.
773 # reproduce the problem.
773 inspect_error()
774 inspect_error()
774 traceback.print_exc(file=self.ostream)
775 traceback.print_exc(file=self.ostream)
775 info('\nUnfortunately, your original traceback can not be constructed.\n')
776 info('\nUnfortunately, your original traceback can not be constructed.\n')
776 return ''
777 return ''
777
778
778 # build some color string templates outside these nested loops
779 # build some color string templates outside these nested loops
779 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
780 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
780 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
781 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
781 ColorsNormal)
782 ColorsNormal)
782 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
783 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
783 (Colors.vName, Colors.valEm, ColorsNormal)
784 (Colors.vName, Colors.valEm, ColorsNormal)
784 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
785 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
785 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
786 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
786 Colors.vName, ColorsNormal)
787 Colors.vName, ColorsNormal)
787 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
788 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
788 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
789 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
789 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
790 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
790 ColorsNormal)
791 ColorsNormal)
791
792
792 # now, loop over all records printing context and info
793 # now, loop over all records printing context and info
793 abspath = os.path.abspath
794 abspath = os.path.abspath
794 for frame, file, lnum, func, lines, index in records:
795 for frame, file, lnum, func, lines, index in records:
795 #print '*** record:',file,lnum,func,lines,index # dbg
796 #print '*** record:',file,lnum,func,lines,index # dbg
796 if not file:
797 if not file:
797 file = '?'
798 file = '?'
798 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
799 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
799 # Guess that filenames like <string> aren't real filenames, so
800 # Guess that filenames like <string> aren't real filenames, so
800 # don't call abspath on them.
801 # don't call abspath on them.
801 try:
802 try:
802 file = abspath(file)
803 file = abspath(file)
803 except OSError:
804 except OSError:
804 # Not sure if this can still happen: abspath now works with
805 # Not sure if this can still happen: abspath now works with
805 # file names like <string>
806 # file names like <string>
806 pass
807 pass
807 file = py3compat.cast_unicode(file, util_path.fs_encoding)
808 file = py3compat.cast_unicode(file, util_path.fs_encoding)
808 link = tpl_link % file
809 link = tpl_link % file
809 args, varargs, varkw, locals = inspect.getargvalues(frame)
810 args, varargs, varkw, locals = inspect.getargvalues(frame)
810
811
811 if func == '?':
812 if func == '?':
812 call = ''
813 call = ''
813 else:
814 else:
814 # Decide whether to include variable details or not
815 # Decide whether to include variable details or not
815 var_repr = self.include_vars and eqrepr or nullrepr
816 var_repr = self.include_vars and eqrepr or nullrepr
816 try:
817 try:
817 call = tpl_call % (func,inspect.formatargvalues(args,
818 call = tpl_call % (func,inspect.formatargvalues(args,
818 varargs, varkw,
819 varargs, varkw,
819 locals,formatvalue=var_repr))
820 locals,formatvalue=var_repr))
820 except KeyError:
821 except KeyError:
821 # This happens in situations like errors inside generator
822 # This happens in situations like errors inside generator
822 # expressions, where local variables are listed in the
823 # expressions, where local variables are listed in the
823 # line, but can't be extracted from the frame. I'm not
824 # line, but can't be extracted from the frame. I'm not
824 # 100% sure this isn't actually a bug in inspect itself,
825 # 100% sure this isn't actually a bug in inspect itself,
825 # but since there's no info for us to compute with, the
826 # but since there's no info for us to compute with, the
826 # best we can do is report the failure and move on. Here
827 # best we can do is report the failure and move on. Here
827 # we must *not* call any traceback construction again,
828 # we must *not* call any traceback construction again,
828 # because that would mess up use of %debug later on. So we
829 # because that would mess up use of %debug later on. So we
829 # simply report the failure and move on. The only
830 # simply report the failure and move on. The only
830 # limitation will be that this frame won't have locals
831 # limitation will be that this frame won't have locals
831 # listed in the call signature. Quite subtle problem...
832 # listed in the call signature. Quite subtle problem...
832 # I can't think of a good way to validate this in a unit
833 # I can't think of a good way to validate this in a unit
833 # test, but running a script consisting of:
834 # test, but running a script consisting of:
834 # dict( (k,v.strip()) for (k,v) in range(10) )
835 # dict( (k,v.strip()) for (k,v) in range(10) )
835 # will illustrate the error, if this exception catch is
836 # will illustrate the error, if this exception catch is
836 # disabled.
837 # disabled.
837 call = tpl_call_fail % func
838 call = tpl_call_fail % func
838
839
839 # Don't attempt to tokenize binary files.
840 # Don't attempt to tokenize binary files.
840 if file.endswith(('.so', '.pyd', '.dll')):
841 if file.endswith(('.so', '.pyd', '.dll')):
841 frames.append('%s %s\n' % (link,call))
842 frames.append('%s %s\n' % (link,call))
842 continue
843 continue
843 elif file.endswith(('.pyc','.pyo')):
844 elif file.endswith(('.pyc','.pyo')):
844 # Look up the corresponding source file.
845 # Look up the corresponding source file.
845 file = openpy.source_from_cache(file)
846 file = openpy.source_from_cache(file)
846
847
847 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
848 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
848 line = getline(file, lnum[0])
849 line = getline(file, lnum[0])
849 lnum[0] += 1
850 lnum[0] += 1
850 return line
851 return line
851
852
852 # Build the list of names on this line of code where the exception
853 # Build the list of names on this line of code where the exception
853 # occurred.
854 # occurred.
854 try:
855 try:
855 names = []
856 names = []
856 name_cont = False
857 name_cont = False
857
858
858 for token_type, token, start, end, line in generate_tokens(linereader):
859 for token_type, token, start, end, line in generate_tokens(linereader):
859 # build composite names
860 # build composite names
860 if token_type == tokenize.NAME and token not in keyword.kwlist:
861 if token_type == tokenize.NAME and token not in keyword.kwlist:
861 if name_cont:
862 if name_cont:
862 # Continuation of a dotted name
863 # Continuation of a dotted name
863 try:
864 try:
864 names[-1].append(token)
865 names[-1].append(token)
865 except IndexError:
866 except IndexError:
866 names.append([token])
867 names.append([token])
867 name_cont = False
868 name_cont = False
868 else:
869 else:
869 # Regular new names. We append everything, the caller
870 # Regular new names. We append everything, the caller
870 # will be responsible for pruning the list later. It's
871 # will be responsible for pruning the list later. It's
871 # very tricky to try to prune as we go, b/c composite
872 # very tricky to try to prune as we go, b/c composite
872 # names can fool us. The pruning at the end is easy
873 # names can fool us. The pruning at the end is easy
873 # to do (or the caller can print a list with repeated
874 # to do (or the caller can print a list with repeated
874 # names if so desired.
875 # names if so desired.
875 names.append([token])
876 names.append([token])
876 elif token == '.':
877 elif token == '.':
877 name_cont = True
878 name_cont = True
878 elif token_type == tokenize.NEWLINE:
879 elif token_type == tokenize.NEWLINE:
879 break
880 break
880
881
881 except (IndexError, UnicodeDecodeError):
882 except (IndexError, UnicodeDecodeError):
882 # signals exit of tokenizer
883 # signals exit of tokenizer
883 pass
884 pass
884 except tokenize.TokenError as msg:
885 except tokenize.TokenError as msg:
885 _m = ("An unexpected error occurred while tokenizing input\n"
886 _m = ("An unexpected error occurred while tokenizing input\n"
886 "The following traceback may be corrupted or invalid\n"
887 "The following traceback may be corrupted or invalid\n"
887 "The error message is: %s\n" % msg)
888 "The error message is: %s\n" % msg)
888 error(_m)
889 error(_m)
889
890
890 # Join composite names (e.g. "dict.fromkeys")
891 # Join composite names (e.g. "dict.fromkeys")
891 names = ['.'.join(n) for n in names]
892 names = ['.'.join(n) for n in names]
892 # prune names list of duplicates, but keep the right order
893 # prune names list of duplicates, but keep the right order
893 unique_names = uniq_stable(names)
894 unique_names = uniq_stable(names)
894
895
895 # Start loop over vars
896 # Start loop over vars
896 lvals = []
897 lvals = []
897 if self.include_vars:
898 if self.include_vars:
898 for name_full in unique_names:
899 for name_full in unique_names:
899 name_base = name_full.split('.',1)[0]
900 name_base = name_full.split('.',1)[0]
900 if name_base in frame.f_code.co_varnames:
901 if name_base in frame.f_code.co_varnames:
901 if name_base in locals:
902 if name_base in locals:
902 try:
903 try:
903 value = repr(eval(name_full,locals))
904 value = repr(eval(name_full,locals))
904 except:
905 except:
905 value = undefined
906 value = undefined
906 else:
907 else:
907 value = undefined
908 value = undefined
908 name = tpl_local_var % name_full
909 name = tpl_local_var % name_full
909 else:
910 else:
910 if name_base in frame.f_globals:
911 if name_base in frame.f_globals:
911 try:
912 try:
912 value = repr(eval(name_full,frame.f_globals))
913 value = repr(eval(name_full,frame.f_globals))
913 except:
914 except:
914 value = undefined
915 value = undefined
915 else:
916 else:
916 value = undefined
917 value = undefined
917 name = tpl_global_var % name_full
918 name = tpl_global_var % name_full
918 lvals.append(tpl_name_val % (name,value))
919 lvals.append(tpl_name_val % (name,value))
919 if lvals:
920 if lvals:
920 lvals = '%s%s' % (indent,em_normal.join(lvals))
921 lvals = '%s%s' % (indent,em_normal.join(lvals))
921 else:
922 else:
922 lvals = ''
923 lvals = ''
923
924
924 level = '%s %s\n' % (link,call)
925 level = '%s %s\n' % (link,call)
925
926
926 if index is None:
927 if index is None:
927 frames.append(level)
928 frames.append(level)
928 else:
929 else:
929 frames.append('%s%s' % (level,''.join(
930 frames.append('%s%s' % (level,''.join(
930 _format_traceback_lines(lnum,index,lines,Colors,lvals,
931 _format_traceback_lines(lnum,index,lines,Colors,lvals,
931 col_scheme))))
932 col_scheme))))
932
933
933 # Get (safely) a string form of the exception info
934 # Get (safely) a string form of the exception info
934 try:
935 try:
935 etype_str,evalue_str = map(str,(etype,evalue))
936 etype_str,evalue_str = map(str,(etype,evalue))
936 except:
937 except:
937 # User exception is improperly defined.
938 # User exception is improperly defined.
938 etype,evalue = str,sys.exc_info()[:2]
939 etype,evalue = str,sys.exc_info()[:2]
939 etype_str,evalue_str = map(str,(etype,evalue))
940 etype_str,evalue_str = map(str,(etype,evalue))
940 # ... and format it
941 # ... and format it
941 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
942 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
942 ColorsNormal, py3compat.cast_unicode(evalue_str))]
943 ColorsNormal, py3compat.cast_unicode(evalue_str))]
943 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
944 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
944 try:
945 try:
945 names = [w for w in dir(evalue) if isinstance(w, basestring)]
946 names = [w for w in dir(evalue) if isinstance(w, basestring)]
946 except:
947 except:
947 # Every now and then, an object with funny inernals blows up
948 # Every now and then, an object with funny inernals blows up
948 # when dir() is called on it. We do the best we can to report
949 # when dir() is called on it. We do the best we can to report
949 # the problem and continue
950 # the problem and continue
950 _m = '%sException reporting error (object with broken dir())%s:'
951 _m = '%sException reporting error (object with broken dir())%s:'
951 exception.append(_m % (Colors.excName,ColorsNormal))
952 exception.append(_m % (Colors.excName,ColorsNormal))
952 etype_str,evalue_str = map(str,sys.exc_info()[:2])
953 etype_str,evalue_str = map(str,sys.exc_info()[:2])
953 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
954 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
954 ColorsNormal, py3compat.cast_unicode(evalue_str)))
955 ColorsNormal, py3compat.cast_unicode(evalue_str)))
955 names = []
956 names = []
956 for name in names:
957 for name in names:
957 value = text_repr(getattr(evalue, name))
958 value = text_repr(getattr(evalue, name))
958 exception.append('\n%s%s = %s' % (indent, name, value))
959 exception.append('\n%s%s = %s' % (indent, name, value))
959
960
960 # vds: >>
961 # vds: >>
961 if records:
962 if records:
962 filepath, lnum = records[-1][1:3]
963 filepath, lnum = records[-1][1:3]
963 #print "file:", str(file), "linenb", str(lnum) # dbg
964 #print "file:", str(file), "linenb", str(lnum) # dbg
964 filepath = os.path.abspath(filepath)
965 filepath = os.path.abspath(filepath)
965 ipinst = get_ipython()
966 ipinst = get_ipython()
966 if ipinst is not None:
967 if ipinst is not None:
967 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
968 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
968 # vds: <<
969 # vds: <<
969
970
970 # return all our info assembled as a single string
971 # return all our info assembled as a single string
971 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
972 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
972 return [head] + frames + [''.join(exception[0])]
973 return [head] + frames + [''.join(exception[0])]
973
974
974 def debugger(self,force=False):
975 def debugger(self,force=False):
975 """Call up the pdb debugger if desired, always clean up the tb
976 """Call up the pdb debugger if desired, always clean up the tb
976 reference.
977 reference.
977
978
978 Keywords:
979 Keywords:
979
980
980 - force(False): by default, this routine checks the instance call_pdb
981 - force(False): by default, this routine checks the instance call_pdb
981 flag and does not actually invoke the debugger if the flag is false.
982 flag and does not actually invoke the debugger if the flag is false.
982 The 'force' option forces the debugger to activate even if the flag
983 The 'force' option forces the debugger to activate even if the flag
983 is false.
984 is false.
984
985
985 If the call_pdb flag is set, the pdb interactive debugger is
986 If the call_pdb flag is set, the pdb interactive debugger is
986 invoked. In all cases, the self.tb reference to the current traceback
987 invoked. In all cases, the self.tb reference to the current traceback
987 is deleted to prevent lingering references which hamper memory
988 is deleted to prevent lingering references which hamper memory
988 management.
989 management.
989
990
990 Note that each call to pdb() does an 'import readline', so if your app
991 Note that each call to pdb() does an 'import readline', so if your app
991 requires a special setup for the readline completers, you'll have to
992 requires a special setup for the readline completers, you'll have to
992 fix that by hand after invoking the exception handler."""
993 fix that by hand after invoking the exception handler."""
993
994
994 if force or self.call_pdb:
995 if force or self.call_pdb:
995 if self.pdb is None:
996 if self.pdb is None:
996 self.pdb = debugger.Pdb(
997 self.pdb = debugger.Pdb(
997 self.color_scheme_table.active_scheme_name)
998 self.color_scheme_table.active_scheme_name)
998 # the system displayhook may have changed, restore the original
999 # the system displayhook may have changed, restore the original
999 # for pdb
1000 # for pdb
1000 display_trap = DisplayTrap(hook=sys.__displayhook__)
1001 display_trap = DisplayTrap(hook=sys.__displayhook__)
1001 with display_trap:
1002 with display_trap:
1002 self.pdb.reset()
1003 self.pdb.reset()
1003 # Find the right frame so we don't pop up inside ipython itself
1004 # Find the right frame so we don't pop up inside ipython itself
1004 if hasattr(self,'tb') and self.tb is not None:
1005 if hasattr(self,'tb') and self.tb is not None:
1005 etb = self.tb
1006 etb = self.tb
1006 else:
1007 else:
1007 etb = self.tb = sys.last_traceback
1008 etb = self.tb = sys.last_traceback
1008 while self.tb is not None and self.tb.tb_next is not None:
1009 while self.tb is not None and self.tb.tb_next is not None:
1009 self.tb = self.tb.tb_next
1010 self.tb = self.tb.tb_next
1010 if etb and etb.tb_next:
1011 if etb and etb.tb_next:
1011 etb = etb.tb_next
1012 etb = etb.tb_next
1012 self.pdb.botframe = etb.tb_frame
1013 self.pdb.botframe = etb.tb_frame
1013 self.pdb.interaction(self.tb.tb_frame, self.tb)
1014 self.pdb.interaction(self.tb.tb_frame, self.tb)
1014
1015
1015 if hasattr(self,'tb'):
1016 if hasattr(self,'tb'):
1016 del self.tb
1017 del self.tb
1017
1018
1018 def handler(self, info=None):
1019 def handler(self, info=None):
1019 (etype, evalue, etb) = info or sys.exc_info()
1020 (etype, evalue, etb) = info or sys.exc_info()
1020 self.tb = etb
1021 self.tb = etb
1021 ostream = self.ostream
1022 ostream = self.ostream
1022 ostream.flush()
1023 ostream.flush()
1023 ostream.write(self.text(etype, evalue, etb))
1024 ostream.write(self.text(etype, evalue, etb))
1024 ostream.write('\n')
1025 ostream.write('\n')
1025 ostream.flush()
1026 ostream.flush()
1026
1027
1027 # Changed so an instance can just be called as VerboseTB_inst() and print
1028 # Changed so an instance can just be called as VerboseTB_inst() and print
1028 # out the right info on its own.
1029 # out the right info on its own.
1029 def __call__(self, etype=None, evalue=None, etb=None):
1030 def __call__(self, etype=None, evalue=None, etb=None):
1030 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1031 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1031 if etb is None:
1032 if etb is None:
1032 self.handler()
1033 self.handler()
1033 else:
1034 else:
1034 self.handler((etype, evalue, etb))
1035 self.handler((etype, evalue, etb))
1035 try:
1036 try:
1036 self.debugger()
1037 self.debugger()
1037 except KeyboardInterrupt:
1038 except KeyboardInterrupt:
1038 print "\nKeyboardInterrupt"
1039 print("\nKeyboardInterrupt")
1039
1040
1040 #----------------------------------------------------------------------------
1041 #----------------------------------------------------------------------------
1041 class FormattedTB(VerboseTB, ListTB):
1042 class FormattedTB(VerboseTB, ListTB):
1042 """Subclass ListTB but allow calling with a traceback.
1043 """Subclass ListTB but allow calling with a traceback.
1043
1044
1044 It can thus be used as a sys.excepthook for Python > 2.1.
1045 It can thus be used as a sys.excepthook for Python > 2.1.
1045
1046
1046 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1047 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1047
1048
1048 Allows a tb_offset to be specified. This is useful for situations where
1049 Allows a tb_offset to be specified. This is useful for situations where
1049 one needs to remove a number of topmost frames from the traceback (such as
1050 one needs to remove a number of topmost frames from the traceback (such as
1050 occurs with python programs that themselves execute other python code,
1051 occurs with python programs that themselves execute other python code,
1051 like Python shells). """
1052 like Python shells). """
1052
1053
1053 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1054 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1054 ostream=None,
1055 ostream=None,
1055 tb_offset=0, long_header=False, include_vars=False,
1056 tb_offset=0, long_header=False, include_vars=False,
1056 check_cache=None):
1057 check_cache=None):
1057
1058
1058 # NEVER change the order of this list. Put new modes at the end:
1059 # NEVER change the order of this list. Put new modes at the end:
1059 self.valid_modes = ['Plain','Context','Verbose']
1060 self.valid_modes = ['Plain','Context','Verbose']
1060 self.verbose_modes = self.valid_modes[1:3]
1061 self.verbose_modes = self.valid_modes[1:3]
1061
1062
1062 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1063 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1063 ostream=ostream, tb_offset=tb_offset,
1064 ostream=ostream, tb_offset=tb_offset,
1064 long_header=long_header, include_vars=include_vars,
1065 long_header=long_header, include_vars=include_vars,
1065 check_cache=check_cache)
1066 check_cache=check_cache)
1066
1067
1067 # Different types of tracebacks are joined with different separators to
1068 # Different types of tracebacks are joined with different separators to
1068 # form a single string. They are taken from this dict
1069 # form a single string. They are taken from this dict
1069 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1070 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1070 # set_mode also sets the tb_join_char attribute
1071 # set_mode also sets the tb_join_char attribute
1071 self.set_mode(mode)
1072 self.set_mode(mode)
1072
1073
1073 def _extract_tb(self,tb):
1074 def _extract_tb(self,tb):
1074 if tb:
1075 if tb:
1075 return traceback.extract_tb(tb)
1076 return traceback.extract_tb(tb)
1076 else:
1077 else:
1077 return None
1078 return None
1078
1079
1079 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1080 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1080 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1081 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1081 mode = self.mode
1082 mode = self.mode
1082 if mode in self.verbose_modes:
1083 if mode in self.verbose_modes:
1083 # Verbose modes need a full traceback
1084 # Verbose modes need a full traceback
1084 return VerboseTB.structured_traceback(
1085 return VerboseTB.structured_traceback(
1085 self, etype, value, tb, tb_offset, context
1086 self, etype, value, tb, tb_offset, context
1086 )
1087 )
1087 else:
1088 else:
1088 # We must check the source cache because otherwise we can print
1089 # We must check the source cache because otherwise we can print
1089 # out-of-date source code.
1090 # out-of-date source code.
1090 self.check_cache()
1091 self.check_cache()
1091 # Now we can extract and format the exception
1092 # Now we can extract and format the exception
1092 elist = self._extract_tb(tb)
1093 elist = self._extract_tb(tb)
1093 return ListTB.structured_traceback(
1094 return ListTB.structured_traceback(
1094 self, etype, value, elist, tb_offset, context
1095 self, etype, value, elist, tb_offset, context
1095 )
1096 )
1096
1097
1097 def stb2text(self, stb):
1098 def stb2text(self, stb):
1098 """Convert a structured traceback (a list) to a string."""
1099 """Convert a structured traceback (a list) to a string."""
1099 return self.tb_join_char.join(stb)
1100 return self.tb_join_char.join(stb)
1100
1101
1101
1102
1102 def set_mode(self,mode=None):
1103 def set_mode(self,mode=None):
1103 """Switch to the desired mode.
1104 """Switch to the desired mode.
1104
1105
1105 If mode is not specified, cycles through the available modes."""
1106 If mode is not specified, cycles through the available modes."""
1106
1107
1107 if not mode:
1108 if not mode:
1108 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1109 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1109 len(self.valid_modes)
1110 len(self.valid_modes)
1110 self.mode = self.valid_modes[new_idx]
1111 self.mode = self.valid_modes[new_idx]
1111 elif mode not in self.valid_modes:
1112 elif mode not in self.valid_modes:
1112 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1113 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1113 'Valid modes: '+str(self.valid_modes))
1114 'Valid modes: '+str(self.valid_modes))
1114 else:
1115 else:
1115 self.mode = mode
1116 self.mode = mode
1116 # include variable details only in 'Verbose' mode
1117 # include variable details only in 'Verbose' mode
1117 self.include_vars = (self.mode == self.valid_modes[2])
1118 self.include_vars = (self.mode == self.valid_modes[2])
1118 # Set the join character for generating text tracebacks
1119 # Set the join character for generating text tracebacks
1119 self.tb_join_char = self._join_chars[self.mode]
1120 self.tb_join_char = self._join_chars[self.mode]
1120
1121
1121 # some convenient shorcuts
1122 # some convenient shorcuts
1122 def plain(self):
1123 def plain(self):
1123 self.set_mode(self.valid_modes[0])
1124 self.set_mode(self.valid_modes[0])
1124
1125
1125 def context(self):
1126 def context(self):
1126 self.set_mode(self.valid_modes[1])
1127 self.set_mode(self.valid_modes[1])
1127
1128
1128 def verbose(self):
1129 def verbose(self):
1129 self.set_mode(self.valid_modes[2])
1130 self.set_mode(self.valid_modes[2])
1130
1131
1131 #----------------------------------------------------------------------------
1132 #----------------------------------------------------------------------------
1132 class AutoFormattedTB(FormattedTB):
1133 class AutoFormattedTB(FormattedTB):
1133 """A traceback printer which can be called on the fly.
1134 """A traceback printer which can be called on the fly.
1134
1135
1135 It will find out about exceptions by itself.
1136 It will find out about exceptions by itself.
1136
1137
1137 A brief example::
1138 A brief example::
1138
1139
1139 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1140 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1140 try:
1141 try:
1141 ...
1142 ...
1142 except:
1143 except:
1143 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1144 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1144 """
1145 """
1145
1146
1146 def __call__(self,etype=None,evalue=None,etb=None,
1147 def __call__(self,etype=None,evalue=None,etb=None,
1147 out=None,tb_offset=None):
1148 out=None,tb_offset=None):
1148 """Print out a formatted exception traceback.
1149 """Print out a formatted exception traceback.
1149
1150
1150 Optional arguments:
1151 Optional arguments:
1151 - out: an open file-like object to direct output to.
1152 - out: an open file-like object to direct output to.
1152
1153
1153 - tb_offset: the number of frames to skip over in the stack, on a
1154 - tb_offset: the number of frames to skip over in the stack, on a
1154 per-call basis (this overrides temporarily the instance's tb_offset
1155 per-call basis (this overrides temporarily the instance's tb_offset
1155 given at initialization time. """
1156 given at initialization time. """
1156
1157
1157
1158
1158 if out is None:
1159 if out is None:
1159 out = self.ostream
1160 out = self.ostream
1160 out.flush()
1161 out.flush()
1161 out.write(self.text(etype, evalue, etb, tb_offset))
1162 out.write(self.text(etype, evalue, etb, tb_offset))
1162 out.write('\n')
1163 out.write('\n')
1163 out.flush()
1164 out.flush()
1164 # FIXME: we should remove the auto pdb behavior from here and leave
1165 # FIXME: we should remove the auto pdb behavior from here and leave
1165 # that to the clients.
1166 # that to the clients.
1166 try:
1167 try:
1167 self.debugger()
1168 self.debugger()
1168 except KeyboardInterrupt:
1169 except KeyboardInterrupt:
1169 print "\nKeyboardInterrupt"
1170 print("\nKeyboardInterrupt")
1170
1171
1171 def structured_traceback(self, etype=None, value=None, tb=None,
1172 def structured_traceback(self, etype=None, value=None, tb=None,
1172 tb_offset=None, context=5):
1173 tb_offset=None, context=5):
1173 if etype is None:
1174 if etype is None:
1174 etype,value,tb = sys.exc_info()
1175 etype,value,tb = sys.exc_info()
1175 self.tb = tb
1176 self.tb = tb
1176 return FormattedTB.structured_traceback(
1177 return FormattedTB.structured_traceback(
1177 self, etype, value, tb, tb_offset, context)
1178 self, etype, value, tb, tb_offset, context)
1178
1179
1179 #---------------------------------------------------------------------------
1180 #---------------------------------------------------------------------------
1180
1181
1181 # A simple class to preserve Nathan's original functionality.
1182 # A simple class to preserve Nathan's original functionality.
1182 class ColorTB(FormattedTB):
1183 class ColorTB(FormattedTB):
1183 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1184 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1184 def __init__(self,color_scheme='Linux',call_pdb=0):
1185 def __init__(self,color_scheme='Linux',call_pdb=0):
1185 FormattedTB.__init__(self,color_scheme=color_scheme,
1186 FormattedTB.__init__(self,color_scheme=color_scheme,
1186 call_pdb=call_pdb)
1187 call_pdb=call_pdb)
1187
1188
1188
1189
1189 class SyntaxTB(ListTB):
1190 class SyntaxTB(ListTB):
1190 """Extension which holds some state: the last exception value"""
1191 """Extension which holds some state: the last exception value"""
1191
1192
1192 def __init__(self,color_scheme = 'NoColor'):
1193 def __init__(self,color_scheme = 'NoColor'):
1193 ListTB.__init__(self,color_scheme)
1194 ListTB.__init__(self,color_scheme)
1194 self.last_syntax_error = None
1195 self.last_syntax_error = None
1195
1196
1196 def __call__(self, etype, value, elist):
1197 def __call__(self, etype, value, elist):
1197 self.last_syntax_error = value
1198 self.last_syntax_error = value
1198 ListTB.__call__(self,etype,value,elist)
1199 ListTB.__call__(self,etype,value,elist)
1199
1200
1200 def structured_traceback(self, etype, value, elist, tb_offset=None,
1201 def structured_traceback(self, etype, value, elist, tb_offset=None,
1201 context=5):
1202 context=5):
1202 # If the source file has been edited, the line in the syntax error can
1203 # If the source file has been edited, the line in the syntax error can
1203 # be wrong (retrieved from an outdated cache). This replaces it with
1204 # be wrong (retrieved from an outdated cache). This replaces it with
1204 # the current value.
1205 # the current value.
1205 if isinstance(value, SyntaxError) \
1206 if isinstance(value, SyntaxError) \
1206 and isinstance(value.filename, py3compat.string_types) \
1207 and isinstance(value.filename, py3compat.string_types) \
1207 and isinstance(value.lineno, int):
1208 and isinstance(value.lineno, int):
1208 linecache.checkcache(value.filename)
1209 linecache.checkcache(value.filename)
1209 newtext = ulinecache.getline(value.filename, value.lineno)
1210 newtext = ulinecache.getline(value.filename, value.lineno)
1210 if newtext:
1211 if newtext:
1211 value.text = newtext
1212 value.text = newtext
1212 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1213 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1213 tb_offset=tb_offset, context=context)
1214 tb_offset=tb_offset, context=context)
1214
1215
1215 def clear_err_state(self):
1216 def clear_err_state(self):
1216 """Return the current error state and clear it"""
1217 """Return the current error state and clear it"""
1217 e = self.last_syntax_error
1218 e = self.last_syntax_error
1218 self.last_syntax_error = None
1219 self.last_syntax_error = None
1219 return e
1220 return e
1220
1221
1221 def stb2text(self, stb):
1222 def stb2text(self, stb):
1222 """Convert a structured traceback (a list) to a string."""
1223 """Convert a structured traceback (a list) to a string."""
1223 return ''.join(stb)
1224 return ''.join(stb)
1224
1225
1225
1226
1226 #----------------------------------------------------------------------------
1227 #----------------------------------------------------------------------------
1227 # module testing (minimal)
1228 # module testing (minimal)
1228 if __name__ == "__main__":
1229 if __name__ == "__main__":
1229 def spam(c, d_e):
1230 def spam(c, d_e):
1230 (d, e) = d_e
1231 (d, e) = d_e
1231 x = c + d
1232 x = c + d
1232 y = c * d
1233 y = c * d
1233 foo(x, y)
1234 foo(x, y)
1234
1235
1235 def foo(a, b, bar=1):
1236 def foo(a, b, bar=1):
1236 eggs(a, b + bar)
1237 eggs(a, b + bar)
1237
1238
1238 def eggs(f, g, z=globals()):
1239 def eggs(f, g, z=globals()):
1239 h = f + g
1240 h = f + g
1240 i = f - g
1241 i = f - g
1241 return h / i
1242 return h / i
1242
1243
1243 print ''
1244 print('')
1244 print '*** Before ***'
1245 print('*** Before ***')
1245 try:
1246 try:
1246 print spam(1, (2, 3))
1247 print(spam(1, (2, 3)))
1247 except:
1248 except:
1248 traceback.print_exc()
1249 traceback.print_exc()
1249 print ''
1250 print('')
1250
1251
1251 handler = ColorTB()
1252 handler = ColorTB()
1252 print '*** ColorTB ***'
1253 print('*** ColorTB ***')
1253 try:
1254 try:
1254 print spam(1, (2, 3))
1255 print(spam(1, (2, 3)))
1255 except:
1256 except:
1256 handler(*sys.exc_info())
1257 handler(*sys.exc_info())
1257 print ''
1258 print('')
1258
1259
1259 handler = VerboseTB()
1260 handler = VerboseTB()
1260 print '*** VerboseTB ***'
1261 print('*** VerboseTB ***')
1261 try:
1262 try:
1262 print spam(1, (2, 3))
1263 print(spam(1, (2, 3)))
1263 except:
1264 except:
1264 handler(*sys.exc_info())
1265 handler(*sys.exc_info())
1265 print ''
1266 print('')
1266
1267
@@ -1,694 +1,695 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ======
3 ======
4 Rmagic
4 Rmagic
5 ======
5 ======
6
6
7 Magic command interface for interactive work with R via rpy2
7 Magic command interface for interactive work with R via rpy2
8
8
9 .. note::
9 .. note::
10
10
11 The ``rpy2`` package needs to be installed separately. It
11 The ``rpy2`` package needs to be installed separately. It
12 can be obtained using ``easy_install`` or ``pip``.
12 can be obtained using ``easy_install`` or ``pip``.
13
13
14 You will also need a working copy of R.
14 You will also need a working copy of R.
15
15
16 Usage
16 Usage
17 =====
17 =====
18
18
19 To enable the magics below, execute ``%load_ext rmagic``.
19 To enable the magics below, execute ``%load_ext rmagic``.
20
20
21 ``%R``
21 ``%R``
22
22
23 {R_DOC}
23 {R_DOC}
24
24
25 ``%Rpush``
25 ``%Rpush``
26
26
27 {RPUSH_DOC}
27 {RPUSH_DOC}
28
28
29 ``%Rpull``
29 ``%Rpull``
30
30
31 {RPULL_DOC}
31 {RPULL_DOC}
32
32
33 ``%Rget``
33 ``%Rget``
34
34
35 {RGET_DOC}
35 {RGET_DOC}
36
36
37 """
37 """
38 from __future__ import print_function
38
39
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40 # Copyright (C) 2012 The IPython Development Team
41 # Copyright (C) 2012 The IPython Development Team
41 #
42 #
42 # Distributed under the terms of the BSD License. The full license is in
43 # Distributed under the terms of the BSD License. The full license is in
43 # the file COPYING, distributed as part of this software.
44 # the file COPYING, distributed as part of this software.
44 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
45
46
46 import sys
47 import sys
47 import tempfile
48 import tempfile
48 from glob import glob
49 from glob import glob
49 from shutil import rmtree
50 from shutil import rmtree
50
51
51 # numpy and rpy2 imports
52 # numpy and rpy2 imports
52
53
53 import numpy as np
54 import numpy as np
54
55
55 import rpy2.rinterface as ri
56 import rpy2.rinterface as ri
56 import rpy2.robjects as ro
57 import rpy2.robjects as ro
57 try:
58 try:
58 from rpy2.robjects import pandas2ri
59 from rpy2.robjects import pandas2ri
59 pandas2ri.activate()
60 pandas2ri.activate()
60 except ImportError:
61 except ImportError:
61 pandas2ri = None
62 pandas2ri = None
62 from rpy2.robjects import numpy2ri
63 from rpy2.robjects import numpy2ri
63 numpy2ri.activate()
64 numpy2ri.activate()
64
65
65 # IPython imports
66 # IPython imports
66
67
67 from IPython.core.displaypub import publish_display_data
68 from IPython.core.displaypub import publish_display_data
68 from IPython.core.magic import (Magics, magics_class, line_magic,
69 from IPython.core.magic import (Magics, magics_class, line_magic,
69 line_cell_magic, needs_local_scope)
70 line_cell_magic, needs_local_scope)
70 from IPython.testing.skipdoctest import skip_doctest
71 from IPython.testing.skipdoctest import skip_doctest
71 from IPython.core.magic_arguments import (
72 from IPython.core.magic_arguments import (
72 argument, magic_arguments, parse_argstring
73 argument, magic_arguments, parse_argstring
73 )
74 )
74 from IPython.external.simplegeneric import generic
75 from IPython.external.simplegeneric import generic
75 from IPython.utils.py3compat import (str_to_unicode, unicode_to_str, PY3,
76 from IPython.utils.py3compat import (str_to_unicode, unicode_to_str, PY3,
76 unicode_type)
77 unicode_type)
77
78
78 class RInterpreterError(ri.RRuntimeError):
79 class RInterpreterError(ri.RRuntimeError):
79 """An error when running R code in a %%R magic cell."""
80 """An error when running R code in a %%R magic cell."""
80 def __init__(self, line, err, stdout):
81 def __init__(self, line, err, stdout):
81 self.line = line
82 self.line = line
82 self.err = err.rstrip()
83 self.err = err.rstrip()
83 self.stdout = stdout.rstrip()
84 self.stdout = stdout.rstrip()
84
85
85 def __unicode__(self):
86 def __unicode__(self):
86 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
87 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
87 (self.line, self.err)
88 (self.line, self.err)
88 if self.stdout and (self.stdout != self.err):
89 if self.stdout and (self.stdout != self.err):
89 s += '\nR stdout:\n' + self.stdout
90 s += '\nR stdout:\n' + self.stdout
90 return s
91 return s
91
92
92 if PY3:
93 if PY3:
93 __str__ = __unicode__
94 __str__ = __unicode__
94 else:
95 else:
95 def __str__(self):
96 def __str__(self):
96 return unicode_to_str(unicode(self), 'utf-8')
97 return unicode_to_str(unicode(self), 'utf-8')
97
98
98 def Rconverter(Robj, dataframe=False):
99 def Rconverter(Robj, dataframe=False):
99 """
100 """
100 Convert an object in R's namespace to one suitable
101 Convert an object in R's namespace to one suitable
101 for ipython's namespace.
102 for ipython's namespace.
102
103
103 For a data.frame, it tries to return a structured array.
104 For a data.frame, it tries to return a structured array.
104 It first checks for colnames, then names.
105 It first checks for colnames, then names.
105 If all are NULL, it returns np.asarray(Robj), else
106 If all are NULL, it returns np.asarray(Robj), else
106 it tries to construct a recarray
107 it tries to construct a recarray
107
108
108 Parameters
109 Parameters
109 ----------
110 ----------
110
111
111 Robj: an R object returned from rpy2
112 Robj: an R object returned from rpy2
112 """
113 """
113 is_data_frame = ro.r('is.data.frame')
114 is_data_frame = ro.r('is.data.frame')
114 colnames = ro.r('colnames')
115 colnames = ro.r('colnames')
115 rownames = ro.r('rownames') # with pandas, these could be used for the index
116 rownames = ro.r('rownames') # with pandas, these could be used for the index
116 names = ro.r('names')
117 names = ro.r('names')
117
118
118 if dataframe:
119 if dataframe:
119 as_data_frame = ro.r('as.data.frame')
120 as_data_frame = ro.r('as.data.frame')
120 cols = colnames(Robj)
121 cols = colnames(Robj)
121 _names = names(Robj)
122 _names = names(Robj)
122 if cols != ri.NULL:
123 if cols != ri.NULL:
123 Robj = as_data_frame(Robj)
124 Robj = as_data_frame(Robj)
124 names = tuple(np.array(cols))
125 names = tuple(np.array(cols))
125 elif _names != ri.NULL:
126 elif _names != ri.NULL:
126 names = tuple(np.array(_names))
127 names = tuple(np.array(_names))
127 else: # failed to find names
128 else: # failed to find names
128 return np.asarray(Robj)
129 return np.asarray(Robj)
129 Robj = np.rec.fromarrays(Robj, names = names)
130 Robj = np.rec.fromarrays(Robj, names = names)
130 return np.asarray(Robj)
131 return np.asarray(Robj)
131
132
132 @generic
133 @generic
133 def pyconverter(pyobj):
134 def pyconverter(pyobj):
134 """Convert Python objects to R objects. Add types using the decorator:
135 """Convert Python objects to R objects. Add types using the decorator:
135
136
136 @pyconverter.when_type
137 @pyconverter.when_type
137 """
138 """
138 return pyobj
139 return pyobj
139
140
140 # The default conversion for lists seems to make them a nested list. That has
141 # The default conversion for lists seems to make them a nested list. That has
141 # some advantages, but is rarely convenient, so for interactive use, we convert
142 # some advantages, but is rarely convenient, so for interactive use, we convert
142 # lists to a numpy array, which becomes an R vector.
143 # lists to a numpy array, which becomes an R vector.
143 @pyconverter.when_type(list)
144 @pyconverter.when_type(list)
144 def pyconverter_list(pyobj):
145 def pyconverter_list(pyobj):
145 return np.asarray(pyobj)
146 return np.asarray(pyobj)
146
147
147 if pandas2ri is None:
148 if pandas2ri is None:
148 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
149 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
149 # conversion function.
150 # conversion function.
150 try:
151 try:
151 from pandas import DataFrame
152 from pandas import DataFrame
152 from pandas.rpy.common import convert_to_r_dataframe
153 from pandas.rpy.common import convert_to_r_dataframe
153 @pyconverter.when_type(DataFrame)
154 @pyconverter.when_type(DataFrame)
154 def pyconverter_dataframe(pyobj):
155 def pyconverter_dataframe(pyobj):
155 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
156 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
156 except ImportError:
157 except ImportError:
157 pass
158 pass
158
159
159 @magics_class
160 @magics_class
160 class RMagics(Magics):
161 class RMagics(Magics):
161 """A set of magics useful for interactive work with R via rpy2.
162 """A set of magics useful for interactive work with R via rpy2.
162 """
163 """
163
164
164 def __init__(self, shell, Rconverter=Rconverter,
165 def __init__(self, shell, Rconverter=Rconverter,
165 pyconverter=pyconverter,
166 pyconverter=pyconverter,
166 cache_display_data=False):
167 cache_display_data=False):
167 """
168 """
168 Parameters
169 Parameters
169 ----------
170 ----------
170
171
171 shell : IPython shell
172 shell : IPython shell
172
173
173 Rconverter : callable
174 Rconverter : callable
174 To be called on values taken from R before putting them in the
175 To be called on values taken from R before putting them in the
175 IPython namespace.
176 IPython namespace.
176
177
177 pyconverter : callable
178 pyconverter : callable
178 To be called on values in ipython namespace before
179 To be called on values in ipython namespace before
179 assigning to variables in rpy2.
180 assigning to variables in rpy2.
180
181
181 cache_display_data : bool
182 cache_display_data : bool
182 If True, the published results of the final call to R are
183 If True, the published results of the final call to R are
183 cached in the variable 'display_cache'.
184 cached in the variable 'display_cache'.
184
185
185 """
186 """
186 super(RMagics, self).__init__(shell)
187 super(RMagics, self).__init__(shell)
187 self.cache_display_data = cache_display_data
188 self.cache_display_data = cache_display_data
188
189
189 self.r = ro.R()
190 self.r = ro.R()
190
191
191 self.Rstdout_cache = []
192 self.Rstdout_cache = []
192 self.pyconverter = pyconverter
193 self.pyconverter = pyconverter
193 self.Rconverter = Rconverter
194 self.Rconverter = Rconverter
194
195
195 def eval(self, line):
196 def eval(self, line):
196 '''
197 '''
197 Parse and evaluate a line of R code with rpy2.
198 Parse and evaluate a line of R code with rpy2.
198 Returns the output to R's stdout() connection,
199 Returns the output to R's stdout() connection,
199 the value generated by evaluating the code, and a
200 the value generated by evaluating the code, and a
200 boolean indicating whether the return value would be
201 boolean indicating whether the return value would be
201 visible if the line of code were evaluated in an R REPL.
202 visible if the line of code were evaluated in an R REPL.
202
203
203 R Code evaluation and visibility determination are
204 R Code evaluation and visibility determination are
204 done via an R call of the form withVisible({<code>})
205 done via an R call of the form withVisible({<code>})
205
206
206 '''
207 '''
207 old_writeconsole = ri.get_writeconsole()
208 old_writeconsole = ri.get_writeconsole()
208 ri.set_writeconsole(self.write_console)
209 ri.set_writeconsole(self.write_console)
209 try:
210 try:
210 res = ro.r("withVisible({%s})" % line)
211 res = ro.r("withVisible({%s})" % line)
211 value = res[0] #value (R object)
212 value = res[0] #value (R object)
212 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
213 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
213 except (ri.RRuntimeError, ValueError) as exception:
214 except (ri.RRuntimeError, ValueError) as exception:
214 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
215 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
215 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
216 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
216 text_output = self.flush()
217 text_output = self.flush()
217 ri.set_writeconsole(old_writeconsole)
218 ri.set_writeconsole(old_writeconsole)
218 return text_output, value, visible
219 return text_output, value, visible
219
220
220 def write_console(self, output):
221 def write_console(self, output):
221 '''
222 '''
222 A hook to capture R's stdout in a cache.
223 A hook to capture R's stdout in a cache.
223 '''
224 '''
224 self.Rstdout_cache.append(output)
225 self.Rstdout_cache.append(output)
225
226
226 def flush(self):
227 def flush(self):
227 '''
228 '''
228 Flush R's stdout cache to a string, returning the string.
229 Flush R's stdout cache to a string, returning the string.
229 '''
230 '''
230 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
231 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
231 self.Rstdout_cache = []
232 self.Rstdout_cache = []
232 return value
233 return value
233
234
234 @skip_doctest
235 @skip_doctest
235 @needs_local_scope
236 @needs_local_scope
236 @line_magic
237 @line_magic
237 def Rpush(self, line, local_ns=None):
238 def Rpush(self, line, local_ns=None):
238 '''
239 '''
239 A line-level magic for R that pushes
240 A line-level magic for R that pushes
240 variables from python to rpy2. The line should be made up
241 variables from python to rpy2. The line should be made up
241 of whitespace separated variable names in the IPython
242 of whitespace separated variable names in the IPython
242 namespace::
243 namespace::
243
244
244 In [7]: import numpy as np
245 In [7]: import numpy as np
245
246
246 In [8]: X = np.array([4.5,6.3,7.9])
247 In [8]: X = np.array([4.5,6.3,7.9])
247
248
248 In [9]: X.mean()
249 In [9]: X.mean()
249 Out[9]: 6.2333333333333343
250 Out[9]: 6.2333333333333343
250
251
251 In [10]: %Rpush X
252 In [10]: %Rpush X
252
253
253 In [11]: %R mean(X)
254 In [11]: %R mean(X)
254 Out[11]: array([ 6.23333333])
255 Out[11]: array([ 6.23333333])
255
256
256 '''
257 '''
257 if local_ns is None:
258 if local_ns is None:
258 local_ns = {}
259 local_ns = {}
259
260
260 inputs = line.split(' ')
261 inputs = line.split(' ')
261 for input in inputs:
262 for input in inputs:
262 try:
263 try:
263 val = local_ns[input]
264 val = local_ns[input]
264 except KeyError:
265 except KeyError:
265 try:
266 try:
266 val = self.shell.user_ns[input]
267 val = self.shell.user_ns[input]
267 except KeyError:
268 except KeyError:
268 # reraise the KeyError as a NameError so that it looks like
269 # reraise the KeyError as a NameError so that it looks like
269 # the standard python behavior when you use an unnamed
270 # the standard python behavior when you use an unnamed
270 # variable
271 # variable
271 raise NameError("name '%s' is not defined" % input)
272 raise NameError("name '%s' is not defined" % input)
272
273
273 self.r.assign(input, self.pyconverter(val))
274 self.r.assign(input, self.pyconverter(val))
274
275
275 @skip_doctest
276 @skip_doctest
276 @magic_arguments()
277 @magic_arguments()
277 @argument(
278 @argument(
278 '-d', '--as_dataframe', action='store_true',
279 '-d', '--as_dataframe', action='store_true',
279 default=False,
280 default=False,
280 help='Convert objects to data.frames before returning to ipython.'
281 help='Convert objects to data.frames before returning to ipython.'
281 )
282 )
282 @argument(
283 @argument(
283 'outputs',
284 'outputs',
284 nargs='*',
285 nargs='*',
285 )
286 )
286 @line_magic
287 @line_magic
287 def Rpull(self, line):
288 def Rpull(self, line):
288 '''
289 '''
289 A line-level magic for R that pulls
290 A line-level magic for R that pulls
290 variables from python to rpy2::
291 variables from python to rpy2::
291
292
292 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
293 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
293
294
294 In [19]: %Rpull x y z
295 In [19]: %Rpull x y z
295
296
296 In [20]: x
297 In [20]: x
297 Out[20]: array([ 3. , 4. , 6.7])
298 Out[20]: array([ 3. , 4. , 6.7])
298
299
299 In [21]: y
300 In [21]: y
300 Out[21]: array([ 4., 6., 7.])
301 Out[21]: array([ 4., 6., 7.])
301
302
302 In [22]: z
303 In [22]: z
303 Out[22]:
304 Out[22]:
304 array(['a', '3', '4'],
305 array(['a', '3', '4'],
305 dtype='|S1')
306 dtype='|S1')
306
307
307
308
308 If --as_dataframe, then each object is returned as a structured array
309 If --as_dataframe, then each object is returned as a structured array
309 after first passed through "as.data.frame" in R before
310 after first passed through "as.data.frame" in R before
310 being calling self.Rconverter.
311 being calling self.Rconverter.
311 This is useful when a structured array is desired as output, or
312 This is useful when a structured array is desired as output, or
312 when the object in R has mixed data types.
313 when the object in R has mixed data types.
313 See the %%R docstring for more examples.
314 See the %%R docstring for more examples.
314
315
315 Notes
316 Notes
316 -----
317 -----
317
318
318 Beware that R names can have '.' so this is not fool proof.
319 Beware that R names can have '.' so this is not fool proof.
319 To avoid this, don't name your R objects with '.'s...
320 To avoid this, don't name your R objects with '.'s...
320
321
321 '''
322 '''
322 args = parse_argstring(self.Rpull, line)
323 args = parse_argstring(self.Rpull, line)
323 outputs = args.outputs
324 outputs = args.outputs
324 for output in outputs:
325 for output in outputs:
325 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
326 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
326
327
327 @skip_doctest
328 @skip_doctest
328 @magic_arguments()
329 @magic_arguments()
329 @argument(
330 @argument(
330 '-d', '--as_dataframe', action='store_true',
331 '-d', '--as_dataframe', action='store_true',
331 default=False,
332 default=False,
332 help='Convert objects to data.frames before returning to ipython.'
333 help='Convert objects to data.frames before returning to ipython.'
333 )
334 )
334 @argument(
335 @argument(
335 'output',
336 'output',
336 nargs=1,
337 nargs=1,
337 type=str,
338 type=str,
338 )
339 )
339 @line_magic
340 @line_magic
340 def Rget(self, line):
341 def Rget(self, line):
341 '''
342 '''
342 Return an object from rpy2, possibly as a structured array (if possible).
343 Return an object from rpy2, possibly as a structured array (if possible).
343 Similar to Rpull except only one argument is accepted and the value is
344 Similar to Rpull except only one argument is accepted and the value is
344 returned rather than pushed to self.shell.user_ns::
345 returned rather than pushed to self.shell.user_ns::
345
346
346 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
347 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
347
348
348 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
349 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
349
350
350 In [5]: %R -i datapy
351 In [5]: %R -i datapy
351
352
352 In [6]: %Rget datapy
353 In [6]: %Rget datapy
353 Out[6]:
354 Out[6]:
354 array([['1', '2', '3', '4'],
355 array([['1', '2', '3', '4'],
355 ['2', '3', '2', '5'],
356 ['2', '3', '2', '5'],
356 ['a', 'b', 'c', 'e']],
357 ['a', 'b', 'c', 'e']],
357 dtype='|S1')
358 dtype='|S1')
358
359
359 In [7]: %Rget -d datapy
360 In [7]: %Rget -d datapy
360 Out[7]:
361 Out[7]:
361 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
362 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
362 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
363 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
363
364
364 '''
365 '''
365 args = parse_argstring(self.Rget, line)
366 args = parse_argstring(self.Rget, line)
366 output = args.output
367 output = args.output
367 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
368 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
368
369
369
370
370 @skip_doctest
371 @skip_doctest
371 @magic_arguments()
372 @magic_arguments()
372 @argument(
373 @argument(
373 '-i', '--input', action='append',
374 '-i', '--input', action='append',
374 help='Names of input variable from shell.user_ns to be assigned to R variables of the same names after calling self.pyconverter. Multiple names can be passed separated only by commas with no whitespace.'
375 help='Names of input variable from shell.user_ns to be assigned to R variables of the same names after calling self.pyconverter. Multiple names can be passed separated only by commas with no whitespace.'
375 )
376 )
376 @argument(
377 @argument(
377 '-o', '--output', action='append',
378 '-o', '--output', action='append',
378 help='Names of variables to be pushed from rpy2 to shell.user_ns after executing cell body and applying self.Rconverter. Multiple names can be passed separated only by commas with no whitespace.'
379 help='Names of variables to be pushed from rpy2 to shell.user_ns after executing cell body and applying self.Rconverter. Multiple names can be passed separated only by commas with no whitespace.'
379 )
380 )
380 @argument(
381 @argument(
381 '-w', '--width', type=int,
382 '-w', '--width', type=int,
382 help='Width of png plotting device sent as an argument to *png* in R.'
383 help='Width of png plotting device sent as an argument to *png* in R.'
383 )
384 )
384 @argument(
385 @argument(
385 '-h', '--height', type=int,
386 '-h', '--height', type=int,
386 help='Height of png plotting device sent as an argument to *png* in R.'
387 help='Height of png plotting device sent as an argument to *png* in R.'
387 )
388 )
388
389
389 @argument(
390 @argument(
390 '-d', '--dataframe', action='append',
391 '-d', '--dataframe', action='append',
391 help='Convert these objects to data.frames and return as structured arrays.'
392 help='Convert these objects to data.frames and return as structured arrays.'
392 )
393 )
393 @argument(
394 @argument(
394 '-u', '--units', type=unicode_type, choices=["px", "in", "cm", "mm"],
395 '-u', '--units', type=unicode_type, choices=["px", "in", "cm", "mm"],
395 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
396 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
396 )
397 )
397 @argument(
398 @argument(
398 '-r', '--res', type=int,
399 '-r', '--res', type=int,
399 help='Resolution of png plotting device sent as an argument to *png* in R. Defaults to 72 if *units* is one of ["in", "cm", "mm"].'
400 help='Resolution of png plotting device sent as an argument to *png* in R. Defaults to 72 if *units* is one of ["in", "cm", "mm"].'
400 )
401 )
401 @argument(
402 @argument(
402 '-p', '--pointsize', type=int,
403 '-p', '--pointsize', type=int,
403 help='Pointsize of png plotting device sent as an argument to *png* in R.'
404 help='Pointsize of png plotting device sent as an argument to *png* in R.'
404 )
405 )
405 @argument(
406 @argument(
406 '-b', '--bg',
407 '-b', '--bg',
407 help='Background of png plotting device sent as an argument to *png* in R.'
408 help='Background of png plotting device sent as an argument to *png* in R.'
408 )
409 )
409 @argument(
410 @argument(
410 '-n', '--noreturn',
411 '-n', '--noreturn',
411 help='Force the magic to not return anything.',
412 help='Force the magic to not return anything.',
412 action='store_true',
413 action='store_true',
413 default=False
414 default=False
414 )
415 )
415 @argument(
416 @argument(
416 'code',
417 'code',
417 nargs='*',
418 nargs='*',
418 )
419 )
419 @needs_local_scope
420 @needs_local_scope
420 @line_cell_magic
421 @line_cell_magic
421 def R(self, line, cell=None, local_ns=None):
422 def R(self, line, cell=None, local_ns=None):
422 '''
423 '''
423 Execute code in R, and pull some of the results back into the Python namespace.
424 Execute code in R, and pull some of the results back into the Python namespace.
424
425
425 In line mode, this will evaluate an expression and convert the returned value to a Python object.
426 In line mode, this will evaluate an expression and convert the returned value to a Python object.
426 The return value is determined by rpy2's behaviour of returning the result of evaluating the
427 The return value is determined by rpy2's behaviour of returning the result of evaluating the
427 final line.
428 final line.
428
429
429 Multiple R lines can be executed by joining them with semicolons::
430 Multiple R lines can be executed by joining them with semicolons::
430
431
431 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
432 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
432 Out[9]: array([ 4.25])
433 Out[9]: array([ 4.25])
433
434
434 In cell mode, this will run a block of R code. The resulting value
435 In cell mode, this will run a block of R code. The resulting value
435 is printed if it would printed be when evaluating the same code
436 is printed if it would printed be when evaluating the same code
436 within a standard R REPL.
437 within a standard R REPL.
437
438
438 Nothing is returned to python by default in cell mode::
439 Nothing is returned to python by default in cell mode::
439
440
440 In [10]: %%R
441 In [10]: %%R
441 ....: Y = c(2,4,3,9)
442 ....: Y = c(2,4,3,9)
442 ....: summary(lm(Y~X))
443 ....: summary(lm(Y~X))
443
444
444 Call:
445 Call:
445 lm(formula = Y ~ X)
446 lm(formula = Y ~ X)
446
447
447 Residuals:
448 Residuals:
448 1 2 3 4
449 1 2 3 4
449 0.88 -0.24 -2.28 1.64
450 0.88 -0.24 -2.28 1.64
450
451
451 Coefficients:
452 Coefficients:
452 Estimate Std. Error t value Pr(>|t|)
453 Estimate Std. Error t value Pr(>|t|)
453 (Intercept) 0.0800 2.3000 0.035 0.975
454 (Intercept) 0.0800 2.3000 0.035 0.975
454 X 1.0400 0.4822 2.157 0.164
455 X 1.0400 0.4822 2.157 0.164
455
456
456 Residual standard error: 2.088 on 2 degrees of freedom
457 Residual standard error: 2.088 on 2 degrees of freedom
457 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
458 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
458 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
459 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
459
460
460 In the notebook, plots are published as the output of the cell::
461 In the notebook, plots are published as the output of the cell::
461
462
462 %R plot(X, Y)
463 %R plot(X, Y)
463
464
464 will create a scatter plot of X bs Y.
465 will create a scatter plot of X bs Y.
465
466
466 If cell is not None and line has some R code, it is prepended to
467 If cell is not None and line has some R code, it is prepended to
467 the R code in cell.
468 the R code in cell.
468
469
469 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
470 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
470
471
471 In [14]: Z = np.array([1,4,5,10])
472 In [14]: Z = np.array([1,4,5,10])
472
473
473 In [15]: %R -i Z mean(Z)
474 In [15]: %R -i Z mean(Z)
474 Out[15]: array([ 5.])
475 Out[15]: array([ 5.])
475
476
476
477
477 In [16]: %R -o W W=Z*mean(Z)
478 In [16]: %R -o W W=Z*mean(Z)
478 Out[16]: array([ 5., 20., 25., 50.])
479 Out[16]: array([ 5., 20., 25., 50.])
479
480
480 In [17]: W
481 In [17]: W
481 Out[17]: array([ 5., 20., 25., 50.])
482 Out[17]: array([ 5., 20., 25., 50.])
482
483
483 The return value is determined by these rules:
484 The return value is determined by these rules:
484
485
485 * If the cell is not None, the magic returns None.
486 * If the cell is not None, the magic returns None.
486
487
487 * If the cell evaluates as False, the resulting value is returned
488 * If the cell evaluates as False, the resulting value is returned
488 unless the final line prints something to the console, in
489 unless the final line prints something to the console, in
489 which case None is returned.
490 which case None is returned.
490
491
491 * If the final line results in a NULL value when evaluated
492 * If the final line results in a NULL value when evaluated
492 by rpy2, then None is returned.
493 by rpy2, then None is returned.
493
494
494 * No attempt is made to convert the final value to a structured array.
495 * No attempt is made to convert the final value to a structured array.
495 Use the --dataframe flag or %Rget to push / return a structured array.
496 Use the --dataframe flag or %Rget to push / return a structured array.
496
497
497 * If the -n flag is present, there is no return value.
498 * If the -n flag is present, there is no return value.
498
499
499 * A trailing ';' will also result in no return value as the last
500 * A trailing ';' will also result in no return value as the last
500 value in the line is an empty string.
501 value in the line is an empty string.
501
502
502 The --dataframe argument will attempt to return structured arrays.
503 The --dataframe argument will attempt to return structured arrays.
503 This is useful for dataframes with
504 This is useful for dataframes with
504 mixed data types. Note also that for a data.frame,
505 mixed data types. Note also that for a data.frame,
505 if it is returned as an ndarray, it is transposed::
506 if it is returned as an ndarray, it is transposed::
506
507
507 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
508 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
508
509
509 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
510 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
510
511
511 In [20]: %%R -o datar
512 In [20]: %%R -o datar
512 datar = datapy
513 datar = datapy
513 ....:
514 ....:
514
515
515 In [21]: datar
516 In [21]: datar
516 Out[21]:
517 Out[21]:
517 array([['1', '2', '3', '4'],
518 array([['1', '2', '3', '4'],
518 ['2', '3', '2', '5'],
519 ['2', '3', '2', '5'],
519 ['a', 'b', 'c', 'e']],
520 ['a', 'b', 'c', 'e']],
520 dtype='|S1')
521 dtype='|S1')
521
522
522 In [22]: %%R -d datar
523 In [22]: %%R -d datar
523 datar = datapy
524 datar = datapy
524 ....:
525 ....:
525
526
526 In [23]: datar
527 In [23]: datar
527 Out[23]:
528 Out[23]:
528 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
529 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
529 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
530 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
530
531
531 The --dataframe argument first tries colnames, then names.
532 The --dataframe argument first tries colnames, then names.
532 If both are NULL, it returns an ndarray (i.e. unstructured)::
533 If both are NULL, it returns an ndarray (i.e. unstructured)::
533
534
534 In [1]: %R mydata=c(4,6,8.3); NULL
535 In [1]: %R mydata=c(4,6,8.3); NULL
535
536
536 In [2]: %R -d mydata
537 In [2]: %R -d mydata
537
538
538 In [3]: mydata
539 In [3]: mydata
539 Out[3]: array([ 4. , 6. , 8.3])
540 Out[3]: array([ 4. , 6. , 8.3])
540
541
541 In [4]: %R names(mydata) = c('a','b','c'); NULL
542 In [4]: %R names(mydata) = c('a','b','c'); NULL
542
543
543 In [5]: %R -d mydata
544 In [5]: %R -d mydata
544
545
545 In [6]: mydata
546 In [6]: mydata
546 Out[6]:
547 Out[6]:
547 array((4.0, 6.0, 8.3),
548 array((4.0, 6.0, 8.3),
548 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
549 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
549
550
550 In [7]: %R -o mydata
551 In [7]: %R -o mydata
551
552
552 In [8]: mydata
553 In [8]: mydata
553 Out[8]: array([ 4. , 6. , 8.3])
554 Out[8]: array([ 4. , 6. , 8.3])
554
555
555 '''
556 '''
556
557
557 args = parse_argstring(self.R, line)
558 args = parse_argstring(self.R, line)
558
559
559 # arguments 'code' in line are prepended to
560 # arguments 'code' in line are prepended to
560 # the cell lines
561 # the cell lines
561
562
562 if cell is None:
563 if cell is None:
563 code = ''
564 code = ''
564 return_output = True
565 return_output = True
565 line_mode = True
566 line_mode = True
566 else:
567 else:
567 code = cell
568 code = cell
568 return_output = False
569 return_output = False
569 line_mode = False
570 line_mode = False
570
571
571 code = ' '.join(args.code) + code
572 code = ' '.join(args.code) + code
572
573
573 # if there is no local namespace then default to an empty dict
574 # if there is no local namespace then default to an empty dict
574 if local_ns is None:
575 if local_ns is None:
575 local_ns = {}
576 local_ns = {}
576
577
577 if args.input:
578 if args.input:
578 for input in ','.join(args.input).split(','):
579 for input in ','.join(args.input).split(','):
579 try:
580 try:
580 val = local_ns[input]
581 val = local_ns[input]
581 except KeyError:
582 except KeyError:
582 try:
583 try:
583 val = self.shell.user_ns[input]
584 val = self.shell.user_ns[input]
584 except KeyError:
585 except KeyError:
585 raise NameError("name '%s' is not defined" % input)
586 raise NameError("name '%s' is not defined" % input)
586 self.r.assign(input, self.pyconverter(val))
587 self.r.assign(input, self.pyconverter(val))
587
588
588 if getattr(args, 'units') is not None:
589 if getattr(args, 'units') is not None:
589 if args.units != "px" and getattr(args, 'res') is None:
590 if args.units != "px" and getattr(args, 'res') is None:
590 args.res = 72
591 args.res = 72
591 args.units = '"%s"' % args.units
592 args.units = '"%s"' % args.units
592
593
593 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
594 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
594 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
595 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
595 # execute the R code in a temporary directory
596 # execute the R code in a temporary directory
596
597
597 tmpd = tempfile.mkdtemp()
598 tmpd = tempfile.mkdtemp()
598 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
599 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
599
600
600 text_output = ''
601 text_output = ''
601 try:
602 try:
602 if line_mode:
603 if line_mode:
603 for line in code.split(';'):
604 for line in code.split(';'):
604 text_result, result, visible = self.eval(line)
605 text_result, result, visible = self.eval(line)
605 text_output += text_result
606 text_output += text_result
606 if text_result:
607 if text_result:
607 # the last line printed something to the console so we won't return it
608 # the last line printed something to the console so we won't return it
608 return_output = False
609 return_output = False
609 else:
610 else:
610 text_result, result, visible = self.eval(code)
611 text_result, result, visible = self.eval(code)
611 text_output += text_result
612 text_output += text_result
612 if visible:
613 if visible:
613 old_writeconsole = ri.get_writeconsole()
614 old_writeconsole = ri.get_writeconsole()
614 ri.set_writeconsole(self.write_console)
615 ri.set_writeconsole(self.write_console)
615 ro.r.show(result)
616 ro.r.show(result)
616 text_output += self.flush()
617 text_output += self.flush()
617 ri.set_writeconsole(old_writeconsole)
618 ri.set_writeconsole(old_writeconsole)
618
619
619 except RInterpreterError as e:
620 except RInterpreterError as e:
620 print(e.stdout)
621 print((e.stdout))
621 if not e.stdout.endswith(e.err):
622 if not e.stdout.endswith(e.err):
622 print(e.err)
623 print((e.err))
623 rmtree(tmpd)
624 rmtree(tmpd)
624 return
625 return
625
626
626 self.r('dev.off()')
627 self.r('dev.off()')
627
628
628 # read out all the saved .png files
629 # read out all the saved .png files
629
630
630 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
631 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
631
632
632 # now publish the images
633 # now publish the images
633 # mimicking IPython/zmq/pylab/backend_inline.py
634 # mimicking IPython/zmq/pylab/backend_inline.py
634 fmt = 'png'
635 fmt = 'png'
635 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
636 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
636 mime = mimetypes[fmt]
637 mime = mimetypes[fmt]
637
638
638 # publish the printed R objects, if any
639 # publish the printed R objects, if any
639
640
640 display_data = []
641 display_data = []
641 if text_output:
642 if text_output:
642 display_data.append(('RMagic.R', {'text/plain':text_output}))
643 display_data.append(('RMagic.R', {'text/plain':text_output}))
643
644
644 # flush text streams before sending figures, helps a little with output
645 # flush text streams before sending figures, helps a little with output
645 for image in images:
646 for image in images:
646 # synchronization in the console (though it's a bandaid, not a real sln)
647 # synchronization in the console (though it's a bandaid, not a real sln)
647 sys.stdout.flush(); sys.stderr.flush()
648 sys.stdout.flush(); sys.stderr.flush()
648 display_data.append(('RMagic.R', {mime: image}))
649 display_data.append(('RMagic.R', {mime: image}))
649
650
650 # kill the temporary directory
651 # kill the temporary directory
651 rmtree(tmpd)
652 rmtree(tmpd)
652
653
653 # try to turn every output into a numpy array
654 # try to turn every output into a numpy array
654 # this means that output are assumed to be castable
655 # this means that output are assumed to be castable
655 # as numpy arrays
656 # as numpy arrays
656
657
657 if args.output:
658 if args.output:
658 for output in ','.join(args.output).split(','):
659 for output in ','.join(args.output).split(','):
659 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
660 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
660
661
661 if args.dataframe:
662 if args.dataframe:
662 for output in ','.join(args.dataframe).split(','):
663 for output in ','.join(args.dataframe).split(','):
663 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
664 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
664
665
665 for tag, disp_d in display_data:
666 for tag, disp_d in display_data:
666 publish_display_data(tag, disp_d)
667 publish_display_data(tag, disp_d)
667
668
668 # this will keep a reference to the display_data
669 # this will keep a reference to the display_data
669 # which might be useful to other objects who happen to use
670 # which might be useful to other objects who happen to use
670 # this method
671 # this method
671
672
672 if self.cache_display_data:
673 if self.cache_display_data:
673 self.display_cache = display_data
674 self.display_cache = display_data
674
675
675 # if in line mode and return_output, return the result as an ndarray
676 # if in line mode and return_output, return the result as an ndarray
676 if return_output and not args.noreturn:
677 if return_output and not args.noreturn:
677 if result != ri.NULL:
678 if result != ri.NULL:
678 return self.Rconverter(result, dataframe=False)
679 return self.Rconverter(result, dataframe=False)
679
680
680 __doc__ = __doc__.format(
681 __doc__ = __doc__.format(
681 R_DOC = ' '*8 + RMagics.R.__doc__,
682 R_DOC = ' '*8 + RMagics.R.__doc__,
682 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
683 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
683 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
684 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
684 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
685 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
685 )
686 )
686
687
687
688
688 def load_ipython_extension(ip):
689 def load_ipython_extension(ip):
689 """Load the extension in IPython."""
690 """Load the extension in IPython."""
690 ip.register_magics(RMagics)
691 ip.register_magics(RMagics)
691 # Initialising rpy2 interferes with readline. Since, at this point, we've
692 # Initialising rpy2 interferes with readline. Since, at this point, we've
692 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
693 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
693 if ip.has_readline:
694 if ip.has_readline:
694 ip.readline.set_completer_delims(ip.readline_delims)
695 ip.readline.set_completer_delims(ip.readline_delims)
@@ -1,241 +1,242 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 %store magic for lightweight persistence.
3 %store magic for lightweight persistence.
4
4
5 Stores variables, aliases and macros in IPython's database.
5 Stores variables, aliases and macros in IPython's database.
6
6
7 To automatically restore stored variables at startup, add this to your
7 To automatically restore stored variables at startup, add this to your
8 :file:`ipython_config.py` file::
8 :file:`ipython_config.py` file::
9
9
10 c.StoreMagic.autorestore = True
10 c.StoreMagic.autorestore = True
11 """
11 """
12 from __future__ import print_function
12 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
13 # Copyright (c) 2012, The IPython Development Team.
14 # Copyright (c) 2012, The IPython Development Team.
14 #
15 #
15 # Distributed under the terms of the Modified BSD License.
16 # Distributed under the terms of the Modified BSD License.
16 #
17 #
17 # The full license is in the file COPYING.txt, distributed with this software.
18 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19
20
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21 # Imports
22 # Imports
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23
24
24 # Stdlib
25 # Stdlib
25 import inspect, os, sys, textwrap
26 import inspect, os, sys, textwrap
26
27
27 # Our own
28 # Our own
28 from IPython.core.error import UsageError
29 from IPython.core.error import UsageError
29 from IPython.core.magic import Magics, magics_class, line_magic
30 from IPython.core.magic import Magics, magics_class, line_magic
30 from IPython.testing.skipdoctest import skip_doctest
31 from IPython.testing.skipdoctest import skip_doctest
31 from IPython.utils.traitlets import Bool
32 from IPython.utils.traitlets import Bool
32
33
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34 # Functions and classes
35 # Functions and classes
35 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
36
37
37 def restore_aliases(ip):
38 def restore_aliases(ip):
38 staliases = ip.db.get('stored_aliases', {})
39 staliases = ip.db.get('stored_aliases', {})
39 for k,v in staliases.items():
40 for k,v in staliases.items():
40 #print "restore alias",k,v # dbg
41 #print "restore alias",k,v # dbg
41 #self.alias_table[k] = v
42 #self.alias_table[k] = v
42 ip.alias_manager.define_alias(k,v)
43 ip.alias_manager.define_alias(k,v)
43
44
44
45
45 def refresh_variables(ip):
46 def refresh_variables(ip):
46 db = ip.db
47 db = ip.db
47 for key in db.keys('autorestore/*'):
48 for key in db.keys('autorestore/*'):
48 # strip autorestore
49 # strip autorestore
49 justkey = os.path.basename(key)
50 justkey = os.path.basename(key)
50 try:
51 try:
51 obj = db[key]
52 obj = db[key]
52 except KeyError:
53 except KeyError:
53 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
54 print("Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey)
54 print "The error was:", sys.exc_info()[0]
55 print("The error was:", sys.exc_info()[0])
55 else:
56 else:
56 #print "restored",justkey,"=",obj #dbg
57 #print "restored",justkey,"=",obj #dbg
57 ip.user_ns[justkey] = obj
58 ip.user_ns[justkey] = obj
58
59
59
60
60 def restore_dhist(ip):
61 def restore_dhist(ip):
61 ip.user_ns['_dh'] = ip.db.get('dhist',[])
62 ip.user_ns['_dh'] = ip.db.get('dhist',[])
62
63
63
64
64 def restore_data(ip):
65 def restore_data(ip):
65 refresh_variables(ip)
66 refresh_variables(ip)
66 restore_aliases(ip)
67 restore_aliases(ip)
67 restore_dhist(ip)
68 restore_dhist(ip)
68
69
69
70
70 @magics_class
71 @magics_class
71 class StoreMagics(Magics):
72 class StoreMagics(Magics):
72 """Lightweight persistence for python variables.
73 """Lightweight persistence for python variables.
73
74
74 Provides the %store magic."""
75 Provides the %store magic."""
75
76
76 autorestore = Bool(False, config=True, help=
77 autorestore = Bool(False, config=True, help=
77 """If True, any %store-d variables will be automatically restored
78 """If True, any %store-d variables will be automatically restored
78 when IPython starts.
79 when IPython starts.
79 """
80 """
80 )
81 )
81
82
82 def __init__(self, shell):
83 def __init__(self, shell):
83 super(StoreMagics, self).__init__(shell=shell)
84 super(StoreMagics, self).__init__(shell=shell)
84 self.shell.configurables.append(self)
85 self.shell.configurables.append(self)
85 if self.autorestore:
86 if self.autorestore:
86 restore_data(self.shell)
87 restore_data(self.shell)
87
88
88 @skip_doctest
89 @skip_doctest
89 @line_magic
90 @line_magic
90 def store(self, parameter_s=''):
91 def store(self, parameter_s=''):
91 """Lightweight persistence for python variables.
92 """Lightweight persistence for python variables.
92
93
93 Example::
94 Example::
94
95
95 In [1]: l = ['hello',10,'world']
96 In [1]: l = ['hello',10,'world']
96 In [2]: %store l
97 In [2]: %store l
97 In [3]: exit
98 In [3]: exit
98
99
99 (IPython session is closed and started again...)
100 (IPython session is closed and started again...)
100
101
101 ville@badger:~$ ipython
102 ville@badger:~$ ipython
102 In [1]: l
103 In [1]: l
103 NameError: name 'l' is not defined
104 NameError: name 'l' is not defined
104 In [2]: %store -r
105 In [2]: %store -r
105 In [3]: l
106 In [3]: l
106 Out[3]: ['hello', 10, 'world']
107 Out[3]: ['hello', 10, 'world']
107
108
108 Usage:
109 Usage:
109
110
110 * ``%store`` - Show list of all variables and their current
111 * ``%store`` - Show list of all variables and their current
111 values
112 values
112 * ``%store spam`` - Store the *current* value of the variable spam
113 * ``%store spam`` - Store the *current* value of the variable spam
113 to disk
114 to disk
114 * ``%store -d spam`` - Remove the variable and its value from storage
115 * ``%store -d spam`` - Remove the variable and its value from storage
115 * ``%store -z`` - Remove all variables from storage
116 * ``%store -z`` - Remove all variables from storage
116 * ``%store -r`` - Refresh all variables from store (overwrite
117 * ``%store -r`` - Refresh all variables from store (overwrite
117 current vals)
118 current vals)
118 * ``%store -r spam bar`` - Refresh specified variables from store
119 * ``%store -r spam bar`` - Refresh specified variables from store
119 (delete current val)
120 (delete current val)
120 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
121 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
121 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
122 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
122
123
123 It should be noted that if you change the value of a variable, you
124 It should be noted that if you change the value of a variable, you
124 need to %store it again if you want to persist the new value.
125 need to %store it again if you want to persist the new value.
125
126
126 Note also that the variables will need to be pickleable; most basic
127 Note also that the variables will need to be pickleable; most basic
127 python types can be safely %store'd.
128 python types can be safely %store'd.
128
129
129 Also aliases can be %store'd across sessions.
130 Also aliases can be %store'd across sessions.
130 """
131 """
131
132
132 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
133 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
133 args = argsl.split(None,1)
134 args = argsl.split(None,1)
134 ip = self.shell
135 ip = self.shell
135 db = ip.db
136 db = ip.db
136 # delete
137 # delete
137 if 'd' in opts:
138 if 'd' in opts:
138 try:
139 try:
139 todel = args[0]
140 todel = args[0]
140 except IndexError:
141 except IndexError:
141 raise UsageError('You must provide the variable to forget')
142 raise UsageError('You must provide the variable to forget')
142 else:
143 else:
143 try:
144 try:
144 del db['autorestore/' + todel]
145 del db['autorestore/' + todel]
145 except:
146 except:
146 raise UsageError("Can't delete variable '%s'" % todel)
147 raise UsageError("Can't delete variable '%s'" % todel)
147 # reset
148 # reset
148 elif 'z' in opts:
149 elif 'z' in opts:
149 for k in db.keys('autorestore/*'):
150 for k in db.keys('autorestore/*'):
150 del db[k]
151 del db[k]
151
152
152 elif 'r' in opts:
153 elif 'r' in opts:
153 if args:
154 if args:
154 for arg in args:
155 for arg in args:
155 try:
156 try:
156 obj = db['autorestore/' + arg]
157 obj = db['autorestore/' + arg]
157 except KeyError:
158 except KeyError:
158 print "no stored variable %s" % arg
159 print("no stored variable %s" % arg)
159 else:
160 else:
160 ip.user_ns[arg] = obj
161 ip.user_ns[arg] = obj
161 else:
162 else:
162 restore_data(ip)
163 restore_data(ip)
163
164
164 # run without arguments -> list variables & values
165 # run without arguments -> list variables & values
165 elif not args:
166 elif not args:
166 vars = db.keys('autorestore/*')
167 vars = db.keys('autorestore/*')
167 vars.sort()
168 vars.sort()
168 if vars:
169 if vars:
169 size = max(map(len, vars))
170 size = max(map(len, vars))
170 else:
171 else:
171 size = 0
172 size = 0
172
173
173 print 'Stored variables and their in-db values:'
174 print('Stored variables and their in-db values:')
174 fmt = '%-'+str(size)+'s -> %s'
175 fmt = '%-'+str(size)+'s -> %s'
175 get = db.get
176 get = db.get
176 for var in vars:
177 for var in vars:
177 justkey = os.path.basename(var)
178 justkey = os.path.basename(var)
178 # print 30 first characters from every var
179 # print 30 first characters from every var
179 print fmt % (justkey, repr(get(var, '<unavailable>'))[:50])
180 print(fmt % (justkey, repr(get(var, '<unavailable>'))[:50]))
180
181
181 # default action - store the variable
182 # default action - store the variable
182 else:
183 else:
183 # %store foo >file.txt or >>file.txt
184 # %store foo >file.txt or >>file.txt
184 if len(args) > 1 and args[1].startswith('>'):
185 if len(args) > 1 and args[1].startswith('>'):
185 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
186 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
186 if args[1].startswith('>>'):
187 if args[1].startswith('>>'):
187 fil = open(fnam, 'a')
188 fil = open(fnam, 'a')
188 else:
189 else:
189 fil = open(fnam, 'w')
190 fil = open(fnam, 'w')
190 obj = ip.ev(args[0])
191 obj = ip.ev(args[0])
191 print "Writing '%s' (%s) to file '%s'." % (args[0],
192 print("Writing '%s' (%s) to file '%s'." % (args[0],
192 obj.__class__.__name__, fnam)
193 obj.__class__.__name__, fnam))
193
194
194
195
195 if not isinstance (obj, basestring):
196 if not isinstance (obj, basestring):
196 from pprint import pprint
197 from pprint import pprint
197 pprint(obj, fil)
198 pprint(obj, fil)
198 else:
199 else:
199 fil.write(obj)
200 fil.write(obj)
200 if not obj.endswith('\n'):
201 if not obj.endswith('\n'):
201 fil.write('\n')
202 fil.write('\n')
202
203
203 fil.close()
204 fil.close()
204 return
205 return
205
206
206 # %store foo
207 # %store foo
207 try:
208 try:
208 obj = ip.user_ns[args[0]]
209 obj = ip.user_ns[args[0]]
209 except KeyError:
210 except KeyError:
210 # it might be an alias
211 # it might be an alias
211 name = args[0]
212 name = args[0]
212 try:
213 try:
213 cmd = ip.alias_manager.retrieve_alias(name)
214 cmd = ip.alias_manager.retrieve_alias(name)
214 except ValueError:
215 except ValueError:
215 raise UsageError("Unknown variable '%s'" % name)
216 raise UsageError("Unknown variable '%s'" % name)
216
217
217 staliases = db.get('stored_aliases',{})
218 staliases = db.get('stored_aliases',{})
218 staliases[name] = cmd
219 staliases[name] = cmd
219 db['stored_aliases'] = staliases
220 db['stored_aliases'] = staliases
220 print "Alias stored: %s (%s)" % (name, cmd)
221 print("Alias stored: %s (%s)" % (name, cmd))
221 return
222 return
222
223
223 else:
224 else:
224 modname = getattr(inspect.getmodule(obj), '__name__', '')
225 modname = getattr(inspect.getmodule(obj), '__name__', '')
225 if modname == '__main__':
226 if modname == '__main__':
226 print textwrap.dedent("""\
227 print(textwrap.dedent("""\
227 Warning:%s is %s
228 Warning:%s is %s
228 Proper storage of interactively declared classes (or instances
229 Proper storage of interactively declared classes (or instances
229 of those classes) is not possible! Only instances
230 of those classes) is not possible! Only instances
230 of classes in real modules on file system can be %%store'd.
231 of classes in real modules on file system can be %%store'd.
231 """ % (args[0], obj) )
232 """ % (args[0], obj) ))
232 return
233 return
233 #pickled = pickle.dumps(obj)
234 #pickled = pickle.dumps(obj)
234 db[ 'autorestore/' + args[0] ] = obj
235 db[ 'autorestore/' + args[0] ] = obj
235 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
236 print("Stored '%s' (%s)" % (args[0], obj.__class__.__name__))
236
237
237
238
238 def load_ipython_extension(ip):
239 def load_ipython_extension(ip):
239 """Load the extension in IPython."""
240 """Load the extension in IPython."""
240 ip.register_magics(StoreMagics)
241 ip.register_magics(StoreMagics)
241
242
@@ -1,220 +1,221 b''
1 ########################## LICENCE ###############################
1 ########################## LICENCE ###############################
2
2
3 # Copyright (c) 2005-2012, Michele Simionato
3 # Copyright (c) 2005-2012, Michele Simionato
4 # All rights reserved.
4 # All rights reserved.
5
5
6 # Redistribution and use in source and binary forms, with or without
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
7 # modification, are permitted provided that the following conditions are
8 # met:
8 # met:
9
9
10 # Redistributions of source code must retain the above copyright
10 # Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
11 # notice, this list of conditions and the following disclaimer.
12 # Redistributions in bytecode form must reproduce the above copyright
12 # Redistributions in bytecode form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in
13 # notice, this list of conditions and the following disclaimer in
14 # the documentation and/or other materials provided with the
14 # the documentation and/or other materials provided with the
15 # distribution.
15 # distribution.
16
16
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 # DAMAGE.
28 # DAMAGE.
29
29
30 """
30 """
31 Decorator module, see http://pypi.python.org/pypi/decorator
31 Decorator module, see http://pypi.python.org/pypi/decorator
32 for the documentation.
32 for the documentation.
33 """
33 """
34 from __future__ import print_function
34
35
35 __version__ = '3.3.3'
36 __version__ = '3.3.3'
36
37
37 __all__ = ["decorator", "FunctionMaker", "partial"]
38 __all__ = ["decorator", "FunctionMaker", "partial"]
38
39
39 import sys, re, inspect
40 import sys, re, inspect
40
41
41 try:
42 try:
42 from functools import partial
43 from functools import partial
43 except ImportError: # for Python version < 2.5
44 except ImportError: # for Python version < 2.5
44 class partial(object):
45 class partial(object):
45 "A simple replacement of functools.partial"
46 "A simple replacement of functools.partial"
46 def __init__(self, func, *args, **kw):
47 def __init__(self, func, *args, **kw):
47 self.func = func
48 self.func = func
48 self.args = args
49 self.args = args
49 self.keywords = kw
50 self.keywords = kw
50 def __call__(self, *otherargs, **otherkw):
51 def __call__(self, *otherargs, **otherkw):
51 kw = self.keywords.copy()
52 kw = self.keywords.copy()
52 kw.update(otherkw)
53 kw.update(otherkw)
53 return self.func(*(self.args + otherargs), **kw)
54 return self.func(*(self.args + otherargs), **kw)
54
55
55 if sys.version >= '3':
56 if sys.version >= '3':
56 from inspect import getfullargspec
57 from inspect import getfullargspec
57 else:
58 else:
58 class getfullargspec(object):
59 class getfullargspec(object):
59 "A quick and dirty replacement for getfullargspec for Python 2.X"
60 "A quick and dirty replacement for getfullargspec for Python 2.X"
60 def __init__(self, f):
61 def __init__(self, f):
61 self.args, self.varargs, self.varkw, self.defaults = \
62 self.args, self.varargs, self.varkw, self.defaults = \
62 inspect.getargspec(f)
63 inspect.getargspec(f)
63 self.kwonlyargs = []
64 self.kwonlyargs = []
64 self.kwonlydefaults = None
65 self.kwonlydefaults = None
65 def __iter__(self):
66 def __iter__(self):
66 yield self.args
67 yield self.args
67 yield self.varargs
68 yield self.varargs
68 yield self.varkw
69 yield self.varkw
69 yield self.defaults
70 yield self.defaults
70
71
71 DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
72 DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
72
73
73 # basic functionality
74 # basic functionality
74 class FunctionMaker(object):
75 class FunctionMaker(object):
75 """
76 """
76 An object with the ability to create functions with a given signature.
77 An object with the ability to create functions with a given signature.
77 It has attributes name, doc, module, signature, defaults, dict and
78 It has attributes name, doc, module, signature, defaults, dict and
78 methods update and make.
79 methods update and make.
79 """
80 """
80 def __init__(self, func=None, name=None, signature=None,
81 def __init__(self, func=None, name=None, signature=None,
81 defaults=None, doc=None, module=None, funcdict=None):
82 defaults=None, doc=None, module=None, funcdict=None):
82 self.shortsignature = signature
83 self.shortsignature = signature
83 if func:
84 if func:
84 # func can be a class or a callable, but not an instance method
85 # func can be a class or a callable, but not an instance method
85 self.name = func.__name__
86 self.name = func.__name__
86 if self.name == '<lambda>': # small hack for lambda functions
87 if self.name == '<lambda>': # small hack for lambda functions
87 self.name = '_lambda_'
88 self.name = '_lambda_'
88 self.doc = func.__doc__
89 self.doc = func.__doc__
89 self.module = func.__module__
90 self.module = func.__module__
90 if inspect.isfunction(func):
91 if inspect.isfunction(func):
91 argspec = getfullargspec(func)
92 argspec = getfullargspec(func)
92 self.annotations = getattr(func, '__annotations__', {})
93 self.annotations = getattr(func, '__annotations__', {})
93 for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
94 for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
94 'kwonlydefaults'):
95 'kwonlydefaults'):
95 setattr(self, a, getattr(argspec, a))
96 setattr(self, a, getattr(argspec, a))
96 for i, arg in enumerate(self.args):
97 for i, arg in enumerate(self.args):
97 setattr(self, 'arg%d' % i, arg)
98 setattr(self, 'arg%d' % i, arg)
98 if sys.version < '3': # easy way
99 if sys.version < '3': # easy way
99 self.shortsignature = self.signature = \
100 self.shortsignature = self.signature = \
100 inspect.formatargspec(
101 inspect.formatargspec(
101 formatvalue=lambda val: "", *argspec)[1:-1]
102 formatvalue=lambda val: "", *argspec)[1:-1]
102 else: # Python 3 way
103 else: # Python 3 way
103 self.signature = self.shortsignature = ', '.join(self.args)
104 self.signature = self.shortsignature = ', '.join(self.args)
104 if self.varargs:
105 if self.varargs:
105 self.signature += ', *' + self.varargs
106 self.signature += ', *' + self.varargs
106 self.shortsignature += ', *' + self.varargs
107 self.shortsignature += ', *' + self.varargs
107 if self.kwonlyargs:
108 if self.kwonlyargs:
108 for a in self.kwonlyargs:
109 for a in self.kwonlyargs:
109 self.signature += ', %s=None' % a
110 self.signature += ', %s=None' % a
110 self.shortsignature += ', %s=%s' % (a, a)
111 self.shortsignature += ', %s=%s' % (a, a)
111 if self.varkw:
112 if self.varkw:
112 self.signature += ', **' + self.varkw
113 self.signature += ', **' + self.varkw
113 self.shortsignature += ', **' + self.varkw
114 self.shortsignature += ', **' + self.varkw
114 self.dict = func.__dict__.copy()
115 self.dict = func.__dict__.copy()
115 # func=None happens when decorating a caller
116 # func=None happens when decorating a caller
116 if name:
117 if name:
117 self.name = name
118 self.name = name
118 if signature is not None:
119 if signature is not None:
119 self.signature = signature
120 self.signature = signature
120 if defaults:
121 if defaults:
121 self.defaults = defaults
122 self.defaults = defaults
122 if doc:
123 if doc:
123 self.doc = doc
124 self.doc = doc
124 if module:
125 if module:
125 self.module = module
126 self.module = module
126 if funcdict:
127 if funcdict:
127 self.dict = funcdict
128 self.dict = funcdict
128 # check existence required attributes
129 # check existence required attributes
129 assert hasattr(self, 'name')
130 assert hasattr(self, 'name')
130 if not hasattr(self, 'signature'):
131 if not hasattr(self, 'signature'):
131 raise TypeError('You are decorating a non function: %s' % func)
132 raise TypeError('You are decorating a non function: %s' % func)
132
133
133 def update(self, func, **kw):
134 def update(self, func, **kw):
134 "Update the signature of func with the data in self"
135 "Update the signature of func with the data in self"
135 func.__name__ = self.name
136 func.__name__ = self.name
136 func.__doc__ = getattr(self, 'doc', None)
137 func.__doc__ = getattr(self, 'doc', None)
137 func.__dict__ = getattr(self, 'dict', {})
138 func.__dict__ = getattr(self, 'dict', {})
138 func.func_defaults = getattr(self, 'defaults', ())
139 func.func_defaults = getattr(self, 'defaults', ())
139 func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None)
140 func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None)
140 func.__annotations__ = getattr(self, 'annotations', None)
141 func.__annotations__ = getattr(self, 'annotations', None)
141 callermodule = sys._getframe(3).f_globals.get('__name__', '?')
142 callermodule = sys._getframe(3).f_globals.get('__name__', '?')
142 func.__module__ = getattr(self, 'module', callermodule)
143 func.__module__ = getattr(self, 'module', callermodule)
143 func.__dict__.update(kw)
144 func.__dict__.update(kw)
144
145
145 def make(self, src_templ, evaldict=None, addsource=False, **attrs):
146 def make(self, src_templ, evaldict=None, addsource=False, **attrs):
146 "Make a new function from a given template and update the signature"
147 "Make a new function from a given template and update the signature"
147 src = src_templ % vars(self) # expand name and signature
148 src = src_templ % vars(self) # expand name and signature
148 evaldict = evaldict or {}
149 evaldict = evaldict or {}
149 mo = DEF.match(src)
150 mo = DEF.match(src)
150 if mo is None:
151 if mo is None:
151 raise SyntaxError('not a valid function template\n%s' % src)
152 raise SyntaxError('not a valid function template\n%s' % src)
152 name = mo.group(1) # extract the function name
153 name = mo.group(1) # extract the function name
153 names = set([name] + [arg.strip(' *') for arg in
154 names = set([name] + [arg.strip(' *') for arg in
154 self.shortsignature.split(',')])
155 self.shortsignature.split(',')])
155 for n in names:
156 for n in names:
156 if n in ('_func_', '_call_'):
157 if n in ('_func_', '_call_'):
157 raise NameError('%s is overridden in\n%s' % (n, src))
158 raise NameError('%s is overridden in\n%s' % (n, src))
158 if not src.endswith('\n'): # add a newline just for safety
159 if not src.endswith('\n'): # add a newline just for safety
159 src += '\n' # this is needed in old versions of Python
160 src += '\n' # this is needed in old versions of Python
160 try:
161 try:
161 code = compile(src, '<string>', 'single')
162 code = compile(src, '<string>', 'single')
162 # print >> sys.stderr, 'Compiling %s' % src
163 # print >> sys.stderr, 'Compiling %s' % src
163 exec code in evaldict
164 exec code in evaldict
164 except:
165 except:
165 print >> sys.stderr, 'Error in generated code:'
166 print('Error in generated code:', file=sys.stderr)
166 print >> sys.stderr, src
167 print(src, file=sys.stderr)
167 raise
168 raise
168 func = evaldict[name]
169 func = evaldict[name]
169 if addsource:
170 if addsource:
170 attrs['__source__'] = src
171 attrs['__source__'] = src
171 self.update(func, **attrs)
172 self.update(func, **attrs)
172 return func
173 return func
173
174
174 @classmethod
175 @classmethod
175 def create(cls, obj, body, evaldict, defaults=None,
176 def create(cls, obj, body, evaldict, defaults=None,
176 doc=None, module=None, addsource=True, **attrs):
177 doc=None, module=None, addsource=True, **attrs):
177 """
178 """
178 Create a function from the strings name, signature and body.
179 Create a function from the strings name, signature and body.
179 evaldict is the evaluation dictionary. If addsource is true an attribute
180 evaldict is the evaluation dictionary. If addsource is true an attribute
180 __source__ is added to the result. The attributes attrs are added,
181 __source__ is added to the result. The attributes attrs are added,
181 if any.
182 if any.
182 """
183 """
183 if isinstance(obj, str): # "name(signature)"
184 if isinstance(obj, str): # "name(signature)"
184 name, rest = obj.strip().split('(', 1)
185 name, rest = obj.strip().split('(', 1)
185 signature = rest[:-1] #strip a right parens
186 signature = rest[:-1] #strip a right parens
186 func = None
187 func = None
187 else: # a function
188 else: # a function
188 name = None
189 name = None
189 signature = None
190 signature = None
190 func = obj
191 func = obj
191 self = cls(func, name, signature, defaults, doc, module)
192 self = cls(func, name, signature, defaults, doc, module)
192 ibody = '\n'.join(' ' + line for line in body.splitlines())
193 ibody = '\n'.join(' ' + line for line in body.splitlines())
193 return self.make('def %(name)s(%(signature)s):\n' + ibody,
194 return self.make('def %(name)s(%(signature)s):\n' + ibody,
194 evaldict, addsource, **attrs)
195 evaldict, addsource, **attrs)
195
196
196 def decorator(caller, func=None):
197 def decorator(caller, func=None):
197 """
198 """
198 decorator(caller) converts a caller function into a decorator;
199 decorator(caller) converts a caller function into a decorator;
199 decorator(caller, func) decorates a function using a caller.
200 decorator(caller, func) decorates a function using a caller.
200 """
201 """
201 if func is not None: # returns a decorated function
202 if func is not None: # returns a decorated function
202 evaldict = func.func_globals.copy()
203 evaldict = func.func_globals.copy()
203 evaldict['_call_'] = caller
204 evaldict['_call_'] = caller
204 evaldict['_func_'] = func
205 evaldict['_func_'] = func
205 return FunctionMaker.create(
206 return FunctionMaker.create(
206 func, "return _call_(_func_, %(shortsignature)s)",
207 func, "return _call_(_func_, %(shortsignature)s)",
207 evaldict, undecorated=func, __wrapped__=func)
208 evaldict, undecorated=func, __wrapped__=func)
208 else: # returns a decorator
209 else: # returns a decorator
209 if isinstance(caller, partial):
210 if isinstance(caller, partial):
210 return partial(decorator, caller)
211 return partial(decorator, caller)
211 # otherwise assume caller is a function
212 # otherwise assume caller is a function
212 first = inspect.getargspec(caller)[0][0] # first arg
213 first = inspect.getargspec(caller)[0][0] # first arg
213 evaldict = caller.func_globals.copy()
214 evaldict = caller.func_globals.copy()
214 evaldict['_call_'] = caller
215 evaldict['_call_'] = caller
215 evaldict['decorator'] = decorator
216 evaldict['decorator'] = decorator
216 return FunctionMaker.create(
217 return FunctionMaker.create(
217 '%s(%s)' % (caller.__name__, first),
218 '%s(%s)' % (caller.__name__, first),
218 'return decorator(_call_, %s)' % first,
219 'return decorator(_call_, %s)' % first,
219 evaldict, undecorated=caller, __wrapped__=caller,
220 evaldict, undecorated=caller, __wrapped__=caller,
220 doc=caller.__doc__, module=caller.__module__)
221 doc=caller.__doc__, module=caller.__module__)
@@ -1,233 +1,234 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 """Utility function for installing MathJax javascript library into
2 """Utility function for installing MathJax javascript library into
3 your IPython nbextensions directory, for offline use.
3 your IPython nbextensions directory, for offline use.
4
4
5 Authors:
5 Authors:
6
6
7 * Min RK
7 * Min RK
8 * Mark Sienkiewicz
8 * Mark Sienkiewicz
9 * Matthias Bussonnier
9 * Matthias Bussonnier
10
10
11 To download and install MathJax:
11 To download and install MathJax:
12
12
13 From Python:
13 From Python:
14
14
15 >>> from IPython.external.mathjax import install_mathjax
15 >>> from IPython.external.mathjax import install_mathjax
16 >>> install_mathjax()
16 >>> install_mathjax()
17
17
18 From the command line:
18 From the command line:
19
19
20 $ python -m IPython.external.mathjax
20 $ python -m IPython.external.mathjax
21
21
22 To a specific location:
22 To a specific location:
23
23
24 $ python -m IPython.external.mathjax -i /usr/share/
24 $ python -m IPython.external.mathjax -i /usr/share/
25
25
26 will install mathjax to /usr/share/mathjax
26 will install mathjax to /usr/share/mathjax
27
27
28 To install MathJax from a file you have already downloaded:
28 To install MathJax from a file you have already downloaded:
29
29
30 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
30 $ python -m IPython.external.mathjax mathjax-xxx.tar.gz
31 $ python -m IPython.external.mathjax mathjax-xxx.zip
31 $ python -m IPython.external.mathjax mathjax-xxx.zip
32
32
33 It will not install MathJax if it is already there. Use -r to
33 It will not install MathJax if it is already there. Use -r to
34 replace the existing copy of MathJax.
34 replace the existing copy of MathJax.
35
35
36 To find the directory where IPython would like MathJax installed:
36 To find the directory where IPython would like MathJax installed:
37
37
38 $ python -m IPython.external.mathjax -d
38 $ python -m IPython.external.mathjax -d
39
39
40 """
40 """
41 from __future__ import print_function
41
42
42
43
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44 # Copyright (C) 2011 The IPython Development Team
45 # Copyright (C) 2011 The IPython Development Team
45 #
46 #
46 # Distributed under the terms of the BSD License. The full license is in
47 # Distributed under the terms of the BSD License. The full license is in
47 # the file COPYING, distributed as part of this software.
48 # the file COPYING, distributed as part of this software.
48 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
49
50
50
51
51 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
52 # Imports
53 # Imports
53 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
54
55
55 import argparse
56 import argparse
56 import os
57 import os
57 import shutil
58 import shutil
58 import sys
59 import sys
59 import tarfile
60 import tarfile
60 import urllib2
61 import urllib2
61 import zipfile
62 import zipfile
62
63
63 from IPython.utils.path import get_ipython_dir
64 from IPython.utils.path import get_ipython_dir
64
65
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66 #
67 #
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68
69
69 # Where mathjax will be installed
70 # Where mathjax will be installed
70
71
71 nbextensions = os.path.join(get_ipython_dir(), 'nbextensions')
72 nbextensions = os.path.join(get_ipython_dir(), 'nbextensions')
72 default_dest = os.path.join(nbextensions, 'mathjax')
73 default_dest = os.path.join(nbextensions, 'mathjax')
73
74
74 # Test for access to install mathjax
75 # Test for access to install mathjax
75
76
76 def prepare_dest(dest, replace=False):
77 def prepare_dest(dest, replace=False):
77 """prepare the destination folder for mathjax install
78 """prepare the destination folder for mathjax install
78
79
79 Returns False if mathjax appears to already be installed and there is nothing to do,
80 Returns False if mathjax appears to already be installed and there is nothing to do,
80 True otherwise.
81 True otherwise.
81 """
82 """
82
83
83 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
84 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
84 if not os.path.exists(parent):
85 if not os.path.exists(parent):
85 os.makedirs(parent)
86 os.makedirs(parent)
86
87
87 if os.path.exists(dest):
88 if os.path.exists(dest):
88 if replace:
89 if replace:
89 print "removing existing MathJax at %s" % dest
90 print("removing existing MathJax at %s" % dest)
90 shutil.rmtree(dest)
91 shutil.rmtree(dest)
91 return True
92 return True
92 else:
93 else:
93 mathjax_js = os.path.join(dest, 'MathJax.js')
94 mathjax_js = os.path.join(dest, 'MathJax.js')
94 if not os.path.exists(mathjax_js):
95 if not os.path.exists(mathjax_js):
95 raise IOError("%s exists, but does not contain MathJax.js" % dest)
96 raise IOError("%s exists, but does not contain MathJax.js" % dest)
96 print "%s already exists" % mathjax_js
97 print("%s already exists" % mathjax_js)
97 return False
98 return False
98 else:
99 else:
99 return True
100 return True
100
101
101
102
102 def extract_tar(fd, dest):
103 def extract_tar(fd, dest):
103 """extract a tarball from filelike `fd` to destination `dest`"""
104 """extract a tarball from filelike `fd` to destination `dest`"""
104 # use 'r|gz' stream mode, because socket file-like objects can't seek:
105 # use 'r|gz' stream mode, because socket file-like objects can't seek:
105 tar = tarfile.open(fileobj=fd, mode='r|gz')
106 tar = tarfile.open(fileobj=fd, mode='r|gz')
106
107
107 # The first entry in the archive is the top-level dir
108 # The first entry in the archive is the top-level dir
108 topdir = tar.firstmember.path
109 topdir = tar.firstmember.path
109
110
110 # extract the archive (contains a single directory) to the destination directory
111 # extract the archive (contains a single directory) to the destination directory
111 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
112 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
112 tar.extractall(parent)
113 tar.extractall(parent)
113
114
114 # it will be mathjax-MathJax-<sha>, rename to just mathjax
115 # it will be mathjax-MathJax-<sha>, rename to just mathjax
115 os.rename(os.path.join(parent, topdir), dest)
116 os.rename(os.path.join(parent, topdir), dest)
116
117
117
118
118 def extract_zip(fd, dest):
119 def extract_zip(fd, dest):
119 """extract a zip file from filelike `fd` to destination `dest`"""
120 """extract a zip file from filelike `fd` to destination `dest`"""
120 z = zipfile.ZipFile(fd, 'r')
121 z = zipfile.ZipFile(fd, 'r')
121
122
122 # The first entry in the archive is the top-level dir
123 # The first entry in the archive is the top-level dir
123 topdir = z.namelist()[0]
124 topdir = z.namelist()[0]
124
125
125 # extract the archive (contains a single directory) to the static/ directory
126 # extract the archive (contains a single directory) to the static/ directory
126 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
127 parent = os.path.abspath(os.path.join(dest, os.path.pardir))
127 z.extractall(parent)
128 z.extractall(parent)
128
129
129 # it will be mathjax-MathJax-<sha>, rename to just mathjax
130 # it will be mathjax-MathJax-<sha>, rename to just mathjax
130 d = os.path.join(parent, topdir)
131 d = os.path.join(parent, topdir)
131 os.rename(os.path.join(parent, topdir), dest)
132 os.rename(os.path.join(parent, topdir), dest)
132
133
133
134
134 def install_mathjax(tag='v2.2', dest=default_dest, replace=False, file=None, extractor=extract_tar):
135 def install_mathjax(tag='v2.2', dest=default_dest, replace=False, file=None, extractor=extract_tar):
135 """Download and/or install MathJax for offline use.
136 """Download and/or install MathJax for offline use.
136
137
137 This will install mathjax to the nbextensions dir in your IPYTHONDIR.
138 This will install mathjax to the nbextensions dir in your IPYTHONDIR.
138
139
139 MathJax is a ~15MB download, and ~150MB installed.
140 MathJax is a ~15MB download, and ~150MB installed.
140
141
141 Parameters
142 Parameters
142 ----------
143 ----------
143
144
144 replace : bool [False]
145 replace : bool [False]
145 Whether to remove and replace an existing install.
146 Whether to remove and replace an existing install.
146 dest : str [IPYTHONDIR/nbextensions/mathjax]
147 dest : str [IPYTHONDIR/nbextensions/mathjax]
147 Where to install mathjax
148 Where to install mathjax
148 tag : str ['v2.2']
149 tag : str ['v2.2']
149 Which tag to download. Default is 'v2.2', the current stable release,
150 Which tag to download. Default is 'v2.2', the current stable release,
150 but alternatives include 'v1.1a' and 'master'.
151 but alternatives include 'v1.1a' and 'master'.
151 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
152 file : file like object [ defualt to content of https://github.com/mathjax/MathJax/tarball/#{tag}]
152 File handle from which to untar/unzip/... mathjax
153 File handle from which to untar/unzip/... mathjax
153 extractor : function
154 extractor : function
154 Method to use to untar/unzip/... `file`
155 Method to use to untar/unzip/... `file`
155 """
156 """
156 try:
157 try:
157 anything_to_do = prepare_dest(dest, replace)
158 anything_to_do = prepare_dest(dest, replace)
158 except OSError as e:
159 except OSError as e:
159 print("ERROR %s, require write access to %s" % (e, dest))
160 print(("ERROR %s, require write access to %s" % (e, dest)))
160 return 1
161 return 1
161 else:
162 else:
162 if not anything_to_do:
163 if not anything_to_do:
163 return 0
164 return 0
164
165
165 if file is None:
166 if file is None:
166 # download mathjax
167 # download mathjax
167 mathjax_url = "https://github.com/mathjax/MathJax/archive/%s.tar.gz" %tag
168 mathjax_url = "https://github.com/mathjax/MathJax/archive/%s.tar.gz" %tag
168 print "Downloading mathjax source from %s" % mathjax_url
169 print("Downloading mathjax source from %s" % mathjax_url)
169 response = urllib2.urlopen(mathjax_url)
170 response = urllib2.urlopen(mathjax_url)
170 file = response.fp
171 file = response.fp
171
172
172 print "Extracting to %s" % dest
173 print("Extracting to %s" % dest)
173 extractor(file, dest)
174 extractor(file, dest)
174 return 0
175 return 0
175
176
176
177
177 def main():
178 def main():
178 parser = argparse.ArgumentParser(
179 parser = argparse.ArgumentParser(
179 description="""Install mathjax from internet or local archive""",
180 description="""Install mathjax from internet or local archive""",
180 )
181 )
181
182
182 parser.add_argument(
183 parser.add_argument(
183 '-i',
184 '-i',
184 '--install-dir',
185 '--install-dir',
185 default=nbextensions,
186 default=nbextensions,
186 help='custom installation directory. Mathjax will be installed in here/mathjax')
187 help='custom installation directory. Mathjax will be installed in here/mathjax')
187
188
188 parser.add_argument(
189 parser.add_argument(
189 '-d',
190 '-d',
190 '--print-dest',
191 '--print-dest',
191 action='store_true',
192 action='store_true',
192 help='print where mathjax would be installed and exit')
193 help='print where mathjax would be installed and exit')
193 parser.add_argument(
194 parser.add_argument(
194 '-r',
195 '-r',
195 '--replace',
196 '--replace',
196 action='store_true',
197 action='store_true',
197 help='Whether to replace current mathjax if it already exists')
198 help='Whether to replace current mathjax if it already exists')
198 parser.add_argument('filename',
199 parser.add_argument('filename',
199 help="the local tar/zip-ball filename containing mathjax",
200 help="the local tar/zip-ball filename containing mathjax",
200 nargs='?',
201 nargs='?',
201 metavar='filename')
202 metavar='filename')
202
203
203 pargs = parser.parse_args()
204 pargs = parser.parse_args()
204
205
205 dest = os.path.join(pargs.install_dir, 'mathjax')
206 dest = os.path.join(pargs.install_dir, 'mathjax')
206
207
207 if pargs.print_dest:
208 if pargs.print_dest:
208 print dest
209 print(dest)
209 return
210 return
210
211
211 # remove/replace existing mathjax?
212 # remove/replace existing mathjax?
212 replace = pargs.replace
213 replace = pargs.replace
213
214
214 # do it
215 # do it
215 if pargs.filename:
216 if pargs.filename:
216 fname = pargs.filename
217 fname = pargs.filename
217
218
218 # automatically detect zip/tar - could do something based
219 # automatically detect zip/tar - could do something based
219 # on file content, but really not cost-effective here.
220 # on file content, but really not cost-effective here.
220 if fname.endswith('.zip'):
221 if fname.endswith('.zip'):
221 extractor = extract_zip
222 extractor = extract_zip
222 else :
223 else :
223 extractor = extract_tar
224 extractor = extract_tar
224 # do it
225 # do it
225 return install_mathjax(file=open(fname, "rb"), replace=replace, extractor=extractor, dest=dest)
226 return install_mathjax(file=open(fname, "rb"), replace=replace, extractor=extractor, dest=dest)
226 else:
227 else:
227 return install_mathjax(replace=replace, dest=dest)
228 return install_mathjax(replace=replace, dest=dest)
228
229
229
230
230 if __name__ == '__main__' :
231 if __name__ == '__main__' :
231 sys.exit(main())
232 sys.exit(main())
232
233
233 __all__ = ['install_mathjax', 'main', 'default_dest']
234 __all__ = ['install_mathjax', 'main', 'default_dest']
@@ -1,747 +1,748 b''
1 # coding: utf-8
1 # coding: utf-8
2 """A tornado based IPython notebook server.
2 """A tornado based IPython notebook server.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 from __future__ import print_function
8 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
9 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
10 #
11 #
11 # 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
12 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14
15
15 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
16 # Imports
17 # Imports
17 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
18
19
19 # stdlib
20 # stdlib
20 import errno
21 import errno
21 import logging
22 import logging
22 import os
23 import os
23 import random
24 import random
24 import select
25 import select
25 import signal
26 import signal
26 import socket
27 import socket
27 import sys
28 import sys
28 import threading
29 import threading
29 import time
30 import time
30 import webbrowser
31 import webbrowser
31
32
32
33
33 # Third party
34 # Third party
34 # check for pyzmq 2.1.11
35 # check for pyzmq 2.1.11
35 from IPython.utils.zmqrelated import check_for_zmq
36 from IPython.utils.zmqrelated import check_for_zmq
36 check_for_zmq('2.1.11', 'IPython.html')
37 check_for_zmq('2.1.11', 'IPython.html')
37
38
38 from jinja2 import Environment, FileSystemLoader
39 from jinja2 import Environment, FileSystemLoader
39
40
40 # Install the pyzmq ioloop. This has to be done before anything else from
41 # Install the pyzmq ioloop. This has to be done before anything else from
41 # tornado is imported.
42 # tornado is imported.
42 from zmq.eventloop import ioloop
43 from zmq.eventloop import ioloop
43 ioloop.install()
44 ioloop.install()
44
45
45 # check for tornado 3.1.0
46 # check for tornado 3.1.0
46 msg = "The IPython Notebook requires tornado >= 3.1.0"
47 msg = "The IPython Notebook requires tornado >= 3.1.0"
47 try:
48 try:
48 import tornado
49 import tornado
49 except ImportError:
50 except ImportError:
50 raise ImportError(msg)
51 raise ImportError(msg)
51 try:
52 try:
52 version_info = tornado.version_info
53 version_info = tornado.version_info
53 except AttributeError:
54 except AttributeError:
54 raise ImportError(msg + ", but you have < 1.1.0")
55 raise ImportError(msg + ", but you have < 1.1.0")
55 if version_info < (3,1,0):
56 if version_info < (3,1,0):
56 raise ImportError(msg + ", but you have %s" % tornado.version)
57 raise ImportError(msg + ", but you have %s" % tornado.version)
57
58
58 from tornado import httpserver
59 from tornado import httpserver
59 from tornado import web
60 from tornado import web
60
61
61 # Our own libraries
62 # Our own libraries
62 from IPython.html import DEFAULT_STATIC_FILES_PATH
63 from IPython.html import DEFAULT_STATIC_FILES_PATH
63
64
64 from .services.kernels.kernelmanager import MappingKernelManager
65 from .services.kernels.kernelmanager import MappingKernelManager
65 from .services.notebooks.nbmanager import NotebookManager
66 from .services.notebooks.nbmanager import NotebookManager
66 from .services.notebooks.filenbmanager import FileNotebookManager
67 from .services.notebooks.filenbmanager import FileNotebookManager
67 from .services.clusters.clustermanager import ClusterManager
68 from .services.clusters.clustermanager import ClusterManager
68 from .services.sessions.sessionmanager import SessionManager
69 from .services.sessions.sessionmanager import SessionManager
69
70
70 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
71 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
71
72
72 from IPython.config.application import catch_config_error, boolean_flag
73 from IPython.config.application import catch_config_error, boolean_flag
73 from IPython.core.application import BaseIPythonApplication
74 from IPython.core.application import BaseIPythonApplication
74 from IPython.consoleapp import IPythonConsoleApp
75 from IPython.consoleapp import IPythonConsoleApp
75 from IPython.kernel import swallow_argv
76 from IPython.kernel import swallow_argv
76 from IPython.kernel.zmq.session import default_secure
77 from IPython.kernel.zmq.session import default_secure
77 from IPython.kernel.zmq.kernelapp import (
78 from IPython.kernel.zmq.kernelapp import (
78 kernel_flags,
79 kernel_flags,
79 kernel_aliases,
80 kernel_aliases,
80 )
81 )
81 from IPython.utils.importstring import import_item
82 from IPython.utils.importstring import import_item
82 from IPython.utils.localinterfaces import localhost
83 from IPython.utils.localinterfaces import localhost
83 from IPython.utils import submodule
84 from IPython.utils import submodule
84 from IPython.utils.traitlets import (
85 from IPython.utils.traitlets import (
85 Dict, Unicode, Integer, List, Bool, Bytes,
86 Dict, Unicode, Integer, List, Bool, Bytes,
86 DottedObjectName
87 DottedObjectName
87 )
88 )
88 from IPython.utils import py3compat
89 from IPython.utils import py3compat
89 from IPython.utils.path import filefind, get_ipython_dir
90 from IPython.utils.path import filefind, get_ipython_dir
90
91
91 from .utils import url_path_join
92 from .utils import url_path_join
92
93
93 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
94 # Module globals
95 # Module globals
95 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
96
97
97 _examples = """
98 _examples = """
98 ipython notebook # start the notebook
99 ipython notebook # start the notebook
99 ipython notebook --profile=sympy # use the sympy profile
100 ipython notebook --profile=sympy # use the sympy profile
100 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
101 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
101 """
102 """
102
103
103 #-----------------------------------------------------------------------------
104 #-----------------------------------------------------------------------------
104 # Helper functions
105 # Helper functions
105 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
106
107
107 def random_ports(port, n):
108 def random_ports(port, n):
108 """Generate a list of n random ports near the given port.
109 """Generate a list of n random ports near the given port.
109
110
110 The first 5 ports will be sequential, and the remaining n-5 will be
111 The first 5 ports will be sequential, and the remaining n-5 will be
111 randomly selected in the range [port-2*n, port+2*n].
112 randomly selected in the range [port-2*n, port+2*n].
112 """
113 """
113 for i in range(min(5, n)):
114 for i in range(min(5, n)):
114 yield port + i
115 yield port + i
115 for i in range(n-5):
116 for i in range(n-5):
116 yield max(1, port + random.randint(-2*n, 2*n))
117 yield max(1, port + random.randint(-2*n, 2*n))
117
118
118 def load_handlers(name):
119 def load_handlers(name):
119 """Load the (URL pattern, handler) tuples for each component."""
120 """Load the (URL pattern, handler) tuples for each component."""
120 name = 'IPython.html.' + name
121 name = 'IPython.html.' + name
121 mod = __import__(name, fromlist=['default_handlers'])
122 mod = __import__(name, fromlist=['default_handlers'])
122 return mod.default_handlers
123 return mod.default_handlers
123
124
124 #-----------------------------------------------------------------------------
125 #-----------------------------------------------------------------------------
125 # The Tornado web application
126 # The Tornado web application
126 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
127
128
128 class NotebookWebApplication(web.Application):
129 class NotebookWebApplication(web.Application):
129
130
130 def __init__(self, ipython_app, kernel_manager, notebook_manager,
131 def __init__(self, ipython_app, kernel_manager, notebook_manager,
131 cluster_manager, session_manager, log, base_project_url,
132 cluster_manager, session_manager, log, base_project_url,
132 settings_overrides):
133 settings_overrides):
133
134
134 settings = self.init_settings(
135 settings = self.init_settings(
135 ipython_app, kernel_manager, notebook_manager, cluster_manager,
136 ipython_app, kernel_manager, notebook_manager, cluster_manager,
136 session_manager, log, base_project_url, settings_overrides)
137 session_manager, log, base_project_url, settings_overrides)
137 handlers = self.init_handlers(settings)
138 handlers = self.init_handlers(settings)
138
139
139 super(NotebookWebApplication, self).__init__(handlers, **settings)
140 super(NotebookWebApplication, self).__init__(handlers, **settings)
140
141
141 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
142 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
142 cluster_manager, session_manager, log, base_project_url,
143 cluster_manager, session_manager, log, base_project_url,
143 settings_overrides):
144 settings_overrides):
144 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
145 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
145 # base_project_url will always be unicode, which will in turn
146 # base_project_url will always be unicode, which will in turn
146 # make the patterns unicode, and ultimately result in unicode
147 # make the patterns unicode, and ultimately result in unicode
147 # keys in kwargs to handler._execute(**kwargs) in tornado.
148 # keys in kwargs to handler._execute(**kwargs) in tornado.
148 # This enforces that base_project_url be ascii in that situation.
149 # This enforces that base_project_url be ascii in that situation.
149 #
150 #
150 # Note that the URLs these patterns check against are escaped,
151 # Note that the URLs these patterns check against are escaped,
151 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
152 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
152 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
153 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
153 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
154 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
154 settings = dict(
155 settings = dict(
155 # basics
156 # basics
156 base_project_url=base_project_url,
157 base_project_url=base_project_url,
157 base_kernel_url=ipython_app.base_kernel_url,
158 base_kernel_url=ipython_app.base_kernel_url,
158 template_path=template_path,
159 template_path=template_path,
159 static_path=ipython_app.static_file_path,
160 static_path=ipython_app.static_file_path,
160 static_handler_class = FileFindHandler,
161 static_handler_class = FileFindHandler,
161 static_url_prefix = url_path_join(base_project_url,'/static/'),
162 static_url_prefix = url_path_join(base_project_url,'/static/'),
162
163
163 # authentication
164 # authentication
164 cookie_secret=ipython_app.cookie_secret,
165 cookie_secret=ipython_app.cookie_secret,
165 login_url=url_path_join(base_project_url,'/login'),
166 login_url=url_path_join(base_project_url,'/login'),
166 password=ipython_app.password,
167 password=ipython_app.password,
167
168
168 # managers
169 # managers
169 kernel_manager=kernel_manager,
170 kernel_manager=kernel_manager,
170 notebook_manager=notebook_manager,
171 notebook_manager=notebook_manager,
171 cluster_manager=cluster_manager,
172 cluster_manager=cluster_manager,
172 session_manager=session_manager,
173 session_manager=session_manager,
173
174
174 # IPython stuff
175 # IPython stuff
175 nbextensions_path = ipython_app.nbextensions_path,
176 nbextensions_path = ipython_app.nbextensions_path,
176 mathjax_url=ipython_app.mathjax_url,
177 mathjax_url=ipython_app.mathjax_url,
177 config=ipython_app.config,
178 config=ipython_app.config,
178 use_less=ipython_app.use_less,
179 use_less=ipython_app.use_less,
179 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
180 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
180 )
181 )
181
182
182 # allow custom overrides for the tornado web app.
183 # allow custom overrides for the tornado web app.
183 settings.update(settings_overrides)
184 settings.update(settings_overrides)
184 return settings
185 return settings
185
186
186 def init_handlers(self, settings):
187 def init_handlers(self, settings):
187 # Load the (URL pattern, handler) tuples for each component.
188 # Load the (URL pattern, handler) tuples for each component.
188 handlers = []
189 handlers = []
189 handlers.extend(load_handlers('base.handlers'))
190 handlers.extend(load_handlers('base.handlers'))
190 handlers.extend(load_handlers('tree.handlers'))
191 handlers.extend(load_handlers('tree.handlers'))
191 handlers.extend(load_handlers('auth.login'))
192 handlers.extend(load_handlers('auth.login'))
192 handlers.extend(load_handlers('auth.logout'))
193 handlers.extend(load_handlers('auth.logout'))
193 handlers.extend(load_handlers('notebook.handlers'))
194 handlers.extend(load_handlers('notebook.handlers'))
194 handlers.extend(load_handlers('services.kernels.handlers'))
195 handlers.extend(load_handlers('services.kernels.handlers'))
195 handlers.extend(load_handlers('services.notebooks.handlers'))
196 handlers.extend(load_handlers('services.notebooks.handlers'))
196 handlers.extend(load_handlers('services.clusters.handlers'))
197 handlers.extend(load_handlers('services.clusters.handlers'))
197 handlers.extend(load_handlers('services.sessions.handlers'))
198 handlers.extend(load_handlers('services.sessions.handlers'))
198 handlers.extend([
199 handlers.extend([
199 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
200 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
200 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
201 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
201 ])
202 ])
202 # prepend base_project_url onto the patterns that we match
203 # prepend base_project_url onto the patterns that we match
203 new_handlers = []
204 new_handlers = []
204 for handler in handlers:
205 for handler in handlers:
205 pattern = url_path_join(settings['base_project_url'], handler[0])
206 pattern = url_path_join(settings['base_project_url'], handler[0])
206 new_handler = tuple([pattern] + list(handler[1:]))
207 new_handler = tuple([pattern] + list(handler[1:]))
207 new_handlers.append(new_handler)
208 new_handlers.append(new_handler)
208 return new_handlers
209 return new_handlers
209
210
210
211
211
212
212 #-----------------------------------------------------------------------------
213 #-----------------------------------------------------------------------------
213 # Aliases and Flags
214 # Aliases and Flags
214 #-----------------------------------------------------------------------------
215 #-----------------------------------------------------------------------------
215
216
216 flags = dict(kernel_flags)
217 flags = dict(kernel_flags)
217 flags['no-browser']=(
218 flags['no-browser']=(
218 {'NotebookApp' : {'open_browser' : False}},
219 {'NotebookApp' : {'open_browser' : False}},
219 "Don't open the notebook in a browser after startup."
220 "Don't open the notebook in a browser after startup."
220 )
221 )
221 flags['no-mathjax']=(
222 flags['no-mathjax']=(
222 {'NotebookApp' : {'enable_mathjax' : False}},
223 {'NotebookApp' : {'enable_mathjax' : False}},
223 """Disable MathJax
224 """Disable MathJax
224
225
225 MathJax is the javascript library IPython uses to render math/LaTeX. It is
226 MathJax is the javascript library IPython uses to render math/LaTeX. It is
226 very large, so you may want to disable it if you have a slow internet
227 very large, so you may want to disable it if you have a slow internet
227 connection, or for offline use of the notebook.
228 connection, or for offline use of the notebook.
228
229
229 When disabled, equations etc. will appear as their untransformed TeX source.
230 When disabled, equations etc. will appear as their untransformed TeX source.
230 """
231 """
231 )
232 )
232
233
233 # Add notebook manager flags
234 # Add notebook manager flags
234 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
235 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
235 'Auto-save a .py script everytime the .ipynb notebook is saved',
236 'Auto-save a .py script everytime the .ipynb notebook is saved',
236 'Do not auto-save .py scripts for every notebook'))
237 'Do not auto-save .py scripts for every notebook'))
237
238
238 # the flags that are specific to the frontend
239 # the flags that are specific to the frontend
239 # these must be scrubbed before being passed to the kernel,
240 # these must be scrubbed before being passed to the kernel,
240 # or it will raise an error on unrecognized flags
241 # or it will raise an error on unrecognized flags
241 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
242 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
242
243
243 aliases = dict(kernel_aliases)
244 aliases = dict(kernel_aliases)
244
245
245 aliases.update({
246 aliases.update({
246 'ip': 'NotebookApp.ip',
247 'ip': 'NotebookApp.ip',
247 'port': 'NotebookApp.port',
248 'port': 'NotebookApp.port',
248 'port-retries': 'NotebookApp.port_retries',
249 'port-retries': 'NotebookApp.port_retries',
249 'transport': 'KernelManager.transport',
250 'transport': 'KernelManager.transport',
250 'keyfile': 'NotebookApp.keyfile',
251 'keyfile': 'NotebookApp.keyfile',
251 'certfile': 'NotebookApp.certfile',
252 'certfile': 'NotebookApp.certfile',
252 'notebook-dir': 'NotebookManager.notebook_dir',
253 'notebook-dir': 'NotebookManager.notebook_dir',
253 'browser': 'NotebookApp.browser',
254 'browser': 'NotebookApp.browser',
254 })
255 })
255
256
256 # remove ipkernel flags that are singletons, and don't make sense in
257 # remove ipkernel flags that are singletons, and don't make sense in
257 # multi-kernel evironment:
258 # multi-kernel evironment:
258 aliases.pop('f', None)
259 aliases.pop('f', None)
259
260
260 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
261 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
261 u'notebook-dir', u'profile', u'profile-dir']
262 u'notebook-dir', u'profile', u'profile-dir']
262
263
263 #-----------------------------------------------------------------------------
264 #-----------------------------------------------------------------------------
264 # NotebookApp
265 # NotebookApp
265 #-----------------------------------------------------------------------------
266 #-----------------------------------------------------------------------------
266
267
267 class NotebookApp(BaseIPythonApplication):
268 class NotebookApp(BaseIPythonApplication):
268
269
269 name = 'ipython-notebook'
270 name = 'ipython-notebook'
270
271
271 description = """
272 description = """
272 The IPython HTML Notebook.
273 The IPython HTML Notebook.
273
274
274 This launches a Tornado based HTML Notebook Server that serves up an
275 This launches a Tornado based HTML Notebook Server that serves up an
275 HTML5/Javascript Notebook client.
276 HTML5/Javascript Notebook client.
276 """
277 """
277 examples = _examples
278 examples = _examples
278
279
279 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
280 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
280 FileNotebookManager]
281 FileNotebookManager]
281 flags = Dict(flags)
282 flags = Dict(flags)
282 aliases = Dict(aliases)
283 aliases = Dict(aliases)
283
284
284 kernel_argv = List(Unicode)
285 kernel_argv = List(Unicode)
285
286
286 def _log_level_default(self):
287 def _log_level_default(self):
287 return logging.INFO
288 return logging.INFO
288
289
289 def _log_format_default(self):
290 def _log_format_default(self):
290 """override default log format to include time"""
291 """override default log format to include time"""
291 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
292 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
292
293
293 # create requested profiles by default, if they don't exist:
294 # create requested profiles by default, if they don't exist:
294 auto_create = Bool(True)
295 auto_create = Bool(True)
295
296
296 # file to be opened in the notebook server
297 # file to be opened in the notebook server
297 file_to_run = Unicode('')
298 file_to_run = Unicode('')
298
299
299 # Network related information.
300 # Network related information.
300
301
301 ip = Unicode(config=True,
302 ip = Unicode(config=True,
302 help="The IP address the notebook server will listen on."
303 help="The IP address the notebook server will listen on."
303 )
304 )
304 def _ip_default(self):
305 def _ip_default(self):
305 return localhost()
306 return localhost()
306
307
307 def _ip_changed(self, name, old, new):
308 def _ip_changed(self, name, old, new):
308 if new == u'*': self.ip = u''
309 if new == u'*': self.ip = u''
309
310
310 port = Integer(8888, config=True,
311 port = Integer(8888, config=True,
311 help="The port the notebook server will listen on."
312 help="The port the notebook server will listen on."
312 )
313 )
313 port_retries = Integer(50, config=True,
314 port_retries = Integer(50, config=True,
314 help="The number of additional ports to try if the specified port is not available."
315 help="The number of additional ports to try if the specified port is not available."
315 )
316 )
316
317
317 certfile = Unicode(u'', config=True,
318 certfile = Unicode(u'', config=True,
318 help="""The full path to an SSL/TLS certificate file."""
319 help="""The full path to an SSL/TLS certificate file."""
319 )
320 )
320
321
321 keyfile = Unicode(u'', config=True,
322 keyfile = Unicode(u'', config=True,
322 help="""The full path to a private key file for usage with SSL/TLS."""
323 help="""The full path to a private key file for usage with SSL/TLS."""
323 )
324 )
324
325
325 cookie_secret = Bytes(b'', config=True,
326 cookie_secret = Bytes(b'', config=True,
326 help="""The random bytes used to secure cookies.
327 help="""The random bytes used to secure cookies.
327 By default this is a new random number every time you start the Notebook.
328 By default this is a new random number every time you start the Notebook.
328 Set it to a value in a config file to enable logins to persist across server sessions.
329 Set it to a value in a config file to enable logins to persist across server sessions.
329
330
330 Note: Cookie secrets should be kept private, do not share config files with
331 Note: Cookie secrets should be kept private, do not share config files with
331 cookie_secret stored in plaintext (you can read the value from a file).
332 cookie_secret stored in plaintext (you can read the value from a file).
332 """
333 """
333 )
334 )
334 def _cookie_secret_default(self):
335 def _cookie_secret_default(self):
335 return os.urandom(1024)
336 return os.urandom(1024)
336
337
337 password = Unicode(u'', config=True,
338 password = Unicode(u'', config=True,
338 help="""Hashed password to use for web authentication.
339 help="""Hashed password to use for web authentication.
339
340
340 To generate, type in a python/IPython shell:
341 To generate, type in a python/IPython shell:
341
342
342 from IPython.lib import passwd; passwd()
343 from IPython.lib import passwd; passwd()
343
344
344 The string should be of the form type:salt:hashed-password.
345 The string should be of the form type:salt:hashed-password.
345 """
346 """
346 )
347 )
347
348
348 open_browser = Bool(True, config=True,
349 open_browser = Bool(True, config=True,
349 help="""Whether to open in a browser after starting.
350 help="""Whether to open in a browser after starting.
350 The specific browser used is platform dependent and
351 The specific browser used is platform dependent and
351 determined by the python standard library `webbrowser`
352 determined by the python standard library `webbrowser`
352 module, unless it is overridden using the --browser
353 module, unless it is overridden using the --browser
353 (NotebookApp.browser) configuration option.
354 (NotebookApp.browser) configuration option.
354 """)
355 """)
355
356
356 browser = Unicode(u'', config=True,
357 browser = Unicode(u'', config=True,
357 help="""Specify what command to use to invoke a web
358 help="""Specify what command to use to invoke a web
358 browser when opening the notebook. If not specified, the
359 browser when opening the notebook. If not specified, the
359 default browser will be determined by the `webbrowser`
360 default browser will be determined by the `webbrowser`
360 standard library module, which allows setting of the
361 standard library module, which allows setting of the
361 BROWSER environment variable to override it.
362 BROWSER environment variable to override it.
362 """)
363 """)
363
364
364 use_less = Bool(False, config=True,
365 use_less = Bool(False, config=True,
365 help="""Wether to use Browser Side less-css parsing
366 help="""Wether to use Browser Side less-css parsing
366 instead of compiled css version in templates that allows
367 instead of compiled css version in templates that allows
367 it. This is mainly convenient when working on the less
368 it. This is mainly convenient when working on the less
368 file to avoid a build step, or if user want to overwrite
369 file to avoid a build step, or if user want to overwrite
369 some of the less variables without having to recompile
370 some of the less variables without having to recompile
370 everything.
371 everything.
371
372
372 You will need to install the less.js component in the static directory
373 You will need to install the less.js component in the static directory
373 either in the source tree or in your profile folder.
374 either in the source tree or in your profile folder.
374 """)
375 """)
375
376
376 webapp_settings = Dict(config=True,
377 webapp_settings = Dict(config=True,
377 help="Supply overrides for the tornado.web.Application that the "
378 help="Supply overrides for the tornado.web.Application that the "
378 "IPython notebook uses.")
379 "IPython notebook uses.")
379
380
380 enable_mathjax = Bool(True, config=True,
381 enable_mathjax = Bool(True, config=True,
381 help="""Whether to enable MathJax for typesetting math/TeX
382 help="""Whether to enable MathJax for typesetting math/TeX
382
383
383 MathJax is the javascript library IPython uses to render math/LaTeX. It is
384 MathJax is the javascript library IPython uses to render math/LaTeX. It is
384 very large, so you may want to disable it if you have a slow internet
385 very large, so you may want to disable it if you have a slow internet
385 connection, or for offline use of the notebook.
386 connection, or for offline use of the notebook.
386
387
387 When disabled, equations etc. will appear as their untransformed TeX source.
388 When disabled, equations etc. will appear as their untransformed TeX source.
388 """
389 """
389 )
390 )
390 def _enable_mathjax_changed(self, name, old, new):
391 def _enable_mathjax_changed(self, name, old, new):
391 """set mathjax url to empty if mathjax is disabled"""
392 """set mathjax url to empty if mathjax is disabled"""
392 if not new:
393 if not new:
393 self.mathjax_url = u''
394 self.mathjax_url = u''
394
395
395 base_project_url = Unicode('/', config=True,
396 base_project_url = Unicode('/', config=True,
396 help='''The base URL for the notebook server.
397 help='''The base URL for the notebook server.
397
398
398 Leading and trailing slashes can be omitted,
399 Leading and trailing slashes can be omitted,
399 and will automatically be added.
400 and will automatically be added.
400 ''')
401 ''')
401 def _base_project_url_changed(self, name, old, new):
402 def _base_project_url_changed(self, name, old, new):
402 if not new.startswith('/'):
403 if not new.startswith('/'):
403 self.base_project_url = '/'+new
404 self.base_project_url = '/'+new
404 elif not new.endswith('/'):
405 elif not new.endswith('/'):
405 self.base_project_url = new+'/'
406 self.base_project_url = new+'/'
406
407
407 base_kernel_url = Unicode('/', config=True,
408 base_kernel_url = Unicode('/', config=True,
408 help='''The base URL for the kernel server
409 help='''The base URL for the kernel server
409
410
410 Leading and trailing slashes can be omitted,
411 Leading and trailing slashes can be omitted,
411 and will automatically be added.
412 and will automatically be added.
412 ''')
413 ''')
413 def _base_kernel_url_changed(self, name, old, new):
414 def _base_kernel_url_changed(self, name, old, new):
414 if not new.startswith('/'):
415 if not new.startswith('/'):
415 self.base_kernel_url = '/'+new
416 self.base_kernel_url = '/'+new
416 elif not new.endswith('/'):
417 elif not new.endswith('/'):
417 self.base_kernel_url = new+'/'
418 self.base_kernel_url = new+'/'
418
419
419 websocket_url = Unicode("", config=True,
420 websocket_url = Unicode("", config=True,
420 help="""The base URL for the websocket server,
421 help="""The base URL for the websocket server,
421 if it differs from the HTTP server (hint: it almost certainly doesn't).
422 if it differs from the HTTP server (hint: it almost certainly doesn't).
422
423
423 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
424 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
424 """
425 """
425 )
426 )
426
427
427 extra_static_paths = List(Unicode, config=True,
428 extra_static_paths = List(Unicode, config=True,
428 help="""Extra paths to search for serving static files.
429 help="""Extra paths to search for serving static files.
429
430
430 This allows adding javascript/css to be available from the notebook server machine,
431 This allows adding javascript/css to be available from the notebook server machine,
431 or overriding individual files in the IPython"""
432 or overriding individual files in the IPython"""
432 )
433 )
433 def _extra_static_paths_default(self):
434 def _extra_static_paths_default(self):
434 return [os.path.join(self.profile_dir.location, 'static')]
435 return [os.path.join(self.profile_dir.location, 'static')]
435
436
436 @property
437 @property
437 def static_file_path(self):
438 def static_file_path(self):
438 """return extra paths + the default location"""
439 """return extra paths + the default location"""
439 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
440 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
440
441
441 nbextensions_path = List(Unicode, config=True,
442 nbextensions_path = List(Unicode, config=True,
442 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
443 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
443 )
444 )
444 def _nbextensions_path_default(self):
445 def _nbextensions_path_default(self):
445 return [os.path.join(get_ipython_dir(), 'nbextensions')]
446 return [os.path.join(get_ipython_dir(), 'nbextensions')]
446
447
447 mathjax_url = Unicode("", config=True,
448 mathjax_url = Unicode("", config=True,
448 help="""The url for MathJax.js."""
449 help="""The url for MathJax.js."""
449 )
450 )
450 def _mathjax_url_default(self):
451 def _mathjax_url_default(self):
451 if not self.enable_mathjax:
452 if not self.enable_mathjax:
452 return u''
453 return u''
453 static_url_prefix = self.webapp_settings.get("static_url_prefix",
454 static_url_prefix = self.webapp_settings.get("static_url_prefix",
454 url_path_join(self.base_project_url, "static")
455 url_path_join(self.base_project_url, "static")
455 )
456 )
456
457
457 # try local mathjax, either in nbextensions/mathjax or static/mathjax
458 # try local mathjax, either in nbextensions/mathjax or static/mathjax
458 for (url_prefix, search_path) in [
459 for (url_prefix, search_path) in [
459 (url_path_join(self.base_project_url, "nbextensions"), self.nbextensions_path),
460 (url_path_join(self.base_project_url, "nbextensions"), self.nbextensions_path),
460 (static_url_prefix, self.static_file_path),
461 (static_url_prefix, self.static_file_path),
461 ]:
462 ]:
462 self.log.debug("searching for local mathjax in %s", search_path)
463 self.log.debug("searching for local mathjax in %s", search_path)
463 try:
464 try:
464 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
465 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
465 except IOError:
466 except IOError:
466 continue
467 continue
467 else:
468 else:
468 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
469 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
469 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
470 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
470 return url
471 return url
471
472
472 # no local mathjax, serve from CDN
473 # no local mathjax, serve from CDN
473 if self.certfile:
474 if self.certfile:
474 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
475 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
475 host = u"https://c328740.ssl.cf1.rackcdn.com"
476 host = u"https://c328740.ssl.cf1.rackcdn.com"
476 else:
477 else:
477 host = u"http://cdn.mathjax.org"
478 host = u"http://cdn.mathjax.org"
478
479
479 url = host + u"/mathjax/latest/MathJax.js"
480 url = host + u"/mathjax/latest/MathJax.js"
480 self.log.info("Using MathJax from CDN: %s", url)
481 self.log.info("Using MathJax from CDN: %s", url)
481 return url
482 return url
482
483
483 def _mathjax_url_changed(self, name, old, new):
484 def _mathjax_url_changed(self, name, old, new):
484 if new and not self.enable_mathjax:
485 if new and not self.enable_mathjax:
485 # enable_mathjax=False overrides mathjax_url
486 # enable_mathjax=False overrides mathjax_url
486 self.mathjax_url = u''
487 self.mathjax_url = u''
487 else:
488 else:
488 self.log.info("Using MathJax: %s", new)
489 self.log.info("Using MathJax: %s", new)
489
490
490 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
491 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
491 config=True,
492 config=True,
492 help='The notebook manager class to use.')
493 help='The notebook manager class to use.')
493
494
494 trust_xheaders = Bool(False, config=True,
495 trust_xheaders = Bool(False, config=True,
495 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
496 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
496 "sent by the upstream reverse proxy. Neccesary if the proxy handles SSL")
497 "sent by the upstream reverse proxy. Neccesary if the proxy handles SSL")
497 )
498 )
498
499
499 def parse_command_line(self, argv=None):
500 def parse_command_line(self, argv=None):
500 super(NotebookApp, self).parse_command_line(argv)
501 super(NotebookApp, self).parse_command_line(argv)
501
502
502 if self.extra_args:
503 if self.extra_args:
503 arg0 = self.extra_args[0]
504 arg0 = self.extra_args[0]
504 f = os.path.abspath(arg0)
505 f = os.path.abspath(arg0)
505 self.argv.remove(arg0)
506 self.argv.remove(arg0)
506 if not os.path.exists(f):
507 if not os.path.exists(f):
507 self.log.critical("No such file or directory: %s", f)
508 self.log.critical("No such file or directory: %s", f)
508 self.exit(1)
509 self.exit(1)
509 if os.path.isdir(f):
510 if os.path.isdir(f):
510 self.config.FileNotebookManager.notebook_dir = f
511 self.config.FileNotebookManager.notebook_dir = f
511 elif os.path.isfile(f):
512 elif os.path.isfile(f):
512 self.file_to_run = f
513 self.file_to_run = f
513
514
514 def init_kernel_argv(self):
515 def init_kernel_argv(self):
515 """construct the kernel arguments"""
516 """construct the kernel arguments"""
516 # Scrub frontend-specific flags
517 # Scrub frontend-specific flags
517 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
518 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
518 # Kernel should inherit default config file from frontend
519 # Kernel should inherit default config file from frontend
519 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
520 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
520 # Kernel should get *absolute* path to profile directory
521 # Kernel should get *absolute* path to profile directory
521 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
522 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
522
523
523 def init_configurables(self):
524 def init_configurables(self):
524 # force Session default to be secure
525 # force Session default to be secure
525 default_secure(self.config)
526 default_secure(self.config)
526 self.kernel_manager = MappingKernelManager(
527 self.kernel_manager = MappingKernelManager(
527 parent=self, log=self.log, kernel_argv=self.kernel_argv,
528 parent=self, log=self.log, kernel_argv=self.kernel_argv,
528 connection_dir = self.profile_dir.security_dir,
529 connection_dir = self.profile_dir.security_dir,
529 )
530 )
530 kls = import_item(self.notebook_manager_class)
531 kls = import_item(self.notebook_manager_class)
531 self.notebook_manager = kls(parent=self, log=self.log)
532 self.notebook_manager = kls(parent=self, log=self.log)
532 self.session_manager = SessionManager(parent=self, log=self.log)
533 self.session_manager = SessionManager(parent=self, log=self.log)
533 self.cluster_manager = ClusterManager(parent=self, log=self.log)
534 self.cluster_manager = ClusterManager(parent=self, log=self.log)
534 self.cluster_manager.update_profiles()
535 self.cluster_manager.update_profiles()
535
536
536 def init_logging(self):
537 def init_logging(self):
537 # This prevents double log messages because tornado use a root logger that
538 # This prevents double log messages because tornado use a root logger that
538 # self.log is a child of. The logging module dipatches log messages to a log
539 # self.log is a child of. The logging module dipatches log messages to a log
539 # and all of its ancenstors until propagate is set to False.
540 # and all of its ancenstors until propagate is set to False.
540 self.log.propagate = False
541 self.log.propagate = False
541
542
542 # hook up tornado 3's loggers to our app handlers
543 # hook up tornado 3's loggers to our app handlers
543 for name in ('access', 'application', 'general'):
544 for name in ('access', 'application', 'general'):
544 logger = logging.getLogger('tornado.%s' % name)
545 logger = logging.getLogger('tornado.%s' % name)
545 logger.parent = self.log
546 logger.parent = self.log
546 logger.setLevel(self.log.level)
547 logger.setLevel(self.log.level)
547
548
548 def init_webapp(self):
549 def init_webapp(self):
549 """initialize tornado webapp and httpserver"""
550 """initialize tornado webapp and httpserver"""
550 self.web_app = NotebookWebApplication(
551 self.web_app = NotebookWebApplication(
551 self, self.kernel_manager, self.notebook_manager,
552 self, self.kernel_manager, self.notebook_manager,
552 self.cluster_manager, self.session_manager,
553 self.cluster_manager, self.session_manager,
553 self.log, self.base_project_url, self.webapp_settings
554 self.log, self.base_project_url, self.webapp_settings
554 )
555 )
555 if self.certfile:
556 if self.certfile:
556 ssl_options = dict(certfile=self.certfile)
557 ssl_options = dict(certfile=self.certfile)
557 if self.keyfile:
558 if self.keyfile:
558 ssl_options['keyfile'] = self.keyfile
559 ssl_options['keyfile'] = self.keyfile
559 else:
560 else:
560 ssl_options = None
561 ssl_options = None
561 self.web_app.password = self.password
562 self.web_app.password = self.password
562 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
563 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
563 xheaders=self.trust_xheaders)
564 xheaders=self.trust_xheaders)
564 if not self.ip:
565 if not self.ip:
565 warning = "WARNING: The notebook server is listening on all IP addresses"
566 warning = "WARNING: The notebook server is listening on all IP addresses"
566 if ssl_options is None:
567 if ssl_options is None:
567 self.log.critical(warning + " and not using encryption. This "
568 self.log.critical(warning + " and not using encryption. This "
568 "is not recommended.")
569 "is not recommended.")
569 if not self.password:
570 if not self.password:
570 self.log.critical(warning + " and not using authentication. "
571 self.log.critical(warning + " and not using authentication. "
571 "This is highly insecure and not recommended.")
572 "This is highly insecure and not recommended.")
572 success = None
573 success = None
573 for port in random_ports(self.port, self.port_retries+1):
574 for port in random_ports(self.port, self.port_retries+1):
574 try:
575 try:
575 self.http_server.listen(port, self.ip)
576 self.http_server.listen(port, self.ip)
576 except socket.error as e:
577 except socket.error as e:
577 if e.errno == errno.EADDRINUSE:
578 if e.errno == errno.EADDRINUSE:
578 self.log.info('The port %i is already in use, trying another random port.' % port)
579 self.log.info('The port %i is already in use, trying another random port.' % port)
579 continue
580 continue
580 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
581 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
581 self.log.warn("Permission to listen on port %i denied" % port)
582 self.log.warn("Permission to listen on port %i denied" % port)
582 continue
583 continue
583 else:
584 else:
584 raise
585 raise
585 else:
586 else:
586 self.port = port
587 self.port = port
587 success = True
588 success = True
588 break
589 break
589 if not success:
590 if not success:
590 self.log.critical('ERROR: the notebook server could not be started because '
591 self.log.critical('ERROR: the notebook server could not be started because '
591 'no available port could be found.')
592 'no available port could be found.')
592 self.exit(1)
593 self.exit(1)
593
594
594 def init_signal(self):
595 def init_signal(self):
595 if not sys.platform.startswith('win'):
596 if not sys.platform.startswith('win'):
596 signal.signal(signal.SIGINT, self._handle_sigint)
597 signal.signal(signal.SIGINT, self._handle_sigint)
597 signal.signal(signal.SIGTERM, self._signal_stop)
598 signal.signal(signal.SIGTERM, self._signal_stop)
598 if hasattr(signal, 'SIGUSR1'):
599 if hasattr(signal, 'SIGUSR1'):
599 # Windows doesn't support SIGUSR1
600 # Windows doesn't support SIGUSR1
600 signal.signal(signal.SIGUSR1, self._signal_info)
601 signal.signal(signal.SIGUSR1, self._signal_info)
601 if hasattr(signal, 'SIGINFO'):
602 if hasattr(signal, 'SIGINFO'):
602 # only on BSD-based systems
603 # only on BSD-based systems
603 signal.signal(signal.SIGINFO, self._signal_info)
604 signal.signal(signal.SIGINFO, self._signal_info)
604
605
605 def _handle_sigint(self, sig, frame):
606 def _handle_sigint(self, sig, frame):
606 """SIGINT handler spawns confirmation dialog"""
607 """SIGINT handler spawns confirmation dialog"""
607 # register more forceful signal handler for ^C^C case
608 # register more forceful signal handler for ^C^C case
608 signal.signal(signal.SIGINT, self._signal_stop)
609 signal.signal(signal.SIGINT, self._signal_stop)
609 # request confirmation dialog in bg thread, to avoid
610 # request confirmation dialog in bg thread, to avoid
610 # blocking the App
611 # blocking the App
611 thread = threading.Thread(target=self._confirm_exit)
612 thread = threading.Thread(target=self._confirm_exit)
612 thread.daemon = True
613 thread.daemon = True
613 thread.start()
614 thread.start()
614
615
615 def _restore_sigint_handler(self):
616 def _restore_sigint_handler(self):
616 """callback for restoring original SIGINT handler"""
617 """callback for restoring original SIGINT handler"""
617 signal.signal(signal.SIGINT, self._handle_sigint)
618 signal.signal(signal.SIGINT, self._handle_sigint)
618
619
619 def _confirm_exit(self):
620 def _confirm_exit(self):
620 """confirm shutdown on ^C
621 """confirm shutdown on ^C
621
622
622 A second ^C, or answering 'y' within 5s will cause shutdown,
623 A second ^C, or answering 'y' within 5s will cause shutdown,
623 otherwise original SIGINT handler will be restored.
624 otherwise original SIGINT handler will be restored.
624
625
625 This doesn't work on Windows.
626 This doesn't work on Windows.
626 """
627 """
627 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
628 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
628 time.sleep(0.1)
629 time.sleep(0.1)
629 info = self.log.info
630 info = self.log.info
630 info('interrupted')
631 info('interrupted')
631 print self.notebook_info()
632 print(self.notebook_info())
632 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
633 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
633 sys.stdout.flush()
634 sys.stdout.flush()
634 r,w,x = select.select([sys.stdin], [], [], 5)
635 r,w,x = select.select([sys.stdin], [], [], 5)
635 if r:
636 if r:
636 line = sys.stdin.readline()
637 line = sys.stdin.readline()
637 if line.lower().startswith('y'):
638 if line.lower().startswith('y'):
638 self.log.critical("Shutdown confirmed")
639 self.log.critical("Shutdown confirmed")
639 ioloop.IOLoop.instance().stop()
640 ioloop.IOLoop.instance().stop()
640 return
641 return
641 else:
642 else:
642 print "No answer for 5s:",
643 print("No answer for 5s:", end=' ')
643 print "resuming operation..."
644 print("resuming operation...")
644 # no answer, or answer is no:
645 # no answer, or answer is no:
645 # set it back to original SIGINT handler
646 # set it back to original SIGINT handler
646 # use IOLoop.add_callback because signal.signal must be called
647 # use IOLoop.add_callback because signal.signal must be called
647 # from main thread
648 # from main thread
648 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
649 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
649
650
650 def _signal_stop(self, sig, frame):
651 def _signal_stop(self, sig, frame):
651 self.log.critical("received signal %s, stopping", sig)
652 self.log.critical("received signal %s, stopping", sig)
652 ioloop.IOLoop.instance().stop()
653 ioloop.IOLoop.instance().stop()
653
654
654 def _signal_info(self, sig, frame):
655 def _signal_info(self, sig, frame):
655 print self.notebook_info()
656 print(self.notebook_info())
656
657
657 def init_components(self):
658 def init_components(self):
658 """Check the components submodule, and warn if it's unclean"""
659 """Check the components submodule, and warn if it's unclean"""
659 status = submodule.check_submodule_status()
660 status = submodule.check_submodule_status()
660 if status == 'missing':
661 if status == 'missing':
661 self.log.warn("components submodule missing, running `git submodule update`")
662 self.log.warn("components submodule missing, running `git submodule update`")
662 submodule.update_submodules(submodule.ipython_parent())
663 submodule.update_submodules(submodule.ipython_parent())
663 elif status == 'unclean':
664 elif status == 'unclean':
664 self.log.warn("components submodule unclean, you may see 404s on static/components")
665 self.log.warn("components submodule unclean, you may see 404s on static/components")
665 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
666 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
666
667
667
668
668 @catch_config_error
669 @catch_config_error
669 def initialize(self, argv=None):
670 def initialize(self, argv=None):
670 super(NotebookApp, self).initialize(argv)
671 super(NotebookApp, self).initialize(argv)
671 self.init_logging()
672 self.init_logging()
672 self.init_kernel_argv()
673 self.init_kernel_argv()
673 self.init_configurables()
674 self.init_configurables()
674 self.init_components()
675 self.init_components()
675 self.init_webapp()
676 self.init_webapp()
676 self.init_signal()
677 self.init_signal()
677
678
678 def cleanup_kernels(self):
679 def cleanup_kernels(self):
679 """Shutdown all kernels.
680 """Shutdown all kernels.
680
681
681 The kernels will shutdown themselves when this process no longer exists,
682 The kernels will shutdown themselves when this process no longer exists,
682 but explicit shutdown allows the KernelManagers to cleanup the connection files.
683 but explicit shutdown allows the KernelManagers to cleanup the connection files.
683 """
684 """
684 self.log.info('Shutting down kernels')
685 self.log.info('Shutting down kernels')
685 self.kernel_manager.shutdown_all()
686 self.kernel_manager.shutdown_all()
686
687
687 def notebook_info(self):
688 def notebook_info(self):
688 "Return the current working directory and the server url information"
689 "Return the current working directory and the server url information"
689 info = self.notebook_manager.info_string() + "\n"
690 info = self.notebook_manager.info_string() + "\n"
690 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
691 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
691 return info + "The IPython Notebook is running at: %s" % self._url
692 return info + "The IPython Notebook is running at: %s" % self._url
692
693
693 def start(self):
694 def start(self):
694 """ Start the IPython Notebook server app, after initialization
695 """ Start the IPython Notebook server app, after initialization
695
696
696 This method takes no arguments so all configuration and initialization
697 This method takes no arguments so all configuration and initialization
697 must be done prior to calling this method."""
698 must be done prior to calling this method."""
698 ip = self.ip if self.ip else '[all ip addresses on your system]'
699 ip = self.ip if self.ip else '[all ip addresses on your system]'
699 proto = 'https' if self.certfile else 'http'
700 proto = 'https' if self.certfile else 'http'
700 info = self.log.info
701 info = self.log.info
701 self._url = "%s://%s:%i%s" % (proto, ip, self.port,
702 self._url = "%s://%s:%i%s" % (proto, ip, self.port,
702 self.base_project_url)
703 self.base_project_url)
703 for line in self.notebook_info().split("\n"):
704 for line in self.notebook_info().split("\n"):
704 info(line)
705 info(line)
705 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
706 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
706
707
707 if self.open_browser or self.file_to_run:
708 if self.open_browser or self.file_to_run:
708 ip = self.ip or localhost()
709 ip = self.ip or localhost()
709 try:
710 try:
710 browser = webbrowser.get(self.browser or None)
711 browser = webbrowser.get(self.browser or None)
711 except webbrowser.Error as e:
712 except webbrowser.Error as e:
712 self.log.warn('No web browser found: %s.' % e)
713 self.log.warn('No web browser found: %s.' % e)
713 browser = None
714 browser = None
714
715
715 nbdir = os.path.abspath(self.notebook_manager.notebook_dir)
716 nbdir = os.path.abspath(self.notebook_manager.notebook_dir)
716 f = self.file_to_run
717 f = self.file_to_run
717 if f and f.startswith(nbdir):
718 if f and f.startswith(nbdir):
718 f = f[len(nbdir):]
719 f = f[len(nbdir):]
719 else:
720 else:
720 self.log.warn(
721 self.log.warn(
721 "Probably won't be able to open notebook %s "
722 "Probably won't be able to open notebook %s "
722 "because it is not in notebook_dir %s",
723 "because it is not in notebook_dir %s",
723 f, nbdir,
724 f, nbdir,
724 )
725 )
725
726
726 if os.path.isfile(self.file_to_run):
727 if os.path.isfile(self.file_to_run):
727 url = url_path_join('notebooks', f)
728 url = url_path_join('notebooks', f)
728 else:
729 else:
729 url = url_path_join('tree', f)
730 url = url_path_join('tree', f)
730 if browser:
731 if browser:
731 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
732 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
732 self.port, self.base_project_url, url), new=2)
733 self.port, self.base_project_url, url), new=2)
733 threading.Thread(target=b).start()
734 threading.Thread(target=b).start()
734 try:
735 try:
735 ioloop.IOLoop.instance().start()
736 ioloop.IOLoop.instance().start()
736 except KeyboardInterrupt:
737 except KeyboardInterrupt:
737 info("Interrupted...")
738 info("Interrupted...")
738 finally:
739 finally:
739 self.cleanup_kernels()
740 self.cleanup_kernels()
740
741
741
742
742 #-----------------------------------------------------------------------------
743 #-----------------------------------------------------------------------------
743 # Main entry point
744 # Main entry point
744 #-----------------------------------------------------------------------------
745 #-----------------------------------------------------------------------------
745
746
746 launch_new_instance = NotebookApp.launch_instance
747 launch_new_instance = NotebookApp.launch_instance
747
748
@@ -1,230 +1,231 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for the notebook manager."""
2 """Tests for the notebook manager."""
3 from __future__ import print_function
3
4
4 import os
5 import os
5
6
6 from tornado.web import HTTPError
7 from tornado.web import HTTPError
7 from unittest import TestCase
8 from unittest import TestCase
8 from tempfile import NamedTemporaryFile
9 from tempfile import NamedTemporaryFile
9
10
10 from IPython.utils.tempdir import TemporaryDirectory
11 from IPython.utils.tempdir import TemporaryDirectory
11 from IPython.utils.traitlets import TraitError
12 from IPython.utils.traitlets import TraitError
12 from IPython.html.utils import url_path_join
13 from IPython.html.utils import url_path_join
13
14
14 from ..filenbmanager import FileNotebookManager
15 from ..filenbmanager import FileNotebookManager
15 from ..nbmanager import NotebookManager
16 from ..nbmanager import NotebookManager
16
17
17 class TestFileNotebookManager(TestCase):
18 class TestFileNotebookManager(TestCase):
18
19
19 def test_nb_dir(self):
20 def test_nb_dir(self):
20 with TemporaryDirectory() as td:
21 with TemporaryDirectory() as td:
21 fm = FileNotebookManager(notebook_dir=td)
22 fm = FileNotebookManager(notebook_dir=td)
22 self.assertEqual(fm.notebook_dir, td)
23 self.assertEqual(fm.notebook_dir, td)
23
24
24 def test_create_nb_dir(self):
25 def test_create_nb_dir(self):
25 with TemporaryDirectory() as td:
26 with TemporaryDirectory() as td:
26 nbdir = os.path.join(td, 'notebooks')
27 nbdir = os.path.join(td, 'notebooks')
27 fm = FileNotebookManager(notebook_dir=nbdir)
28 fm = FileNotebookManager(notebook_dir=nbdir)
28 self.assertEqual(fm.notebook_dir, nbdir)
29 self.assertEqual(fm.notebook_dir, nbdir)
29
30
30 def test_missing_nb_dir(self):
31 def test_missing_nb_dir(self):
31 with TemporaryDirectory() as td:
32 with TemporaryDirectory() as td:
32 nbdir = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
33 nbdir = os.path.join(td, 'notebook', 'dir', 'is', 'missing')
33 self.assertRaises(TraitError, FileNotebookManager, notebook_dir=nbdir)
34 self.assertRaises(TraitError, FileNotebookManager, notebook_dir=nbdir)
34
35
35 def test_invalid_nb_dir(self):
36 def test_invalid_nb_dir(self):
36 with NamedTemporaryFile() as tf:
37 with NamedTemporaryFile() as tf:
37 self.assertRaises(TraitError, FileNotebookManager, notebook_dir=tf.name)
38 self.assertRaises(TraitError, FileNotebookManager, notebook_dir=tf.name)
38
39
39 def test_get_os_path(self):
40 def test_get_os_path(self):
40 # full filesystem path should be returned with correct operating system
41 # full filesystem path should be returned with correct operating system
41 # separators.
42 # separators.
42 with TemporaryDirectory() as td:
43 with TemporaryDirectory() as td:
43 nbdir = os.path.join(td, 'notebooks')
44 nbdir = os.path.join(td, 'notebooks')
44 fm = FileNotebookManager(notebook_dir=nbdir)
45 fm = FileNotebookManager(notebook_dir=nbdir)
45 path = fm.get_os_path('test.ipynb', '/path/to/notebook/')
46 path = fm.get_os_path('test.ipynb', '/path/to/notebook/')
46 rel_path_list = '/path/to/notebook/test.ipynb'.split('/')
47 rel_path_list = '/path/to/notebook/test.ipynb'.split('/')
47 fs_path = os.path.join(fm.notebook_dir, *rel_path_list)
48 fs_path = os.path.join(fm.notebook_dir, *rel_path_list)
48 self.assertEqual(path, fs_path)
49 self.assertEqual(path, fs_path)
49
50
50 fm = FileNotebookManager(notebook_dir=nbdir)
51 fm = FileNotebookManager(notebook_dir=nbdir)
51 path = fm.get_os_path('test.ipynb')
52 path = fm.get_os_path('test.ipynb')
52 fs_path = os.path.join(fm.notebook_dir, 'test.ipynb')
53 fs_path = os.path.join(fm.notebook_dir, 'test.ipynb')
53 self.assertEqual(path, fs_path)
54 self.assertEqual(path, fs_path)
54
55
55 fm = FileNotebookManager(notebook_dir=nbdir)
56 fm = FileNotebookManager(notebook_dir=nbdir)
56 path = fm.get_os_path('test.ipynb', '////')
57 path = fm.get_os_path('test.ipynb', '////')
57 fs_path = os.path.join(fm.notebook_dir, 'test.ipynb')
58 fs_path = os.path.join(fm.notebook_dir, 'test.ipynb')
58 self.assertEqual(path, fs_path)
59 self.assertEqual(path, fs_path)
59
60
60 class TestNotebookManager(TestCase):
61 class TestNotebookManager(TestCase):
61
62
62 def make_dir(self, abs_path, rel_path):
63 def make_dir(self, abs_path, rel_path):
63 """make subdirectory, rel_path is the relative path
64 """make subdirectory, rel_path is the relative path
64 to that directory from the location where the server started"""
65 to that directory from the location where the server started"""
65 os_path = os.path.join(abs_path, rel_path)
66 os_path = os.path.join(abs_path, rel_path)
66 try:
67 try:
67 os.makedirs(os_path)
68 os.makedirs(os_path)
68 except OSError:
69 except OSError:
69 print "Directory already exists."
70 print("Directory already exists.")
70
71
71 def test_create_notebook_model(self):
72 def test_create_notebook_model(self):
72 with TemporaryDirectory() as td:
73 with TemporaryDirectory() as td:
73 # Test in root directory
74 # Test in root directory
74 nm = FileNotebookManager(notebook_dir=td)
75 nm = FileNotebookManager(notebook_dir=td)
75 model = nm.create_notebook_model()
76 model = nm.create_notebook_model()
76 assert isinstance(model, dict)
77 assert isinstance(model, dict)
77 self.assertIn('name', model)
78 self.assertIn('name', model)
78 self.assertIn('path', model)
79 self.assertIn('path', model)
79 self.assertEqual(model['name'], 'Untitled0.ipynb')
80 self.assertEqual(model['name'], 'Untitled0.ipynb')
80 self.assertEqual(model['path'], '')
81 self.assertEqual(model['path'], '')
81
82
82 # Test in sub-directory
83 # Test in sub-directory
83 sub_dir = '/foo/'
84 sub_dir = '/foo/'
84 self.make_dir(nm.notebook_dir, 'foo')
85 self.make_dir(nm.notebook_dir, 'foo')
85 model = nm.create_notebook_model(None, sub_dir)
86 model = nm.create_notebook_model(None, sub_dir)
86 assert isinstance(model, dict)
87 assert isinstance(model, dict)
87 self.assertIn('name', model)
88 self.assertIn('name', model)
88 self.assertIn('path', model)
89 self.assertIn('path', model)
89 self.assertEqual(model['name'], 'Untitled0.ipynb')
90 self.assertEqual(model['name'], 'Untitled0.ipynb')
90 self.assertEqual(model['path'], sub_dir.strip('/'))
91 self.assertEqual(model['path'], sub_dir.strip('/'))
91
92
92 def test_get_notebook_model(self):
93 def test_get_notebook_model(self):
93 with TemporaryDirectory() as td:
94 with TemporaryDirectory() as td:
94 # Test in root directory
95 # Test in root directory
95 # Create a notebook
96 # Create a notebook
96 nm = FileNotebookManager(notebook_dir=td)
97 nm = FileNotebookManager(notebook_dir=td)
97 model = nm.create_notebook_model()
98 model = nm.create_notebook_model()
98 name = model['name']
99 name = model['name']
99 path = model['path']
100 path = model['path']
100
101
101 # Check that we 'get' on the notebook we just created
102 # Check that we 'get' on the notebook we just created
102 model2 = nm.get_notebook_model(name, path)
103 model2 = nm.get_notebook_model(name, path)
103 assert isinstance(model2, dict)
104 assert isinstance(model2, dict)
104 self.assertIn('name', model2)
105 self.assertIn('name', model2)
105 self.assertIn('path', model2)
106 self.assertIn('path', model2)
106 self.assertEqual(model['name'], name)
107 self.assertEqual(model['name'], name)
107 self.assertEqual(model['path'], path)
108 self.assertEqual(model['path'], path)
108
109
109 # Test in sub-directory
110 # Test in sub-directory
110 sub_dir = '/foo/'
111 sub_dir = '/foo/'
111 self.make_dir(nm.notebook_dir, 'foo')
112 self.make_dir(nm.notebook_dir, 'foo')
112 model = nm.create_notebook_model(None, sub_dir)
113 model = nm.create_notebook_model(None, sub_dir)
113 model2 = nm.get_notebook_model(name, sub_dir)
114 model2 = nm.get_notebook_model(name, sub_dir)
114 assert isinstance(model2, dict)
115 assert isinstance(model2, dict)
115 self.assertIn('name', model2)
116 self.assertIn('name', model2)
116 self.assertIn('path', model2)
117 self.assertIn('path', model2)
117 self.assertIn('content', model2)
118 self.assertIn('content', model2)
118 self.assertEqual(model2['name'], 'Untitled0.ipynb')
119 self.assertEqual(model2['name'], 'Untitled0.ipynb')
119 self.assertEqual(model2['path'], sub_dir.strip('/'))
120 self.assertEqual(model2['path'], sub_dir.strip('/'))
120
121
121 def test_update_notebook_model(self):
122 def test_update_notebook_model(self):
122 with TemporaryDirectory() as td:
123 with TemporaryDirectory() as td:
123 # Test in root directory
124 # Test in root directory
124 # Create a notebook
125 # Create a notebook
125 nm = FileNotebookManager(notebook_dir=td)
126 nm = FileNotebookManager(notebook_dir=td)
126 model = nm.create_notebook_model()
127 model = nm.create_notebook_model()
127 name = model['name']
128 name = model['name']
128 path = model['path']
129 path = model['path']
129
130
130 # Change the name in the model for rename
131 # Change the name in the model for rename
131 model['name'] = 'test.ipynb'
132 model['name'] = 'test.ipynb'
132 model = nm.update_notebook_model(model, name, path)
133 model = nm.update_notebook_model(model, name, path)
133 assert isinstance(model, dict)
134 assert isinstance(model, dict)
134 self.assertIn('name', model)
135 self.assertIn('name', model)
135 self.assertIn('path', model)
136 self.assertIn('path', model)
136 self.assertEqual(model['name'], 'test.ipynb')
137 self.assertEqual(model['name'], 'test.ipynb')
137
138
138 # Make sure the old name is gone
139 # Make sure the old name is gone
139 self.assertRaises(HTTPError, nm.get_notebook_model, name, path)
140 self.assertRaises(HTTPError, nm.get_notebook_model, name, path)
140
141
141 # Test in sub-directory
142 # Test in sub-directory
142 # Create a directory and notebook in that directory
143 # Create a directory and notebook in that directory
143 sub_dir = '/foo/'
144 sub_dir = '/foo/'
144 self.make_dir(nm.notebook_dir, 'foo')
145 self.make_dir(nm.notebook_dir, 'foo')
145 model = nm.create_notebook_model(None, sub_dir)
146 model = nm.create_notebook_model(None, sub_dir)
146 name = model['name']
147 name = model['name']
147 path = model['path']
148 path = model['path']
148
149
149 # Change the name in the model for rename
150 # Change the name in the model for rename
150 model['name'] = 'test_in_sub.ipynb'
151 model['name'] = 'test_in_sub.ipynb'
151 model = nm.update_notebook_model(model, name, path)
152 model = nm.update_notebook_model(model, name, path)
152 assert isinstance(model, dict)
153 assert isinstance(model, dict)
153 self.assertIn('name', model)
154 self.assertIn('name', model)
154 self.assertIn('path', model)
155 self.assertIn('path', model)
155 self.assertEqual(model['name'], 'test_in_sub.ipynb')
156 self.assertEqual(model['name'], 'test_in_sub.ipynb')
156 self.assertEqual(model['path'], sub_dir.strip('/'))
157 self.assertEqual(model['path'], sub_dir.strip('/'))
157
158
158 # Make sure the old name is gone
159 # Make sure the old name is gone
159 self.assertRaises(HTTPError, nm.get_notebook_model, name, path)
160 self.assertRaises(HTTPError, nm.get_notebook_model, name, path)
160
161
161 def test_save_notebook_model(self):
162 def test_save_notebook_model(self):
162 with TemporaryDirectory() as td:
163 with TemporaryDirectory() as td:
163 # Test in the root directory
164 # Test in the root directory
164 # Create a notebook
165 # Create a notebook
165 nm = FileNotebookManager(notebook_dir=td)
166 nm = FileNotebookManager(notebook_dir=td)
166 model = nm.create_notebook_model()
167 model = nm.create_notebook_model()
167 name = model['name']
168 name = model['name']
168 path = model['path']
169 path = model['path']
169
170
170 # Get the model with 'content'
171 # Get the model with 'content'
171 full_model = nm.get_notebook_model(name, path)
172 full_model = nm.get_notebook_model(name, path)
172
173
173 # Save the notebook
174 # Save the notebook
174 model = nm.save_notebook_model(full_model, name, path)
175 model = nm.save_notebook_model(full_model, name, path)
175 assert isinstance(model, dict)
176 assert isinstance(model, dict)
176 self.assertIn('name', model)
177 self.assertIn('name', model)
177 self.assertIn('path', model)
178 self.assertIn('path', model)
178 self.assertEqual(model['name'], name)
179 self.assertEqual(model['name'], name)
179 self.assertEqual(model['path'], path)
180 self.assertEqual(model['path'], path)
180
181
181 # Test in sub-directory
182 # Test in sub-directory
182 # Create a directory and notebook in that directory
183 # Create a directory and notebook in that directory
183 sub_dir = '/foo/'
184 sub_dir = '/foo/'
184 self.make_dir(nm.notebook_dir, 'foo')
185 self.make_dir(nm.notebook_dir, 'foo')
185 model = nm.create_notebook_model(None, sub_dir)
186 model = nm.create_notebook_model(None, sub_dir)
186 name = model['name']
187 name = model['name']
187 path = model['path']
188 path = model['path']
188 model = nm.get_notebook_model(name, path)
189 model = nm.get_notebook_model(name, path)
189
190
190 # Change the name in the model for rename
191 # Change the name in the model for rename
191 model = nm.save_notebook_model(model, name, path)
192 model = nm.save_notebook_model(model, name, path)
192 assert isinstance(model, dict)
193 assert isinstance(model, dict)
193 self.assertIn('name', model)
194 self.assertIn('name', model)
194 self.assertIn('path', model)
195 self.assertIn('path', model)
195 self.assertEqual(model['name'], 'Untitled0.ipynb')
196 self.assertEqual(model['name'], 'Untitled0.ipynb')
196 self.assertEqual(model['path'], sub_dir.strip('/'))
197 self.assertEqual(model['path'], sub_dir.strip('/'))
197
198
198 def test_delete_notebook_model(self):
199 def test_delete_notebook_model(self):
199 with TemporaryDirectory() as td:
200 with TemporaryDirectory() as td:
200 # Test in the root directory
201 # Test in the root directory
201 # Create a notebook
202 # Create a notebook
202 nm = FileNotebookManager(notebook_dir=td)
203 nm = FileNotebookManager(notebook_dir=td)
203 model = nm.create_notebook_model()
204 model = nm.create_notebook_model()
204 name = model['name']
205 name = model['name']
205 path = model['path']
206 path = model['path']
206
207
207 # Delete the notebook
208 # Delete the notebook
208 nm.delete_notebook_model(name, path)
209 nm.delete_notebook_model(name, path)
209
210
210 # Check that a 'get' on the deleted notebook raises and error
211 # Check that a 'get' on the deleted notebook raises and error
211 self.assertRaises(HTTPError, nm.get_notebook_model, name, path)
212 self.assertRaises(HTTPError, nm.get_notebook_model, name, path)
212
213
213 def test_copy_notebook(self):
214 def test_copy_notebook(self):
214 with TemporaryDirectory() as td:
215 with TemporaryDirectory() as td:
215 # Test in the root directory
216 # Test in the root directory
216 # Create a notebook
217 # Create a notebook
217 nm = FileNotebookManager(notebook_dir=td)
218 nm = FileNotebookManager(notebook_dir=td)
218 path = u'å b'
219 path = u'å b'
219 name = u'nb √.ipynb'
220 name = u'nb √.ipynb'
220 os.mkdir(os.path.join(td, path))
221 os.mkdir(os.path.join(td, path))
221 orig = nm.create_notebook_model({'name' : name}, path=path)
222 orig = nm.create_notebook_model({'name' : name}, path=path)
222
223
223 # copy with unspecified name
224 # copy with unspecified name
224 copy = nm.copy_notebook(name, path=path)
225 copy = nm.copy_notebook(name, path=path)
225 self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy0.ipynb'))
226 self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy0.ipynb'))
226
227
227 # copy with specified name
228 # copy with specified name
228 copy2 = nm.copy_notebook(name, u'copy 2.ipynb', path=path)
229 copy2 = nm.copy_notebook(name, u'copy 2.ipynb', path=path)
229 self.assertEqual(copy2['name'], u'copy 2.ipynb')
230 self.assertEqual(copy2['name'], u'copy 2.ipynb')
230
231
@@ -1,484 +1,485 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 from __future__ import print_function
24
25
25 #*****************************************************************************
26 #*****************************************************************************
26 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
27 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
27 #
28 #
28 # Distributed under the terms of the BSD License. The full license is in
29 # Distributed under the terms of the BSD License. The full license is in
29 # the file COPYING, distributed as part of this software.
30 # the file COPYING, distributed as part of this software.
30 #*****************************************************************************
31 #*****************************************************************************
31
32
32 # Code begins
33 # Code begins
33 import sys
34 import sys
34 import threading
35 import threading
35
36
36 from IPython import get_ipython
37 from IPython import get_ipython
37 from IPython.core.ultratb import AutoFormattedTB
38 from IPython.core.ultratb import AutoFormattedTB
38 from IPython.utils.warn import error
39 from IPython.utils.warn import error
39
40
40
41
41 class BackgroundJobManager(object):
42 class BackgroundJobManager(object):
42 """Class to manage a pool of backgrounded threaded jobs.
43 """Class to manage a pool of backgrounded threaded jobs.
43
44
44 Below, we assume that 'jobs' is a BackgroundJobManager instance.
45 Below, we assume that 'jobs' is a BackgroundJobManager instance.
45
46
46 Usage summary (see the method docstrings for details):
47 Usage summary (see the method docstrings for details):
47
48
48 jobs.new(...) -> start a new job
49 jobs.new(...) -> start a new job
49
50
50 jobs() or jobs.status() -> print status summary of all jobs
51 jobs() or jobs.status() -> print status summary of all jobs
51
52
52 jobs[N] -> returns job number N.
53 jobs[N] -> returns job number N.
53
54
54 foo = jobs[N].result -> assign to variable foo the result of job N
55 foo = jobs[N].result -> assign to variable foo the result of job N
55
56
56 jobs[N].traceback() -> print the traceback of dead job N
57 jobs[N].traceback() -> print the traceback of dead job N
57
58
58 jobs.remove(N) -> remove (finished) job N
59 jobs.remove(N) -> remove (finished) job N
59
60
60 jobs.flush() -> remove all finished jobs
61 jobs.flush() -> remove all finished jobs
61
62
62 As a convenience feature, BackgroundJobManager instances provide the
63 As a convenience feature, BackgroundJobManager instances provide the
63 utility result and traceback methods which retrieve the corresponding
64 utility result and traceback methods which retrieve the corresponding
64 information from the jobs list:
65 information from the jobs list:
65
66
66 jobs.result(N) <--> jobs[N].result
67 jobs.result(N) <--> jobs[N].result
67 jobs.traceback(N) <--> jobs[N].traceback()
68 jobs.traceback(N) <--> jobs[N].traceback()
68
69
69 While this appears minor, it allows you to use tab completion
70 While this appears minor, it allows you to use tab completion
70 interactively on the job manager instance.
71 interactively on the job manager instance.
71 """
72 """
72
73
73 def __init__(self):
74 def __init__(self):
74 # Lists for job management, accessed via a property to ensure they're
75 # Lists for job management, accessed via a property to ensure they're
75 # up to date.x
76 # up to date.x
76 self._running = []
77 self._running = []
77 self._completed = []
78 self._completed = []
78 self._dead = []
79 self._dead = []
79 # A dict of all jobs, so users can easily access any of them
80 # A dict of all jobs, so users can easily access any of them
80 self.all = {}
81 self.all = {}
81 # For reporting
82 # For reporting
82 self._comp_report = []
83 self._comp_report = []
83 self._dead_report = []
84 self._dead_report = []
84 # Store status codes locally for fast lookups
85 # Store status codes locally for fast lookups
85 self._s_created = BackgroundJobBase.stat_created_c
86 self._s_created = BackgroundJobBase.stat_created_c
86 self._s_running = BackgroundJobBase.stat_running_c
87 self._s_running = BackgroundJobBase.stat_running_c
87 self._s_completed = BackgroundJobBase.stat_completed_c
88 self._s_completed = BackgroundJobBase.stat_completed_c
88 self._s_dead = BackgroundJobBase.stat_dead_c
89 self._s_dead = BackgroundJobBase.stat_dead_c
89
90
90 @property
91 @property
91 def running(self):
92 def running(self):
92 self._update_status()
93 self._update_status()
93 return self._running
94 return self._running
94
95
95 @property
96 @property
96 def dead(self):
97 def dead(self):
97 self._update_status()
98 self._update_status()
98 return self._dead
99 return self._dead
99
100
100 @property
101 @property
101 def completed(self):
102 def completed(self):
102 self._update_status()
103 self._update_status()
103 return self._completed
104 return self._completed
104
105
105 def new(self, func_or_exp, *args, **kwargs):
106 def new(self, func_or_exp, *args, **kwargs):
106 """Add a new background job and start it in a separate thread.
107 """Add a new background job and start it in a separate thread.
107
108
108 There are two types of jobs which can be created:
109 There are two types of jobs which can be created:
109
110
110 1. Jobs based on expressions which can be passed to an eval() call.
111 1. Jobs based on expressions which can be passed to an eval() call.
111 The expression must be given as a string. For example:
112 The expression must be given as a string. For example:
112
113
113 job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]])
114 job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]])
114
115
115 The given expression is passed to eval(), along with the optional
116 The given expression is passed to eval(), along with the optional
116 global/local dicts provided. If no dicts are given, they are
117 global/local dicts provided. If no dicts are given, they are
117 extracted automatically from the caller's frame.
118 extracted automatically from the caller's frame.
118
119
119 A Python statement is NOT a valid eval() expression. Basically, you
120 A Python statement is NOT a valid eval() expression. Basically, you
120 can only use as an eval() argument something which can go on the right
121 can only use as an eval() argument something which can go on the right
121 of an '=' sign and be assigned to a variable.
122 of an '=' sign and be assigned to a variable.
122
123
123 For example,"print 'hello'" is not valid, but '2+3' is.
124 For example,"print 'hello'" is not valid, but '2+3' is.
124
125
125 2. Jobs given a function object, optionally passing additional
126 2. Jobs given a function object, optionally passing additional
126 positional arguments:
127 positional arguments:
127
128
128 job_manager.new(myfunc, x, y)
129 job_manager.new(myfunc, x, y)
129
130
130 The function is called with the given arguments.
131 The function is called with the given arguments.
131
132
132 If you need to pass keyword arguments to your function, you must
133 If you need to pass keyword arguments to your function, you must
133 supply them as a dict named kw:
134 supply them as a dict named kw:
134
135
135 job_manager.new(myfunc, x, y, kw=dict(z=1))
136 job_manager.new(myfunc, x, y, kw=dict(z=1))
136
137
137 The reason for this assymmetry is that the new() method needs to
138 The reason for this assymmetry is that the new() method needs to
138 maintain access to its own keywords, and this prevents name collisions
139 maintain access to its own keywords, and this prevents name collisions
139 between arguments to new() and arguments to your own functions.
140 between arguments to new() and arguments to your own functions.
140
141
141 In both cases, the result is stored in the job.result field of the
142 In both cases, the result is stored in the job.result field of the
142 background job object.
143 background job object.
143
144
144 You can set `daemon` attribute of the thread by giving the keyword
145 You can set `daemon` attribute of the thread by giving the keyword
145 argument `daemon`.
146 argument `daemon`.
146
147
147 Notes and caveats:
148 Notes and caveats:
148
149
149 1. All threads running share the same standard output. Thus, if your
150 1. All threads running share the same standard output. Thus, if your
150 background jobs generate output, it will come out on top of whatever
151 background jobs generate output, it will come out on top of whatever
151 you are currently writing. For this reason, background jobs are best
152 you are currently writing. For this reason, background jobs are best
152 used with silent functions which simply return their output.
153 used with silent functions which simply return their output.
153
154
154 2. Threads also all work within the same global namespace, and this
155 2. Threads also all work within the same global namespace, and this
155 system does not lock interactive variables. So if you send job to the
156 system does not lock interactive variables. So if you send job to the
156 background which operates on a mutable object for a long time, and
157 background which operates on a mutable object for a long time, and
157 start modifying that same mutable object interactively (or in another
158 start modifying that same mutable object interactively (or in another
158 backgrounded job), all sorts of bizarre behaviour will occur.
159 backgrounded job), all sorts of bizarre behaviour will occur.
159
160
160 3. If a background job is spending a lot of time inside a C extension
161 3. If a background job is spending a lot of time inside a C extension
161 module which does not release the Python Global Interpreter Lock
162 module which does not release the Python Global Interpreter Lock
162 (GIL), this will block the IPython prompt. This is simply because the
163 (GIL), this will block the IPython prompt. This is simply because the
163 Python interpreter can only switch between threads at Python
164 Python interpreter can only switch between threads at Python
164 bytecodes. While the execution is inside C code, the interpreter must
165 bytecodes. While the execution is inside C code, the interpreter must
165 simply wait unless the extension module releases the GIL.
166 simply wait unless the extension module releases the GIL.
166
167
167 4. There is no way, due to limitations in the Python threads library,
168 4. There is no way, due to limitations in the Python threads library,
168 to kill a thread once it has started."""
169 to kill a thread once it has started."""
169
170
170 if callable(func_or_exp):
171 if callable(func_or_exp):
171 kw = kwargs.get('kw',{})
172 kw = kwargs.get('kw',{})
172 job = BackgroundJobFunc(func_or_exp,*args,**kw)
173 job = BackgroundJobFunc(func_or_exp,*args,**kw)
173 elif isinstance(func_or_exp, basestring):
174 elif isinstance(func_or_exp, basestring):
174 if not args:
175 if not args:
175 frame = sys._getframe(1)
176 frame = sys._getframe(1)
176 glob, loc = frame.f_globals, frame.f_locals
177 glob, loc = frame.f_globals, frame.f_locals
177 elif len(args)==1:
178 elif len(args)==1:
178 glob = loc = args[0]
179 glob = loc = args[0]
179 elif len(args)==2:
180 elif len(args)==2:
180 glob,loc = args
181 glob,loc = args
181 else:
182 else:
182 raise ValueError(
183 raise ValueError(
183 'Expression jobs take at most 2 args (globals,locals)')
184 'Expression jobs take at most 2 args (globals,locals)')
184 job = BackgroundJobExpr(func_or_exp, glob, loc)
185 job = BackgroundJobExpr(func_or_exp, glob, loc)
185 else:
186 else:
186 raise TypeError('invalid args for new job')
187 raise TypeError('invalid args for new job')
187
188
188 if kwargs.get('daemon', False):
189 if kwargs.get('daemon', False):
189 job.daemon = True
190 job.daemon = True
190 job.num = len(self.all)+1 if self.all else 0
191 job.num = len(self.all)+1 if self.all else 0
191 self.running.append(job)
192 self.running.append(job)
192 self.all[job.num] = job
193 self.all[job.num] = job
193 print 'Starting job # %s in a separate thread.' % job.num
194 print('Starting job # %s in a separate thread.' % job.num)
194 job.start()
195 job.start()
195 return job
196 return job
196
197
197 def __getitem__(self, job_key):
198 def __getitem__(self, job_key):
198 num = job_key if isinstance(job_key, int) else job_key.num
199 num = job_key if isinstance(job_key, int) else job_key.num
199 return self.all[num]
200 return self.all[num]
200
201
201 def __call__(self):
202 def __call__(self):
202 """An alias to self.status(),
203 """An alias to self.status(),
203
204
204 This allows you to simply call a job manager instance much like the
205 This allows you to simply call a job manager instance much like the
205 Unix `jobs` shell command."""
206 Unix `jobs` shell command."""
206
207
207 return self.status()
208 return self.status()
208
209
209 def _update_status(self):
210 def _update_status(self):
210 """Update the status of the job lists.
211 """Update the status of the job lists.
211
212
212 This method moves finished jobs to one of two lists:
213 This method moves finished jobs to one of two lists:
213 - self.completed: jobs which completed successfully
214 - self.completed: jobs which completed successfully
214 - self.dead: jobs which finished but died.
215 - self.dead: jobs which finished but died.
215
216
216 It also copies those jobs to corresponding _report lists. These lists
217 It also copies those jobs to corresponding _report lists. These lists
217 are used to report jobs completed/dead since the last update, and are
218 are used to report jobs completed/dead since the last update, and are
218 then cleared by the reporting function after each call."""
219 then cleared by the reporting function after each call."""
219
220
220 # Status codes
221 # Status codes
221 srun, scomp, sdead = self._s_running, self._s_completed, self._s_dead
222 srun, scomp, sdead = self._s_running, self._s_completed, self._s_dead
222 # State lists, use the actual lists b/c the public names are properties
223 # State lists, use the actual lists b/c the public names are properties
223 # that call this very function on access
224 # that call this very function on access
224 running, completed, dead = self._running, self._completed, self._dead
225 running, completed, dead = self._running, self._completed, self._dead
225
226
226 # Now, update all state lists
227 # Now, update all state lists
227 for num, job in enumerate(running):
228 for num, job in enumerate(running):
228 stat = job.stat_code
229 stat = job.stat_code
229 if stat == srun:
230 if stat == srun:
230 continue
231 continue
231 elif stat == scomp:
232 elif stat == scomp:
232 completed.append(job)
233 completed.append(job)
233 self._comp_report.append(job)
234 self._comp_report.append(job)
234 running[num] = False
235 running[num] = False
235 elif stat == sdead:
236 elif stat == sdead:
236 dead.append(job)
237 dead.append(job)
237 self._dead_report.append(job)
238 self._dead_report.append(job)
238 running[num] = False
239 running[num] = False
239 # Remove dead/completed jobs from running list
240 # Remove dead/completed jobs from running list
240 running[:] = filter(None, running)
241 running[:] = filter(None, running)
241
242
242 def _group_report(self,group,name):
243 def _group_report(self,group,name):
243 """Report summary for a given job group.
244 """Report summary for a given job group.
244
245
245 Return True if the group had any elements."""
246 Return True if the group had any elements."""
246
247
247 if group:
248 if group:
248 print '%s jobs:' % name
249 print('%s jobs:' % name)
249 for job in group:
250 for job in group:
250 print '%s : %s' % (job.num,job)
251 print('%s : %s' % (job.num,job))
251 print
252 print()
252 return True
253 return True
253
254
254 def _group_flush(self,group,name):
255 def _group_flush(self,group,name):
255 """Flush a given job group
256 """Flush a given job group
256
257
257 Return True if the group had any elements."""
258 Return True if the group had any elements."""
258
259
259 njobs = len(group)
260 njobs = len(group)
260 if njobs:
261 if njobs:
261 plural = {1:''}.setdefault(njobs,'s')
262 plural = {1:''}.setdefault(njobs,'s')
262 print 'Flushing %s %s job%s.' % (njobs,name,plural)
263 print('Flushing %s %s job%s.' % (njobs,name,plural))
263 group[:] = []
264 group[:] = []
264 return True
265 return True
265
266
266 def _status_new(self):
267 def _status_new(self):
267 """Print the status of newly finished jobs.
268 """Print the status of newly finished jobs.
268
269
269 Return True if any new jobs are reported.
270 Return True if any new jobs are reported.
270
271
271 This call resets its own state every time, so it only reports jobs
272 This call resets its own state every time, so it only reports jobs
272 which have finished since the last time it was called."""
273 which have finished since the last time it was called."""
273
274
274 self._update_status()
275 self._update_status()
275 new_comp = self._group_report(self._comp_report, 'Completed')
276 new_comp = self._group_report(self._comp_report, 'Completed')
276 new_dead = self._group_report(self._dead_report,
277 new_dead = self._group_report(self._dead_report,
277 'Dead, call jobs.traceback() for details')
278 'Dead, call jobs.traceback() for details')
278 self._comp_report[:] = []
279 self._comp_report[:] = []
279 self._dead_report[:] = []
280 self._dead_report[:] = []
280 return new_comp or new_dead
281 return new_comp or new_dead
281
282
282 def status(self,verbose=0):
283 def status(self,verbose=0):
283 """Print a status of all jobs currently being managed."""
284 """Print a status of all jobs currently being managed."""
284
285
285 self._update_status()
286 self._update_status()
286 self._group_report(self.running,'Running')
287 self._group_report(self.running,'Running')
287 self._group_report(self.completed,'Completed')
288 self._group_report(self.completed,'Completed')
288 self._group_report(self.dead,'Dead')
289 self._group_report(self.dead,'Dead')
289 # Also flush the report queues
290 # Also flush the report queues
290 self._comp_report[:] = []
291 self._comp_report[:] = []
291 self._dead_report[:] = []
292 self._dead_report[:] = []
292
293
293 def remove(self,num):
294 def remove(self,num):
294 """Remove a finished (completed or dead) job."""
295 """Remove a finished (completed or dead) job."""
295
296
296 try:
297 try:
297 job = self.all[num]
298 job = self.all[num]
298 except KeyError:
299 except KeyError:
299 error('Job #%s not found' % num)
300 error('Job #%s not found' % num)
300 else:
301 else:
301 stat_code = job.stat_code
302 stat_code = job.stat_code
302 if stat_code == self._s_running:
303 if stat_code == self._s_running:
303 error('Job #%s is still running, it can not be removed.' % num)
304 error('Job #%s is still running, it can not be removed.' % num)
304 return
305 return
305 elif stat_code == self._s_completed:
306 elif stat_code == self._s_completed:
306 self.completed.remove(job)
307 self.completed.remove(job)
307 elif stat_code == self._s_dead:
308 elif stat_code == self._s_dead:
308 self.dead.remove(job)
309 self.dead.remove(job)
309
310
310 def flush(self):
311 def flush(self):
311 """Flush all finished jobs (completed and dead) from lists.
312 """Flush all finished jobs (completed and dead) from lists.
312
313
313 Running jobs are never flushed.
314 Running jobs are never flushed.
314
315
315 It first calls _status_new(), to update info. If any jobs have
316 It first calls _status_new(), to update info. If any jobs have
316 completed since the last _status_new() call, the flush operation
317 completed since the last _status_new() call, the flush operation
317 aborts."""
318 aborts."""
318
319
319 # Remove the finished jobs from the master dict
320 # Remove the finished jobs from the master dict
320 alljobs = self.all
321 alljobs = self.all
321 for job in self.completed+self.dead:
322 for job in self.completed+self.dead:
322 del(alljobs[job.num])
323 del(alljobs[job.num])
323
324
324 # Now flush these lists completely
325 # Now flush these lists completely
325 fl_comp = self._group_flush(self.completed, 'Completed')
326 fl_comp = self._group_flush(self.completed, 'Completed')
326 fl_dead = self._group_flush(self.dead, 'Dead')
327 fl_dead = self._group_flush(self.dead, 'Dead')
327 if not (fl_comp or fl_dead):
328 if not (fl_comp or fl_dead):
328 print 'No jobs to flush.'
329 print('No jobs to flush.')
329
330
330 def result(self,num):
331 def result(self,num):
331 """result(N) -> return the result of job N."""
332 """result(N) -> return the result of job N."""
332 try:
333 try:
333 return self.all[num].result
334 return self.all[num].result
334 except KeyError:
335 except KeyError:
335 error('Job #%s not found' % num)
336 error('Job #%s not found' % num)
336
337
337 def _traceback(self, job):
338 def _traceback(self, job):
338 num = job if isinstance(job, int) else job.num
339 num = job if isinstance(job, int) else job.num
339 try:
340 try:
340 self.all[num].traceback()
341 self.all[num].traceback()
341 except KeyError:
342 except KeyError:
342 error('Job #%s not found' % num)
343 error('Job #%s not found' % num)
343
344
344 def traceback(self, job=None):
345 def traceback(self, job=None):
345 if job is None:
346 if job is None:
346 self._update_status()
347 self._update_status()
347 for deadjob in self.dead:
348 for deadjob in self.dead:
348 print "Traceback for: %r" % deadjob
349 print("Traceback for: %r" % deadjob)
349 self._traceback(deadjob)
350 self._traceback(deadjob)
350 print
351 print()
351 else:
352 else:
352 self._traceback(job)
353 self._traceback(job)
353
354
354
355
355 class BackgroundJobBase(threading.Thread):
356 class BackgroundJobBase(threading.Thread):
356 """Base class to build BackgroundJob classes.
357 """Base class to build BackgroundJob classes.
357
358
358 The derived classes must implement:
359 The derived classes must implement:
359
360
360 - Their own __init__, since the one here raises NotImplementedError. The
361 - Their own __init__, since the one here raises NotImplementedError. The
361 derived constructor must call self._init() at the end, to provide common
362 derived constructor must call self._init() at the end, to provide common
362 initialization.
363 initialization.
363
364
364 - A strform attribute used in calls to __str__.
365 - A strform attribute used in calls to __str__.
365
366
366 - A call() method, which will make the actual execution call and must
367 - A call() method, which will make the actual execution call and must
367 return a value to be held in the 'result' field of the job object."""
368 return a value to be held in the 'result' field of the job object."""
368
369
369 # Class constants for status, in string and as numerical codes (when
370 # Class constants for status, in string and as numerical codes (when
370 # updating jobs lists, we don't want to do string comparisons). This will
371 # updating jobs lists, we don't want to do string comparisons). This will
371 # be done at every user prompt, so it has to be as fast as possible
372 # be done at every user prompt, so it has to be as fast as possible
372 stat_created = 'Created'; stat_created_c = 0
373 stat_created = 'Created'; stat_created_c = 0
373 stat_running = 'Running'; stat_running_c = 1
374 stat_running = 'Running'; stat_running_c = 1
374 stat_completed = 'Completed'; stat_completed_c = 2
375 stat_completed = 'Completed'; stat_completed_c = 2
375 stat_dead = 'Dead (Exception), call jobs.traceback() for details'
376 stat_dead = 'Dead (Exception), call jobs.traceback() for details'
376 stat_dead_c = -1
377 stat_dead_c = -1
377
378
378 def __init__(self):
379 def __init__(self):
379 raise NotImplementedError("This class can not be instantiated directly.")
380 raise NotImplementedError("This class can not be instantiated directly.")
380
381
381 def _init(self):
382 def _init(self):
382 """Common initialization for all BackgroundJob objects"""
383 """Common initialization for all BackgroundJob objects"""
383
384
384 for attr in ['call','strform']:
385 for attr in ['call','strform']:
385 assert hasattr(self,attr), "Missing attribute <%s>" % attr
386 assert hasattr(self,attr), "Missing attribute <%s>" % attr
386
387
387 # The num tag can be set by an external job manager
388 # The num tag can be set by an external job manager
388 self.num = None
389 self.num = None
389
390
390 self.status = BackgroundJobBase.stat_created
391 self.status = BackgroundJobBase.stat_created
391 self.stat_code = BackgroundJobBase.stat_created_c
392 self.stat_code = BackgroundJobBase.stat_created_c
392 self.finished = False
393 self.finished = False
393 self.result = '<BackgroundJob has not completed>'
394 self.result = '<BackgroundJob has not completed>'
394
395
395 # reuse the ipython traceback handler if we can get to it, otherwise
396 # reuse the ipython traceback handler if we can get to it, otherwise
396 # make a new one
397 # make a new one
397 try:
398 try:
398 make_tb = get_ipython().InteractiveTB.text
399 make_tb = get_ipython().InteractiveTB.text
399 except:
400 except:
400 make_tb = AutoFormattedTB(mode = 'Context',
401 make_tb = AutoFormattedTB(mode = 'Context',
401 color_scheme='NoColor',
402 color_scheme='NoColor',
402 tb_offset = 1).text
403 tb_offset = 1).text
403 # Note that the actual API for text() requires the three args to be
404 # Note that the actual API for text() requires the three args to be
404 # passed in, so we wrap it in a simple lambda.
405 # passed in, so we wrap it in a simple lambda.
405 self._make_tb = lambda : make_tb(None, None, None)
406 self._make_tb = lambda : make_tb(None, None, None)
406
407
407 # Hold a formatted traceback if one is generated.
408 # Hold a formatted traceback if one is generated.
408 self._tb = None
409 self._tb = None
409
410
410 threading.Thread.__init__(self)
411 threading.Thread.__init__(self)
411
412
412 def __str__(self):
413 def __str__(self):
413 return self.strform
414 return self.strform
414
415
415 def __repr__(self):
416 def __repr__(self):
416 return '<BackgroundJob #%d: %s>' % (self.num, self.strform)
417 return '<BackgroundJob #%d: %s>' % (self.num, self.strform)
417
418
418 def traceback(self):
419 def traceback(self):
419 print self._tb
420 print(self._tb)
420
421
421 def run(self):
422 def run(self):
422 try:
423 try:
423 self.status = BackgroundJobBase.stat_running
424 self.status = BackgroundJobBase.stat_running
424 self.stat_code = BackgroundJobBase.stat_running_c
425 self.stat_code = BackgroundJobBase.stat_running_c
425 self.result = self.call()
426 self.result = self.call()
426 except:
427 except:
427 self.status = BackgroundJobBase.stat_dead
428 self.status = BackgroundJobBase.stat_dead
428 self.stat_code = BackgroundJobBase.stat_dead_c
429 self.stat_code = BackgroundJobBase.stat_dead_c
429 self.finished = None
430 self.finished = None
430 self.result = ('<BackgroundJob died, call jobs.traceback() for details>')
431 self.result = ('<BackgroundJob died, call jobs.traceback() for details>')
431 self._tb = self._make_tb()
432 self._tb = self._make_tb()
432 else:
433 else:
433 self.status = BackgroundJobBase.stat_completed
434 self.status = BackgroundJobBase.stat_completed
434 self.stat_code = BackgroundJobBase.stat_completed_c
435 self.stat_code = BackgroundJobBase.stat_completed_c
435 self.finished = True
436 self.finished = True
436
437
437
438
438 class BackgroundJobExpr(BackgroundJobBase):
439 class BackgroundJobExpr(BackgroundJobBase):
439 """Evaluate an expression as a background job (uses a separate thread)."""
440 """Evaluate an expression as a background job (uses a separate thread)."""
440
441
441 def __init__(self, expression, glob=None, loc=None):
442 def __init__(self, expression, glob=None, loc=None):
442 """Create a new job from a string which can be fed to eval().
443 """Create a new job from a string which can be fed to eval().
443
444
444 global/locals dicts can be provided, which will be passed to the eval
445 global/locals dicts can be provided, which will be passed to the eval
445 call."""
446 call."""
446
447
447 # fail immediately if the given expression can't be compiled
448 # fail immediately if the given expression can't be compiled
448 self.code = compile(expression,'<BackgroundJob compilation>','eval')
449 self.code = compile(expression,'<BackgroundJob compilation>','eval')
449
450
450 glob = {} if glob is None else glob
451 glob = {} if glob is None else glob
451 loc = {} if loc is None else loc
452 loc = {} if loc is None else loc
452 self.expression = self.strform = expression
453 self.expression = self.strform = expression
453 self.glob = glob
454 self.glob = glob
454 self.loc = loc
455 self.loc = loc
455 self._init()
456 self._init()
456
457
457 def call(self):
458 def call(self):
458 return eval(self.code,self.glob,self.loc)
459 return eval(self.code,self.glob,self.loc)
459
460
460
461
461 class BackgroundJobFunc(BackgroundJobBase):
462 class BackgroundJobFunc(BackgroundJobBase):
462 """Run a function call as a background job (uses a separate thread)."""
463 """Run a function call as a background job (uses a separate thread)."""
463
464
464 def __init__(self, func, *args, **kwargs):
465 def __init__(self, func, *args, **kwargs):
465 """Create a new job from a callable object.
466 """Create a new job from a callable object.
466
467
467 Any positional arguments and keyword args given to this constructor
468 Any positional arguments and keyword args given to this constructor
468 after the initial callable are passed directly to it."""
469 after the initial callable are passed directly to it."""
469
470
470 if not callable(func):
471 if not callable(func):
471 raise TypeError(
472 raise TypeError(
472 'first argument to BackgroundJobFunc must be callable')
473 'first argument to BackgroundJobFunc must be callable')
473
474
474 self.func = func
475 self.func = func
475 self.args = args
476 self.args = args
476 self.kwargs = kwargs
477 self.kwargs = kwargs
477 # The string form will only include the function passed, because
478 # The string form will only include the function passed, because
478 # generating string representations of the arguments is a potentially
479 # generating string representations of the arguments is a potentially
479 # _very_ expensive operation (e.g. with large arrays).
480 # _very_ expensive operation (e.g. with large arrays).
480 self.strform = str(func)
481 self.strform = str(func)
481 self._init()
482 self._init()
482
483
483 def call(self):
484 def call(self):
484 return self.func(*self.args, **self.kwargs)
485 return self.func(*self.args, **self.kwargs)
@@ -1,337 +1,338 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 A module to change reload() so that it acts recursively.
3 A module to change reload() so that it acts recursively.
4 To enable it type::
4 To enable it type::
5
5
6 import __builtin__, deepreload
6 import __builtin__, deepreload
7 __builtin__.reload = deepreload.reload
7 __builtin__.reload = deepreload.reload
8
8
9 You can then disable it with::
9 You can then disable it with::
10
10
11 __builtin__.reload = deepreload.original_reload
11 __builtin__.reload = deepreload.original_reload
12
12
13 Alternatively, you can add a dreload builtin alongside normal reload with::
13 Alternatively, you can add a dreload builtin alongside normal reload with::
14
14
15 __builtin__.dreload = deepreload.reload
15 __builtin__.dreload = deepreload.reload
16
16
17 This code is almost entirely based on knee.py, which is a Python
17 This code is almost entirely based on knee.py, which is a Python
18 re-implementation of hierarchical module import.
18 re-implementation of hierarchical module import.
19 """
19 """
20 from __future__ import print_function
20 #*****************************************************************************
21 #*****************************************************************************
21 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
22 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
22 #
23 #
23 # Distributed under the terms of the BSD License. The full license is in
24 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
25 # the file COPYING, distributed as part of this software.
25 #*****************************************************************************
26 #*****************************************************************************
26
27
27 import __builtin__
28 import __builtin__
28 from contextlib import contextmanager
29 from contextlib import contextmanager
29 import imp
30 import imp
30 import sys
31 import sys
31
32
32 from types import ModuleType
33 from types import ModuleType
33 from warnings import warn
34 from warnings import warn
34
35
35 original_import = __builtin__.__import__
36 original_import = __builtin__.__import__
36
37
37 @contextmanager
38 @contextmanager
38 def replace_import_hook(new_import):
39 def replace_import_hook(new_import):
39 saved_import = __builtin__.__import__
40 saved_import = __builtin__.__import__
40 __builtin__.__import__ = new_import
41 __builtin__.__import__ = new_import
41 try:
42 try:
42 yield
43 yield
43 finally:
44 finally:
44 __builtin__.__import__ = saved_import
45 __builtin__.__import__ = saved_import
45
46
46 def get_parent(globals, level):
47 def get_parent(globals, level):
47 """
48 """
48 parent, name = get_parent(globals, level)
49 parent, name = get_parent(globals, level)
49
50
50 Return the package that an import is being performed in. If globals comes
51 Return the package that an import is being performed in. If globals comes
51 from the module foo.bar.bat (not itself a package), this returns the
52 from the module foo.bar.bat (not itself a package), this returns the
52 sys.modules entry for foo.bar. If globals is from a package's __init__.py,
53 sys.modules entry for foo.bar. If globals is from a package's __init__.py,
53 the package's entry in sys.modules is returned.
54 the package's entry in sys.modules is returned.
54
55
55 If globals doesn't come from a package or a module in a package, or a
56 If globals doesn't come from a package or a module in a package, or a
56 corresponding entry is not found in sys.modules, None is returned.
57 corresponding entry is not found in sys.modules, None is returned.
57 """
58 """
58 orig_level = level
59 orig_level = level
59
60
60 if not level or not isinstance(globals, dict):
61 if not level or not isinstance(globals, dict):
61 return None, ''
62 return None, ''
62
63
63 pkgname = globals.get('__package__', None)
64 pkgname = globals.get('__package__', None)
64
65
65 if pkgname is not None:
66 if pkgname is not None:
66 # __package__ is set, so use it
67 # __package__ is set, so use it
67 if not hasattr(pkgname, 'rindex'):
68 if not hasattr(pkgname, 'rindex'):
68 raise ValueError('__package__ set to non-string')
69 raise ValueError('__package__ set to non-string')
69 if len(pkgname) == 0:
70 if len(pkgname) == 0:
70 if level > 0:
71 if level > 0:
71 raise ValueError('Attempted relative import in non-package')
72 raise ValueError('Attempted relative import in non-package')
72 return None, ''
73 return None, ''
73 name = pkgname
74 name = pkgname
74 else:
75 else:
75 # __package__ not set, so figure it out and set it
76 # __package__ not set, so figure it out and set it
76 if '__name__' not in globals:
77 if '__name__' not in globals:
77 return None, ''
78 return None, ''
78 modname = globals['__name__']
79 modname = globals['__name__']
79
80
80 if '__path__' in globals:
81 if '__path__' in globals:
81 # __path__ is set, so modname is already the package name
82 # __path__ is set, so modname is already the package name
82 globals['__package__'] = name = modname
83 globals['__package__'] = name = modname
83 else:
84 else:
84 # Normal module, so work out the package name if any
85 # Normal module, so work out the package name if any
85 lastdot = modname.rfind('.')
86 lastdot = modname.rfind('.')
86 if lastdot < 0 and level > 0:
87 if lastdot < 0 and level > 0:
87 raise ValueError("Attempted relative import in non-package")
88 raise ValueError("Attempted relative import in non-package")
88 if lastdot < 0:
89 if lastdot < 0:
89 globals['__package__'] = None
90 globals['__package__'] = None
90 return None, ''
91 return None, ''
91 globals['__package__'] = name = modname[:lastdot]
92 globals['__package__'] = name = modname[:lastdot]
92
93
93 dot = len(name)
94 dot = len(name)
94 for x in xrange(level, 1, -1):
95 for x in xrange(level, 1, -1):
95 try:
96 try:
96 dot = name.rindex('.', 0, dot)
97 dot = name.rindex('.', 0, dot)
97 except ValueError:
98 except ValueError:
98 raise ValueError("attempted relative import beyond top-level "
99 raise ValueError("attempted relative import beyond top-level "
99 "package")
100 "package")
100 name = name[:dot]
101 name = name[:dot]
101
102
102 try:
103 try:
103 parent = sys.modules[name]
104 parent = sys.modules[name]
104 except:
105 except:
105 if orig_level < 1:
106 if orig_level < 1:
106 warn("Parent module '%.200s' not found while handling absolute "
107 warn("Parent module '%.200s' not found while handling absolute "
107 "import" % name)
108 "import" % name)
108 parent = None
109 parent = None
109 else:
110 else:
110 raise SystemError("Parent module '%.200s' not loaded, cannot "
111 raise SystemError("Parent module '%.200s' not loaded, cannot "
111 "perform relative import" % name)
112 "perform relative import" % name)
112
113
113 # We expect, but can't guarantee, if parent != None, that:
114 # We expect, but can't guarantee, if parent != None, that:
114 # - parent.__name__ == name
115 # - parent.__name__ == name
115 # - parent.__dict__ is globals
116 # - parent.__dict__ is globals
116 # If this is violated... Who cares?
117 # If this is violated... Who cares?
117 return parent, name
118 return parent, name
118
119
119 def load_next(mod, altmod, name, buf):
120 def load_next(mod, altmod, name, buf):
120 """
121 """
121 mod, name, buf = load_next(mod, altmod, name, buf)
122 mod, name, buf = load_next(mod, altmod, name, buf)
122
123
123 altmod is either None or same as mod
124 altmod is either None or same as mod
124 """
125 """
125
126
126 if len(name) == 0:
127 if len(name) == 0:
127 # completely empty module name should only happen in
128 # completely empty module name should only happen in
128 # 'from . import' (or '__import__("")')
129 # 'from . import' (or '__import__("")')
129 return mod, None, buf
130 return mod, None, buf
130
131
131 dot = name.find('.')
132 dot = name.find('.')
132 if dot == 0:
133 if dot == 0:
133 raise ValueError('Empty module name')
134 raise ValueError('Empty module name')
134
135
135 if dot < 0:
136 if dot < 0:
136 subname = name
137 subname = name
137 next = None
138 next = None
138 else:
139 else:
139 subname = name[:dot]
140 subname = name[:dot]
140 next = name[dot+1:]
141 next = name[dot+1:]
141
142
142 if buf != '':
143 if buf != '':
143 buf += '.'
144 buf += '.'
144 buf += subname
145 buf += subname
145
146
146 result = import_submodule(mod, subname, buf)
147 result = import_submodule(mod, subname, buf)
147 if result is None and mod != altmod:
148 if result is None and mod != altmod:
148 result = import_submodule(altmod, subname, subname)
149 result = import_submodule(altmod, subname, subname)
149 if result is not None:
150 if result is not None:
150 buf = subname
151 buf = subname
151
152
152 if result is None:
153 if result is None:
153 raise ImportError("No module named %.200s" % name)
154 raise ImportError("No module named %.200s" % name)
154
155
155 return result, next, buf
156 return result, next, buf
156
157
157 # Need to keep track of what we've already reloaded to prevent cyclic evil
158 # Need to keep track of what we've already reloaded to prevent cyclic evil
158 found_now = {}
159 found_now = {}
159
160
160 def import_submodule(mod, subname, fullname):
161 def import_submodule(mod, subname, fullname):
161 """m = import_submodule(mod, subname, fullname)"""
162 """m = import_submodule(mod, subname, fullname)"""
162 # Require:
163 # Require:
163 # if mod == None: subname == fullname
164 # if mod == None: subname == fullname
164 # else: mod.__name__ + "." + subname == fullname
165 # else: mod.__name__ + "." + subname == fullname
165
166
166 global found_now
167 global found_now
167 if fullname in found_now and fullname in sys.modules:
168 if fullname in found_now and fullname in sys.modules:
168 m = sys.modules[fullname]
169 m = sys.modules[fullname]
169 else:
170 else:
170 print 'Reloading', fullname
171 print('Reloading', fullname)
171 found_now[fullname] = 1
172 found_now[fullname] = 1
172 oldm = sys.modules.get(fullname, None)
173 oldm = sys.modules.get(fullname, None)
173
174
174 if mod is None:
175 if mod is None:
175 path = None
176 path = None
176 elif hasattr(mod, '__path__'):
177 elif hasattr(mod, '__path__'):
177 path = mod.__path__
178 path = mod.__path__
178 else:
179 else:
179 return None
180 return None
180
181
181 try:
182 try:
182 # This appears to be necessary on Python 3, because imp.find_module()
183 # This appears to be necessary on Python 3, because imp.find_module()
183 # tries to import standard libraries (like io) itself, and we don't
184 # tries to import standard libraries (like io) itself, and we don't
184 # want them to be processed by our deep_import_hook.
185 # want them to be processed by our deep_import_hook.
185 with replace_import_hook(original_import):
186 with replace_import_hook(original_import):
186 fp, filename, stuff = imp.find_module(subname, path)
187 fp, filename, stuff = imp.find_module(subname, path)
187 except ImportError:
188 except ImportError:
188 return None
189 return None
189
190
190 try:
191 try:
191 m = imp.load_module(fullname, fp, filename, stuff)
192 m = imp.load_module(fullname, fp, filename, stuff)
192 except:
193 except:
193 # load_module probably removed name from modules because of
194 # load_module probably removed name from modules because of
194 # the error. Put back the original module object.
195 # the error. Put back the original module object.
195 if oldm:
196 if oldm:
196 sys.modules[fullname] = oldm
197 sys.modules[fullname] = oldm
197 raise
198 raise
198 finally:
199 finally:
199 if fp: fp.close()
200 if fp: fp.close()
200
201
201 add_submodule(mod, m, fullname, subname)
202 add_submodule(mod, m, fullname, subname)
202
203
203 return m
204 return m
204
205
205 def add_submodule(mod, submod, fullname, subname):
206 def add_submodule(mod, submod, fullname, subname):
206 """mod.{subname} = submod"""
207 """mod.{subname} = submod"""
207 if mod is None:
208 if mod is None:
208 return #Nothing to do here.
209 return #Nothing to do here.
209
210
210 if submod is None:
211 if submod is None:
211 submod = sys.modules[fullname]
212 submod = sys.modules[fullname]
212
213
213 setattr(mod, subname, submod)
214 setattr(mod, subname, submod)
214
215
215 return
216 return
216
217
217 def ensure_fromlist(mod, fromlist, buf, recursive):
218 def ensure_fromlist(mod, fromlist, buf, recursive):
218 """Handle 'from module import a, b, c' imports."""
219 """Handle 'from module import a, b, c' imports."""
219 if not hasattr(mod, '__path__'):
220 if not hasattr(mod, '__path__'):
220 return
221 return
221 for item in fromlist:
222 for item in fromlist:
222 if not hasattr(item, 'rindex'):
223 if not hasattr(item, 'rindex'):
223 raise TypeError("Item in ``from list'' not a string")
224 raise TypeError("Item in ``from list'' not a string")
224 if item == '*':
225 if item == '*':
225 if recursive:
226 if recursive:
226 continue # avoid endless recursion
227 continue # avoid endless recursion
227 try:
228 try:
228 all = mod.__all__
229 all = mod.__all__
229 except AttributeError:
230 except AttributeError:
230 pass
231 pass
231 else:
232 else:
232 ret = ensure_fromlist(mod, all, buf, 1)
233 ret = ensure_fromlist(mod, all, buf, 1)
233 if not ret:
234 if not ret:
234 return 0
235 return 0
235 elif not hasattr(mod, item):
236 elif not hasattr(mod, item):
236 import_submodule(mod, item, buf + '.' + item)
237 import_submodule(mod, item, buf + '.' + item)
237
238
238 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
239 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
239 """Replacement for __import__()"""
240 """Replacement for __import__()"""
240 parent, buf = get_parent(globals, level)
241 parent, buf = get_parent(globals, level)
241
242
242 head, name, buf = load_next(parent, None if level < 0 else parent, name, buf)
243 head, name, buf = load_next(parent, None if level < 0 else parent, name, buf)
243
244
244 tail = head
245 tail = head
245 while name:
246 while name:
246 tail, name, buf = load_next(tail, tail, name, buf)
247 tail, name, buf = load_next(tail, tail, name, buf)
247
248
248 # If tail is None, both get_parent and load_next found
249 # If tail is None, both get_parent and load_next found
249 # an empty module name: someone called __import__("") or
250 # an empty module name: someone called __import__("") or
250 # doctored faulty bytecode
251 # doctored faulty bytecode
251 if tail is None:
252 if tail is None:
252 raise ValueError('Empty module name')
253 raise ValueError('Empty module name')
253
254
254 if not fromlist:
255 if not fromlist:
255 return head
256 return head
256
257
257 ensure_fromlist(tail, fromlist, buf, 0)
258 ensure_fromlist(tail, fromlist, buf, 0)
258 return tail
259 return tail
259
260
260 modules_reloading = {}
261 modules_reloading = {}
261
262
262 def deep_reload_hook(m):
263 def deep_reload_hook(m):
263 """Replacement for reload()."""
264 """Replacement for reload()."""
264 if not isinstance(m, ModuleType):
265 if not isinstance(m, ModuleType):
265 raise TypeError("reload() argument must be module")
266 raise TypeError("reload() argument must be module")
266
267
267 name = m.__name__
268 name = m.__name__
268
269
269 if name not in sys.modules:
270 if name not in sys.modules:
270 raise ImportError("reload(): module %.200s not in sys.modules" % name)
271 raise ImportError("reload(): module %.200s not in sys.modules" % name)
271
272
272 global modules_reloading
273 global modules_reloading
273 try:
274 try:
274 return modules_reloading[name]
275 return modules_reloading[name]
275 except:
276 except:
276 modules_reloading[name] = m
277 modules_reloading[name] = m
277
278
278 dot = name.rfind('.')
279 dot = name.rfind('.')
279 if dot < 0:
280 if dot < 0:
280 subname = name
281 subname = name
281 path = None
282 path = None
282 else:
283 else:
283 try:
284 try:
284 parent = sys.modules[name[:dot]]
285 parent = sys.modules[name[:dot]]
285 except KeyError:
286 except KeyError:
286 modules_reloading.clear()
287 modules_reloading.clear()
287 raise ImportError("reload(): parent %.200s not in sys.modules" % name[:dot])
288 raise ImportError("reload(): parent %.200s not in sys.modules" % name[:dot])
288 subname = name[dot+1:]
289 subname = name[dot+1:]
289 path = getattr(parent, "__path__", None)
290 path = getattr(parent, "__path__", None)
290
291
291 try:
292 try:
292 # This appears to be necessary on Python 3, because imp.find_module()
293 # This appears to be necessary on Python 3, because imp.find_module()
293 # tries to import standard libraries (like io) itself, and we don't
294 # tries to import standard libraries (like io) itself, and we don't
294 # want them to be processed by our deep_import_hook.
295 # want them to be processed by our deep_import_hook.
295 with replace_import_hook(original_import):
296 with replace_import_hook(original_import):
296 fp, filename, stuff = imp.find_module(subname, path)
297 fp, filename, stuff = imp.find_module(subname, path)
297 finally:
298 finally:
298 modules_reloading.clear()
299 modules_reloading.clear()
299
300
300 try:
301 try:
301 newm = imp.load_module(name, fp, filename, stuff)
302 newm = imp.load_module(name, fp, filename, stuff)
302 except:
303 except:
303 # load_module probably removed name from modules because of
304 # load_module probably removed name from modules because of
304 # the error. Put back the original module object.
305 # the error. Put back the original module object.
305 sys.modules[name] = m
306 sys.modules[name] = m
306 raise
307 raise
307 finally:
308 finally:
308 if fp: fp.close()
309 if fp: fp.close()
309
310
310 modules_reloading.clear()
311 modules_reloading.clear()
311 return newm
312 return newm
312
313
313 # Save the original hooks
314 # Save the original hooks
314 try:
315 try:
315 original_reload = __builtin__.reload
316 original_reload = __builtin__.reload
316 except AttributeError:
317 except AttributeError:
317 original_reload = imp.reload # Python 3
318 original_reload = imp.reload # Python 3
318
319
319 # Replacement for reload()
320 # Replacement for reload()
320 def reload(module, exclude=['sys', 'os.path', '__builtin__', '__main__']):
321 def reload(module, exclude=['sys', 'os.path', '__builtin__', '__main__']):
321 """Recursively reload all modules used in the given module. Optionally
322 """Recursively reload all modules used in the given module. Optionally
322 takes a list of modules to exclude from reloading. The default exclude
323 takes a list of modules to exclude from reloading. The default exclude
323 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
324 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
324 display, exception, and io hooks.
325 display, exception, and io hooks.
325 """
326 """
326 global found_now
327 global found_now
327 for i in exclude:
328 for i in exclude:
328 found_now[i] = 1
329 found_now[i] = 1
329 try:
330 try:
330 with replace_import_hook(deep_import_hook):
331 with replace_import_hook(deep_import_hook):
331 return deep_reload_hook(module)
332 return deep_reload_hook(module)
332 finally:
333 finally:
333 found_now = {}
334 found_now = {}
334
335
335 # Uncomment the following to automatically activate deep reloading whenever
336 # Uncomment the following to automatically activate deep reloading whenever
336 # this module is imported
337 # this module is imported
337 #__builtin__.reload = reload
338 #__builtin__.reload = reload
@@ -1,122 +1,123 b''
1 """ 'editor' hooks for common editors that work well with ipython
1 """ 'editor' hooks for common editors that work well with ipython
2
2
3 They should honor the line number argument, at least.
3 They should honor the line number argument, at least.
4
4
5 Contributions are *very* welcome.
5 Contributions are *very* welcome.
6 """
6 """
7 from __future__ import print_function
7
8
8 import os
9 import os
9 import pipes
10 import pipes
10 import subprocess
11 import subprocess
11
12
12 from IPython import get_ipython
13 from IPython import get_ipython
13 from IPython.core.error import TryNext
14 from IPython.core.error import TryNext
14
15
15
16
16 def install_editor(template, wait=False):
17 def install_editor(template, wait=False):
17 """Installs the editor that is called by IPython for the %edit magic.
18 """Installs the editor that is called by IPython for the %edit magic.
18
19
19 This overrides the default editor, which is generally set by your EDITOR
20 This overrides the default editor, which is generally set by your EDITOR
20 environment variable or is notepad (windows) or vi (linux). By supplying a
21 environment variable or is notepad (windows) or vi (linux). By supplying a
21 template string `run_template`, you can control how the editor is invoked
22 template string `run_template`, you can control how the editor is invoked
22 by IPython -- (e.g. the format in which it accepts command line options)
23 by IPython -- (e.g. the format in which it accepts command line options)
23
24
24 Parameters
25 Parameters
25 ----------
26 ----------
26 template : basestring
27 template : basestring
27 run_template acts as a template for how your editor is invoked by
28 run_template acts as a template for how your editor is invoked by
28 the shell. It should contain '{filename}', which will be replaced on
29 the shell. It should contain '{filename}', which will be replaced on
29 invokation with the file name, and '{line}', $line by line number
30 invokation with the file name, and '{line}', $line by line number
30 (or 0) to invoke the file with.
31 (or 0) to invoke the file with.
31 wait : bool
32 wait : bool
32 If `wait` is true, wait until the user presses enter before returning,
33 If `wait` is true, wait until the user presses enter before returning,
33 to facilitate non-blocking editors that exit immediately after
34 to facilitate non-blocking editors that exit immediately after
34 the call.
35 the call.
35 """
36 """
36
37
37 # not all editors support $line, so we'll leave out this check
38 # not all editors support $line, so we'll leave out this check
38 # for substitution in ['$file', '$line']:
39 # for substitution in ['$file', '$line']:
39 # if not substitution in run_template:
40 # if not substitution in run_template:
40 # raise ValueError(('run_template should contain %s'
41 # raise ValueError(('run_template should contain %s'
41 # ' for string substitution. You supplied "%s"' % (substitution,
42 # ' for string substitution. You supplied "%s"' % (substitution,
42 # run_template)))
43 # run_template)))
43
44
44 def call_editor(self, filename, line=0):
45 def call_editor(self, filename, line=0):
45 if line is None:
46 if line is None:
46 line = 0
47 line = 0
47 cmd = template.format(filename=pipes.quote(filename), line=line)
48 cmd = template.format(filename=pipes.quote(filename), line=line)
48 print ">", cmd
49 print(">", cmd)
49 proc = subprocess.Popen(cmd, shell=True)
50 proc = subprocess.Popen(cmd, shell=True)
50 if wait and proc.wait() != 0:
51 if wait and proc.wait() != 0:
51 raise TryNext()
52 raise TryNext()
52 if wait:
53 if wait:
53 raw_input("Press Enter when done editing:")
54 raw_input("Press Enter when done editing:")
54
55
55 get_ipython().set_hook('editor', call_editor)
56 get_ipython().set_hook('editor', call_editor)
56 get_ipython().editor = template
57 get_ipython().editor = template
57
58
58
59
59 # in these, exe is always the path/name of the executable. Useful
60 # in these, exe is always the path/name of the executable. Useful
60 # if you don't have the editor directory in your path
61 # if you don't have the editor directory in your path
61 def komodo(exe=u'komodo'):
62 def komodo(exe=u'komodo'):
62 """ Activestate Komodo [Edit] """
63 """ Activestate Komodo [Edit] """
63 install_editor(exe + u' -l {line} {filename}', wait=True)
64 install_editor(exe + u' -l {line} {filename}', wait=True)
64
65
65
66
66 def scite(exe=u"scite"):
67 def scite(exe=u"scite"):
67 """ SciTE or Sc1 """
68 """ SciTE or Sc1 """
68 install_editor(exe + u' {filename} -goto:{line}')
69 install_editor(exe + u' {filename} -goto:{line}')
69
70
70
71
71 def notepadplusplus(exe=u'notepad++'):
72 def notepadplusplus(exe=u'notepad++'):
72 """ Notepad++ http://notepad-plus.sourceforge.net """
73 """ Notepad++ http://notepad-plus.sourceforge.net """
73 install_editor(exe + u' -n{line} {filename}')
74 install_editor(exe + u' -n{line} {filename}')
74
75
75
76
76 def jed(exe=u'jed'):
77 def jed(exe=u'jed'):
77 """ JED, the lightweight emacsish editor """
78 """ JED, the lightweight emacsish editor """
78 install_editor(exe + u' +{line} {filename}')
79 install_editor(exe + u' +{line} {filename}')
79
80
80
81
81 def idle(exe=u'idle'):
82 def idle(exe=u'idle'):
82 """ Idle, the editor bundled with python
83 """ Idle, the editor bundled with python
83
84
84 Parameters
85 Parameters
85 ----------
86 ----------
86 exe : str, None
87 exe : str, None
87 If none, should be pretty smart about finding the executable.
88 If none, should be pretty smart about finding the executable.
88 """
89 """
89 if exe is None:
90 if exe is None:
90 import idlelib
91 import idlelib
91 p = os.path.dirname(idlelib.__filename__)
92 p = os.path.dirname(idlelib.__filename__)
92 # i'm not sure if this actually works. Is this idle.py script
93 # i'm not sure if this actually works. Is this idle.py script
93 # guarenteed to be executable?
94 # guarenteed to be executable?
94 exe = os.path.join(p, 'idle.py')
95 exe = os.path.join(p, 'idle.py')
95 install_editor(exe + u' {filename}')
96 install_editor(exe + u' {filename}')
96
97
97
98
98 def mate(exe=u'mate'):
99 def mate(exe=u'mate'):
99 """ TextMate, the missing editor"""
100 """ TextMate, the missing editor"""
100 # wait=True is not required since we're using the -w flag to mate
101 # wait=True is not required since we're using the -w flag to mate
101 install_editor(exe + u' -w -l {line} {filename}')
102 install_editor(exe + u' -w -l {line} {filename}')
102
103
103
104
104 # ##########################################
105 # ##########################################
105 # these are untested, report any problems
106 # these are untested, report any problems
106 # ##########################################
107 # ##########################################
107
108
108
109
109 def emacs(exe=u'emacs'):
110 def emacs(exe=u'emacs'):
110 install_editor(exe + u' +{line} {filename}')
111 install_editor(exe + u' +{line} {filename}')
111
112
112
113
113 def gnuclient(exe=u'gnuclient'):
114 def gnuclient(exe=u'gnuclient'):
114 install_editor(exe + u' -nw +{line} {filename}')
115 install_editor(exe + u' -nw +{line} {filename}')
115
116
116
117
117 def crimson_editor(exe=u'cedt.exe'):
118 def crimson_editor(exe=u'cedt.exe'):
118 install_editor(exe + u' /L:{line} {filename}')
119 install_editor(exe + u' /L:{line} {filename}')
119
120
120
121
121 def kate(exe=u'kate'):
122 def kate(exe=u'kate'):
122 install_editor(exe + u' -u -l {line} {filename}')
123 install_editor(exe + u' -u -l {line} {filename}')
@@ -1,172 +1,173 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 GLUT Inputhook support functions
3 GLUT Inputhook support functions
4 """
4 """
5 from __future__ import print_function
5
6
6 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
8 #
9 #
9 # 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
10 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12
13
13 # GLUT is quite an old library and it is difficult to ensure proper
14 # GLUT is quite an old library and it is difficult to ensure proper
14 # integration within IPython since original GLUT does not allow to handle
15 # integration within IPython since original GLUT does not allow to handle
15 # events one by one. Instead, it requires for the mainloop to be entered
16 # events one by one. Instead, it requires for the mainloop to be entered
16 # and never returned (there is not even a function to exit he
17 # and never returned (there is not even a function to exit he
17 # mainloop). Fortunately, there are alternatives such as freeglut
18 # mainloop). Fortunately, there are alternatives such as freeglut
18 # (available for linux and windows) and the OSX implementation gives
19 # (available for linux and windows) and the OSX implementation gives
19 # access to a glutCheckLoop() function that blocks itself until a new
20 # access to a glutCheckLoop() function that blocks itself until a new
20 # event is received. This means we have to setup the idle callback to
21 # event is received. This means we have to setup the idle callback to
21 # ensure we got at least one event that will unblock the function.
22 # ensure we got at least one event that will unblock the function.
22 #
23 #
23 # Furthermore, it is not possible to install these handlers without a window
24 # Furthermore, it is not possible to install these handlers without a window
24 # being first created. We choose to make this window invisible. This means that
25 # being first created. We choose to make this window invisible. This means that
25 # display mode options are set at this level and user won't be able to change
26 # display mode options are set at this level and user won't be able to change
26 # them later without modifying the code. This should probably be made available
27 # them later without modifying the code. This should probably be made available
27 # via IPython options system.
28 # via IPython options system.
28
29
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30 # Imports
31 # Imports
31 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
32 import os
33 import os
33 import sys
34 import sys
34 import time
35 import time
35 import signal
36 import signal
36 import OpenGL.GLUT as glut
37 import OpenGL.GLUT as glut
37 import OpenGL.platform as platform
38 import OpenGL.platform as platform
38 from timeit import default_timer as clock
39 from timeit import default_timer as clock
39
40
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41 # Constants
42 # Constants
42 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
43
44
44 # Frame per second : 60
45 # Frame per second : 60
45 # Should probably be an IPython option
46 # Should probably be an IPython option
46 glut_fps = 60
47 glut_fps = 60
47
48
48
49
49 # Display mode : double buffeed + rgba + depth
50 # Display mode : double buffeed + rgba + depth
50 # Should probably be an IPython option
51 # Should probably be an IPython option
51 glut_display_mode = (glut.GLUT_DOUBLE |
52 glut_display_mode = (glut.GLUT_DOUBLE |
52 glut.GLUT_RGBA |
53 glut.GLUT_RGBA |
53 glut.GLUT_DEPTH)
54 glut.GLUT_DEPTH)
54
55
55 glutMainLoopEvent = None
56 glutMainLoopEvent = None
56 if sys.platform == 'darwin':
57 if sys.platform == 'darwin':
57 try:
58 try:
58 glutCheckLoop = platform.createBaseFunction(
59 glutCheckLoop = platform.createBaseFunction(
59 'glutCheckLoop', dll=platform.GLUT, resultType=None,
60 'glutCheckLoop', dll=platform.GLUT, resultType=None,
60 argTypes=[],
61 argTypes=[],
61 doc='glutCheckLoop( ) -> None',
62 doc='glutCheckLoop( ) -> None',
62 argNames=(),
63 argNames=(),
63 )
64 )
64 except AttributeError:
65 except AttributeError:
65 raise RuntimeError(
66 raise RuntimeError(
66 '''Your glut implementation does not allow interactive sessions'''
67 '''Your glut implementation does not allow interactive sessions'''
67 '''Consider installing freeglut.''')
68 '''Consider installing freeglut.''')
68 glutMainLoopEvent = glutCheckLoop
69 glutMainLoopEvent = glutCheckLoop
69 elif glut.HAVE_FREEGLUT:
70 elif glut.HAVE_FREEGLUT:
70 glutMainLoopEvent = glut.glutMainLoopEvent
71 glutMainLoopEvent = glut.glutMainLoopEvent
71 else:
72 else:
72 raise RuntimeError(
73 raise RuntimeError(
73 '''Your glut implementation does not allow interactive sessions. '''
74 '''Your glut implementation does not allow interactive sessions. '''
74 '''Consider installing freeglut.''')
75 '''Consider installing freeglut.''')
75
76
76
77
77 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
78 # Platform-dependent imports and functions
79 # Platform-dependent imports and functions
79 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
80
81
81 if os.name == 'posix':
82 if os.name == 'posix':
82 import select
83 import select
83
84
84 def stdin_ready():
85 def stdin_ready():
85 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
86 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
86 if infds:
87 if infds:
87 return True
88 return True
88 else:
89 else:
89 return False
90 return False
90
91
91 elif sys.platform == 'win32':
92 elif sys.platform == 'win32':
92 import msvcrt
93 import msvcrt
93
94
94 def stdin_ready():
95 def stdin_ready():
95 return msvcrt.kbhit()
96 return msvcrt.kbhit()
96
97
97 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
98 # Callback functions
99 # Callback functions
99 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
100
101
101 def glut_display():
102 def glut_display():
102 # Dummy display function
103 # Dummy display function
103 pass
104 pass
104
105
105 def glut_idle():
106 def glut_idle():
106 # Dummy idle function
107 # Dummy idle function
107 pass
108 pass
108
109
109 def glut_close():
110 def glut_close():
110 # Close function only hides the current window
111 # Close function only hides the current window
111 glut.glutHideWindow()
112 glut.glutHideWindow()
112 glutMainLoopEvent()
113 glutMainLoopEvent()
113
114
114 def glut_int_handler(signum, frame):
115 def glut_int_handler(signum, frame):
115 # Catch sigint and print the defautl message
116 # Catch sigint and print the defautl message
116 signal.signal(signal.SIGINT, signal.default_int_handler)
117 signal.signal(signal.SIGINT, signal.default_int_handler)
117 print '\nKeyboardInterrupt'
118 print('\nKeyboardInterrupt')
118 # Need to reprint the prompt at this stage
119 # Need to reprint the prompt at this stage
119
120
120
121
121
122
122 #-----------------------------------------------------------------------------
123 #-----------------------------------------------------------------------------
123 # Code
124 # Code
124 #-----------------------------------------------------------------------------
125 #-----------------------------------------------------------------------------
125 def inputhook_glut():
126 def inputhook_glut():
126 """Run the pyglet event loop by processing pending events only.
127 """Run the pyglet event loop by processing pending events only.
127
128
128 This keeps processing pending events until stdin is ready. After
129 This keeps processing pending events until stdin is ready. After
129 processing all pending events, a call to time.sleep is inserted. This is
130 processing all pending events, a call to time.sleep is inserted. This is
130 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
131 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
131 though for best performance.
132 though for best performance.
132 """
133 """
133 # We need to protect against a user pressing Control-C when IPython is
134 # We need to protect against a user pressing Control-C when IPython is
134 # idle and this is running. We trap KeyboardInterrupt and pass.
135 # idle and this is running. We trap KeyboardInterrupt and pass.
135
136
136 signal.signal(signal.SIGINT, glut_int_handler)
137 signal.signal(signal.SIGINT, glut_int_handler)
137
138
138 try:
139 try:
139 t = clock()
140 t = clock()
140
141
141 # Make sure the default window is set after a window has been closed
142 # Make sure the default window is set after a window has been closed
142 if glut.glutGetWindow() == 0:
143 if glut.glutGetWindow() == 0:
143 glut.glutSetWindow( 1 )
144 glut.glutSetWindow( 1 )
144 glutMainLoopEvent()
145 glutMainLoopEvent()
145 return 0
146 return 0
146
147
147 while not stdin_ready():
148 while not stdin_ready():
148 glutMainLoopEvent()
149 glutMainLoopEvent()
149 # We need to sleep at this point to keep the idle CPU load
150 # We need to sleep at this point to keep the idle CPU load
150 # low. However, if sleep to long, GUI response is poor. As
151 # low. However, if sleep to long, GUI response is poor. As
151 # a compromise, we watch how often GUI events are being processed
152 # a compromise, we watch how often GUI events are being processed
152 # and switch between a short and long sleep time. Here are some
153 # and switch between a short and long sleep time. Here are some
153 # stats useful in helping to tune this.
154 # stats useful in helping to tune this.
154 # time CPU load
155 # time CPU load
155 # 0.001 13%
156 # 0.001 13%
156 # 0.005 3%
157 # 0.005 3%
157 # 0.01 1.5%
158 # 0.01 1.5%
158 # 0.05 0.5%
159 # 0.05 0.5%
159 used_time = clock() - t
160 used_time = clock() - t
160 if used_time > 10.0:
161 if used_time > 10.0:
161 # print 'Sleep for 1 s' # dbg
162 # print 'Sleep for 1 s' # dbg
162 time.sleep(1.0)
163 time.sleep(1.0)
163 elif used_time > 0.1:
164 elif used_time > 0.1:
164 # Few GUI events coming in, so we can sleep longer
165 # Few GUI events coming in, so we can sleep longer
165 # print 'Sleep for 0.05 s' # dbg
166 # print 'Sleep for 0.05 s' # dbg
166 time.sleep(0.05)
167 time.sleep(0.05)
167 else:
168 else:
168 # Many GUI events coming in, so sleep only very little
169 # Many GUI events coming in, so sleep only very little
169 time.sleep(0.001)
170 time.sleep(0.001)
170 except KeyboardInterrupt:
171 except KeyboardInterrupt:
171 pass
172 pass
172 return 0
173 return 0
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now