##// END OF EJS Templates
allow_none=False by default for Type and Instance
Sylvain Corlay -
Show More

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

@@ -1,622 +1,622 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A base class for a configurable application."""
2 """A base class for a configurable application."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import json
9 import json
10 import logging
10 import logging
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14 from copy import deepcopy
14 from copy import deepcopy
15 from collections import defaultdict
15 from collections import defaultdict
16
16
17 from decorator import decorator
17 from decorator import decorator
18
18
19 from IPython.config.configurable import SingletonConfigurable
19 from IPython.config.configurable import SingletonConfigurable
20 from IPython.config.loader import (
20 from IPython.config.loader import (
21 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
21 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
22 )
22 )
23
23
24 from IPython.utils.traitlets import (
24 from IPython.utils.traitlets import (
25 Unicode, List, Enum, Dict, Instance, TraitError
25 Unicode, List, Enum, Dict, Instance, TraitError
26 )
26 )
27 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
28 from IPython.utils.text import indent, wrap_paragraphs, dedent
28 from IPython.utils.text import indent, wrap_paragraphs, dedent
29 from IPython.utils import py3compat
29 from IPython.utils import py3compat
30 from IPython.utils.py3compat import string_types, iteritems
30 from IPython.utils.py3compat import string_types, iteritems
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Descriptions for the various sections
33 # Descriptions for the various sections
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 # merge flags&aliases into options
36 # merge flags&aliases into options
37 option_description = """
37 option_description = """
38 Arguments that take values are actually convenience aliases to full
38 Arguments that take values are actually convenience aliases to full
39 Configurables, whose aliases are listed on the help line. For more information
39 Configurables, whose aliases are listed on the help line. For more information
40 on full configurables, see '--help-all'.
40 on full configurables, see '--help-all'.
41 """.strip() # trim newlines of front and back
41 """.strip() # trim newlines of front and back
42
42
43 keyvalue_description = """
43 keyvalue_description = """
44 Parameters are set from command-line arguments of the form:
44 Parameters are set from command-line arguments of the form:
45 `--Class.trait=value`.
45 `--Class.trait=value`.
46 This line is evaluated in Python, so simple expressions are allowed, e.g.::
46 This line is evaluated in Python, so simple expressions are allowed, e.g.::
47 `--C.a='range(3)'` For setting C.a=[0,1,2].
47 `--C.a='range(3)'` For setting C.a=[0,1,2].
48 """.strip() # trim newlines of front and back
48 """.strip() # trim newlines of front and back
49
49
50 # sys.argv can be missing, for example when python is embedded. See the docs
50 # sys.argv can be missing, for example when python is embedded. See the docs
51 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
51 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
52 if not hasattr(sys, "argv"):
52 if not hasattr(sys, "argv"):
53 sys.argv = [""]
53 sys.argv = [""]
54
54
55 subcommand_description = """
55 subcommand_description = """
56 Subcommands are launched as `{app} cmd [args]`. For information on using
56 Subcommands are launched as `{app} cmd [args]`. For information on using
57 subcommand 'cmd', do: `{app} cmd -h`.
57 subcommand 'cmd', do: `{app} cmd -h`.
58 """
58 """
59 # get running program name
59 # get running program name
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Application class
62 # Application class
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 @decorator
65 @decorator
66 def catch_config_error(method, app, *args, **kwargs):
66 def catch_config_error(method, app, *args, **kwargs):
67 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
67 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
68
68
69 On a TraitError (generally caused by bad config), this will print the trait's
69 On a TraitError (generally caused by bad config), this will print the trait's
70 message, and exit the app.
70 message, and exit the app.
71
71
72 For use on init methods, to prevent invoking excepthook on invalid input.
72 For use on init methods, to prevent invoking excepthook on invalid input.
73 """
73 """
74 try:
74 try:
75 return method(app, *args, **kwargs)
75 return method(app, *args, **kwargs)
76 except (TraitError, ArgumentError) as e:
76 except (TraitError, ArgumentError) as e:
77 app.print_help()
77 app.print_help()
78 app.log.fatal("Bad config encountered during initialization:")
78 app.log.fatal("Bad config encountered during initialization:")
79 app.log.fatal(str(e))
79 app.log.fatal(str(e))
80 app.log.debug("Config at the time: %s", app.config)
80 app.log.debug("Config at the time: %s", app.config)
81 app.exit(1)
81 app.exit(1)
82
82
83
83
84 class ApplicationError(Exception):
84 class ApplicationError(Exception):
85 pass
85 pass
86
86
87 class LevelFormatter(logging.Formatter):
87 class LevelFormatter(logging.Formatter):
88 """Formatter with additional `highlevel` record
88 """Formatter with additional `highlevel` record
89
89
90 This field is empty if log level is less than highlevel_limit,
90 This field is empty if log level is less than highlevel_limit,
91 otherwise it is formatted with self.highlevel_format.
91 otherwise it is formatted with self.highlevel_format.
92
92
93 Useful for adding 'WARNING' to warning messages,
93 Useful for adding 'WARNING' to warning messages,
94 without adding 'INFO' to info, etc.
94 without adding 'INFO' to info, etc.
95 """
95 """
96 highlevel_limit = logging.WARN
96 highlevel_limit = logging.WARN
97 highlevel_format = " %(levelname)s |"
97 highlevel_format = " %(levelname)s |"
98
98
99 def format(self, record):
99 def format(self, record):
100 if record.levelno >= self.highlevel_limit:
100 if record.levelno >= self.highlevel_limit:
101 record.highlevel = self.highlevel_format % record.__dict__
101 record.highlevel = self.highlevel_format % record.__dict__
102 else:
102 else:
103 record.highlevel = ""
103 record.highlevel = ""
104 return super(LevelFormatter, self).format(record)
104 return super(LevelFormatter, self).format(record)
105
105
106
106
107 class Application(SingletonConfigurable):
107 class Application(SingletonConfigurable):
108 """A singleton application with full configuration support."""
108 """A singleton application with full configuration support."""
109
109
110 # The name of the application, will usually match the name of the command
110 # The name of the application, will usually match the name of the command
111 # line application
111 # line application
112 name = Unicode(u'application')
112 name = Unicode(u'application')
113
113
114 # The description of the application that is printed at the beginning
114 # The description of the application that is printed at the beginning
115 # of the help.
115 # of the help.
116 description = Unicode(u'This is an application.')
116 description = Unicode(u'This is an application.')
117 # default section descriptions
117 # default section descriptions
118 option_description = Unicode(option_description)
118 option_description = Unicode(option_description)
119 keyvalue_description = Unicode(keyvalue_description)
119 keyvalue_description = Unicode(keyvalue_description)
120 subcommand_description = Unicode(subcommand_description)
120 subcommand_description = Unicode(subcommand_description)
121
121
122 python_config_loader_class = PyFileConfigLoader
122 python_config_loader_class = PyFileConfigLoader
123 json_config_loader_class = JSONFileConfigLoader
123 json_config_loader_class = JSONFileConfigLoader
124
124
125 # The usage and example string that goes at the end of the help string.
125 # The usage and example string that goes at the end of the help string.
126 examples = Unicode()
126 examples = Unicode()
127
127
128 # A sequence of Configurable subclasses whose config=True attributes will
128 # A sequence of Configurable subclasses whose config=True attributes will
129 # be exposed at the command line.
129 # be exposed at the command line.
130 classes = []
130 classes = []
131 @property
131 @property
132 def _help_classes(self):
132 def _help_classes(self):
133 """Define `App.help_classes` if CLI classes should differ from config file classes"""
133 """Define `App.help_classes` if CLI classes should differ from config file classes"""
134 return getattr(self, 'help_classes', self.classes)
134 return getattr(self, 'help_classes', self.classes)
135
135
136 @property
136 @property
137 def _config_classes(self):
137 def _config_classes(self):
138 """Define `App.config_classes` if config file classes should differ from CLI classes."""
138 """Define `App.config_classes` if config file classes should differ from CLI classes."""
139 return getattr(self, 'config_classes', self.classes)
139 return getattr(self, 'config_classes', self.classes)
140
140
141 # The version string of this application.
141 # The version string of this application.
142 version = Unicode(u'0.0')
142 version = Unicode(u'0.0')
143
143
144 # the argv used to initialize the application
144 # the argv used to initialize the application
145 argv = List()
145 argv = List()
146
146
147 # The log level for the application
147 # The log level for the application
148 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
148 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
149 default_value=logging.WARN,
149 default_value=logging.WARN,
150 config=True,
150 config=True,
151 help="Set the log level by value or name.")
151 help="Set the log level by value or name.")
152 def _log_level_changed(self, name, old, new):
152 def _log_level_changed(self, name, old, new):
153 """Adjust the log level when log_level is set."""
153 """Adjust the log level when log_level is set."""
154 if isinstance(new, string_types):
154 if isinstance(new, string_types):
155 new = getattr(logging, new)
155 new = getattr(logging, new)
156 self.log_level = new
156 self.log_level = new
157 self.log.setLevel(new)
157 self.log.setLevel(new)
158
158
159 _log_formatter_cls = LevelFormatter
159 _log_formatter_cls = LevelFormatter
160
160
161 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
161 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
162 help="The date format used by logging formatters for %(asctime)s"
162 help="The date format used by logging formatters for %(asctime)s"
163 )
163 )
164 def _log_datefmt_changed(self, name, old, new):
164 def _log_datefmt_changed(self, name, old, new):
165 self._log_format_changed('log_format', self.log_format, self.log_format)
165 self._log_format_changed('log_format', self.log_format, self.log_format)
166
166
167 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
167 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
168 help="The Logging format template",
168 help="The Logging format template",
169 )
169 )
170 def _log_format_changed(self, name, old, new):
170 def _log_format_changed(self, name, old, new):
171 """Change the log formatter when log_format is set."""
171 """Change the log formatter when log_format is set."""
172 _log_handler = self.log.handlers[0]
172 _log_handler = self.log.handlers[0]
173 _log_formatter = self._log_formatter_cls(fmt=new, datefmt=self.log_datefmt)
173 _log_formatter = self._log_formatter_cls(fmt=new, datefmt=self.log_datefmt)
174 _log_handler.setFormatter(_log_formatter)
174 _log_handler.setFormatter(_log_formatter)
175
175
176
176
177 log = Instance(logging.Logger)
177 log = Instance(logging.Logger, allow_none=True)
178 def _log_default(self):
178 def _log_default(self):
179 """Start logging for this application.
179 """Start logging for this application.
180
180
181 The default is to log to stderr using a StreamHandler, if no default
181 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
182 handler already exists. The log level starts at logging.WARN, but this
183 can be adjusted by setting the ``log_level`` attribute.
183 can be adjusted by setting the ``log_level`` attribute.
184 """
184 """
185 log = logging.getLogger(self.__class__.__name__)
185 log = logging.getLogger(self.__class__.__name__)
186 log.setLevel(self.log_level)
186 log.setLevel(self.log_level)
187 log.propagate = False
187 log.propagate = False
188 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
188 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
189 while _log:
189 while _log:
190 if _log.handlers:
190 if _log.handlers:
191 return log
191 return log
192 if not _log.propagate:
192 if not _log.propagate:
193 break
193 break
194 else:
194 else:
195 _log = _log.parent
195 _log = _log.parent
196 if sys.executable.endswith('pythonw.exe'):
196 if sys.executable.endswith('pythonw.exe'):
197 # this should really go to a file, but file-logging is only
197 # this should really go to a file, but file-logging is only
198 # hooked up in parallel applications
198 # hooked up in parallel applications
199 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
199 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
200 else:
200 else:
201 _log_handler = logging.StreamHandler()
201 _log_handler = logging.StreamHandler()
202 _log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt)
202 _log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt)
203 _log_handler.setFormatter(_log_formatter)
203 _log_handler.setFormatter(_log_formatter)
204 log.addHandler(_log_handler)
204 log.addHandler(_log_handler)
205 return log
205 return log
206
206
207 # the alias map for configurables
207 # the alias map for configurables
208 aliases = Dict({'log-level' : 'Application.log_level'})
208 aliases = Dict({'log-level' : 'Application.log_level'})
209
209
210 # flags for loading Configurables or store_const style flags
210 # flags for loading Configurables or store_const style flags
211 # flags are loaded from this dict by '--key' flags
211 # 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
212 # 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
213 # and the second being the help string for the flag
214 flags = Dict()
214 flags = Dict()
215 def _flags_changed(self, name, old, new):
215 def _flags_changed(self, name, old, new):
216 """ensure flags dict is valid"""
216 """ensure flags dict is valid"""
217 for key,value in iteritems(new):
217 for key,value in iteritems(new):
218 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
218 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
219 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
219 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
220 assert isinstance(value[1], string_types), "Bad flag: %r:%s"%(key,value)
220 assert isinstance(value[1], string_types), "Bad flag: %r:%s"%(key,value)
221
221
222
222
223 # subcommands for launching other applications
223 # subcommands for launching other applications
224 # if this is not empty, this will be a parent Application
224 # if this is not empty, this will be a parent Application
225 # this must be a dict of two-tuples,
225 # this must be a dict of two-tuples,
226 # the first element being the application class/import string
226 # the first element being the application class/import string
227 # and the second being the help string for the subcommand
227 # and the second being the help string for the subcommand
228 subcommands = Dict()
228 subcommands = Dict()
229 # parse_command_line will initialize a subapp, if requested
229 # parse_command_line will initialize a subapp, if requested
230 subapp = Instance('IPython.config.application.Application', allow_none=True)
230 subapp = Instance('IPython.config.application.Application', allow_none=True)
231
231
232 # extra command-line arguments that don't set config values
232 # extra command-line arguments that don't set config values
233 extra_args = List(Unicode)
233 extra_args = List(Unicode)
234
234
235
235
236 def __init__(self, **kwargs):
236 def __init__(self, **kwargs):
237 SingletonConfigurable.__init__(self, **kwargs)
237 SingletonConfigurable.__init__(self, **kwargs)
238 # Ensure my class is in self.classes, so my attributes appear in command line
238 # Ensure my class is in self.classes, so my attributes appear in command line
239 # options and config files.
239 # options and config files.
240 if self.__class__ not in self.classes:
240 if self.__class__ not in self.classes:
241 self.classes.insert(0, self.__class__)
241 self.classes.insert(0, self.__class__)
242
242
243 def _config_changed(self, name, old, new):
243 def _config_changed(self, name, old, new):
244 SingletonConfigurable._config_changed(self, name, old, new)
244 SingletonConfigurable._config_changed(self, name, old, new)
245 self.log.debug('Config changed:')
245 self.log.debug('Config changed:')
246 self.log.debug(repr(new))
246 self.log.debug(repr(new))
247
247
248 @catch_config_error
248 @catch_config_error
249 def initialize(self, argv=None):
249 def initialize(self, argv=None):
250 """Do the basic steps to configure me.
250 """Do the basic steps to configure me.
251
251
252 Override in subclasses.
252 Override in subclasses.
253 """
253 """
254 self.parse_command_line(argv)
254 self.parse_command_line(argv)
255
255
256
256
257 def start(self):
257 def start(self):
258 """Start the app mainloop.
258 """Start the app mainloop.
259
259
260 Override in subclasses.
260 Override in subclasses.
261 """
261 """
262 if self.subapp is not None:
262 if self.subapp is not None:
263 return self.subapp.start()
263 return self.subapp.start()
264
264
265 def print_alias_help(self):
265 def print_alias_help(self):
266 """Print the alias part of the help."""
266 """Print the alias part of the help."""
267 if not self.aliases:
267 if not self.aliases:
268 return
268 return
269
269
270 lines = []
270 lines = []
271 classdict = {}
271 classdict = {}
272 for cls in self._help_classes:
272 for cls in self._help_classes:
273 # include all parents (up to, but excluding Configurable) in available names
273 # include all parents (up to, but excluding Configurable) in available names
274 for c in cls.mro()[:-3]:
274 for c in cls.mro()[:-3]:
275 classdict[c.__name__] = c
275 classdict[c.__name__] = c
276
276
277 for alias, longname in iteritems(self.aliases):
277 for alias, longname in iteritems(self.aliases):
278 classname, traitname = longname.split('.',1)
278 classname, traitname = longname.split('.',1)
279 cls = classdict[classname]
279 cls = classdict[classname]
280
280
281 trait = cls.class_traits(config=True)[traitname]
281 trait = cls.class_traits(config=True)[traitname]
282 help = cls.class_get_trait_help(trait).splitlines()
282 help = cls.class_get_trait_help(trait).splitlines()
283 # reformat first line
283 # reformat first line
284 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
284 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
285 if len(alias) == 1:
285 if len(alias) == 1:
286 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
286 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
287 lines.extend(help)
287 lines.extend(help)
288 # lines.append('')
288 # lines.append('')
289 print(os.linesep.join(lines))
289 print(os.linesep.join(lines))
290
290
291 def print_flag_help(self):
291 def print_flag_help(self):
292 """Print the flag part of the help."""
292 """Print the flag part of the help."""
293 if not self.flags:
293 if not self.flags:
294 return
294 return
295
295
296 lines = []
296 lines = []
297 for m, (cfg,help) in iteritems(self.flags):
297 for m, (cfg,help) in iteritems(self.flags):
298 prefix = '--' if len(m) > 1 else '-'
298 prefix = '--' if len(m) > 1 else '-'
299 lines.append(prefix+m)
299 lines.append(prefix+m)
300 lines.append(indent(dedent(help.strip())))
300 lines.append(indent(dedent(help.strip())))
301 # lines.append('')
301 # lines.append('')
302 print(os.linesep.join(lines))
302 print(os.linesep.join(lines))
303
303
304 def print_options(self):
304 def print_options(self):
305 if not self.flags and not self.aliases:
305 if not self.flags and not self.aliases:
306 return
306 return
307 lines = ['Options']
307 lines = ['Options']
308 lines.append('-'*len(lines[0]))
308 lines.append('-'*len(lines[0]))
309 lines.append('')
309 lines.append('')
310 for p in wrap_paragraphs(self.option_description):
310 for p in wrap_paragraphs(self.option_description):
311 lines.append(p)
311 lines.append(p)
312 lines.append('')
312 lines.append('')
313 print(os.linesep.join(lines))
313 print(os.linesep.join(lines))
314 self.print_flag_help()
314 self.print_flag_help()
315 self.print_alias_help()
315 self.print_alias_help()
316 print()
316 print()
317
317
318 def print_subcommands(self):
318 def print_subcommands(self):
319 """Print the subcommand part of the help."""
319 """Print the subcommand part of the help."""
320 if not self.subcommands:
320 if not self.subcommands:
321 return
321 return
322
322
323 lines = ["Subcommands"]
323 lines = ["Subcommands"]
324 lines.append('-'*len(lines[0]))
324 lines.append('-'*len(lines[0]))
325 lines.append('')
325 lines.append('')
326 for p in wrap_paragraphs(self.subcommand_description.format(
326 for p in wrap_paragraphs(self.subcommand_description.format(
327 app=self.name)):
327 app=self.name)):
328 lines.append(p)
328 lines.append(p)
329 lines.append('')
329 lines.append('')
330 for subc, (cls, help) in iteritems(self.subcommands):
330 for subc, (cls, help) in iteritems(self.subcommands):
331 lines.append(subc)
331 lines.append(subc)
332 if help:
332 if help:
333 lines.append(indent(dedent(help.strip())))
333 lines.append(indent(dedent(help.strip())))
334 lines.append('')
334 lines.append('')
335 print(os.linesep.join(lines))
335 print(os.linesep.join(lines))
336
336
337 def print_help(self, classes=False):
337 def print_help(self, classes=False):
338 """Print the help for each Configurable class in self.classes.
338 """Print the help for each Configurable class in self.classes.
339
339
340 If classes=False (the default), only flags and aliases are printed.
340 If classes=False (the default), only flags and aliases are printed.
341 """
341 """
342 self.print_description()
342 self.print_description()
343 self.print_subcommands()
343 self.print_subcommands()
344 self.print_options()
344 self.print_options()
345
345
346 if classes:
346 if classes:
347 help_classes = self._help_classes
347 help_classes = self._help_classes
348 if help_classes:
348 if help_classes:
349 print("Class parameters")
349 print("Class parameters")
350 print("----------------")
350 print("----------------")
351 print()
351 print()
352 for p in wrap_paragraphs(self.keyvalue_description):
352 for p in wrap_paragraphs(self.keyvalue_description):
353 print(p)
353 print(p)
354 print()
354 print()
355
355
356 for cls in help_classes:
356 for cls in help_classes:
357 cls.class_print_help()
357 cls.class_print_help()
358 print()
358 print()
359 else:
359 else:
360 print("To see all available configurables, use `--help-all`")
360 print("To see all available configurables, use `--help-all`")
361 print()
361 print()
362
362
363 self.print_examples()
363 self.print_examples()
364
364
365
365
366 def print_description(self):
366 def print_description(self):
367 """Print the application description."""
367 """Print the application description."""
368 for p in wrap_paragraphs(self.description):
368 for p in wrap_paragraphs(self.description):
369 print(p)
369 print(p)
370 print()
370 print()
371
371
372 def print_examples(self):
372 def print_examples(self):
373 """Print usage and examples.
373 """Print usage and examples.
374
374
375 This usage string goes at the end of the command line help string
375 This usage string goes at the end of the command line help string
376 and should contain examples of the application's usage.
376 and should contain examples of the application's usage.
377 """
377 """
378 if self.examples:
378 if self.examples:
379 print("Examples")
379 print("Examples")
380 print("--------")
380 print("--------")
381 print()
381 print()
382 print(indent(dedent(self.examples.strip())))
382 print(indent(dedent(self.examples.strip())))
383 print()
383 print()
384
384
385 def print_version(self):
385 def print_version(self):
386 """Print the version string."""
386 """Print the version string."""
387 print(self.version)
387 print(self.version)
388
388
389 def update_config(self, config):
389 def update_config(self, config):
390 """Fire the traits events when the config is updated."""
390 """Fire the traits events when the config is updated."""
391 # Save a copy of the current config.
391 # Save a copy of the current config.
392 newconfig = deepcopy(self.config)
392 newconfig = deepcopy(self.config)
393 # Merge the new config into the current one.
393 # Merge the new config into the current one.
394 newconfig.merge(config)
394 newconfig.merge(config)
395 # Save the combined config as self.config, which triggers the traits
395 # Save the combined config as self.config, which triggers the traits
396 # events.
396 # events.
397 self.config = newconfig
397 self.config = newconfig
398
398
399 @catch_config_error
399 @catch_config_error
400 def initialize_subcommand(self, subc, argv=None):
400 def initialize_subcommand(self, subc, argv=None):
401 """Initialize a subcommand with argv."""
401 """Initialize a subcommand with argv."""
402 subapp,help = self.subcommands.get(subc)
402 subapp,help = self.subcommands.get(subc)
403
403
404 if isinstance(subapp, string_types):
404 if isinstance(subapp, string_types):
405 subapp = import_item(subapp)
405 subapp = import_item(subapp)
406
406
407 # clear existing instances
407 # clear existing instances
408 self.__class__.clear_instance()
408 self.__class__.clear_instance()
409 # instantiate
409 # instantiate
410 self.subapp = subapp.instance(config=self.config)
410 self.subapp = subapp.instance(config=self.config)
411 # and initialize subapp
411 # and initialize subapp
412 self.subapp.initialize(argv)
412 self.subapp.initialize(argv)
413
413
414 def flatten_flags(self):
414 def flatten_flags(self):
415 """flatten flags and aliases, so cl-args override as expected.
415 """flatten flags and aliases, so cl-args override as expected.
416
416
417 This prevents issues such as an alias pointing to InteractiveShell,
417 This prevents issues such as an alias pointing to InteractiveShell,
418 but a config file setting the same trait in TerminalInteraciveShell
418 but a config file setting the same trait in TerminalInteraciveShell
419 getting inappropriate priority over the command-line arg.
419 getting inappropriate priority over the command-line arg.
420
420
421 Only aliases with exactly one descendent in the class list
421 Only aliases with exactly one descendent in the class list
422 will be promoted.
422 will be promoted.
423
423
424 """
424 """
425 # build a tree of classes in our list that inherit from a particular
425 # build a tree of classes in our list that inherit from a particular
426 # it will be a dict by parent classname of classes in our list
426 # it will be a dict by parent classname of classes in our list
427 # that are descendents
427 # that are descendents
428 mro_tree = defaultdict(list)
428 mro_tree = defaultdict(list)
429 for cls in self._help_classes:
429 for cls in self._help_classes:
430 clsname = cls.__name__
430 clsname = cls.__name__
431 for parent in cls.mro()[1:-3]:
431 for parent in cls.mro()[1:-3]:
432 # exclude cls itself and Configurable,HasTraits,object
432 # exclude cls itself and Configurable,HasTraits,object
433 mro_tree[parent.__name__].append(clsname)
433 mro_tree[parent.__name__].append(clsname)
434 # flatten aliases, which have the form:
434 # flatten aliases, which have the form:
435 # { 'alias' : 'Class.trait' }
435 # { 'alias' : 'Class.trait' }
436 aliases = {}
436 aliases = {}
437 for alias, cls_trait in iteritems(self.aliases):
437 for alias, cls_trait in iteritems(self.aliases):
438 cls,trait = cls_trait.split('.',1)
438 cls,trait = cls_trait.split('.',1)
439 children = mro_tree[cls]
439 children = mro_tree[cls]
440 if len(children) == 1:
440 if len(children) == 1:
441 # exactly one descendent, promote alias
441 # exactly one descendent, promote alias
442 cls = children[0]
442 cls = children[0]
443 aliases[alias] = '.'.join([cls,trait])
443 aliases[alias] = '.'.join([cls,trait])
444
444
445 # flatten flags, which are of the form:
445 # flatten flags, which are of the form:
446 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
446 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
447 flags = {}
447 flags = {}
448 for key, (flagdict, help) in iteritems(self.flags):
448 for key, (flagdict, help) in iteritems(self.flags):
449 newflag = {}
449 newflag = {}
450 for cls, subdict in iteritems(flagdict):
450 for cls, subdict in iteritems(flagdict):
451 children = mro_tree[cls]
451 children = mro_tree[cls]
452 # exactly one descendent, promote flag section
452 # exactly one descendent, promote flag section
453 if len(children) == 1:
453 if len(children) == 1:
454 cls = children[0]
454 cls = children[0]
455 newflag[cls] = subdict
455 newflag[cls] = subdict
456 flags[key] = (newflag, help)
456 flags[key] = (newflag, help)
457 return flags, aliases
457 return flags, aliases
458
458
459 @catch_config_error
459 @catch_config_error
460 def parse_command_line(self, argv=None):
460 def parse_command_line(self, argv=None):
461 """Parse the command line arguments."""
461 """Parse the command line arguments."""
462 argv = sys.argv[1:] if argv is None else argv
462 argv = sys.argv[1:] if argv is None else argv
463 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
463 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
464
464
465 if argv and argv[0] == 'help':
465 if argv and argv[0] == 'help':
466 # turn `ipython help notebook` into `ipython notebook -h`
466 # turn `ipython help notebook` into `ipython notebook -h`
467 argv = argv[1:] + ['-h']
467 argv = argv[1:] + ['-h']
468
468
469 if self.subcommands and len(argv) > 0:
469 if self.subcommands and len(argv) > 0:
470 # we have subcommands, and one may have been specified
470 # we have subcommands, and one may have been specified
471 subc, subargv = argv[0], argv[1:]
471 subc, subargv = argv[0], argv[1:]
472 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
472 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
473 # it's a subcommand, and *not* a flag or class parameter
473 # it's a subcommand, and *not* a flag or class parameter
474 return self.initialize_subcommand(subc, subargv)
474 return self.initialize_subcommand(subc, subargv)
475
475
476 # Arguments after a '--' argument are for the script IPython may be
476 # Arguments after a '--' argument are for the script IPython may be
477 # about to run, not IPython iteslf. For arguments parsed here (help and
477 # about to run, not IPython iteslf. For arguments parsed here (help and
478 # version), we want to only search the arguments up to the first
478 # version), we want to only search the arguments up to the first
479 # occurrence of '--', which we're calling interpreted_argv.
479 # occurrence of '--', which we're calling interpreted_argv.
480 try:
480 try:
481 interpreted_argv = argv[:argv.index('--')]
481 interpreted_argv = argv[:argv.index('--')]
482 except ValueError:
482 except ValueError:
483 interpreted_argv = argv
483 interpreted_argv = argv
484
484
485 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
485 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
486 self.print_help('--help-all' in interpreted_argv)
486 self.print_help('--help-all' in interpreted_argv)
487 self.exit(0)
487 self.exit(0)
488
488
489 if '--version' in interpreted_argv or '-V' in interpreted_argv:
489 if '--version' in interpreted_argv or '-V' in interpreted_argv:
490 self.print_version()
490 self.print_version()
491 self.exit(0)
491 self.exit(0)
492
492
493 # flatten flags&aliases, so cl-args get appropriate priority:
493 # flatten flags&aliases, so cl-args get appropriate priority:
494 flags,aliases = self.flatten_flags()
494 flags,aliases = self.flatten_flags()
495 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
495 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
496 flags=flags, log=self.log)
496 flags=flags, log=self.log)
497 config = loader.load_config()
497 config = loader.load_config()
498 self.update_config(config)
498 self.update_config(config)
499 # store unparsed args in extra_args
499 # store unparsed args in extra_args
500 self.extra_args = loader.extra_args
500 self.extra_args = loader.extra_args
501
501
502 @classmethod
502 @classmethod
503 def _load_config_files(cls, basefilename, path=None, log=None):
503 def _load_config_files(cls, basefilename, path=None, log=None):
504 """Load config files (py,json) by filename and path.
504 """Load config files (py,json) by filename and path.
505
505
506 yield each config object in turn.
506 yield each config object in turn.
507 """
507 """
508
508
509 if not isinstance(path, list):
509 if not isinstance(path, list):
510 path = [path]
510 path = [path]
511 for path in path[::-1]:
511 for path in path[::-1]:
512 # path list is in descending priority order, so load files backwards:
512 # path list is in descending priority order, so load files backwards:
513 pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log)
513 pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log)
514 jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log)
514 jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log)
515 config = None
515 config = None
516 for loader in [pyloader, jsonloader]:
516 for loader in [pyloader, jsonloader]:
517 try:
517 try:
518 config = loader.load_config()
518 config = loader.load_config()
519 except ConfigFileNotFound:
519 except ConfigFileNotFound:
520 pass
520 pass
521 except Exception:
521 except Exception:
522 # try to get the full filename, but it will be empty in the
522 # try to get the full filename, but it will be empty in the
523 # unlikely event that the error raised before filefind finished
523 # unlikely event that the error raised before filefind finished
524 filename = loader.full_filename or basefilename
524 filename = loader.full_filename or basefilename
525 # problem while running the file
525 # problem while running the file
526 if log:
526 if log:
527 log.error("Exception while loading config file %s",
527 log.error("Exception while loading config file %s",
528 filename, exc_info=True)
528 filename, exc_info=True)
529 else:
529 else:
530 if log:
530 if log:
531 log.debug("Loaded config file: %s", loader.full_filename)
531 log.debug("Loaded config file: %s", loader.full_filename)
532 if config:
532 if config:
533 yield config
533 yield config
534
534
535 raise StopIteration
535 raise StopIteration
536
536
537
537
538 @catch_config_error
538 @catch_config_error
539 def load_config_file(self, filename, path=None):
539 def load_config_file(self, filename, path=None):
540 """Load config files by filename and path."""
540 """Load config files by filename and path."""
541 filename, ext = os.path.splitext(filename)
541 filename, ext = os.path.splitext(filename)
542 loaded = []
542 loaded = []
543 for config in self._load_config_files(filename, path=path, log=self.log):
543 for config in self._load_config_files(filename, path=path, log=self.log):
544 loaded.append(config)
544 loaded.append(config)
545 self.update_config(config)
545 self.update_config(config)
546 if len(loaded) > 1:
546 if len(loaded) > 1:
547 collisions = loaded[0].collisions(loaded[1])
547 collisions = loaded[0].collisions(loaded[1])
548 if collisions:
548 if collisions:
549 self.log.warn("Collisions detected in {0}.py and {0}.json config files."
549 self.log.warn("Collisions detected in {0}.py and {0}.json config files."
550 " {0}.json has higher priority: {1}".format(
550 " {0}.json has higher priority: {1}".format(
551 filename, json.dumps(collisions, indent=2),
551 filename, json.dumps(collisions, indent=2),
552 ))
552 ))
553
553
554
554
555 def generate_config_file(self):
555 def generate_config_file(self):
556 """generate default config file from Configurables"""
556 """generate default config file from Configurables"""
557 lines = ["# Configuration file for %s." % self.name]
557 lines = ["# Configuration file for %s." % self.name]
558 lines.append('')
558 lines.append('')
559 for cls in self._config_classes:
559 for cls in self._config_classes:
560 lines.append(cls.class_config_section())
560 lines.append(cls.class_config_section())
561 return '\n'.join(lines)
561 return '\n'.join(lines)
562
562
563 def exit(self, exit_status=0):
563 def exit(self, exit_status=0):
564 self.log.debug("Exiting application: %s" % self.name)
564 self.log.debug("Exiting application: %s" % self.name)
565 sys.exit(exit_status)
565 sys.exit(exit_status)
566
566
567 @classmethod
567 @classmethod
568 def launch_instance(cls, argv=None, **kwargs):
568 def launch_instance(cls, argv=None, **kwargs):
569 """Launch a global instance of this Application
569 """Launch a global instance of this Application
570
570
571 If a global instance already exists, this reinitializes and starts it
571 If a global instance already exists, this reinitializes and starts it
572 """
572 """
573 app = cls.instance(**kwargs)
573 app = cls.instance(**kwargs)
574 app.initialize(argv)
574 app.initialize(argv)
575 app.start()
575 app.start()
576
576
577 #-----------------------------------------------------------------------------
577 #-----------------------------------------------------------------------------
578 # utility functions, for convenience
578 # utility functions, for convenience
579 #-----------------------------------------------------------------------------
579 #-----------------------------------------------------------------------------
580
580
581 def boolean_flag(name, configurable, set_help='', unset_help=''):
581 def boolean_flag(name, configurable, set_help='', unset_help=''):
582 """Helper for building basic --trait, --no-trait flags.
582 """Helper for building basic --trait, --no-trait flags.
583
583
584 Parameters
584 Parameters
585 ----------
585 ----------
586
586
587 name : str
587 name : str
588 The name of the flag.
588 The name of the flag.
589 configurable : str
589 configurable : str
590 The 'Class.trait' string of the trait to be set/unset with the flag
590 The 'Class.trait' string of the trait to be set/unset with the flag
591 set_help : unicode
591 set_help : unicode
592 help string for --name flag
592 help string for --name flag
593 unset_help : unicode
593 unset_help : unicode
594 help string for --no-name flag
594 help string for --no-name flag
595
595
596 Returns
596 Returns
597 -------
597 -------
598
598
599 cfg : dict
599 cfg : dict
600 A dict with two keys: 'name', and 'no-name', for setting and unsetting
600 A dict with two keys: 'name', and 'no-name', for setting and unsetting
601 the trait, respectively.
601 the trait, respectively.
602 """
602 """
603 # default helpstrings
603 # default helpstrings
604 set_help = set_help or "set %s=True"%configurable
604 set_help = set_help or "set %s=True"%configurable
605 unset_help = unset_help or "set %s=False"%configurable
605 unset_help = unset_help or "set %s=False"%configurable
606
606
607 cls,trait = configurable.split('.')
607 cls,trait = configurable.split('.')
608
608
609 setter = {cls : {trait : True}}
609 setter = {cls : {trait : True}}
610 unsetter = {cls : {trait : False}}
610 unsetter = {cls : {trait : False}}
611 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
611 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
612
612
613
613
614 def get_config():
614 def get_config():
615 """Get the config object for the global Application instance, if there is one
615 """Get the config object for the global Application instance, if there is one
616
616
617 otherwise return an empty config object
617 otherwise return an empty config object
618 """
618 """
619 if Application.initialized():
619 if Application.initialized():
620 return Application.instance().config
620 return Application.instance().config
621 else:
621 else:
622 return Config()
622 return Config()
@@ -1,380 +1,380 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A base class for objects that are configurable."""
2 """A base class for objects that are configurable."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import logging
9 import logging
10 from copy import deepcopy
10 from copy import deepcopy
11
11
12 from .loader import Config, LazyConfigValue
12 from .loader import Config, LazyConfigValue
13 from IPython.utils.traitlets import HasTraits, Instance
13 from IPython.utils.traitlets import HasTraits, Instance
14 from IPython.utils.text import indent, wrap_paragraphs
14 from IPython.utils.text import indent, wrap_paragraphs
15 from IPython.utils.py3compat import iteritems
15 from IPython.utils.py3compat import iteritems
16
16
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Helper classes for Configurables
19 # Helper classes for Configurables
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22
22
23 class ConfigurableError(Exception):
23 class ConfigurableError(Exception):
24 pass
24 pass
25
25
26
26
27 class MultipleInstanceError(ConfigurableError):
27 class MultipleInstanceError(ConfigurableError):
28 pass
28 pass
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Configurable implementation
31 # Configurable implementation
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 class Configurable(HasTraits):
34 class Configurable(HasTraits):
35
35
36 config = Instance(Config, (), {})
36 config = Instance(Config, (), {})
37 parent = Instance('IPython.config.configurable.Configurable')
37 parent = Instance('IPython.config.configurable.Configurable', allow_none=True)
38
38
39 def __init__(self, **kwargs):
39 def __init__(self, **kwargs):
40 """Create a configurable given a config config.
40 """Create a configurable given a config config.
41
41
42 Parameters
42 Parameters
43 ----------
43 ----------
44 config : Config
44 config : Config
45 If this is empty, default values are used. If config is a
45 If this is empty, default values are used. If config is a
46 :class:`Config` instance, it will be used to configure the
46 :class:`Config` instance, it will be used to configure the
47 instance.
47 instance.
48 parent : Configurable instance, optional
48 parent : Configurable instance, optional
49 The parent Configurable instance of this object.
49 The parent Configurable instance of this object.
50
50
51 Notes
51 Notes
52 -----
52 -----
53 Subclasses of Configurable must call the :meth:`__init__` method of
53 Subclasses of Configurable must call the :meth:`__init__` method of
54 :class:`Configurable` *before* doing anything else and using
54 :class:`Configurable` *before* doing anything else and using
55 :func:`super`::
55 :func:`super`::
56
56
57 class MyConfigurable(Configurable):
57 class MyConfigurable(Configurable):
58 def __init__(self, config=None):
58 def __init__(self, config=None):
59 super(MyConfigurable, self).__init__(config=config)
59 super(MyConfigurable, self).__init__(config=config)
60 # Then any other code you need to finish initialization.
60 # Then any other code you need to finish initialization.
61
61
62 This ensures that instances will be configured properly.
62 This ensures that instances will be configured properly.
63 """
63 """
64 parent = kwargs.pop('parent', None)
64 parent = kwargs.pop('parent', None)
65 if parent is not None:
65 if parent is not None:
66 # config is implied from parent
66 # config is implied from parent
67 if kwargs.get('config', None) is None:
67 if kwargs.get('config', None) is None:
68 kwargs['config'] = parent.config
68 kwargs['config'] = parent.config
69 self.parent = parent
69 self.parent = parent
70
70
71 config = kwargs.pop('config', None)
71 config = kwargs.pop('config', None)
72
72
73 # load kwarg traits, other than config
73 # load kwarg traits, other than config
74 super(Configurable, self).__init__(**kwargs)
74 super(Configurable, self).__init__(**kwargs)
75
75
76 # load config
76 # load config
77 if config is not None:
77 if config is not None:
78 # We used to deepcopy, but for now we are trying to just save
78 # We used to deepcopy, but for now we are trying to just save
79 # by reference. This *could* have side effects as all components
79 # by reference. This *could* have side effects as all components
80 # will share config. In fact, I did find such a side effect in
80 # will share config. In fact, I did find such a side effect in
81 # _config_changed below. If a config attribute value was a mutable type
81 # _config_changed below. If a config attribute value was a mutable type
82 # all instances of a component were getting the same copy, effectively
82 # all instances of a component were getting the same copy, effectively
83 # making that a class attribute.
83 # making that a class attribute.
84 # self.config = deepcopy(config)
84 # self.config = deepcopy(config)
85 self.config = config
85 self.config = config
86 else:
86 else:
87 # allow _config_default to return something
87 # allow _config_default to return something
88 self._load_config(self.config)
88 self._load_config(self.config)
89
89
90 # Ensure explicit kwargs are applied after loading config.
90 # Ensure explicit kwargs are applied after loading config.
91 # This is usually redundant, but ensures config doesn't override
91 # This is usually redundant, but ensures config doesn't override
92 # explicitly assigned values.
92 # explicitly assigned values.
93 for key, value in kwargs.items():
93 for key, value in kwargs.items():
94 setattr(self, key, value)
94 setattr(self, key, value)
95
95
96 #-------------------------------------------------------------------------
96 #-------------------------------------------------------------------------
97 # Static trait notifiations
97 # Static trait notifiations
98 #-------------------------------------------------------------------------
98 #-------------------------------------------------------------------------
99
99
100 @classmethod
100 @classmethod
101 def section_names(cls):
101 def section_names(cls):
102 """return section names as a list"""
102 """return section names as a list"""
103 return [c.__name__ for c in reversed(cls.__mro__) if
103 return [c.__name__ for c in reversed(cls.__mro__) if
104 issubclass(c, Configurable) and issubclass(cls, c)
104 issubclass(c, Configurable) and issubclass(cls, c)
105 ]
105 ]
106
106
107 def _find_my_config(self, cfg):
107 def _find_my_config(self, cfg):
108 """extract my config from a global Config object
108 """extract my config from a global Config object
109
109
110 will construct a Config object of only the config values that apply to me
110 will construct a Config object of only the config values that apply to me
111 based on my mro(), as well as those of my parent(s) if they exist.
111 based on my mro(), as well as those of my parent(s) if they exist.
112
112
113 If I am Bar and my parent is Foo, and their parent is Tim,
113 If I am Bar and my parent is Foo, and their parent is Tim,
114 this will return merge following config sections, in this order::
114 this will return merge following config sections, in this order::
115
115
116 [Bar, Foo.bar, Tim.Foo.Bar]
116 [Bar, Foo.bar, Tim.Foo.Bar]
117
117
118 With the last item being the highest priority.
118 With the last item being the highest priority.
119 """
119 """
120 cfgs = [cfg]
120 cfgs = [cfg]
121 if self.parent:
121 if self.parent:
122 cfgs.append(self.parent._find_my_config(cfg))
122 cfgs.append(self.parent._find_my_config(cfg))
123 my_config = Config()
123 my_config = Config()
124 for c in cfgs:
124 for c in cfgs:
125 for sname in self.section_names():
125 for sname in self.section_names():
126 # Don't do a blind getattr as that would cause the config to
126 # Don't do a blind getattr as that would cause the config to
127 # dynamically create the section with name Class.__name__.
127 # dynamically create the section with name Class.__name__.
128 if c._has_section(sname):
128 if c._has_section(sname):
129 my_config.merge(c[sname])
129 my_config.merge(c[sname])
130 return my_config
130 return my_config
131
131
132 def _load_config(self, cfg, section_names=None, traits=None):
132 def _load_config(self, cfg, section_names=None, traits=None):
133 """load traits from a Config object"""
133 """load traits from a Config object"""
134
134
135 if traits is None:
135 if traits is None:
136 traits = self.traits(config=True)
136 traits = self.traits(config=True)
137 if section_names is None:
137 if section_names is None:
138 section_names = self.section_names()
138 section_names = self.section_names()
139
139
140 my_config = self._find_my_config(cfg)
140 my_config = self._find_my_config(cfg)
141
141
142 # hold trait notifications until after all config has been loaded
142 # hold trait notifications until after all config has been loaded
143 with self.hold_trait_notifications():
143 with self.hold_trait_notifications():
144 for name, config_value in iteritems(my_config):
144 for name, config_value in iteritems(my_config):
145 if name in traits:
145 if name in traits:
146 if isinstance(config_value, LazyConfigValue):
146 if isinstance(config_value, LazyConfigValue):
147 # ConfigValue is a wrapper for using append / update on containers
147 # ConfigValue is a wrapper for using append / update on containers
148 # without having to copy the initial value
148 # without having to copy the initial value
149 initial = getattr(self, name)
149 initial = getattr(self, name)
150 config_value = config_value.get_value(initial)
150 config_value = config_value.get_value(initial)
151 # We have to do a deepcopy here if we don't deepcopy the entire
151 # We have to do a deepcopy here if we don't deepcopy the entire
152 # config object. If we don't, a mutable config_value will be
152 # config object. If we don't, a mutable config_value will be
153 # shared by all instances, effectively making it a class attribute.
153 # shared by all instances, effectively making it a class attribute.
154 setattr(self, name, deepcopy(config_value))
154 setattr(self, name, deepcopy(config_value))
155
155
156 def _config_changed(self, name, old, new):
156 def _config_changed(self, name, old, new):
157 """Update all the class traits having ``config=True`` as metadata.
157 """Update all the class traits having ``config=True`` as metadata.
158
158
159 For any class trait with a ``config`` metadata attribute that is
159 For any class trait with a ``config`` metadata attribute that is
160 ``True``, we update the trait with the value of the corresponding
160 ``True``, we update the trait with the value of the corresponding
161 config entry.
161 config entry.
162 """
162 """
163 # Get all traits with a config metadata entry that is True
163 # Get all traits with a config metadata entry that is True
164 traits = self.traits(config=True)
164 traits = self.traits(config=True)
165
165
166 # We auto-load config section for this class as well as any parent
166 # We auto-load config section for this class as well as any parent
167 # classes that are Configurable subclasses. This starts with Configurable
167 # classes that are Configurable subclasses. This starts with Configurable
168 # and works down the mro loading the config for each section.
168 # and works down the mro loading the config for each section.
169 section_names = self.section_names()
169 section_names = self.section_names()
170 self._load_config(new, traits=traits, section_names=section_names)
170 self._load_config(new, traits=traits, section_names=section_names)
171
171
172 def update_config(self, config):
172 def update_config(self, config):
173 """Fire the traits events when the config is updated."""
173 """Fire the traits events when the config is updated."""
174 # Save a copy of the current config.
174 # Save a copy of the current config.
175 newconfig = deepcopy(self.config)
175 newconfig = deepcopy(self.config)
176 # Merge the new config into the current one.
176 # Merge the new config into the current one.
177 newconfig.merge(config)
177 newconfig.merge(config)
178 # Save the combined config as self.config, which triggers the traits
178 # Save the combined config as self.config, which triggers the traits
179 # events.
179 # events.
180 self.config = newconfig
180 self.config = newconfig
181
181
182 @classmethod
182 @classmethod
183 def class_get_help(cls, inst=None):
183 def class_get_help(cls, inst=None):
184 """Get the help string for this class in ReST format.
184 """Get the help string for this class in ReST format.
185
185
186 If `inst` is given, it's current trait values will be used in place of
186 If `inst` is given, it's current trait values will be used in place of
187 class defaults.
187 class defaults.
188 """
188 """
189 assert inst is None or isinstance(inst, cls)
189 assert inst is None or isinstance(inst, cls)
190 final_help = []
190 final_help = []
191 final_help.append(u'%s options' % cls.__name__)
191 final_help.append(u'%s options' % cls.__name__)
192 final_help.append(len(final_help[0])*u'-')
192 final_help.append(len(final_help[0])*u'-')
193 for k, v in sorted(cls.class_traits(config=True).items()):
193 for k, v in sorted(cls.class_traits(config=True).items()):
194 help = cls.class_get_trait_help(v, inst)
194 help = cls.class_get_trait_help(v, inst)
195 final_help.append(help)
195 final_help.append(help)
196 return '\n'.join(final_help)
196 return '\n'.join(final_help)
197
197
198 @classmethod
198 @classmethod
199 def class_get_trait_help(cls, trait, inst=None):
199 def class_get_trait_help(cls, trait, inst=None):
200 """Get the help string for a single trait.
200 """Get the help string for a single trait.
201
201
202 If `inst` is given, it's current trait values will be used in place of
202 If `inst` is given, it's current trait values will be used in place of
203 the class default.
203 the class default.
204 """
204 """
205 assert inst is None or isinstance(inst, cls)
205 assert inst is None or isinstance(inst, cls)
206 lines = []
206 lines = []
207 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
207 header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
208 lines.append(header)
208 lines.append(header)
209 if inst is not None:
209 if inst is not None:
210 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
210 lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
211 else:
211 else:
212 try:
212 try:
213 dvr = repr(trait.get_default_value())
213 dvr = repr(trait.get_default_value())
214 except Exception:
214 except Exception:
215 dvr = None # ignore defaults we can't construct
215 dvr = None # ignore defaults we can't construct
216 if dvr is not None:
216 if dvr is not None:
217 if len(dvr) > 64:
217 if len(dvr) > 64:
218 dvr = dvr[:61]+'...'
218 dvr = dvr[:61]+'...'
219 lines.append(indent('Default: %s' % dvr, 4))
219 lines.append(indent('Default: %s' % dvr, 4))
220 if 'Enum' in trait.__class__.__name__:
220 if 'Enum' in trait.__class__.__name__:
221 # include Enum choices
221 # include Enum choices
222 lines.append(indent('Choices: %r' % (trait.values,)))
222 lines.append(indent('Choices: %r' % (trait.values,)))
223
223
224 help = trait.get_metadata('help')
224 help = trait.get_metadata('help')
225 if help is not None:
225 if help is not None:
226 help = '\n'.join(wrap_paragraphs(help, 76))
226 help = '\n'.join(wrap_paragraphs(help, 76))
227 lines.append(indent(help, 4))
227 lines.append(indent(help, 4))
228 return '\n'.join(lines)
228 return '\n'.join(lines)
229
229
230 @classmethod
230 @classmethod
231 def class_print_help(cls, inst=None):
231 def class_print_help(cls, inst=None):
232 """Get the help string for a single trait and print it."""
232 """Get the help string for a single trait and print it."""
233 print(cls.class_get_help(inst))
233 print(cls.class_get_help(inst))
234
234
235 @classmethod
235 @classmethod
236 def class_config_section(cls):
236 def class_config_section(cls):
237 """Get the config class config section"""
237 """Get the config class config section"""
238 def c(s):
238 def c(s):
239 """return a commented, wrapped block."""
239 """return a commented, wrapped block."""
240 s = '\n\n'.join(wrap_paragraphs(s, 78))
240 s = '\n\n'.join(wrap_paragraphs(s, 78))
241
241
242 return '# ' + s.replace('\n', '\n# ')
242 return '# ' + s.replace('\n', '\n# ')
243
243
244 # section header
244 # section header
245 breaker = '#' + '-'*78
245 breaker = '#' + '-'*78
246 s = "# %s configuration" % cls.__name__
246 s = "# %s configuration" % cls.__name__
247 lines = [breaker, s, breaker, '']
247 lines = [breaker, s, breaker, '']
248 # get the description trait
248 # get the description trait
249 desc = cls.class_traits().get('description')
249 desc = cls.class_traits().get('description')
250 if desc:
250 if desc:
251 desc = desc.default_value
251 desc = desc.default_value
252 else:
252 else:
253 # no description trait, use __doc__
253 # no description trait, use __doc__
254 desc = getattr(cls, '__doc__', '')
254 desc = getattr(cls, '__doc__', '')
255 if desc:
255 if desc:
256 lines.append(c(desc))
256 lines.append(c(desc))
257 lines.append('')
257 lines.append('')
258
258
259 parents = []
259 parents = []
260 for parent in cls.mro():
260 for parent in cls.mro():
261 # only include parents that are not base classes
261 # only include parents that are not base classes
262 # and are not the class itself
262 # and are not the class itself
263 # and have some configurable traits to inherit
263 # and have some configurable traits to inherit
264 if parent is not cls and issubclass(parent, Configurable) and \
264 if parent is not cls and issubclass(parent, Configurable) and \
265 parent.class_traits(config=True):
265 parent.class_traits(config=True):
266 parents.append(parent)
266 parents.append(parent)
267
267
268 if parents:
268 if parents:
269 pstr = ', '.join([ p.__name__ for p in parents ])
269 pstr = ', '.join([ p.__name__ for p in parents ])
270 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
270 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
271 lines.append('')
271 lines.append('')
272
272
273 for name, trait in iteritems(cls.class_traits(config=True)):
273 for name, trait in iteritems(cls.class_traits(config=True)):
274 help = trait.get_metadata('help') or ''
274 help = trait.get_metadata('help') or ''
275 lines.append(c(help))
275 lines.append(c(help))
276 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
276 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
277 lines.append('')
277 lines.append('')
278 return '\n'.join(lines)
278 return '\n'.join(lines)
279
279
280
280
281
281
282 class SingletonConfigurable(Configurable):
282 class SingletonConfigurable(Configurable):
283 """A configurable that only allows one instance.
283 """A configurable that only allows one instance.
284
284
285 This class is for classes that should only have one instance of itself
285 This class is for classes that should only have one instance of itself
286 or *any* subclass. To create and retrieve such a class use the
286 or *any* subclass. To create and retrieve such a class use the
287 :meth:`SingletonConfigurable.instance` method.
287 :meth:`SingletonConfigurable.instance` method.
288 """
288 """
289
289
290 _instance = None
290 _instance = None
291
291
292 @classmethod
292 @classmethod
293 def _walk_mro(cls):
293 def _walk_mro(cls):
294 """Walk the cls.mro() for parent classes that are also singletons
294 """Walk the cls.mro() for parent classes that are also singletons
295
295
296 For use in instance()
296 For use in instance()
297 """
297 """
298
298
299 for subclass in cls.mro():
299 for subclass in cls.mro():
300 if issubclass(cls, subclass) and \
300 if issubclass(cls, subclass) and \
301 issubclass(subclass, SingletonConfigurable) and \
301 issubclass(subclass, SingletonConfigurable) and \
302 subclass != SingletonConfigurable:
302 subclass != SingletonConfigurable:
303 yield subclass
303 yield subclass
304
304
305 @classmethod
305 @classmethod
306 def clear_instance(cls):
306 def clear_instance(cls):
307 """unset _instance for this class and singleton parents.
307 """unset _instance for this class and singleton parents.
308 """
308 """
309 if not cls.initialized():
309 if not cls.initialized():
310 return
310 return
311 for subclass in cls._walk_mro():
311 for subclass in cls._walk_mro():
312 if isinstance(subclass._instance, cls):
312 if isinstance(subclass._instance, cls):
313 # only clear instances that are instances
313 # only clear instances that are instances
314 # of the calling class
314 # of the calling class
315 subclass._instance = None
315 subclass._instance = None
316
316
317 @classmethod
317 @classmethod
318 def instance(cls, *args, **kwargs):
318 def instance(cls, *args, **kwargs):
319 """Returns a global instance of this class.
319 """Returns a global instance of this class.
320
320
321 This method create a new instance if none have previously been created
321 This method create a new instance if none have previously been created
322 and returns a previously created instance is one already exists.
322 and returns a previously created instance is one already exists.
323
323
324 The arguments and keyword arguments passed to this method are passed
324 The arguments and keyword arguments passed to this method are passed
325 on to the :meth:`__init__` method of the class upon instantiation.
325 on to the :meth:`__init__` method of the class upon instantiation.
326
326
327 Examples
327 Examples
328 --------
328 --------
329
329
330 Create a singleton class using instance, and retrieve it::
330 Create a singleton class using instance, and retrieve it::
331
331
332 >>> from IPython.config.configurable import SingletonConfigurable
332 >>> from IPython.config.configurable import SingletonConfigurable
333 >>> class Foo(SingletonConfigurable): pass
333 >>> class Foo(SingletonConfigurable): pass
334 >>> foo = Foo.instance()
334 >>> foo = Foo.instance()
335 >>> foo == Foo.instance()
335 >>> foo == Foo.instance()
336 True
336 True
337
337
338 Create a subclass that is retrived using the base class instance::
338 Create a subclass that is retrived using the base class instance::
339
339
340 >>> class Bar(SingletonConfigurable): pass
340 >>> class Bar(SingletonConfigurable): pass
341 >>> class Bam(Bar): pass
341 >>> class Bam(Bar): pass
342 >>> bam = Bam.instance()
342 >>> bam = Bam.instance()
343 >>> bam == Bar.instance()
343 >>> bam == Bar.instance()
344 True
344 True
345 """
345 """
346 # Create and save the instance
346 # Create and save the instance
347 if cls._instance is None:
347 if cls._instance is None:
348 inst = cls(*args, **kwargs)
348 inst = cls(*args, **kwargs)
349 # Now make sure that the instance will also be returned by
349 # Now make sure that the instance will also be returned by
350 # parent classes' _instance attribute.
350 # parent classes' _instance attribute.
351 for subclass in cls._walk_mro():
351 for subclass in cls._walk_mro():
352 subclass._instance = inst
352 subclass._instance = inst
353
353
354 if isinstance(cls._instance, cls):
354 if isinstance(cls._instance, cls):
355 return cls._instance
355 return cls._instance
356 else:
356 else:
357 raise MultipleInstanceError(
357 raise MultipleInstanceError(
358 'Multiple incompatible subclass instances of '
358 'Multiple incompatible subclass instances of '
359 '%s are being created.' % cls.__name__
359 '%s are being created.' % cls.__name__
360 )
360 )
361
361
362 @classmethod
362 @classmethod
363 def initialized(cls):
363 def initialized(cls):
364 """Has an instance been created?"""
364 """Has an instance been created?"""
365 return hasattr(cls, "_instance") and cls._instance is not None
365 return hasattr(cls, "_instance") and cls._instance is not None
366
366
367
367
368 class LoggingConfigurable(Configurable):
368 class LoggingConfigurable(Configurable):
369 """A parent class for Configurables that log.
369 """A parent class for Configurables that log.
370
370
371 Subclasses have a log trait, and the default behavior
371 Subclasses have a log trait, and the default behavior
372 is to get the logger from the currently running Application.
372 is to get the logger from the currently running Application.
373 """
373 """
374
374
375 log = Instance('logging.Logger')
375 log = Instance('logging.Logger', allow_none=True)
376 def _log_default(self):
376 def _log_default(self):
377 from IPython.utils import log
377 from IPython.utils import log
378 return log.get_logger()
378 return log.get_logger()
379
379
380
380
@@ -1,256 +1,256 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 System command aliases.
3 System command aliases.
4
4
5 Authors:
5 Authors:
6
6
7 * Fernando Perez
7 * Fernando Perez
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License.
14 # Distributed under the terms of the BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import re
24 import re
25 import sys
25 import sys
26
26
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.core.error import UsageError
28 from IPython.core.error import UsageError
29
29
30 from IPython.utils.py3compat import string_types
30 from IPython.utils.py3compat import string_types
31 from IPython.utils.traitlets import List, Instance
31 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.warn import error
32 from IPython.utils.warn import error
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Utilities
35 # Utilities
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 # This is used as the pattern for calls to split_user_input.
38 # This is used as the pattern for calls to split_user_input.
39 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
39 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
40
40
41 def default_aliases():
41 def default_aliases():
42 """Return list of shell aliases to auto-define.
42 """Return list of shell aliases to auto-define.
43 """
43 """
44 # Note: the aliases defined here should be safe to use on a kernel
44 # Note: the aliases defined here should be safe to use on a kernel
45 # regardless of what frontend it is attached to. Frontends that use a
45 # regardless of what frontend it is attached to. Frontends that use a
46 # kernel in-process can define additional aliases that will only work in
46 # kernel in-process can define additional aliases that will only work in
47 # their case. For example, things like 'less' or 'clear' that manipulate
47 # their case. For example, things like 'less' or 'clear' that manipulate
48 # the terminal should NOT be declared here, as they will only work if the
48 # the terminal should NOT be declared here, as they will only work if the
49 # kernel is running inside a true terminal, and not over the network.
49 # kernel is running inside a true terminal, and not over the network.
50
50
51 if os.name == 'posix':
51 if os.name == 'posix':
52 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
52 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
53 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
53 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
54 ('cat', 'cat'),
54 ('cat', 'cat'),
55 ]
55 ]
56 # Useful set of ls aliases. The GNU and BSD options are a little
56 # Useful set of ls aliases. The GNU and BSD options are a little
57 # different, so we make aliases that provide as similar as possible
57 # different, so we make aliases that provide as similar as possible
58 # behavior in ipython, by passing the right flags for each platform
58 # behavior in ipython, by passing the right flags for each platform
59 if sys.platform.startswith('linux'):
59 if sys.platform.startswith('linux'):
60 ls_aliases = [('ls', 'ls -F --color'),
60 ls_aliases = [('ls', 'ls -F --color'),
61 # long ls
61 # long ls
62 ('ll', 'ls -F -o --color'),
62 ('ll', 'ls -F -o --color'),
63 # ls normal files only
63 # ls normal files only
64 ('lf', 'ls -F -o --color %l | grep ^-'),
64 ('lf', 'ls -F -o --color %l | grep ^-'),
65 # ls symbolic links
65 # ls symbolic links
66 ('lk', 'ls -F -o --color %l | grep ^l'),
66 ('lk', 'ls -F -o --color %l | grep ^l'),
67 # directories or links to directories,
67 # directories or links to directories,
68 ('ldir', 'ls -F -o --color %l | grep /$'),
68 ('ldir', 'ls -F -o --color %l | grep /$'),
69 # things which are executable
69 # things which are executable
70 ('lx', 'ls -F -o --color %l | grep ^-..x'),
70 ('lx', 'ls -F -o --color %l | grep ^-..x'),
71 ]
71 ]
72 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
72 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
73 # OpenBSD, NetBSD. The ls implementation on these platforms do not support
73 # OpenBSD, NetBSD. The ls implementation on these platforms do not support
74 # the -G switch and lack the ability to use colorized output.
74 # the -G switch and lack the ability to use colorized output.
75 ls_aliases = [('ls', 'ls -F'),
75 ls_aliases = [('ls', 'ls -F'),
76 # long ls
76 # long ls
77 ('ll', 'ls -F -l'),
77 ('ll', 'ls -F -l'),
78 # ls normal files only
78 # ls normal files only
79 ('lf', 'ls -F -l %l | grep ^-'),
79 ('lf', 'ls -F -l %l | grep ^-'),
80 # ls symbolic links
80 # ls symbolic links
81 ('lk', 'ls -F -l %l | grep ^l'),
81 ('lk', 'ls -F -l %l | grep ^l'),
82 # directories or links to directories,
82 # directories or links to directories,
83 ('ldir', 'ls -F -l %l | grep /$'),
83 ('ldir', 'ls -F -l %l | grep /$'),
84 # things which are executable
84 # things which are executable
85 ('lx', 'ls -F -l %l | grep ^-..x'),
85 ('lx', 'ls -F -l %l | grep ^-..x'),
86 ]
86 ]
87 else:
87 else:
88 # BSD, OSX, etc.
88 # BSD, OSX, etc.
89 ls_aliases = [('ls', 'ls -F -G'),
89 ls_aliases = [('ls', 'ls -F -G'),
90 # long ls
90 # long ls
91 ('ll', 'ls -F -l -G'),
91 ('ll', 'ls -F -l -G'),
92 # ls normal files only
92 # ls normal files only
93 ('lf', 'ls -F -l -G %l | grep ^-'),
93 ('lf', 'ls -F -l -G %l | grep ^-'),
94 # ls symbolic links
94 # ls symbolic links
95 ('lk', 'ls -F -l -G %l | grep ^l'),
95 ('lk', 'ls -F -l -G %l | grep ^l'),
96 # directories or links to directories,
96 # directories or links to directories,
97 ('ldir', 'ls -F -G -l %l | grep /$'),
97 ('ldir', 'ls -F -G -l %l | grep /$'),
98 # things which are executable
98 # things which are executable
99 ('lx', 'ls -F -l -G %l | grep ^-..x'),
99 ('lx', 'ls -F -l -G %l | grep ^-..x'),
100 ]
100 ]
101 default_aliases = default_aliases + ls_aliases
101 default_aliases = default_aliases + ls_aliases
102 elif os.name in ['nt', 'dos']:
102 elif os.name in ['nt', 'dos']:
103 default_aliases = [('ls', 'dir /on'),
103 default_aliases = [('ls', 'dir /on'),
104 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
104 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
105 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
105 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
106 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
106 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
107 ]
107 ]
108 else:
108 else:
109 default_aliases = []
109 default_aliases = []
110
110
111 return default_aliases
111 return default_aliases
112
112
113
113
114 class AliasError(Exception):
114 class AliasError(Exception):
115 pass
115 pass
116
116
117
117
118 class InvalidAliasError(AliasError):
118 class InvalidAliasError(AliasError):
119 pass
119 pass
120
120
121 class Alias(object):
121 class Alias(object):
122 """Callable object storing the details of one alias.
122 """Callable object storing the details of one alias.
123
123
124 Instances are registered as magic functions to allow use of aliases.
124 Instances are registered as magic functions to allow use of aliases.
125 """
125 """
126
126
127 # Prepare blacklist
127 # Prepare blacklist
128 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
128 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
129
129
130 def __init__(self, shell, name, cmd):
130 def __init__(self, shell, name, cmd):
131 self.shell = shell
131 self.shell = shell
132 self.name = name
132 self.name = name
133 self.cmd = cmd
133 self.cmd = cmd
134 self.nargs = self.validate()
134 self.nargs = self.validate()
135
135
136 def validate(self):
136 def validate(self):
137 """Validate the alias, and return the number of arguments."""
137 """Validate the alias, and return the number of arguments."""
138 if self.name in self.blacklist:
138 if self.name in self.blacklist:
139 raise InvalidAliasError("The name %s can't be aliased "
139 raise InvalidAliasError("The name %s can't be aliased "
140 "because it is a keyword or builtin." % self.name)
140 "because it is a keyword or builtin." % self.name)
141 try:
141 try:
142 caller = self.shell.magics_manager.magics['line'][self.name]
142 caller = self.shell.magics_manager.magics['line'][self.name]
143 except KeyError:
143 except KeyError:
144 pass
144 pass
145 else:
145 else:
146 if not isinstance(caller, Alias):
146 if not isinstance(caller, Alias):
147 raise InvalidAliasError("The name %s can't be aliased "
147 raise InvalidAliasError("The name %s can't be aliased "
148 "because it is another magic command." % self.name)
148 "because it is another magic command." % self.name)
149
149
150 if not (isinstance(self.cmd, string_types)):
150 if not (isinstance(self.cmd, string_types)):
151 raise InvalidAliasError("An alias command must be a string, "
151 raise InvalidAliasError("An alias command must be a string, "
152 "got: %r" % self.cmd)
152 "got: %r" % self.cmd)
153
153
154 nargs = self.cmd.count('%s') - self.cmd.count('%%s')
154 nargs = self.cmd.count('%s') - self.cmd.count('%%s')
155
155
156 if (nargs > 0) and (self.cmd.find('%l') >= 0):
156 if (nargs > 0) and (self.cmd.find('%l') >= 0):
157 raise InvalidAliasError('The %s and %l specifiers are mutually '
157 raise InvalidAliasError('The %s and %l specifiers are mutually '
158 'exclusive in alias definitions.')
158 'exclusive in alias definitions.')
159
159
160 return nargs
160 return nargs
161
161
162 def __repr__(self):
162 def __repr__(self):
163 return "<alias {} for {!r}>".format(self.name, self.cmd)
163 return "<alias {} for {!r}>".format(self.name, self.cmd)
164
164
165 def __call__(self, rest=''):
165 def __call__(self, rest=''):
166 cmd = self.cmd
166 cmd = self.cmd
167 nargs = self.nargs
167 nargs = self.nargs
168 # Expand the %l special to be the user's input line
168 # Expand the %l special to be the user's input line
169 if cmd.find('%l') >= 0:
169 if cmd.find('%l') >= 0:
170 cmd = cmd.replace('%l', rest)
170 cmd = cmd.replace('%l', rest)
171 rest = ''
171 rest = ''
172
172
173 if nargs==0:
173 if nargs==0:
174 if cmd.find('%%s') >= 1:
174 if cmd.find('%%s') >= 1:
175 cmd = cmd.replace('%%s', '%s')
175 cmd = cmd.replace('%%s', '%s')
176 # Simple, argument-less aliases
176 # Simple, argument-less aliases
177 cmd = '%s %s' % (cmd, rest)
177 cmd = '%s %s' % (cmd, rest)
178 else:
178 else:
179 # Handle aliases with positional arguments
179 # Handle aliases with positional arguments
180 args = rest.split(None, nargs)
180 args = rest.split(None, nargs)
181 if len(args) < nargs:
181 if len(args) < nargs:
182 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
182 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
183 (self.name, nargs, len(args)))
183 (self.name, nargs, len(args)))
184 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
184 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
185
185
186 self.shell.system(cmd)
186 self.shell.system(cmd)
187
187
188 #-----------------------------------------------------------------------------
188 #-----------------------------------------------------------------------------
189 # Main AliasManager class
189 # Main AliasManager class
190 #-----------------------------------------------------------------------------
190 #-----------------------------------------------------------------------------
191
191
192 class AliasManager(Configurable):
192 class AliasManager(Configurable):
193
193
194 default_aliases = List(default_aliases(), config=True)
194 default_aliases = List(default_aliases(), config=True)
195 user_aliases = List(default_value=[], config=True)
195 user_aliases = List(default_value=[], config=True)
196 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
196 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
197
197
198 def __init__(self, shell=None, **kwargs):
198 def __init__(self, shell=None, **kwargs):
199 super(AliasManager, self).__init__(shell=shell, **kwargs)
199 super(AliasManager, self).__init__(shell=shell, **kwargs)
200 # For convenient access
200 # For convenient access
201 self.linemagics = self.shell.magics_manager.magics['line']
201 self.linemagics = self.shell.magics_manager.magics['line']
202 self.init_aliases()
202 self.init_aliases()
203
203
204 def init_aliases(self):
204 def init_aliases(self):
205 # Load default & user aliases
205 # Load default & user aliases
206 for name, cmd in self.default_aliases + self.user_aliases:
206 for name, cmd in self.default_aliases + self.user_aliases:
207 self.soft_define_alias(name, cmd)
207 self.soft_define_alias(name, cmd)
208
208
209 @property
209 @property
210 def aliases(self):
210 def aliases(self):
211 return [(n, func.cmd) for (n, func) in self.linemagics.items()
211 return [(n, func.cmd) for (n, func) in self.linemagics.items()
212 if isinstance(func, Alias)]
212 if isinstance(func, Alias)]
213
213
214 def soft_define_alias(self, name, cmd):
214 def soft_define_alias(self, name, cmd):
215 """Define an alias, but don't raise on an AliasError."""
215 """Define an alias, but don't raise on an AliasError."""
216 try:
216 try:
217 self.define_alias(name, cmd)
217 self.define_alias(name, cmd)
218 except AliasError as e:
218 except AliasError as e:
219 error("Invalid alias: %s" % e)
219 error("Invalid alias: %s" % e)
220
220
221 def define_alias(self, name, cmd):
221 def define_alias(self, name, cmd):
222 """Define a new alias after validating it.
222 """Define a new alias after validating it.
223
223
224 This will raise an :exc:`AliasError` if there are validation
224 This will raise an :exc:`AliasError` if there are validation
225 problems.
225 problems.
226 """
226 """
227 caller = Alias(shell=self.shell, name=name, cmd=cmd)
227 caller = Alias(shell=self.shell, name=name, cmd=cmd)
228 self.shell.magics_manager.register_function(caller, magic_kind='line',
228 self.shell.magics_manager.register_function(caller, magic_kind='line',
229 magic_name=name)
229 magic_name=name)
230
230
231 def get_alias(self, name):
231 def get_alias(self, name):
232 """Return an alias, or None if no alias by that name exists."""
232 """Return an alias, or None if no alias by that name exists."""
233 aname = self.linemagics.get(name, None)
233 aname = self.linemagics.get(name, None)
234 return aname if isinstance(aname, Alias) else None
234 return aname if isinstance(aname, Alias) else None
235
235
236 def is_alias(self, name):
236 def is_alias(self, name):
237 """Return whether or not a given name has been defined as an alias"""
237 """Return whether or not a given name has been defined as an alias"""
238 return self.get_alias(name) is not None
238 return self.get_alias(name) is not None
239
239
240 def undefine_alias(self, name):
240 def undefine_alias(self, name):
241 if self.is_alias(name):
241 if self.is_alias(name):
242 del self.linemagics[name]
242 del self.linemagics[name]
243 else:
243 else:
244 raise ValueError('%s is not an alias' % name)
244 raise ValueError('%s is not an alias' % name)
245
245
246 def clear_aliases(self):
246 def clear_aliases(self):
247 for name, cmd in self.aliases:
247 for name, cmd in self.aliases:
248 self.undefine_alias(name)
248 self.undefine_alias(name)
249
249
250 def retrieve_alias(self, name):
250 def retrieve_alias(self, name):
251 """Retrieve the command to which an alias expands."""
251 """Retrieve the command to which an alias expands."""
252 caller = self.get_alias(name)
252 caller = self.get_alias(name)
253 if caller:
253 if caller:
254 return caller.cmd
254 return caller.cmd
255 else:
255 else:
256 raise ValueError('%s is not an alias' % name)
256 raise ValueError('%s is not an alias' % name)
@@ -1,396 +1,396 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating configurables.
6 handling configuration and creating configurables.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10 """
10 """
11
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import atexit
15 import atexit
16 import glob
16 import glob
17 import logging
17 import logging
18 import os
18 import os
19 import shutil
19 import shutil
20 import sys
20 import sys
21
21
22 from IPython.config.application import Application, catch_config_error
22 from IPython.config.application import Application, catch_config_error
23 from IPython.config.loader import ConfigFileNotFound, PyFileConfigLoader
23 from IPython.config.loader import ConfigFileNotFound, PyFileConfigLoader
24 from IPython.core import release, crashhandler
24 from IPython.core import release, crashhandler
25 from IPython.core.profiledir import ProfileDir, ProfileDirError
25 from IPython.core.profiledir import ProfileDir, ProfileDirError
26 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
26 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
27 from IPython.utils import py3compat
27 from IPython.utils import py3compat
28 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
28 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
29
29
30 if os.name == 'nt':
30 if os.name == 'nt':
31 programdata = os.environ.get('PROGRAMDATA', None)
31 programdata = os.environ.get('PROGRAMDATA', None)
32 if programdata:
32 if programdata:
33 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
33 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
34 else: # PROGRAMDATA is not defined by default on XP.
34 else: # PROGRAMDATA is not defined by default on XP.
35 SYSTEM_CONFIG_DIRS = []
35 SYSTEM_CONFIG_DIRS = []
36 else:
36 else:
37 SYSTEM_CONFIG_DIRS = [
37 SYSTEM_CONFIG_DIRS = [
38 "/usr/local/etc/ipython",
38 "/usr/local/etc/ipython",
39 "/etc/ipython",
39 "/etc/ipython",
40 ]
40 ]
41
41
42
42
43 # aliases and flags
43 # aliases and flags
44
44
45 base_aliases = {
45 base_aliases = {
46 'profile-dir' : 'ProfileDir.location',
46 'profile-dir' : 'ProfileDir.location',
47 'profile' : 'BaseIPythonApplication.profile',
47 'profile' : 'BaseIPythonApplication.profile',
48 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
48 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
49 'log-level' : 'Application.log_level',
49 'log-level' : 'Application.log_level',
50 'config' : 'BaseIPythonApplication.extra_config_file',
50 'config' : 'BaseIPythonApplication.extra_config_file',
51 }
51 }
52
52
53 base_flags = dict(
53 base_flags = dict(
54 debug = ({'Application' : {'log_level' : logging.DEBUG}},
54 debug = ({'Application' : {'log_level' : logging.DEBUG}},
55 "set log level to logging.DEBUG (maximize logging output)"),
55 "set log level to logging.DEBUG (maximize logging output)"),
56 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
56 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
57 "set log level to logging.CRITICAL (minimize logging output)"),
57 "set log level to logging.CRITICAL (minimize logging output)"),
58 init = ({'BaseIPythonApplication' : {
58 init = ({'BaseIPythonApplication' : {
59 'copy_config_files' : True,
59 'copy_config_files' : True,
60 'auto_create' : True}
60 'auto_create' : True}
61 }, """Initialize profile with default config files. This is equivalent
61 }, """Initialize profile with default config files. This is equivalent
62 to running `ipython profile create <profile>` prior to startup.
62 to running `ipython profile create <profile>` prior to startup.
63 """)
63 """)
64 )
64 )
65
65
66 class ProfileAwareConfigLoader(PyFileConfigLoader):
66 class ProfileAwareConfigLoader(PyFileConfigLoader):
67 """A Python file config loader that is aware of IPython profiles."""
67 """A Python file config loader that is aware of IPython profiles."""
68 def load_subconfig(self, fname, path=None, profile=None):
68 def load_subconfig(self, fname, path=None, profile=None):
69 if profile is not None:
69 if profile is not None:
70 try:
70 try:
71 profile_dir = ProfileDir.find_profile_dir_by_name(
71 profile_dir = ProfileDir.find_profile_dir_by_name(
72 get_ipython_dir(),
72 get_ipython_dir(),
73 profile,
73 profile,
74 )
74 )
75 except ProfileDirError:
75 except ProfileDirError:
76 return
76 return
77 path = profile_dir.location
77 path = profile_dir.location
78 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
78 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
79
79
80 class BaseIPythonApplication(Application):
80 class BaseIPythonApplication(Application):
81
81
82 name = Unicode(u'ipython')
82 name = Unicode(u'ipython')
83 description = Unicode(u'IPython: an enhanced interactive Python shell.')
83 description = Unicode(u'IPython: an enhanced interactive Python shell.')
84 version = Unicode(release.version)
84 version = Unicode(release.version)
85
85
86 aliases = Dict(base_aliases)
86 aliases = Dict(base_aliases)
87 flags = Dict(base_flags)
87 flags = Dict(base_flags)
88 classes = List([ProfileDir])
88 classes = List([ProfileDir])
89
89
90 # enable `load_subconfig('cfg.py', profile='name')`
90 # enable `load_subconfig('cfg.py', profile='name')`
91 python_config_loader_class = ProfileAwareConfigLoader
91 python_config_loader_class = ProfileAwareConfigLoader
92
92
93 # Track whether the config_file has changed,
93 # Track whether the config_file has changed,
94 # because some logic happens only if we aren't using the default.
94 # because some logic happens only if we aren't using the default.
95 config_file_specified = Set()
95 config_file_specified = Set()
96
96
97 config_file_name = Unicode()
97 config_file_name = Unicode()
98 def _config_file_name_default(self):
98 def _config_file_name_default(self):
99 return self.name.replace('-','_') + u'_config.py'
99 return self.name.replace('-','_') + u'_config.py'
100 def _config_file_name_changed(self, name, old, new):
100 def _config_file_name_changed(self, name, old, new):
101 if new != old:
101 if new != old:
102 self.config_file_specified.add(new)
102 self.config_file_specified.add(new)
103
103
104 # The directory that contains IPython's builtin profiles.
104 # The directory that contains IPython's builtin profiles.
105 builtin_profile_dir = Unicode(
105 builtin_profile_dir = Unicode(
106 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
106 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
107 )
107 )
108
108
109 config_file_paths = List(Unicode)
109 config_file_paths = List(Unicode)
110 def _config_file_paths_default(self):
110 def _config_file_paths_default(self):
111 return [py3compat.getcwd()]
111 return [py3compat.getcwd()]
112
112
113 extra_config_file = Unicode(config=True,
113 extra_config_file = Unicode(config=True,
114 help="""Path to an extra config file to load.
114 help="""Path to an extra config file to load.
115
115
116 If specified, load this config file in addition to any other IPython config.
116 If specified, load this config file in addition to any other IPython config.
117 """)
117 """)
118 def _extra_config_file_changed(self, name, old, new):
118 def _extra_config_file_changed(self, name, old, new):
119 try:
119 try:
120 self.config_files.remove(old)
120 self.config_files.remove(old)
121 except ValueError:
121 except ValueError:
122 pass
122 pass
123 self.config_file_specified.add(new)
123 self.config_file_specified.add(new)
124 self.config_files.append(new)
124 self.config_files.append(new)
125
125
126 profile = Unicode(u'default', config=True,
126 profile = Unicode(u'default', config=True,
127 help="""The IPython profile to use."""
127 help="""The IPython profile to use."""
128 )
128 )
129
129
130 def _profile_changed(self, name, old, new):
130 def _profile_changed(self, name, old, new):
131 self.builtin_profile_dir = os.path.join(
131 self.builtin_profile_dir = os.path.join(
132 get_ipython_package_dir(), u'config', u'profile', new
132 get_ipython_package_dir(), u'config', u'profile', new
133 )
133 )
134
134
135 ipython_dir = Unicode(config=True,
135 ipython_dir = Unicode(config=True,
136 help="""
136 help="""
137 The name of the IPython directory. This directory is used for logging
137 The name of the IPython directory. This directory is used for logging
138 configuration (through profiles), history storage, etc. The default
138 configuration (through profiles), history storage, etc. The default
139 is usually $HOME/.ipython. This option can also be specified through
139 is usually $HOME/.ipython. This option can also be specified through
140 the environment variable IPYTHONDIR.
140 the environment variable IPYTHONDIR.
141 """
141 """
142 )
142 )
143 def _ipython_dir_default(self):
143 def _ipython_dir_default(self):
144 d = get_ipython_dir()
144 d = get_ipython_dir()
145 self._ipython_dir_changed('ipython_dir', d, d)
145 self._ipython_dir_changed('ipython_dir', d, d)
146 return d
146 return d
147
147
148 _in_init_profile_dir = False
148 _in_init_profile_dir = False
149 profile_dir = Instance(ProfileDir)
149 profile_dir = Instance(ProfileDir, allow_none=True)
150 def _profile_dir_default(self):
150 def _profile_dir_default(self):
151 # avoid recursion
151 # avoid recursion
152 if self._in_init_profile_dir:
152 if self._in_init_profile_dir:
153 return
153 return
154 # profile_dir requested early, force initialization
154 # profile_dir requested early, force initialization
155 self.init_profile_dir()
155 self.init_profile_dir()
156 return self.profile_dir
156 return self.profile_dir
157
157
158 overwrite = Bool(False, config=True,
158 overwrite = Bool(False, config=True,
159 help="""Whether to overwrite existing config files when copying""")
159 help="""Whether to overwrite existing config files when copying""")
160 auto_create = Bool(False, config=True,
160 auto_create = Bool(False, config=True,
161 help="""Whether to create profile dir if it doesn't exist""")
161 help="""Whether to create profile dir if it doesn't exist""")
162
162
163 config_files = List(Unicode)
163 config_files = List(Unicode)
164 def _config_files_default(self):
164 def _config_files_default(self):
165 return [self.config_file_name]
165 return [self.config_file_name]
166
166
167 copy_config_files = Bool(False, config=True,
167 copy_config_files = Bool(False, config=True,
168 help="""Whether to install the default config files into the profile dir.
168 help="""Whether to install the default config files into the profile dir.
169 If a new profile is being created, and IPython contains config files for that
169 If a new profile is being created, and IPython contains config files for that
170 profile, then they will be staged into the new directory. Otherwise,
170 profile, then they will be staged into the new directory. Otherwise,
171 default config files will be automatically generated.
171 default config files will be automatically generated.
172 """)
172 """)
173
173
174 verbose_crash = Bool(False, config=True,
174 verbose_crash = Bool(False, config=True,
175 help="""Create a massive crash report when IPython encounters what may be an
175 help="""Create a massive crash report when IPython encounters what may be an
176 internal error. The default is to append a short message to the
176 internal error. The default is to append a short message to the
177 usual traceback""")
177 usual traceback""")
178
178
179 # The class to use as the crash handler.
179 # The class to use as the crash handler.
180 crash_handler_class = Type(crashhandler.CrashHandler)
180 crash_handler_class = Type(crashhandler.CrashHandler)
181
181
182 @catch_config_error
182 @catch_config_error
183 def __init__(self, **kwargs):
183 def __init__(self, **kwargs):
184 super(BaseIPythonApplication, self).__init__(**kwargs)
184 super(BaseIPythonApplication, self).__init__(**kwargs)
185 # ensure current working directory exists
185 # ensure current working directory exists
186 try:
186 try:
187 directory = py3compat.getcwd()
187 directory = py3compat.getcwd()
188 except:
188 except:
189 # exit if cwd doesn't exist
189 # exit if cwd doesn't exist
190 self.log.error("Current working directory doesn't exist.")
190 self.log.error("Current working directory doesn't exist.")
191 self.exit(1)
191 self.exit(1)
192
192
193 #-------------------------------------------------------------------------
193 #-------------------------------------------------------------------------
194 # Various stages of Application creation
194 # Various stages of Application creation
195 #-------------------------------------------------------------------------
195 #-------------------------------------------------------------------------
196
196
197 def init_crash_handler(self):
197 def init_crash_handler(self):
198 """Create a crash handler, typically setting sys.excepthook to it."""
198 """Create a crash handler, typically setting sys.excepthook to it."""
199 self.crash_handler = self.crash_handler_class(self)
199 self.crash_handler = self.crash_handler_class(self)
200 sys.excepthook = self.excepthook
200 sys.excepthook = self.excepthook
201 def unset_crashhandler():
201 def unset_crashhandler():
202 sys.excepthook = sys.__excepthook__
202 sys.excepthook = sys.__excepthook__
203 atexit.register(unset_crashhandler)
203 atexit.register(unset_crashhandler)
204
204
205 def excepthook(self, etype, evalue, tb):
205 def excepthook(self, etype, evalue, tb):
206 """this is sys.excepthook after init_crashhandler
206 """this is sys.excepthook after init_crashhandler
207
207
208 set self.verbose_crash=True to use our full crashhandler, instead of
208 set self.verbose_crash=True to use our full crashhandler, instead of
209 a regular traceback with a short message (crash_handler_lite)
209 a regular traceback with a short message (crash_handler_lite)
210 """
210 """
211
211
212 if self.verbose_crash:
212 if self.verbose_crash:
213 return self.crash_handler(etype, evalue, tb)
213 return self.crash_handler(etype, evalue, tb)
214 else:
214 else:
215 return crashhandler.crash_handler_lite(etype, evalue, tb)
215 return crashhandler.crash_handler_lite(etype, evalue, tb)
216
216
217 def _ipython_dir_changed(self, name, old, new):
217 def _ipython_dir_changed(self, name, old, new):
218 if old is not None:
218 if old is not None:
219 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
219 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
220 sys.getfilesystemencoding()
220 sys.getfilesystemencoding()
221 )
221 )
222 if str_old in sys.path:
222 if str_old in sys.path:
223 sys.path.remove(str_old)
223 sys.path.remove(str_old)
224 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
224 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
225 sys.getfilesystemencoding()
225 sys.getfilesystemencoding()
226 )
226 )
227 sys.path.append(str_path)
227 sys.path.append(str_path)
228 ensure_dir_exists(new)
228 ensure_dir_exists(new)
229 readme = os.path.join(new, 'README')
229 readme = os.path.join(new, 'README')
230 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
230 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
231 if not os.path.exists(readme) and os.path.exists(readme_src):
231 if not os.path.exists(readme) and os.path.exists(readme_src):
232 shutil.copy(readme_src, readme)
232 shutil.copy(readme_src, readme)
233 for d in ('extensions', 'nbextensions'):
233 for d in ('extensions', 'nbextensions'):
234 path = os.path.join(new, d)
234 path = os.path.join(new, d)
235 try:
235 try:
236 ensure_dir_exists(path)
236 ensure_dir_exists(path)
237 except OSError:
237 except OSError:
238 # this will not be EEXIST
238 # this will not be EEXIST
239 self.log.error("couldn't create path %s: %s", path, e)
239 self.log.error("couldn't create path %s: %s", path, e)
240 self.log.debug("IPYTHONDIR set to: %s" % new)
240 self.log.debug("IPYTHONDIR set to: %s" % new)
241
241
242 def load_config_file(self, suppress_errors=True):
242 def load_config_file(self, suppress_errors=True):
243 """Load the config file.
243 """Load the config file.
244
244
245 By default, errors in loading config are handled, and a warning
245 By default, errors in loading config are handled, and a warning
246 printed on screen. For testing, the suppress_errors option is set
246 printed on screen. For testing, the suppress_errors option is set
247 to False, so errors will make tests fail.
247 to False, so errors will make tests fail.
248 """
248 """
249 self.log.debug("Searching path %s for config files", self.config_file_paths)
249 self.log.debug("Searching path %s for config files", self.config_file_paths)
250 base_config = 'ipython_config.py'
250 base_config = 'ipython_config.py'
251 self.log.debug("Attempting to load config file: %s" %
251 self.log.debug("Attempting to load config file: %s" %
252 base_config)
252 base_config)
253 try:
253 try:
254 Application.load_config_file(
254 Application.load_config_file(
255 self,
255 self,
256 base_config,
256 base_config,
257 path=self.config_file_paths
257 path=self.config_file_paths
258 )
258 )
259 except ConfigFileNotFound:
259 except ConfigFileNotFound:
260 # ignore errors loading parent
260 # ignore errors loading parent
261 self.log.debug("Config file %s not found", base_config)
261 self.log.debug("Config file %s not found", base_config)
262 pass
262 pass
263
263
264 for config_file_name in self.config_files:
264 for config_file_name in self.config_files:
265 if not config_file_name or config_file_name == base_config:
265 if not config_file_name or config_file_name == base_config:
266 continue
266 continue
267 self.log.debug("Attempting to load config file: %s" %
267 self.log.debug("Attempting to load config file: %s" %
268 self.config_file_name)
268 self.config_file_name)
269 try:
269 try:
270 Application.load_config_file(
270 Application.load_config_file(
271 self,
271 self,
272 config_file_name,
272 config_file_name,
273 path=self.config_file_paths
273 path=self.config_file_paths
274 )
274 )
275 except ConfigFileNotFound:
275 except ConfigFileNotFound:
276 # Only warn if the default config file was NOT being used.
276 # Only warn if the default config file was NOT being used.
277 if config_file_name in self.config_file_specified:
277 if config_file_name in self.config_file_specified:
278 msg = self.log.warn
278 msg = self.log.warn
279 else:
279 else:
280 msg = self.log.debug
280 msg = self.log.debug
281 msg("Config file not found, skipping: %s", config_file_name)
281 msg("Config file not found, skipping: %s", config_file_name)
282 except:
282 except:
283 # For testing purposes.
283 # For testing purposes.
284 if not suppress_errors:
284 if not suppress_errors:
285 raise
285 raise
286 self.log.warn("Error loading config file: %s" %
286 self.log.warn("Error loading config file: %s" %
287 self.config_file_name, exc_info=True)
287 self.config_file_name, exc_info=True)
288
288
289 def init_profile_dir(self):
289 def init_profile_dir(self):
290 """initialize the profile dir"""
290 """initialize the profile dir"""
291 self._in_init_profile_dir = True
291 self._in_init_profile_dir = True
292 if self.profile_dir is not None:
292 if self.profile_dir is not None:
293 # already ran
293 # already ran
294 return
294 return
295 if 'ProfileDir.location' not in self.config:
295 if 'ProfileDir.location' not in self.config:
296 # location not specified, find by profile name
296 # location not specified, find by profile name
297 try:
297 try:
298 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
298 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
299 except ProfileDirError:
299 except ProfileDirError:
300 # not found, maybe create it (always create default profile)
300 # not found, maybe create it (always create default profile)
301 if self.auto_create or self.profile == 'default':
301 if self.auto_create or self.profile == 'default':
302 try:
302 try:
303 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
303 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
304 except ProfileDirError:
304 except ProfileDirError:
305 self.log.fatal("Could not create profile: %r"%self.profile)
305 self.log.fatal("Could not create profile: %r"%self.profile)
306 self.exit(1)
306 self.exit(1)
307 else:
307 else:
308 self.log.info("Created profile dir: %r"%p.location)
308 self.log.info("Created profile dir: %r"%p.location)
309 else:
309 else:
310 self.log.fatal("Profile %r not found."%self.profile)
310 self.log.fatal("Profile %r not found."%self.profile)
311 self.exit(1)
311 self.exit(1)
312 else:
312 else:
313 self.log.debug("Using existing profile dir: %r"%p.location)
313 self.log.debug("Using existing profile dir: %r"%p.location)
314 else:
314 else:
315 location = self.config.ProfileDir.location
315 location = self.config.ProfileDir.location
316 # location is fully specified
316 # location is fully specified
317 try:
317 try:
318 p = ProfileDir.find_profile_dir(location, self.config)
318 p = ProfileDir.find_profile_dir(location, self.config)
319 except ProfileDirError:
319 except ProfileDirError:
320 # not found, maybe create it
320 # not found, maybe create it
321 if self.auto_create:
321 if self.auto_create:
322 try:
322 try:
323 p = ProfileDir.create_profile_dir(location, self.config)
323 p = ProfileDir.create_profile_dir(location, self.config)
324 except ProfileDirError:
324 except ProfileDirError:
325 self.log.fatal("Could not create profile directory: %r"%location)
325 self.log.fatal("Could not create profile directory: %r"%location)
326 self.exit(1)
326 self.exit(1)
327 else:
327 else:
328 self.log.debug("Creating new profile dir: %r"%location)
328 self.log.debug("Creating new profile dir: %r"%location)
329 else:
329 else:
330 self.log.fatal("Profile directory %r not found."%location)
330 self.log.fatal("Profile directory %r not found."%location)
331 self.exit(1)
331 self.exit(1)
332 else:
332 else:
333 self.log.info("Using existing profile dir: %r"%location)
333 self.log.info("Using existing profile dir: %r"%location)
334 # if profile_dir is specified explicitly, set profile name
334 # if profile_dir is specified explicitly, set profile name
335 dir_name = os.path.basename(p.location)
335 dir_name = os.path.basename(p.location)
336 if dir_name.startswith('profile_'):
336 if dir_name.startswith('profile_'):
337 self.profile = dir_name[8:]
337 self.profile = dir_name[8:]
338
338
339 self.profile_dir = p
339 self.profile_dir = p
340 self.config_file_paths.append(p.location)
340 self.config_file_paths.append(p.location)
341 self._in_init_profile_dir = False
341 self._in_init_profile_dir = False
342
342
343 def init_config_files(self):
343 def init_config_files(self):
344 """[optionally] copy default config files into profile dir."""
344 """[optionally] copy default config files into profile dir."""
345 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
345 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
346 # copy config files
346 # copy config files
347 path = self.builtin_profile_dir
347 path = self.builtin_profile_dir
348 if self.copy_config_files:
348 if self.copy_config_files:
349 src = self.profile
349 src = self.profile
350
350
351 cfg = self.config_file_name
351 cfg = self.config_file_name
352 if path and os.path.exists(os.path.join(path, cfg)):
352 if path and os.path.exists(os.path.join(path, cfg)):
353 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
353 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
354 cfg, src, self.profile_dir.location, self.overwrite)
354 cfg, src, self.profile_dir.location, self.overwrite)
355 )
355 )
356 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
356 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
357 else:
357 else:
358 self.stage_default_config_file()
358 self.stage_default_config_file()
359 else:
359 else:
360 # Still stage *bundled* config files, but not generated ones
360 # Still stage *bundled* config files, but not generated ones
361 # This is necessary for `ipython profile=sympy` to load the profile
361 # This is necessary for `ipython profile=sympy` to load the profile
362 # on the first go
362 # on the first go
363 files = glob.glob(os.path.join(path, '*.py'))
363 files = glob.glob(os.path.join(path, '*.py'))
364 for fullpath in files:
364 for fullpath in files:
365 cfg = os.path.basename(fullpath)
365 cfg = os.path.basename(fullpath)
366 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
366 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
367 # file was copied
367 # file was copied
368 self.log.warn("Staging bundled %s from %s into %r"%(
368 self.log.warn("Staging bundled %s from %s into %r"%(
369 cfg, self.profile, self.profile_dir.location)
369 cfg, self.profile, self.profile_dir.location)
370 )
370 )
371
371
372
372
373 def stage_default_config_file(self):
373 def stage_default_config_file(self):
374 """auto generate default config file, and stage it into the profile."""
374 """auto generate default config file, and stage it into the profile."""
375 s = self.generate_config_file()
375 s = self.generate_config_file()
376 fname = os.path.join(self.profile_dir.location, self.config_file_name)
376 fname = os.path.join(self.profile_dir.location, self.config_file_name)
377 if self.overwrite or not os.path.exists(fname):
377 if self.overwrite or not os.path.exists(fname):
378 self.log.warn("Generating default config file: %r"%(fname))
378 self.log.warn("Generating default config file: %r"%(fname))
379 with open(fname, 'w') as f:
379 with open(fname, 'w') as f:
380 f.write(s)
380 f.write(s)
381
381
382 @catch_config_error
382 @catch_config_error
383 def initialize(self, argv=None):
383 def initialize(self, argv=None):
384 # don't hook up crash handler before parsing command-line
384 # don't hook up crash handler before parsing command-line
385 self.parse_command_line(argv)
385 self.parse_command_line(argv)
386 self.init_crash_handler()
386 self.init_crash_handler()
387 if self.subapp is not None:
387 if self.subapp is not None:
388 # stop here if subapp is taking over
388 # stop here if subapp is taking over
389 return
389 return
390 cl_config = self.config
390 cl_config = self.config
391 self.init_profile_dir()
391 self.init_profile_dir()
392 self.init_config_files()
392 self.init_config_files()
393 self.load_config_file()
393 self.load_config_file()
394 # enforce cl-opts override configfile opts:
394 # enforce cl-opts override configfile opts:
395 self.update_config(cl_config)
395 self.update_config(cl_config)
396
396
@@ -1,111 +1,112 b''
1 """
1 """
2 A context manager for managing things injected into :mod:`__builtin__`.
2 A context manager for managing things injected into :mod:`__builtin__`.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 * Fernando Perez
7 * Fernando Perez
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team.
10 # Copyright (C) 2010-2011 The IPython Development Team.
11 #
11 #
12 # Distributed under the terms of the BSD License.
12 # Distributed under the terms of the BSD License.
13 #
13 #
14 # Complete license in the file COPYING.txt, distributed with this software.
14 # Complete license in the file COPYING.txt, distributed with this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 from IPython.config.configurable import Configurable
21 from IPython.config.configurable import Configurable
22
22
23 from IPython.utils.py3compat import builtin_mod, iteritems
23 from IPython.utils.py3compat import builtin_mod, iteritems
24 from IPython.utils.traitlets import Instance
24 from IPython.utils.traitlets import Instance
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Classes and functions
27 # Classes and functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class __BuiltinUndefined(object): pass
30 class __BuiltinUndefined(object): pass
31 BuiltinUndefined = __BuiltinUndefined()
31 BuiltinUndefined = __BuiltinUndefined()
32
32
33 class __HideBuiltin(object): pass
33 class __HideBuiltin(object): pass
34 HideBuiltin = __HideBuiltin()
34 HideBuiltin = __HideBuiltin()
35
35
36
36
37 class BuiltinTrap(Configurable):
37 class BuiltinTrap(Configurable):
38
38
39 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
39 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
40 allow_none=True)
40
41
41 def __init__(self, shell=None):
42 def __init__(self, shell=None):
42 super(BuiltinTrap, self).__init__(shell=shell, config=None)
43 super(BuiltinTrap, self).__init__(shell=shell, config=None)
43 self._orig_builtins = {}
44 self._orig_builtins = {}
44 # We define this to track if a single BuiltinTrap is nested.
45 # We define this to track if a single BuiltinTrap is nested.
45 # Only turn off the trap when the outermost call to __exit__ is made.
46 # Only turn off the trap when the outermost call to __exit__ is made.
46 self._nested_level = 0
47 self._nested_level = 0
47 self.shell = shell
48 self.shell = shell
48 # builtins we always add - if set to HideBuiltin, they will just
49 # builtins we always add - if set to HideBuiltin, they will just
49 # be removed instead of being replaced by something else
50 # be removed instead of being replaced by something else
50 self.auto_builtins = {'exit': HideBuiltin,
51 self.auto_builtins = {'exit': HideBuiltin,
51 'quit': HideBuiltin,
52 'quit': HideBuiltin,
52 'get_ipython': self.shell.get_ipython,
53 'get_ipython': self.shell.get_ipython,
53 }
54 }
54 # Recursive reload function
55 # Recursive reload function
55 try:
56 try:
56 from IPython.lib import deepreload
57 from IPython.lib import deepreload
57 if self.shell.deep_reload:
58 if self.shell.deep_reload:
58 self.auto_builtins['reload'] = deepreload.reload
59 self.auto_builtins['reload'] = deepreload.reload
59 else:
60 else:
60 self.auto_builtins['dreload']= deepreload.reload
61 self.auto_builtins['dreload']= deepreload.reload
61 except ImportError:
62 except ImportError:
62 pass
63 pass
63
64
64 def __enter__(self):
65 def __enter__(self):
65 if self._nested_level == 0:
66 if self._nested_level == 0:
66 self.activate()
67 self.activate()
67 self._nested_level += 1
68 self._nested_level += 1
68 # I return self, so callers can use add_builtin in a with clause.
69 # I return self, so callers can use add_builtin in a with clause.
69 return self
70 return self
70
71
71 def __exit__(self, type, value, traceback):
72 def __exit__(self, type, value, traceback):
72 if self._nested_level == 1:
73 if self._nested_level == 1:
73 self.deactivate()
74 self.deactivate()
74 self._nested_level -= 1
75 self._nested_level -= 1
75 # Returning False will cause exceptions to propagate
76 # Returning False will cause exceptions to propagate
76 return False
77 return False
77
78
78 def add_builtin(self, key, value):
79 def add_builtin(self, key, value):
79 """Add a builtin and save the original."""
80 """Add a builtin and save the original."""
80 bdict = builtin_mod.__dict__
81 bdict = builtin_mod.__dict__
81 orig = bdict.get(key, BuiltinUndefined)
82 orig = bdict.get(key, BuiltinUndefined)
82 if value is HideBuiltin:
83 if value is HideBuiltin:
83 if orig is not BuiltinUndefined: #same as 'key in bdict'
84 if orig is not BuiltinUndefined: #same as 'key in bdict'
84 self._orig_builtins[key] = orig
85 self._orig_builtins[key] = orig
85 del bdict[key]
86 del bdict[key]
86 else:
87 else:
87 self._orig_builtins[key] = orig
88 self._orig_builtins[key] = orig
88 bdict[key] = value
89 bdict[key] = value
89
90
90 def remove_builtin(self, key, orig):
91 def remove_builtin(self, key, orig):
91 """Remove an added builtin and re-set the original."""
92 """Remove an added builtin and re-set the original."""
92 if orig is BuiltinUndefined:
93 if orig is BuiltinUndefined:
93 del builtin_mod.__dict__[key]
94 del builtin_mod.__dict__[key]
94 else:
95 else:
95 builtin_mod.__dict__[key] = orig
96 builtin_mod.__dict__[key] = orig
96
97
97 def activate(self):
98 def activate(self):
98 """Store ipython references in the __builtin__ namespace."""
99 """Store ipython references in the __builtin__ namespace."""
99
100
100 add_builtin = self.add_builtin
101 add_builtin = self.add_builtin
101 for name, func in iteritems(self.auto_builtins):
102 for name, func in iteritems(self.auto_builtins):
102 add_builtin(name, func)
103 add_builtin(name, func)
103
104
104 def deactivate(self):
105 def deactivate(self):
105 """Remove any builtins which might have been added by add_builtins, or
106 """Remove any builtins which might have been added by add_builtins, or
106 restore overwritten ones to their previous values."""
107 restore overwritten ones to their previous values."""
107 remove_builtin = self.remove_builtin
108 remove_builtin = self.remove_builtin
108 for key, val in iteritems(self._orig_builtins):
109 for key, val in iteritems(self._orig_builtins):
109 remove_builtin(key, val)
110 remove_builtin(key, val)
110 self._orig_builtins.clear()
111 self._orig_builtins.clear()
111 self._builtins_added = False
112 self._builtins_added = False
@@ -1,282 +1,283 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Displayhook for IPython.
2 """Displayhook for IPython.
3
3
4 This defines a callable class that IPython uses for `sys.displayhook`.
4 This defines a callable class that IPython uses for `sys.displayhook`.
5 """
5 """
6
6
7 # Copyright (c) IPython Development Team.
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9
9
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 import sys
12 import sys
13
13
14 from IPython.core.formatters import _safe_get_formatter_method
14 from IPython.core.formatters import _safe_get_formatter_method
15 from IPython.config.configurable import Configurable
15 from IPython.config.configurable import Configurable
16 from IPython.utils import io
16 from IPython.utils import io
17 from IPython.utils.py3compat import builtin_mod
17 from IPython.utils.py3compat import builtin_mod
18 from IPython.utils.traitlets import Instance, Float
18 from IPython.utils.traitlets import Instance, Float
19 from IPython.utils.warn import warn
19 from IPython.utils.warn import warn
20
20
21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
22 # of these are also attributes of InteractiveShell. They should be on ONE object
22 # of these are also attributes of InteractiveShell. They should be on ONE object
23 # only and the other objects should ask that one object for their values.
23 # only and the other objects should ask that one object for their values.
24
24
25 class DisplayHook(Configurable):
25 class DisplayHook(Configurable):
26 """The custom IPython displayhook to replace sys.displayhook.
26 """The custom IPython displayhook to replace sys.displayhook.
27
27
28 This class does many things, but the basic idea is that it is a callable
28 This class does many things, but the basic idea is that it is a callable
29 that gets called anytime user code returns a value.
29 that gets called anytime user code returns a value.
30 """
30 """
31
31
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
33 allow_none=True)
33 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
34 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
34 allow_none=True)
35 allow_none=True)
35 cull_fraction = Float(0.2)
36 cull_fraction = Float(0.2)
36
37
37 def __init__(self, shell=None, cache_size=1000, **kwargs):
38 def __init__(self, shell=None, cache_size=1000, **kwargs):
38 super(DisplayHook, self).__init__(shell=shell, **kwargs)
39 super(DisplayHook, self).__init__(shell=shell, **kwargs)
39 cache_size_min = 3
40 cache_size_min = 3
40 if cache_size <= 0:
41 if cache_size <= 0:
41 self.do_full_cache = 0
42 self.do_full_cache = 0
42 cache_size = 0
43 cache_size = 0
43 elif cache_size < cache_size_min:
44 elif cache_size < cache_size_min:
44 self.do_full_cache = 0
45 self.do_full_cache = 0
45 cache_size = 0
46 cache_size = 0
46 warn('caching was disabled (min value for cache size is %s).' %
47 warn('caching was disabled (min value for cache size is %s).' %
47 cache_size_min,level=3)
48 cache_size_min,level=3)
48 else:
49 else:
49 self.do_full_cache = 1
50 self.do_full_cache = 1
50
51
51 self.cache_size = cache_size
52 self.cache_size = cache_size
52
53
53 # we need a reference to the user-level namespace
54 # we need a reference to the user-level namespace
54 self.shell = shell
55 self.shell = shell
55
56
56 self._,self.__,self.___ = '','',''
57 self._,self.__,self.___ = '','',''
57
58
58 # these are deliberately global:
59 # these are deliberately global:
59 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
60 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
60 self.shell.user_ns.update(to_user_ns)
61 self.shell.user_ns.update(to_user_ns)
61
62
62 @property
63 @property
63 def prompt_count(self):
64 def prompt_count(self):
64 return self.shell.execution_count
65 return self.shell.execution_count
65
66
66 #-------------------------------------------------------------------------
67 #-------------------------------------------------------------------------
67 # Methods used in __call__. Override these methods to modify the behavior
68 # Methods used in __call__. Override these methods to modify the behavior
68 # of the displayhook.
69 # of the displayhook.
69 #-------------------------------------------------------------------------
70 #-------------------------------------------------------------------------
70
71
71 def check_for_underscore(self):
72 def check_for_underscore(self):
72 """Check if the user has set the '_' variable by hand."""
73 """Check if the user has set the '_' variable by hand."""
73 # If something injected a '_' variable in __builtin__, delete
74 # If something injected a '_' variable in __builtin__, delete
74 # ipython's automatic one so we don't clobber that. gettext() in
75 # ipython's automatic one so we don't clobber that. gettext() in
75 # particular uses _, so we need to stay away from it.
76 # particular uses _, so we need to stay away from it.
76 if '_' in builtin_mod.__dict__:
77 if '_' in builtin_mod.__dict__:
77 try:
78 try:
78 del self.shell.user_ns['_']
79 del self.shell.user_ns['_']
79 except KeyError:
80 except KeyError:
80 pass
81 pass
81
82
82 def quiet(self):
83 def quiet(self):
83 """Should we silence the display hook because of ';'?"""
84 """Should we silence the display hook because of ';'?"""
84 # do not print output if input ends in ';'
85 # do not print output if input ends in ';'
85 try:
86 try:
86 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
87 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
87 return cell.rstrip().endswith(';')
88 return cell.rstrip().endswith(';')
88 except IndexError:
89 except IndexError:
89 # some uses of ipshellembed may fail here
90 # some uses of ipshellembed may fail here
90 return False
91 return False
91
92
92 def start_displayhook(self):
93 def start_displayhook(self):
93 """Start the displayhook, initializing resources."""
94 """Start the displayhook, initializing resources."""
94 pass
95 pass
95
96
96 def write_output_prompt(self):
97 def write_output_prompt(self):
97 """Write the output prompt.
98 """Write the output prompt.
98
99
99 The default implementation simply writes the prompt to
100 The default implementation simply writes the prompt to
100 ``io.stdout``.
101 ``io.stdout``.
101 """
102 """
102 # Use write, not print which adds an extra space.
103 # Use write, not print which adds an extra space.
103 io.stdout.write(self.shell.separate_out)
104 io.stdout.write(self.shell.separate_out)
104 outprompt = self.shell.prompt_manager.render('out')
105 outprompt = self.shell.prompt_manager.render('out')
105 if self.do_full_cache:
106 if self.do_full_cache:
106 io.stdout.write(outprompt)
107 io.stdout.write(outprompt)
107
108
108 def compute_format_data(self, result):
109 def compute_format_data(self, result):
109 """Compute format data of the object to be displayed.
110 """Compute format data of the object to be displayed.
110
111
111 The format data is a generalization of the :func:`repr` of an object.
112 The format data is a generalization of the :func:`repr` of an object.
112 In the default implementation the format data is a :class:`dict` of
113 In the default implementation the format data is a :class:`dict` of
113 key value pair where the keys are valid MIME types and the values
114 key value pair where the keys are valid MIME types and the values
114 are JSON'able data structure containing the raw data for that MIME
115 are JSON'able data structure containing the raw data for that MIME
115 type. It is up to frontends to determine pick a MIME to to use and
116 type. It is up to frontends to determine pick a MIME to to use and
116 display that data in an appropriate manner.
117 display that data in an appropriate manner.
117
118
118 This method only computes the format data for the object and should
119 This method only computes the format data for the object and should
119 NOT actually print or write that to a stream.
120 NOT actually print or write that to a stream.
120
121
121 Parameters
122 Parameters
122 ----------
123 ----------
123 result : object
124 result : object
124 The Python object passed to the display hook, whose format will be
125 The Python object passed to the display hook, whose format will be
125 computed.
126 computed.
126
127
127 Returns
128 Returns
128 -------
129 -------
129 (format_dict, md_dict) : dict
130 (format_dict, md_dict) : dict
130 format_dict is a :class:`dict` whose keys are valid MIME types and values are
131 format_dict is a :class:`dict` whose keys are valid MIME types and values are
131 JSON'able raw data for that MIME type. It is recommended that
132 JSON'able raw data for that MIME type. It is recommended that
132 all return values of this should always include the "text/plain"
133 all return values of this should always include the "text/plain"
133 MIME type representation of the object.
134 MIME type representation of the object.
134 md_dict is a :class:`dict` with the same MIME type keys
135 md_dict is a :class:`dict` with the same MIME type keys
135 of metadata associated with each output.
136 of metadata associated with each output.
136
137
137 """
138 """
138 return self.shell.display_formatter.format(result)
139 return self.shell.display_formatter.format(result)
139
140
140 def write_format_data(self, format_dict, md_dict=None):
141 def write_format_data(self, format_dict, md_dict=None):
141 """Write the format data dict to the frontend.
142 """Write the format data dict to the frontend.
142
143
143 This default version of this method simply writes the plain text
144 This default version of this method simply writes the plain text
144 representation of the object to ``io.stdout``. Subclasses should
145 representation of the object to ``io.stdout``. Subclasses should
145 override this method to send the entire `format_dict` to the
146 override this method to send the entire `format_dict` to the
146 frontends.
147 frontends.
147
148
148 Parameters
149 Parameters
149 ----------
150 ----------
150 format_dict : dict
151 format_dict : dict
151 The format dict for the object passed to `sys.displayhook`.
152 The format dict for the object passed to `sys.displayhook`.
152 md_dict : dict (optional)
153 md_dict : dict (optional)
153 The metadata dict to be associated with the display data.
154 The metadata dict to be associated with the display data.
154 """
155 """
155 if 'text/plain' not in format_dict:
156 if 'text/plain' not in format_dict:
156 # nothing to do
157 # nothing to do
157 return
158 return
158 # We want to print because we want to always make sure we have a
159 # We want to print because we want to always make sure we have a
159 # newline, even if all the prompt separators are ''. This is the
160 # newline, even if all the prompt separators are ''. This is the
160 # standard IPython behavior.
161 # standard IPython behavior.
161 result_repr = format_dict['text/plain']
162 result_repr = format_dict['text/plain']
162 if '\n' in result_repr:
163 if '\n' in result_repr:
163 # So that multi-line strings line up with the left column of
164 # So that multi-line strings line up with the left column of
164 # the screen, instead of having the output prompt mess up
165 # the screen, instead of having the output prompt mess up
165 # their first line.
166 # their first line.
166 # We use the prompt template instead of the expanded prompt
167 # We use the prompt template instead of the expanded prompt
167 # because the expansion may add ANSI escapes that will interfere
168 # because the expansion may add ANSI escapes that will interfere
168 # with our ability to determine whether or not we should add
169 # with our ability to determine whether or not we should add
169 # a newline.
170 # a newline.
170 prompt_template = self.shell.prompt_manager.out_template
171 prompt_template = self.shell.prompt_manager.out_template
171 if prompt_template and not prompt_template.endswith('\n'):
172 if prompt_template and not prompt_template.endswith('\n'):
172 # But avoid extraneous empty lines.
173 # But avoid extraneous empty lines.
173 result_repr = '\n' + result_repr
174 result_repr = '\n' + result_repr
174
175
175 print(result_repr, file=io.stdout)
176 print(result_repr, file=io.stdout)
176
177
177 def update_user_ns(self, result):
178 def update_user_ns(self, result):
178 """Update user_ns with various things like _, __, _1, etc."""
179 """Update user_ns with various things like _, __, _1, etc."""
179
180
180 # Avoid recursive reference when displaying _oh/Out
181 # Avoid recursive reference when displaying _oh/Out
181 if result is not self.shell.user_ns['_oh']:
182 if result is not self.shell.user_ns['_oh']:
182 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
183 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
183 self.cull_cache()
184 self.cull_cache()
184 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
185 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
185 # we cause buggy behavior for things like gettext).
186 # we cause buggy behavior for things like gettext).
186
187
187 if '_' not in builtin_mod.__dict__:
188 if '_' not in builtin_mod.__dict__:
188 self.___ = self.__
189 self.___ = self.__
189 self.__ = self._
190 self.__ = self._
190 self._ = result
191 self._ = result
191 self.shell.push({'_':self._,
192 self.shell.push({'_':self._,
192 '__':self.__,
193 '__':self.__,
193 '___':self.___}, interactive=False)
194 '___':self.___}, interactive=False)
194
195
195 # hackish access to top-level namespace to create _1,_2... dynamically
196 # hackish access to top-level namespace to create _1,_2... dynamically
196 to_main = {}
197 to_main = {}
197 if self.do_full_cache:
198 if self.do_full_cache:
198 new_result = '_'+repr(self.prompt_count)
199 new_result = '_'+repr(self.prompt_count)
199 to_main[new_result] = result
200 to_main[new_result] = result
200 self.shell.push(to_main, interactive=False)
201 self.shell.push(to_main, interactive=False)
201 self.shell.user_ns['_oh'][self.prompt_count] = result
202 self.shell.user_ns['_oh'][self.prompt_count] = result
202
203
203 def fill_exec_result(self, result):
204 def fill_exec_result(self, result):
204 if self.exec_result is not None:
205 if self.exec_result is not None:
205 self.exec_result.result = result
206 self.exec_result.result = result
206
207
207 def log_output(self, format_dict):
208 def log_output(self, format_dict):
208 """Log the output."""
209 """Log the output."""
209 if 'text/plain' not in format_dict:
210 if 'text/plain' not in format_dict:
210 # nothing to do
211 # nothing to do
211 return
212 return
212 if self.shell.logger.log_output:
213 if self.shell.logger.log_output:
213 self.shell.logger.log_write(format_dict['text/plain'], 'output')
214 self.shell.logger.log_write(format_dict['text/plain'], 'output')
214 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
215 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
215 format_dict['text/plain']
216 format_dict['text/plain']
216
217
217 def finish_displayhook(self):
218 def finish_displayhook(self):
218 """Finish up all displayhook activities."""
219 """Finish up all displayhook activities."""
219 io.stdout.write(self.shell.separate_out2)
220 io.stdout.write(self.shell.separate_out2)
220 io.stdout.flush()
221 io.stdout.flush()
221
222
222 def __call__(self, result=None):
223 def __call__(self, result=None):
223 """Printing with history cache management.
224 """Printing with history cache management.
224
225
225 This is invoked everytime the interpreter needs to print, and is
226 This is invoked everytime the interpreter needs to print, and is
226 activated by setting the variable sys.displayhook to it.
227 activated by setting the variable sys.displayhook to it.
227 """
228 """
228 self.check_for_underscore()
229 self.check_for_underscore()
229 if result is not None and not self.quiet():
230 if result is not None and not self.quiet():
230 self.start_displayhook()
231 self.start_displayhook()
231 self.write_output_prompt()
232 self.write_output_prompt()
232 format_dict, md_dict = self.compute_format_data(result)
233 format_dict, md_dict = self.compute_format_data(result)
233 self.update_user_ns(result)
234 self.update_user_ns(result)
234 self.fill_exec_result(result)
235 self.fill_exec_result(result)
235 if format_dict:
236 if format_dict:
236 self.write_format_data(format_dict, md_dict)
237 self.write_format_data(format_dict, md_dict)
237 self.log_output(format_dict)
238 self.log_output(format_dict)
238 self.finish_displayhook()
239 self.finish_displayhook()
239
240
240 def cull_cache(self):
241 def cull_cache(self):
241 """Output cache is full, cull the oldest entries"""
242 """Output cache is full, cull the oldest entries"""
242 oh = self.shell.user_ns.get('_oh', {})
243 oh = self.shell.user_ns.get('_oh', {})
243 sz = len(oh)
244 sz = len(oh)
244 cull_count = max(int(sz * self.cull_fraction), 2)
245 cull_count = max(int(sz * self.cull_fraction), 2)
245 warn('Output cache limit (currently {sz} entries) hit.\n'
246 warn('Output cache limit (currently {sz} entries) hit.\n'
246 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
247 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
247
248
248 for i, n in enumerate(sorted(oh)):
249 for i, n in enumerate(sorted(oh)):
249 if i >= cull_count:
250 if i >= cull_count:
250 break
251 break
251 self.shell.user_ns.pop('_%i' % n, None)
252 self.shell.user_ns.pop('_%i' % n, None)
252 oh.pop(n, None)
253 oh.pop(n, None)
253
254
254
255
255 def flush(self):
256 def flush(self):
256 if not self.do_full_cache:
257 if not self.do_full_cache:
257 raise ValueError("You shouldn't have reached the cache flush "
258 raise ValueError("You shouldn't have reached the cache flush "
258 "if full caching is not enabled!")
259 "if full caching is not enabled!")
259 # delete auto-generated vars from global namespace
260 # delete auto-generated vars from global namespace
260
261
261 for n in range(1,self.prompt_count + 1):
262 for n in range(1,self.prompt_count + 1):
262 key = '_'+repr(n)
263 key = '_'+repr(n)
263 try:
264 try:
264 del self.shell.user_ns[key]
265 del self.shell.user_ns[key]
265 except: pass
266 except: pass
266 # In some embedded circumstances, the user_ns doesn't have the
267 # In some embedded circumstances, the user_ns doesn't have the
267 # '_oh' key set up.
268 # '_oh' key set up.
268 oh = self.shell.user_ns.get('_oh', None)
269 oh = self.shell.user_ns.get('_oh', None)
269 if oh is not None:
270 if oh is not None:
270 oh.clear()
271 oh.clear()
271
272
272 # Release our own references to objects:
273 # Release our own references to objects:
273 self._, self.__, self.___ = '', '', ''
274 self._, self.__, self.___ = '', '', ''
274
275
275 if '_' not in builtin_mod.__dict__:
276 if '_' not in builtin_mod.__dict__:
276 self.shell.user_ns.update({'_':None,'__':None, '___':None})
277 self.shell.user_ns.update({'_':None,'__':None, '___':None})
277 import gc
278 import gc
278 # TODO: Is this really needed?
279 # TODO: Is this really needed?
279 # IronPython blocks here forever
280 # IronPython blocks here forever
280 if sys.platform != "cli":
281 if sys.platform != "cli":
281 gc.collect()
282 gc.collect()
282
283
@@ -1,175 +1,176 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions."""
2 """A class for managing IPython extensions."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 from shutil import copyfile
8 from shutil import copyfile
9 import sys
9 import sys
10
10
11 from IPython.config.configurable import Configurable
11 from IPython.config.configurable import Configurable
12 from IPython.utils.path import ensure_dir_exists
12 from IPython.utils.path import ensure_dir_exists
13 from IPython.utils.traitlets import Instance
13 from IPython.utils.traitlets import Instance
14 from IPython.utils.py3compat import PY3
14 from IPython.utils.py3compat import PY3
15 if PY3:
15 if PY3:
16 from imp import reload
16 from imp import reload
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Main class
19 # Main class
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class ExtensionManager(Configurable):
22 class ExtensionManager(Configurable):
23 """A class to manage IPython extensions.
23 """A class to manage IPython extensions.
24
24
25 An IPython extension is an importable Python module that has
25 An IPython extension is an importable Python module that has
26 a function with the signature::
26 a function with the signature::
27
27
28 def load_ipython_extension(ipython):
28 def load_ipython_extension(ipython):
29 # Do things with ipython
29 # Do things with ipython
30
30
31 This function is called after your extension is imported and the
31 This function is called after your extension is imported and the
32 currently active :class:`InteractiveShell` instance is passed as
32 currently active :class:`InteractiveShell` instance is passed as
33 the only argument. You can do anything you want with IPython at
33 the only argument. You can do anything you want with IPython at
34 that point, including defining new magic and aliases, adding new
34 that point, including defining new magic and aliases, adding new
35 components, etc.
35 components, etc.
36
36
37 You can also optionally define an :func:`unload_ipython_extension(ipython)`
37 You can also optionally define an :func:`unload_ipython_extension(ipython)`
38 function, which will be called if the user unloads or reloads the extension.
38 function, which will be called if the user unloads or reloads the extension.
39 The extension manager will only call :func:`load_ipython_extension` again
39 The extension manager will only call :func:`load_ipython_extension` again
40 if the extension is reloaded.
40 if the extension is reloaded.
41
41
42 You can put your extension modules anywhere you want, as long as
42 You can put your extension modules anywhere you want, as long as
43 they can be imported by Python's standard import mechanism. However,
43 they can be imported by Python's standard import mechanism. However,
44 to make it easy to write extensions, you can also put your extensions
44 to make it easy to write extensions, you can also put your extensions
45 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
45 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
46 is added to ``sys.path`` automatically.
46 is added to ``sys.path`` automatically.
47 """
47 """
48
48
49 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
49 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
50 allow_none=True)
50
51
51 def __init__(self, shell=None, **kwargs):
52 def __init__(self, shell=None, **kwargs):
52 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
53 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
53 self.shell.on_trait_change(
54 self.shell.on_trait_change(
54 self._on_ipython_dir_changed, 'ipython_dir'
55 self._on_ipython_dir_changed, 'ipython_dir'
55 )
56 )
56 self.loaded = set()
57 self.loaded = set()
57
58
58 def __del__(self):
59 def __del__(self):
59 self.shell.on_trait_change(
60 self.shell.on_trait_change(
60 self._on_ipython_dir_changed, 'ipython_dir', remove=True
61 self._on_ipython_dir_changed, 'ipython_dir', remove=True
61 )
62 )
62
63
63 @property
64 @property
64 def ipython_extension_dir(self):
65 def ipython_extension_dir(self):
65 return os.path.join(self.shell.ipython_dir, u'extensions')
66 return os.path.join(self.shell.ipython_dir, u'extensions')
66
67
67 def _on_ipython_dir_changed(self):
68 def _on_ipython_dir_changed(self):
68 ensure_dir_exists(self.ipython_extension_dir)
69 ensure_dir_exists(self.ipython_extension_dir)
69
70
70 def load_extension(self, module_str):
71 def load_extension(self, module_str):
71 """Load an IPython extension by its module name.
72 """Load an IPython extension by its module name.
72
73
73 Returns the string "already loaded" if the extension is already loaded,
74 Returns the string "already loaded" if the extension is already loaded,
74 "no load function" if the module doesn't have a load_ipython_extension
75 "no load function" if the module doesn't have a load_ipython_extension
75 function, or None if it succeeded.
76 function, or None if it succeeded.
76 """
77 """
77 if module_str in self.loaded:
78 if module_str in self.loaded:
78 return "already loaded"
79 return "already loaded"
79
80
80 from IPython.utils.syspathcontext import prepended_to_syspath
81 from IPython.utils.syspathcontext import prepended_to_syspath
81
82
82 with self.shell.builtin_trap:
83 with self.shell.builtin_trap:
83 if module_str not in sys.modules:
84 if module_str not in sys.modules:
84 with prepended_to_syspath(self.ipython_extension_dir):
85 with prepended_to_syspath(self.ipython_extension_dir):
85 __import__(module_str)
86 __import__(module_str)
86 mod = sys.modules[module_str]
87 mod = sys.modules[module_str]
87 if self._call_load_ipython_extension(mod):
88 if self._call_load_ipython_extension(mod):
88 self.loaded.add(module_str)
89 self.loaded.add(module_str)
89 else:
90 else:
90 return "no load function"
91 return "no load function"
91
92
92 def unload_extension(self, module_str):
93 def unload_extension(self, module_str):
93 """Unload an IPython extension by its module name.
94 """Unload an IPython extension by its module name.
94
95
95 This function looks up the extension's name in ``sys.modules`` and
96 This function looks up the extension's name in ``sys.modules`` and
96 simply calls ``mod.unload_ipython_extension(self)``.
97 simply calls ``mod.unload_ipython_extension(self)``.
97
98
98 Returns the string "no unload function" if the extension doesn't define
99 Returns the string "no unload function" if the extension doesn't define
99 a function to unload itself, "not loaded" if the extension isn't loaded,
100 a function to unload itself, "not loaded" if the extension isn't loaded,
100 otherwise None.
101 otherwise None.
101 """
102 """
102 if module_str not in self.loaded:
103 if module_str not in self.loaded:
103 return "not loaded"
104 return "not loaded"
104
105
105 if module_str in sys.modules:
106 if module_str in sys.modules:
106 mod = sys.modules[module_str]
107 mod = sys.modules[module_str]
107 if self._call_unload_ipython_extension(mod):
108 if self._call_unload_ipython_extension(mod):
108 self.loaded.discard(module_str)
109 self.loaded.discard(module_str)
109 else:
110 else:
110 return "no unload function"
111 return "no unload function"
111
112
112 def reload_extension(self, module_str):
113 def reload_extension(self, module_str):
113 """Reload an IPython extension by calling reload.
114 """Reload an IPython extension by calling reload.
114
115
115 If the module has not been loaded before,
116 If the module has not been loaded before,
116 :meth:`InteractiveShell.load_extension` is called. Otherwise
117 :meth:`InteractiveShell.load_extension` is called. Otherwise
117 :func:`reload` is called and then the :func:`load_ipython_extension`
118 :func:`reload` is called and then the :func:`load_ipython_extension`
118 function of the module, if it exists is called.
119 function of the module, if it exists is called.
119 """
120 """
120 from IPython.utils.syspathcontext import prepended_to_syspath
121 from IPython.utils.syspathcontext import prepended_to_syspath
121
122
122 if (module_str in self.loaded) and (module_str in sys.modules):
123 if (module_str in self.loaded) and (module_str in sys.modules):
123 self.unload_extension(module_str)
124 self.unload_extension(module_str)
124 mod = sys.modules[module_str]
125 mod = sys.modules[module_str]
125 with prepended_to_syspath(self.ipython_extension_dir):
126 with prepended_to_syspath(self.ipython_extension_dir):
126 reload(mod)
127 reload(mod)
127 if self._call_load_ipython_extension(mod):
128 if self._call_load_ipython_extension(mod):
128 self.loaded.add(module_str)
129 self.loaded.add(module_str)
129 else:
130 else:
130 self.load_extension(module_str)
131 self.load_extension(module_str)
131
132
132 def _call_load_ipython_extension(self, mod):
133 def _call_load_ipython_extension(self, mod):
133 if hasattr(mod, 'load_ipython_extension'):
134 if hasattr(mod, 'load_ipython_extension'):
134 mod.load_ipython_extension(self.shell)
135 mod.load_ipython_extension(self.shell)
135 return True
136 return True
136
137
137 def _call_unload_ipython_extension(self, mod):
138 def _call_unload_ipython_extension(self, mod):
138 if hasattr(mod, 'unload_ipython_extension'):
139 if hasattr(mod, 'unload_ipython_extension'):
139 mod.unload_ipython_extension(self.shell)
140 mod.unload_ipython_extension(self.shell)
140 return True
141 return True
141
142
142 def install_extension(self, url, filename=None):
143 def install_extension(self, url, filename=None):
143 """Download and install an IPython extension.
144 """Download and install an IPython extension.
144
145
145 If filename is given, the file will be so named (inside the extension
146 If filename is given, the file will be so named (inside the extension
146 directory). Otherwise, the name from the URL will be used. The file must
147 directory). Otherwise, the name from the URL will be used. The file must
147 have a .py or .zip extension; otherwise, a ValueError will be raised.
148 have a .py or .zip extension; otherwise, a ValueError will be raised.
148
149
149 Returns the full path to the installed file.
150 Returns the full path to the installed file.
150 """
151 """
151 # Ensure the extension directory exists
152 # Ensure the extension directory exists
152 ensure_dir_exists(self.ipython_extension_dir)
153 ensure_dir_exists(self.ipython_extension_dir)
153
154
154 if os.path.isfile(url):
155 if os.path.isfile(url):
155 src_filename = os.path.basename(url)
156 src_filename = os.path.basename(url)
156 copy = copyfile
157 copy = copyfile
157 else:
158 else:
158 # Deferred imports
159 # Deferred imports
159 try:
160 try:
160 from urllib.parse import urlparse # Py3
161 from urllib.parse import urlparse # Py3
161 from urllib.request import urlretrieve
162 from urllib.request import urlretrieve
162 except ImportError:
163 except ImportError:
163 from urlparse import urlparse
164 from urlparse import urlparse
164 from urllib import urlretrieve
165 from urllib import urlretrieve
165 src_filename = urlparse(url).path.split('/')[-1]
166 src_filename = urlparse(url).path.split('/')[-1]
166 copy = urlretrieve
167 copy = urlretrieve
167
168
168 if filename is None:
169 if filename is None:
169 filename = src_filename
170 filename = src_filename
170 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
171 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
171 raise ValueError("The file must have a .py or .zip extension", filename)
172 raise ValueError("The file must have a .py or .zip extension", filename)
172
173
173 filename = os.path.join(self.ipython_extension_dir, filename)
174 filename = os.path.join(self.ipython_extension_dir, filename)
174 copy(url, filename)
175 copy(url, filename)
175 return filename
176 return filename
@@ -1,870 +1,872 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010-2011 The IPython Development Team.
3 # Copyright (C) 2010-2011 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 try:
20 try:
21 import sqlite3
21 import sqlite3
22 except ImportError:
22 except ImportError:
23 try:
23 try:
24 from pysqlite2 import dbapi2 as sqlite3
24 from pysqlite2 import dbapi2 as sqlite3
25 except ImportError:
25 except ImportError:
26 sqlite3 = None
26 sqlite3 = None
27 import threading
27 import threading
28
28
29 # Our own packages
29 # Our own packages
30 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
31 from decorator import decorator
31 from decorator import decorator
32 from IPython.utils.decorators import undoc
32 from IPython.utils.decorators import undoc
33 from IPython.utils.path import locate_profile
33 from IPython.utils.path import locate_profile
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35 from IPython.utils.traitlets import (
35 from IPython.utils.traitlets import (
36 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
36 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
37 )
37 )
38 from IPython.utils.warn import warn
38 from IPython.utils.warn import warn
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Classes and functions
41 # Classes and functions
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 @undoc
44 @undoc
45 class DummyDB(object):
45 class DummyDB(object):
46 """Dummy DB that will act as a black hole for history.
46 """Dummy DB that will act as a black hole for history.
47
47
48 Only used in the absence of sqlite"""
48 Only used in the absence of sqlite"""
49 def execute(*args, **kwargs):
49 def execute(*args, **kwargs):
50 return []
50 return []
51
51
52 def commit(self, *args, **kwargs):
52 def commit(self, *args, **kwargs):
53 pass
53 pass
54
54
55 def __enter__(self, *args, **kwargs):
55 def __enter__(self, *args, **kwargs):
56 pass
56 pass
57
57
58 def __exit__(self, *args, **kwargs):
58 def __exit__(self, *args, **kwargs):
59 pass
59 pass
60
60
61
61
62 @decorator
62 @decorator
63 def needs_sqlite(f, self, *a, **kw):
63 def needs_sqlite(f, self, *a, **kw):
64 """Decorator: return an empty list in the absence of sqlite."""
64 """Decorator: return an empty list in the absence of sqlite."""
65 if sqlite3 is None or not self.enabled:
65 if sqlite3 is None or not self.enabled:
66 return []
66 return []
67 else:
67 else:
68 return f(self, *a, **kw)
68 return f(self, *a, **kw)
69
69
70
70
71 if sqlite3 is not None:
71 if sqlite3 is not None:
72 DatabaseError = sqlite3.DatabaseError
72 DatabaseError = sqlite3.DatabaseError
73 else:
73 else:
74 @undoc
74 @undoc
75 class DatabaseError(Exception):
75 class DatabaseError(Exception):
76 "Dummy exception when sqlite could not be imported. Should never occur."
76 "Dummy exception when sqlite could not be imported. Should never occur."
77
77
78 @decorator
78 @decorator
79 def catch_corrupt_db(f, self, *a, **kw):
79 def catch_corrupt_db(f, self, *a, **kw):
80 """A decorator which wraps HistoryAccessor method calls to catch errors from
80 """A decorator which wraps HistoryAccessor method calls to catch errors from
81 a corrupt SQLite database, move the old database out of the way, and create
81 a corrupt SQLite database, move the old database out of the way, and create
82 a new one.
82 a new one.
83 """
83 """
84 try:
84 try:
85 return f(self, *a, **kw)
85 return f(self, *a, **kw)
86 except DatabaseError:
86 except DatabaseError:
87 if os.path.isfile(self.hist_file):
87 if os.path.isfile(self.hist_file):
88 # Try to move the file out of the way
88 # Try to move the file out of the way
89 base,ext = os.path.splitext(self.hist_file)
89 base,ext = os.path.splitext(self.hist_file)
90 newpath = base + '-corrupt' + ext
90 newpath = base + '-corrupt' + ext
91 os.rename(self.hist_file, newpath)
91 os.rename(self.hist_file, newpath)
92 self.init_db()
92 self.init_db()
93 print("ERROR! History file wasn't a valid SQLite database.",
93 print("ERROR! History file wasn't a valid SQLite database.",
94 "It was moved to %s" % newpath, "and a new file created.")
94 "It was moved to %s" % newpath, "and a new file created.")
95 return []
95 return []
96
96
97 else:
97 else:
98 # The hist_file is probably :memory: or something else.
98 # The hist_file is probably :memory: or something else.
99 raise
99 raise
100
100
101 class HistoryAccessorBase(Configurable):
101 class HistoryAccessorBase(Configurable):
102 """An abstract class for History Accessors """
102 """An abstract class for History Accessors """
103
103
104 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
104 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
105 raise NotImplementedError
105 raise NotImplementedError
106
106
107 def search(self, pattern="*", raw=True, search_raw=True,
107 def search(self, pattern="*", raw=True, search_raw=True,
108 output=False, n=None, unique=False):
108 output=False, n=None, unique=False):
109 raise NotImplementedError
109 raise NotImplementedError
110
110
111 def get_range(self, session, start=1, stop=None, raw=True,output=False):
111 def get_range(self, session, start=1, stop=None, raw=True,output=False):
112 raise NotImplementedError
112 raise NotImplementedError
113
113
114 def get_range_by_str(self, rangestr, raw=True, output=False):
114 def get_range_by_str(self, rangestr, raw=True, output=False):
115 raise NotImplementedError
115 raise NotImplementedError
116
116
117
117
118 class HistoryAccessor(HistoryAccessorBase):
118 class HistoryAccessor(HistoryAccessorBase):
119 """Access the history database without adding to it.
119 """Access the history database without adding to it.
120
120
121 This is intended for use by standalone history tools. IPython shells use
121 This is intended for use by standalone history tools. IPython shells use
122 HistoryManager, below, which is a subclass of this."""
122 HistoryManager, below, which is a subclass of this."""
123
123
124 # String holding the path to the history file
124 # String holding the path to the history file
125 hist_file = Unicode(config=True,
125 hist_file = Unicode(config=True,
126 help="""Path to file to use for SQLite history database.
126 help="""Path to file to use for SQLite history database.
127
127
128 By default, IPython will put the history database in the IPython
128 By default, IPython will put the history database in the IPython
129 profile directory. If you would rather share one history among
129 profile directory. If you would rather share one history among
130 profiles, you can set this value in each, so that they are consistent.
130 profiles, you can set this value in each, so that they are consistent.
131
131
132 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
132 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
133 mounts. If you see IPython hanging, try setting this to something on a
133 mounts. If you see IPython hanging, try setting this to something on a
134 local disk, e.g::
134 local disk, e.g::
135
135
136 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
136 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
137
137
138 """)
138 """)
139
139
140 enabled = Bool(True, config=True,
140 enabled = Bool(True, config=True,
141 help="""enable the SQLite history
141 help="""enable the SQLite history
142
142
143 set enabled=False to disable the SQLite history,
143 set enabled=False to disable the SQLite history,
144 in which case there will be no stored history, no SQLite connection,
144 in which case there will be no stored history, no SQLite connection,
145 and no background saving thread. This may be necessary in some
145 and no background saving thread. This may be necessary in some
146 threaded environments where IPython is embedded.
146 threaded environments where IPython is embedded.
147 """
147 """
148 )
148 )
149
149
150 connection_options = Dict(config=True,
150 connection_options = Dict(config=True,
151 help="""Options for configuring the SQLite connection
151 help="""Options for configuring the SQLite connection
152
152
153 These options are passed as keyword args to sqlite3.connect
153 These options are passed as keyword args to sqlite3.connect
154 when establishing database conenctions.
154 when establishing database conenctions.
155 """
155 """
156 )
156 )
157
157
158 # The SQLite database
158 # The SQLite database
159 db = Any()
159 db = Any()
160 def _db_changed(self, name, old, new):
160 def _db_changed(self, name, old, new):
161 """validate the db, since it can be an Instance of two different types"""
161 """validate the db, since it can be an Instance of two different types"""
162 connection_types = (DummyDB,)
162 connection_types = (DummyDB,)
163 if sqlite3 is not None:
163 if sqlite3 is not None:
164 connection_types = (DummyDB, sqlite3.Connection)
164 connection_types = (DummyDB, sqlite3.Connection)
165 if not isinstance(new, connection_types):
165 if not isinstance(new, connection_types):
166 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
166 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
167 (self.__class__.__name__, new)
167 (self.__class__.__name__, new)
168 raise TraitError(msg)
168 raise TraitError(msg)
169
169
170 def __init__(self, profile='default', hist_file=u'', **traits):
170 def __init__(self, profile='default', hist_file=u'', **traits):
171 """Create a new history accessor.
171 """Create a new history accessor.
172
172
173 Parameters
173 Parameters
174 ----------
174 ----------
175 profile : str
175 profile : str
176 The name of the profile from which to open history.
176 The name of the profile from which to open history.
177 hist_file : str
177 hist_file : str
178 Path to an SQLite history database stored by IPython. If specified,
178 Path to an SQLite history database stored by IPython. If specified,
179 hist_file overrides profile.
179 hist_file overrides profile.
180 config : :class:`~IPython.config.loader.Config`
180 config : :class:`~IPython.config.loader.Config`
181 Config object. hist_file can also be set through this.
181 Config object. hist_file can also be set through this.
182 """
182 """
183 # We need a pointer back to the shell for various tasks.
183 # We need a pointer back to the shell for various tasks.
184 super(HistoryAccessor, self).__init__(**traits)
184 super(HistoryAccessor, self).__init__(**traits)
185 # defer setting hist_file from kwarg until after init,
185 # defer setting hist_file from kwarg until after init,
186 # otherwise the default kwarg value would clobber any value
186 # otherwise the default kwarg value would clobber any value
187 # set by config
187 # set by config
188 if hist_file:
188 if hist_file:
189 self.hist_file = hist_file
189 self.hist_file = hist_file
190
190
191 if self.hist_file == u'':
191 if self.hist_file == u'':
192 # No one has set the hist_file, yet.
192 # No one has set the hist_file, yet.
193 self.hist_file = self._get_hist_file_name(profile)
193 self.hist_file = self._get_hist_file_name(profile)
194
194
195 if sqlite3 is None and self.enabled:
195 if sqlite3 is None and self.enabled:
196 warn("IPython History requires SQLite, your history will not be saved")
196 warn("IPython History requires SQLite, your history will not be saved")
197 self.enabled = False
197 self.enabled = False
198
198
199 self.init_db()
199 self.init_db()
200
200
201 def _get_hist_file_name(self, profile='default'):
201 def _get_hist_file_name(self, profile='default'):
202 """Find the history file for the given profile name.
202 """Find the history file for the given profile name.
203
203
204 This is overridden by the HistoryManager subclass, to use the shell's
204 This is overridden by the HistoryManager subclass, to use the shell's
205 active profile.
205 active profile.
206
206
207 Parameters
207 Parameters
208 ----------
208 ----------
209 profile : str
209 profile : str
210 The name of a profile which has a history file.
210 The name of a profile which has a history file.
211 """
211 """
212 return os.path.join(locate_profile(profile), 'history.sqlite')
212 return os.path.join(locate_profile(profile), 'history.sqlite')
213
213
214 @catch_corrupt_db
214 @catch_corrupt_db
215 def init_db(self):
215 def init_db(self):
216 """Connect to the database, and create tables if necessary."""
216 """Connect to the database, and create tables if necessary."""
217 if not self.enabled:
217 if not self.enabled:
218 self.db = DummyDB()
218 self.db = DummyDB()
219 return
219 return
220
220
221 # use detect_types so that timestamps return datetime objects
221 # use detect_types so that timestamps return datetime objects
222 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
222 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
223 kwargs.update(self.connection_options)
223 kwargs.update(self.connection_options)
224 self.db = sqlite3.connect(self.hist_file, **kwargs)
224 self.db = sqlite3.connect(self.hist_file, **kwargs)
225 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
225 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
226 primary key autoincrement, start timestamp,
226 primary key autoincrement, start timestamp,
227 end timestamp, num_cmds integer, remark text)""")
227 end timestamp, num_cmds integer, remark text)""")
228 self.db.execute("""CREATE TABLE IF NOT EXISTS history
228 self.db.execute("""CREATE TABLE IF NOT EXISTS history
229 (session integer, line integer, source text, source_raw text,
229 (session integer, line integer, source text, source_raw text,
230 PRIMARY KEY (session, line))""")
230 PRIMARY KEY (session, line))""")
231 # Output history is optional, but ensure the table's there so it can be
231 # Output history is optional, but ensure the table's there so it can be
232 # enabled later.
232 # enabled later.
233 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
233 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
234 (session integer, line integer, output text,
234 (session integer, line integer, output text,
235 PRIMARY KEY (session, line))""")
235 PRIMARY KEY (session, line))""")
236 self.db.commit()
236 self.db.commit()
237
237
238 def writeout_cache(self):
238 def writeout_cache(self):
239 """Overridden by HistoryManager to dump the cache before certain
239 """Overridden by HistoryManager to dump the cache before certain
240 database lookups."""
240 database lookups."""
241 pass
241 pass
242
242
243 ## -------------------------------
243 ## -------------------------------
244 ## Methods for retrieving history:
244 ## Methods for retrieving history:
245 ## -------------------------------
245 ## -------------------------------
246 def _run_sql(self, sql, params, raw=True, output=False):
246 def _run_sql(self, sql, params, raw=True, output=False):
247 """Prepares and runs an SQL query for the history database.
247 """Prepares and runs an SQL query for the history database.
248
248
249 Parameters
249 Parameters
250 ----------
250 ----------
251 sql : str
251 sql : str
252 Any filtering expressions to go after SELECT ... FROM ...
252 Any filtering expressions to go after SELECT ... FROM ...
253 params : tuple
253 params : tuple
254 Parameters passed to the SQL query (to replace "?")
254 Parameters passed to the SQL query (to replace "?")
255 raw, output : bool
255 raw, output : bool
256 See :meth:`get_range`
256 See :meth:`get_range`
257
257
258 Returns
258 Returns
259 -------
259 -------
260 Tuples as :meth:`get_range`
260 Tuples as :meth:`get_range`
261 """
261 """
262 toget = 'source_raw' if raw else 'source'
262 toget = 'source_raw' if raw else 'source'
263 sqlfrom = "history"
263 sqlfrom = "history"
264 if output:
264 if output:
265 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
265 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
266 toget = "history.%s, output_history.output" % toget
266 toget = "history.%s, output_history.output" % toget
267 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
267 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
268 (toget, sqlfrom) + sql, params)
268 (toget, sqlfrom) + sql, params)
269 if output: # Regroup into 3-tuples, and parse JSON
269 if output: # Regroup into 3-tuples, and parse JSON
270 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
270 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
271 return cur
271 return cur
272
272
273 @needs_sqlite
273 @needs_sqlite
274 @catch_corrupt_db
274 @catch_corrupt_db
275 def get_session_info(self, session):
275 def get_session_info(self, session):
276 """Get info about a session.
276 """Get info about a session.
277
277
278 Parameters
278 Parameters
279 ----------
279 ----------
280
280
281 session : int
281 session : int
282 Session number to retrieve.
282 Session number to retrieve.
283
283
284 Returns
284 Returns
285 -------
285 -------
286
286
287 session_id : int
287 session_id : int
288 Session ID number
288 Session ID number
289 start : datetime
289 start : datetime
290 Timestamp for the start of the session.
290 Timestamp for the start of the session.
291 end : datetime
291 end : datetime
292 Timestamp for the end of the session, or None if IPython crashed.
292 Timestamp for the end of the session, or None if IPython crashed.
293 num_cmds : int
293 num_cmds : int
294 Number of commands run, or None if IPython crashed.
294 Number of commands run, or None if IPython crashed.
295 remark : unicode
295 remark : unicode
296 A manually set description.
296 A manually set description.
297 """
297 """
298 query = "SELECT * from sessions where session == ?"
298 query = "SELECT * from sessions where session == ?"
299 return self.db.execute(query, (session,)).fetchone()
299 return self.db.execute(query, (session,)).fetchone()
300
300
301 @catch_corrupt_db
301 @catch_corrupt_db
302 def get_last_session_id(self):
302 def get_last_session_id(self):
303 """Get the last session ID currently in the database.
303 """Get the last session ID currently in the database.
304
304
305 Within IPython, this should be the same as the value stored in
305 Within IPython, this should be the same as the value stored in
306 :attr:`HistoryManager.session_number`.
306 :attr:`HistoryManager.session_number`.
307 """
307 """
308 for record in self.get_tail(n=1, include_latest=True):
308 for record in self.get_tail(n=1, include_latest=True):
309 return record[0]
309 return record[0]
310
310
311 @catch_corrupt_db
311 @catch_corrupt_db
312 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
312 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
313 """Get the last n lines from the history database.
313 """Get the last n lines from the history database.
314
314
315 Parameters
315 Parameters
316 ----------
316 ----------
317 n : int
317 n : int
318 The number of lines to get
318 The number of lines to get
319 raw, output : bool
319 raw, output : bool
320 See :meth:`get_range`
320 See :meth:`get_range`
321 include_latest : bool
321 include_latest : bool
322 If False (default), n+1 lines are fetched, and the latest one
322 If False (default), n+1 lines are fetched, and the latest one
323 is discarded. This is intended to be used where the function
323 is discarded. This is intended to be used where the function
324 is called by a user command, which it should not return.
324 is called by a user command, which it should not return.
325
325
326 Returns
326 Returns
327 -------
327 -------
328 Tuples as :meth:`get_range`
328 Tuples as :meth:`get_range`
329 """
329 """
330 self.writeout_cache()
330 self.writeout_cache()
331 if not include_latest:
331 if not include_latest:
332 n += 1
332 n += 1
333 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
333 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
334 (n,), raw=raw, output=output)
334 (n,), raw=raw, output=output)
335 if not include_latest:
335 if not include_latest:
336 return reversed(list(cur)[1:])
336 return reversed(list(cur)[1:])
337 return reversed(list(cur))
337 return reversed(list(cur))
338
338
339 @catch_corrupt_db
339 @catch_corrupt_db
340 def search(self, pattern="*", raw=True, search_raw=True,
340 def search(self, pattern="*", raw=True, search_raw=True,
341 output=False, n=None, unique=False):
341 output=False, n=None, unique=False):
342 """Search the database using unix glob-style matching (wildcards
342 """Search the database using unix glob-style matching (wildcards
343 * and ?).
343 * and ?).
344
344
345 Parameters
345 Parameters
346 ----------
346 ----------
347 pattern : str
347 pattern : str
348 The wildcarded pattern to match when searching
348 The wildcarded pattern to match when searching
349 search_raw : bool
349 search_raw : bool
350 If True, search the raw input, otherwise, the parsed input
350 If True, search the raw input, otherwise, the parsed input
351 raw, output : bool
351 raw, output : bool
352 See :meth:`get_range`
352 See :meth:`get_range`
353 n : None or int
353 n : None or int
354 If an integer is given, it defines the limit of
354 If an integer is given, it defines the limit of
355 returned entries.
355 returned entries.
356 unique : bool
356 unique : bool
357 When it is true, return only unique entries.
357 When it is true, return only unique entries.
358
358
359 Returns
359 Returns
360 -------
360 -------
361 Tuples as :meth:`get_range`
361 Tuples as :meth:`get_range`
362 """
362 """
363 tosearch = "source_raw" if search_raw else "source"
363 tosearch = "source_raw" if search_raw else "source"
364 if output:
364 if output:
365 tosearch = "history." + tosearch
365 tosearch = "history." + tosearch
366 self.writeout_cache()
366 self.writeout_cache()
367 sqlform = "WHERE %s GLOB ?" % tosearch
367 sqlform = "WHERE %s GLOB ?" % tosearch
368 params = (pattern,)
368 params = (pattern,)
369 if unique:
369 if unique:
370 sqlform += ' GROUP BY {0}'.format(tosearch)
370 sqlform += ' GROUP BY {0}'.format(tosearch)
371 if n is not None:
371 if n is not None:
372 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
372 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
373 params += (n,)
373 params += (n,)
374 elif unique:
374 elif unique:
375 sqlform += " ORDER BY session, line"
375 sqlform += " ORDER BY session, line"
376 cur = self._run_sql(sqlform, params, raw=raw, output=output)
376 cur = self._run_sql(sqlform, params, raw=raw, output=output)
377 if n is not None:
377 if n is not None:
378 return reversed(list(cur))
378 return reversed(list(cur))
379 return cur
379 return cur
380
380
381 @catch_corrupt_db
381 @catch_corrupt_db
382 def get_range(self, session, start=1, stop=None, raw=True,output=False):
382 def get_range(self, session, start=1, stop=None, raw=True,output=False):
383 """Retrieve input by session.
383 """Retrieve input by session.
384
384
385 Parameters
385 Parameters
386 ----------
386 ----------
387 session : int
387 session : int
388 Session number to retrieve.
388 Session number to retrieve.
389 start : int
389 start : int
390 First line to retrieve.
390 First line to retrieve.
391 stop : int
391 stop : int
392 End of line range (excluded from output itself). If None, retrieve
392 End of line range (excluded from output itself). If None, retrieve
393 to the end of the session.
393 to the end of the session.
394 raw : bool
394 raw : bool
395 If True, return untranslated input
395 If True, return untranslated input
396 output : bool
396 output : bool
397 If True, attempt to include output. This will be 'real' Python
397 If True, attempt to include output. This will be 'real' Python
398 objects for the current session, or text reprs from previous
398 objects for the current session, or text reprs from previous
399 sessions if db_log_output was enabled at the time. Where no output
399 sessions if db_log_output was enabled at the time. Where no output
400 is found, None is used.
400 is found, None is used.
401
401
402 Returns
402 Returns
403 -------
403 -------
404 entries
404 entries
405 An iterator over the desired lines. Each line is a 3-tuple, either
405 An iterator over the desired lines. Each line is a 3-tuple, either
406 (session, line, input) if output is False, or
406 (session, line, input) if output is False, or
407 (session, line, (input, output)) if output is True.
407 (session, line, (input, output)) if output is True.
408 """
408 """
409 if stop:
409 if stop:
410 lineclause = "line >= ? AND line < ?"
410 lineclause = "line >= ? AND line < ?"
411 params = (session, start, stop)
411 params = (session, start, stop)
412 else:
412 else:
413 lineclause = "line>=?"
413 lineclause = "line>=?"
414 params = (session, start)
414 params = (session, start)
415
415
416 return self._run_sql("WHERE session==? AND %s" % lineclause,
416 return self._run_sql("WHERE session==? AND %s" % lineclause,
417 params, raw=raw, output=output)
417 params, raw=raw, output=output)
418
418
419 def get_range_by_str(self, rangestr, raw=True, output=False):
419 def get_range_by_str(self, rangestr, raw=True, output=False):
420 """Get lines of history from a string of ranges, as used by magic
420 """Get lines of history from a string of ranges, as used by magic
421 commands %hist, %save, %macro, etc.
421 commands %hist, %save, %macro, etc.
422
422
423 Parameters
423 Parameters
424 ----------
424 ----------
425 rangestr : str
425 rangestr : str
426 A string specifying ranges, e.g. "5 ~2/1-4". See
426 A string specifying ranges, e.g. "5 ~2/1-4". See
427 :func:`magic_history` for full details.
427 :func:`magic_history` for full details.
428 raw, output : bool
428 raw, output : bool
429 As :meth:`get_range`
429 As :meth:`get_range`
430
430
431 Returns
431 Returns
432 -------
432 -------
433 Tuples as :meth:`get_range`
433 Tuples as :meth:`get_range`
434 """
434 """
435 for sess, s, e in extract_hist_ranges(rangestr):
435 for sess, s, e in extract_hist_ranges(rangestr):
436 for line in self.get_range(sess, s, e, raw=raw, output=output):
436 for line in self.get_range(sess, s, e, raw=raw, output=output):
437 yield line
437 yield line
438
438
439
439
440 class HistoryManager(HistoryAccessor):
440 class HistoryManager(HistoryAccessor):
441 """A class to organize all history-related functionality in one place.
441 """A class to organize all history-related functionality in one place.
442 """
442 """
443 # Public interface
443 # Public interface
444
444
445 # An instance of the IPython shell we are attached to
445 # An instance of the IPython shell we are attached to
446 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
446 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
447 allow_none=True)
447 # Lists to hold processed and raw history. These start with a blank entry
448 # Lists to hold processed and raw history. These start with a blank entry
448 # so that we can index them starting from 1
449 # so that we can index them starting from 1
449 input_hist_parsed = List([""])
450 input_hist_parsed = List([""])
450 input_hist_raw = List([""])
451 input_hist_raw = List([""])
451 # A list of directories visited during session
452 # A list of directories visited during session
452 dir_hist = List()
453 dir_hist = List()
453 def _dir_hist_default(self):
454 def _dir_hist_default(self):
454 try:
455 try:
455 return [py3compat.getcwd()]
456 return [py3compat.getcwd()]
456 except OSError:
457 except OSError:
457 return []
458 return []
458
459
459 # A dict of output history, keyed with ints from the shell's
460 # A dict of output history, keyed with ints from the shell's
460 # execution count.
461 # execution count.
461 output_hist = Dict()
462 output_hist = Dict()
462 # The text/plain repr of outputs.
463 # The text/plain repr of outputs.
463 output_hist_reprs = Dict()
464 output_hist_reprs = Dict()
464
465
465 # The number of the current session in the history database
466 # The number of the current session in the history database
466 session_number = Integer()
467 session_number = Integer()
467
468
468 db_log_output = Bool(False, config=True,
469 db_log_output = Bool(False, config=True,
469 help="Should the history database include output? (default: no)"
470 help="Should the history database include output? (default: no)"
470 )
471 )
471 db_cache_size = Integer(0, config=True,
472 db_cache_size = Integer(0, config=True,
472 help="Write to database every x commands (higher values save disk access & power).\n"
473 help="Write to database every x commands (higher values save disk access & power).\n"
473 "Values of 1 or less effectively disable caching."
474 "Values of 1 or less effectively disable caching."
474 )
475 )
475 # The input and output caches
476 # The input and output caches
476 db_input_cache = List()
477 db_input_cache = List()
477 db_output_cache = List()
478 db_output_cache = List()
478
479
479 # History saving in separate thread
480 # History saving in separate thread
480 save_thread = Instance('IPython.core.history.HistorySavingThread')
481 save_thread = Instance('IPython.core.history.HistorySavingThread',
482 allow_none=True)
481 try: # Event is a function returning an instance of _Event...
483 try: # Event is a function returning an instance of _Event...
482 save_flag = Instance(threading._Event)
484 save_flag = Instance(threading._Event, allow_none=True)
483 except AttributeError: # ...until Python 3.3, when it's a class.
485 except AttributeError: # ...until Python 3.3, when it's a class.
484 save_flag = Instance(threading.Event)
486 save_flag = Instance(threading.Event, allow_none=True)
485
487
486 # Private interface
488 # Private interface
487 # Variables used to store the three last inputs from the user. On each new
489 # Variables used to store the three last inputs from the user. On each new
488 # history update, we populate the user's namespace with these, shifted as
490 # history update, we populate the user's namespace with these, shifted as
489 # necessary.
491 # necessary.
490 _i00 = Unicode(u'')
492 _i00 = Unicode(u'')
491 _i = Unicode(u'')
493 _i = Unicode(u'')
492 _ii = Unicode(u'')
494 _ii = Unicode(u'')
493 _iii = Unicode(u'')
495 _iii = Unicode(u'')
494
496
495 # A regex matching all forms of the exit command, so that we don't store
497 # A regex matching all forms of the exit command, so that we don't store
496 # them in the history (it's annoying to rewind the first entry and land on
498 # them in the history (it's annoying to rewind the first entry and land on
497 # an exit call).
499 # an exit call).
498 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
500 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
499
501
500 def __init__(self, shell=None, config=None, **traits):
502 def __init__(self, shell=None, config=None, **traits):
501 """Create a new history manager associated with a shell instance.
503 """Create a new history manager associated with a shell instance.
502 """
504 """
503 # We need a pointer back to the shell for various tasks.
505 # We need a pointer back to the shell for various tasks.
504 super(HistoryManager, self).__init__(shell=shell, config=config,
506 super(HistoryManager, self).__init__(shell=shell, config=config,
505 **traits)
507 **traits)
506 self.save_flag = threading.Event()
508 self.save_flag = threading.Event()
507 self.db_input_cache_lock = threading.Lock()
509 self.db_input_cache_lock = threading.Lock()
508 self.db_output_cache_lock = threading.Lock()
510 self.db_output_cache_lock = threading.Lock()
509 if self.enabled and self.hist_file != ':memory:':
511 if self.enabled and self.hist_file != ':memory:':
510 self.save_thread = HistorySavingThread(self)
512 self.save_thread = HistorySavingThread(self)
511 self.save_thread.start()
513 self.save_thread.start()
512
514
513 self.new_session()
515 self.new_session()
514
516
515 def _get_hist_file_name(self, profile=None):
517 def _get_hist_file_name(self, profile=None):
516 """Get default history file name based on the Shell's profile.
518 """Get default history file name based on the Shell's profile.
517
519
518 The profile parameter is ignored, but must exist for compatibility with
520 The profile parameter is ignored, but must exist for compatibility with
519 the parent class."""
521 the parent class."""
520 profile_dir = self.shell.profile_dir.location
522 profile_dir = self.shell.profile_dir.location
521 return os.path.join(profile_dir, 'history.sqlite')
523 return os.path.join(profile_dir, 'history.sqlite')
522
524
523 @needs_sqlite
525 @needs_sqlite
524 def new_session(self, conn=None):
526 def new_session(self, conn=None):
525 """Get a new session number."""
527 """Get a new session number."""
526 if conn is None:
528 if conn is None:
527 conn = self.db
529 conn = self.db
528
530
529 with conn:
531 with conn:
530 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
532 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
531 NULL, "") """, (datetime.datetime.now(),))
533 NULL, "") """, (datetime.datetime.now(),))
532 self.session_number = cur.lastrowid
534 self.session_number = cur.lastrowid
533
535
534 def end_session(self):
536 def end_session(self):
535 """Close the database session, filling in the end time and line count."""
537 """Close the database session, filling in the end time and line count."""
536 self.writeout_cache()
538 self.writeout_cache()
537 with self.db:
539 with self.db:
538 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
540 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
539 session==?""", (datetime.datetime.now(),
541 session==?""", (datetime.datetime.now(),
540 len(self.input_hist_parsed)-1, self.session_number))
542 len(self.input_hist_parsed)-1, self.session_number))
541 self.session_number = 0
543 self.session_number = 0
542
544
543 def name_session(self, name):
545 def name_session(self, name):
544 """Give the current session a name in the history database."""
546 """Give the current session a name in the history database."""
545 with self.db:
547 with self.db:
546 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
548 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
547 (name, self.session_number))
549 (name, self.session_number))
548
550
549 def reset(self, new_session=True):
551 def reset(self, new_session=True):
550 """Clear the session history, releasing all object references, and
552 """Clear the session history, releasing all object references, and
551 optionally open a new session."""
553 optionally open a new session."""
552 self.output_hist.clear()
554 self.output_hist.clear()
553 # The directory history can't be completely empty
555 # The directory history can't be completely empty
554 self.dir_hist[:] = [py3compat.getcwd()]
556 self.dir_hist[:] = [py3compat.getcwd()]
555
557
556 if new_session:
558 if new_session:
557 if self.session_number:
559 if self.session_number:
558 self.end_session()
560 self.end_session()
559 self.input_hist_parsed[:] = [""]
561 self.input_hist_parsed[:] = [""]
560 self.input_hist_raw[:] = [""]
562 self.input_hist_raw[:] = [""]
561 self.new_session()
563 self.new_session()
562
564
563 # ------------------------------
565 # ------------------------------
564 # Methods for retrieving history
566 # Methods for retrieving history
565 # ------------------------------
567 # ------------------------------
566 def get_session_info(self, session=0):
568 def get_session_info(self, session=0):
567 """Get info about a session.
569 """Get info about a session.
568
570
569 Parameters
571 Parameters
570 ----------
572 ----------
571
573
572 session : int
574 session : int
573 Session number to retrieve. The current session is 0, and negative
575 Session number to retrieve. The current session is 0, and negative
574 numbers count back from current session, so -1 is the previous session.
576 numbers count back from current session, so -1 is the previous session.
575
577
576 Returns
578 Returns
577 -------
579 -------
578
580
579 session_id : int
581 session_id : int
580 Session ID number
582 Session ID number
581 start : datetime
583 start : datetime
582 Timestamp for the start of the session.
584 Timestamp for the start of the session.
583 end : datetime
585 end : datetime
584 Timestamp for the end of the session, or None if IPython crashed.
586 Timestamp for the end of the session, or None if IPython crashed.
585 num_cmds : int
587 num_cmds : int
586 Number of commands run, or None if IPython crashed.
588 Number of commands run, or None if IPython crashed.
587 remark : unicode
589 remark : unicode
588 A manually set description.
590 A manually set description.
589 """
591 """
590 if session <= 0:
592 if session <= 0:
591 session += self.session_number
593 session += self.session_number
592
594
593 return super(HistoryManager, self).get_session_info(session=session)
595 return super(HistoryManager, self).get_session_info(session=session)
594
596
595 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
597 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
596 """Get input and output history from the current session. Called by
598 """Get input and output history from the current session. Called by
597 get_range, and takes similar parameters."""
599 get_range, and takes similar parameters."""
598 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
600 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
599
601
600 n = len(input_hist)
602 n = len(input_hist)
601 if start < 0:
603 if start < 0:
602 start += n
604 start += n
603 if not stop or (stop > n):
605 if not stop or (stop > n):
604 stop = n
606 stop = n
605 elif stop < 0:
607 elif stop < 0:
606 stop += n
608 stop += n
607
609
608 for i in range(start, stop):
610 for i in range(start, stop):
609 if output:
611 if output:
610 line = (input_hist[i], self.output_hist_reprs.get(i))
612 line = (input_hist[i], self.output_hist_reprs.get(i))
611 else:
613 else:
612 line = input_hist[i]
614 line = input_hist[i]
613 yield (0, i, line)
615 yield (0, i, line)
614
616
615 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
617 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
616 """Retrieve input by session.
618 """Retrieve input by session.
617
619
618 Parameters
620 Parameters
619 ----------
621 ----------
620 session : int
622 session : int
621 Session number to retrieve. The current session is 0, and negative
623 Session number to retrieve. The current session is 0, and negative
622 numbers count back from current session, so -1 is previous session.
624 numbers count back from current session, so -1 is previous session.
623 start : int
625 start : int
624 First line to retrieve.
626 First line to retrieve.
625 stop : int
627 stop : int
626 End of line range (excluded from output itself). If None, retrieve
628 End of line range (excluded from output itself). If None, retrieve
627 to the end of the session.
629 to the end of the session.
628 raw : bool
630 raw : bool
629 If True, return untranslated input
631 If True, return untranslated input
630 output : bool
632 output : bool
631 If True, attempt to include output. This will be 'real' Python
633 If True, attempt to include output. This will be 'real' Python
632 objects for the current session, or text reprs from previous
634 objects for the current session, or text reprs from previous
633 sessions if db_log_output was enabled at the time. Where no output
635 sessions if db_log_output was enabled at the time. Where no output
634 is found, None is used.
636 is found, None is used.
635
637
636 Returns
638 Returns
637 -------
639 -------
638 entries
640 entries
639 An iterator over the desired lines. Each line is a 3-tuple, either
641 An iterator over the desired lines. Each line is a 3-tuple, either
640 (session, line, input) if output is False, or
642 (session, line, input) if output is False, or
641 (session, line, (input, output)) if output is True.
643 (session, line, (input, output)) if output is True.
642 """
644 """
643 if session <= 0:
645 if session <= 0:
644 session += self.session_number
646 session += self.session_number
645 if session==self.session_number: # Current session
647 if session==self.session_number: # Current session
646 return self._get_range_session(start, stop, raw, output)
648 return self._get_range_session(start, stop, raw, output)
647 return super(HistoryManager, self).get_range(session, start, stop, raw,
649 return super(HistoryManager, self).get_range(session, start, stop, raw,
648 output)
650 output)
649
651
650 ## ----------------------------
652 ## ----------------------------
651 ## Methods for storing history:
653 ## Methods for storing history:
652 ## ----------------------------
654 ## ----------------------------
653 def store_inputs(self, line_num, source, source_raw=None):
655 def store_inputs(self, line_num, source, source_raw=None):
654 """Store source and raw input in history and create input cache
656 """Store source and raw input in history and create input cache
655 variables ``_i*``.
657 variables ``_i*``.
656
658
657 Parameters
659 Parameters
658 ----------
660 ----------
659 line_num : int
661 line_num : int
660 The prompt number of this input.
662 The prompt number of this input.
661
663
662 source : str
664 source : str
663 Python input.
665 Python input.
664
666
665 source_raw : str, optional
667 source_raw : str, optional
666 If given, this is the raw input without any IPython transformations
668 If given, this is the raw input without any IPython transformations
667 applied to it. If not given, ``source`` is used.
669 applied to it. If not given, ``source`` is used.
668 """
670 """
669 if source_raw is None:
671 if source_raw is None:
670 source_raw = source
672 source_raw = source
671 source = source.rstrip('\n')
673 source = source.rstrip('\n')
672 source_raw = source_raw.rstrip('\n')
674 source_raw = source_raw.rstrip('\n')
673
675
674 # do not store exit/quit commands
676 # do not store exit/quit commands
675 if self._exit_re.match(source_raw.strip()):
677 if self._exit_re.match(source_raw.strip()):
676 return
678 return
677
679
678 self.input_hist_parsed.append(source)
680 self.input_hist_parsed.append(source)
679 self.input_hist_raw.append(source_raw)
681 self.input_hist_raw.append(source_raw)
680
682
681 with self.db_input_cache_lock:
683 with self.db_input_cache_lock:
682 self.db_input_cache.append((line_num, source, source_raw))
684 self.db_input_cache.append((line_num, source, source_raw))
683 # Trigger to flush cache and write to DB.
685 # Trigger to flush cache and write to DB.
684 if len(self.db_input_cache) >= self.db_cache_size:
686 if len(self.db_input_cache) >= self.db_cache_size:
685 self.save_flag.set()
687 self.save_flag.set()
686
688
687 # update the auto _i variables
689 # update the auto _i variables
688 self._iii = self._ii
690 self._iii = self._ii
689 self._ii = self._i
691 self._ii = self._i
690 self._i = self._i00
692 self._i = self._i00
691 self._i00 = source_raw
693 self._i00 = source_raw
692
694
693 # hackish access to user namespace to create _i1,_i2... dynamically
695 # hackish access to user namespace to create _i1,_i2... dynamically
694 new_i = '_i%s' % line_num
696 new_i = '_i%s' % line_num
695 to_main = {'_i': self._i,
697 to_main = {'_i': self._i,
696 '_ii': self._ii,
698 '_ii': self._ii,
697 '_iii': self._iii,
699 '_iii': self._iii,
698 new_i : self._i00 }
700 new_i : self._i00 }
699
701
700 if self.shell is not None:
702 if self.shell is not None:
701 self.shell.push(to_main, interactive=False)
703 self.shell.push(to_main, interactive=False)
702
704
703 def store_output(self, line_num):
705 def store_output(self, line_num):
704 """If database output logging is enabled, this saves all the
706 """If database output logging is enabled, this saves all the
705 outputs from the indicated prompt number to the database. It's
707 outputs from the indicated prompt number to the database. It's
706 called by run_cell after code has been executed.
708 called by run_cell after code has been executed.
707
709
708 Parameters
710 Parameters
709 ----------
711 ----------
710 line_num : int
712 line_num : int
711 The line number from which to save outputs
713 The line number from which to save outputs
712 """
714 """
713 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
715 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
714 return
716 return
715 output = self.output_hist_reprs[line_num]
717 output = self.output_hist_reprs[line_num]
716
718
717 with self.db_output_cache_lock:
719 with self.db_output_cache_lock:
718 self.db_output_cache.append((line_num, output))
720 self.db_output_cache.append((line_num, output))
719 if self.db_cache_size <= 1:
721 if self.db_cache_size <= 1:
720 self.save_flag.set()
722 self.save_flag.set()
721
723
722 def _writeout_input_cache(self, conn):
724 def _writeout_input_cache(self, conn):
723 with conn:
725 with conn:
724 for line in self.db_input_cache:
726 for line in self.db_input_cache:
725 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
727 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
726 (self.session_number,)+line)
728 (self.session_number,)+line)
727
729
728 def _writeout_output_cache(self, conn):
730 def _writeout_output_cache(self, conn):
729 with conn:
731 with conn:
730 for line in self.db_output_cache:
732 for line in self.db_output_cache:
731 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
733 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
732 (self.session_number,)+line)
734 (self.session_number,)+line)
733
735
734 @needs_sqlite
736 @needs_sqlite
735 def writeout_cache(self, conn=None):
737 def writeout_cache(self, conn=None):
736 """Write any entries in the cache to the database."""
738 """Write any entries in the cache to the database."""
737 if conn is None:
739 if conn is None:
738 conn = self.db
740 conn = self.db
739
741
740 with self.db_input_cache_lock:
742 with self.db_input_cache_lock:
741 try:
743 try:
742 self._writeout_input_cache(conn)
744 self._writeout_input_cache(conn)
743 except sqlite3.IntegrityError:
745 except sqlite3.IntegrityError:
744 self.new_session(conn)
746 self.new_session(conn)
745 print("ERROR! Session/line number was not unique in",
747 print("ERROR! Session/line number was not unique in",
746 "database. History logging moved to new session",
748 "database. History logging moved to new session",
747 self.session_number)
749 self.session_number)
748 try:
750 try:
749 # Try writing to the new session. If this fails, don't
751 # Try writing to the new session. If this fails, don't
750 # recurse
752 # recurse
751 self._writeout_input_cache(conn)
753 self._writeout_input_cache(conn)
752 except sqlite3.IntegrityError:
754 except sqlite3.IntegrityError:
753 pass
755 pass
754 finally:
756 finally:
755 self.db_input_cache = []
757 self.db_input_cache = []
756
758
757 with self.db_output_cache_lock:
759 with self.db_output_cache_lock:
758 try:
760 try:
759 self._writeout_output_cache(conn)
761 self._writeout_output_cache(conn)
760 except sqlite3.IntegrityError:
762 except sqlite3.IntegrityError:
761 print("!! Session/line number for output was not unique",
763 print("!! Session/line number for output was not unique",
762 "in database. Output will not be stored.")
764 "in database. Output will not be stored.")
763 finally:
765 finally:
764 self.db_output_cache = []
766 self.db_output_cache = []
765
767
766
768
767 class HistorySavingThread(threading.Thread):
769 class HistorySavingThread(threading.Thread):
768 """This thread takes care of writing history to the database, so that
770 """This thread takes care of writing history to the database, so that
769 the UI isn't held up while that happens.
771 the UI isn't held up while that happens.
770
772
771 It waits for the HistoryManager's save_flag to be set, then writes out
773 It waits for the HistoryManager's save_flag to be set, then writes out
772 the history cache. The main thread is responsible for setting the flag when
774 the history cache. The main thread is responsible for setting the flag when
773 the cache size reaches a defined threshold."""
775 the cache size reaches a defined threshold."""
774 daemon = True
776 daemon = True
775 stop_now = False
777 stop_now = False
776 enabled = True
778 enabled = True
777 def __init__(self, history_manager):
779 def __init__(self, history_manager):
778 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
780 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
779 self.history_manager = history_manager
781 self.history_manager = history_manager
780 self.enabled = history_manager.enabled
782 self.enabled = history_manager.enabled
781 atexit.register(self.stop)
783 atexit.register(self.stop)
782
784
783 @needs_sqlite
785 @needs_sqlite
784 def run(self):
786 def run(self):
785 # We need a separate db connection per thread:
787 # We need a separate db connection per thread:
786 try:
788 try:
787 self.db = sqlite3.connect(self.history_manager.hist_file,
789 self.db = sqlite3.connect(self.history_manager.hist_file,
788 **self.history_manager.connection_options
790 **self.history_manager.connection_options
789 )
791 )
790 while True:
792 while True:
791 self.history_manager.save_flag.wait()
793 self.history_manager.save_flag.wait()
792 if self.stop_now:
794 if self.stop_now:
793 self.db.close()
795 self.db.close()
794 return
796 return
795 self.history_manager.save_flag.clear()
797 self.history_manager.save_flag.clear()
796 self.history_manager.writeout_cache(self.db)
798 self.history_manager.writeout_cache(self.db)
797 except Exception as e:
799 except Exception as e:
798 print(("The history saving thread hit an unexpected error (%s)."
800 print(("The history saving thread hit an unexpected error (%s)."
799 "History will not be written to the database.") % repr(e))
801 "History will not be written to the database.") % repr(e))
800
802
801 def stop(self):
803 def stop(self):
802 """This can be called from the main thread to safely stop this thread.
804 """This can be called from the main thread to safely stop this thread.
803
805
804 Note that it does not attempt to write out remaining history before
806 Note that it does not attempt to write out remaining history before
805 exiting. That should be done by calling the HistoryManager's
807 exiting. That should be done by calling the HistoryManager's
806 end_session method."""
808 end_session method."""
807 self.stop_now = True
809 self.stop_now = True
808 self.history_manager.save_flag.set()
810 self.history_manager.save_flag.set()
809 self.join()
811 self.join()
810
812
811
813
812 # To match, e.g. ~5/8-~2/3
814 # To match, e.g. ~5/8-~2/3
813 range_re = re.compile(r"""
815 range_re = re.compile(r"""
814 ((?P<startsess>~?\d+)/)?
816 ((?P<startsess>~?\d+)/)?
815 (?P<start>\d+)?
817 (?P<start>\d+)?
816 ((?P<sep>[\-:])
818 ((?P<sep>[\-:])
817 ((?P<endsess>~?\d+)/)?
819 ((?P<endsess>~?\d+)/)?
818 (?P<end>\d+))?
820 (?P<end>\d+))?
819 $""", re.VERBOSE)
821 $""", re.VERBOSE)
820
822
821
823
822 def extract_hist_ranges(ranges_str):
824 def extract_hist_ranges(ranges_str):
823 """Turn a string of history ranges into 3-tuples of (session, start, stop).
825 """Turn a string of history ranges into 3-tuples of (session, start, stop).
824
826
825 Examples
827 Examples
826 --------
828 --------
827 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
829 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
828 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
830 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
829 """
831 """
830 for range_str in ranges_str.split():
832 for range_str in ranges_str.split():
831 rmatch = range_re.match(range_str)
833 rmatch = range_re.match(range_str)
832 if not rmatch:
834 if not rmatch:
833 continue
835 continue
834 start = rmatch.group("start")
836 start = rmatch.group("start")
835 if start:
837 if start:
836 start = int(start)
838 start = int(start)
837 end = rmatch.group("end")
839 end = rmatch.group("end")
838 # If no end specified, get (a, a + 1)
840 # If no end specified, get (a, a + 1)
839 end = int(end) if end else start + 1
841 end = int(end) if end else start + 1
840 else: # start not specified
842 else: # start not specified
841 if not rmatch.group('startsess'): # no startsess
843 if not rmatch.group('startsess'): # no startsess
842 continue
844 continue
843 start = 1
845 start = 1
844 end = None # provide the entire session hist
846 end = None # provide the entire session hist
845
847
846 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
848 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
847 end += 1
849 end += 1
848 startsess = rmatch.group("startsess") or "0"
850 startsess = rmatch.group("startsess") or "0"
849 endsess = rmatch.group("endsess") or startsess
851 endsess = rmatch.group("endsess") or startsess
850 startsess = int(startsess.replace("~","-"))
852 startsess = int(startsess.replace("~","-"))
851 endsess = int(endsess.replace("~","-"))
853 endsess = int(endsess.replace("~","-"))
852 assert endsess >= startsess, "start session must be earlier than end session"
854 assert endsess >= startsess, "start session must be earlier than end session"
853
855
854 if endsess == startsess:
856 if endsess == startsess:
855 yield (startsess, start, end)
857 yield (startsess, start, end)
856 continue
858 continue
857 # Multiple sessions in one range:
859 # Multiple sessions in one range:
858 yield (startsess, start, None)
860 yield (startsess, start, None)
859 for sess in range(startsess+1, endsess):
861 for sess in range(startsess+1, endsess):
860 yield (sess, 1, None)
862 yield (sess, 1, None)
861 yield (endsess, 1, end)
863 yield (endsess, 1, end)
862
864
863
865
864 def _format_lineno(session, line):
866 def _format_lineno(session, line):
865 """Helper function to format line numbers properly."""
867 """Helper function to format line numbers properly."""
866 if session == 0:
868 if session == 0:
867 return str(line)
869 return str(line)
868 return "%s#%s" % (session, line)
870 return "%s#%s" % (session, line)
869
871
870
872
@@ -1,3392 +1,3392 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Main IPython class."""
2 """Main IPython class."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 from __future__ import absolute_import, print_function
13 from __future__ import absolute_import, print_function
14
14
15 import __future__
15 import __future__
16 import abc
16 import abc
17 import ast
17 import ast
18 import atexit
18 import atexit
19 import functools
19 import functools
20 import os
20 import os
21 import re
21 import re
22 import runpy
22 import runpy
23 import sys
23 import sys
24 import tempfile
24 import tempfile
25 import traceback
25 import traceback
26 import types
26 import types
27 import subprocess
27 import subprocess
28 from io import open as io_open
28 from io import open as io_open
29
29
30 from pickleshare import PickleShareDB
30 from pickleshare import PickleShareDB
31
31
32 from IPython.config.configurable import SingletonConfigurable
32 from IPython.config.configurable import SingletonConfigurable
33 from IPython.core import debugger, oinspect
33 from IPython.core import debugger, oinspect
34 from IPython.core import magic
34 from IPython.core import magic
35 from IPython.core import page
35 from IPython.core import page
36 from IPython.core import prefilter
36 from IPython.core import prefilter
37 from IPython.core import shadowns
37 from IPython.core import shadowns
38 from IPython.core import ultratb
38 from IPython.core import ultratb
39 from IPython.core.alias import Alias, AliasManager
39 from IPython.core.alias import Alias, AliasManager
40 from IPython.core.autocall import ExitAutocall
40 from IPython.core.autocall import ExitAutocall
41 from IPython.core.builtin_trap import BuiltinTrap
41 from IPython.core.builtin_trap import BuiltinTrap
42 from IPython.core.events import EventManager, available_events
42 from IPython.core.events import EventManager, available_events
43 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
43 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
44 from IPython.core.display_trap import DisplayTrap
44 from IPython.core.display_trap import DisplayTrap
45 from IPython.core.displayhook import DisplayHook
45 from IPython.core.displayhook import DisplayHook
46 from IPython.core.displaypub import DisplayPublisher
46 from IPython.core.displaypub import DisplayPublisher
47 from IPython.core.error import InputRejected, UsageError
47 from IPython.core.error import InputRejected, UsageError
48 from IPython.core.extensions import ExtensionManager
48 from IPython.core.extensions import ExtensionManager
49 from IPython.core.formatters import DisplayFormatter
49 from IPython.core.formatters import DisplayFormatter
50 from IPython.core.history import HistoryManager
50 from IPython.core.history import HistoryManager
51 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
51 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
52 from IPython.core.logger import Logger
52 from IPython.core.logger import Logger
53 from IPython.core.macro import Macro
53 from IPython.core.macro import Macro
54 from IPython.core.payload import PayloadManager
54 from IPython.core.payload import PayloadManager
55 from IPython.core.prefilter import PrefilterManager
55 from IPython.core.prefilter import PrefilterManager
56 from IPython.core.profiledir import ProfileDir
56 from IPython.core.profiledir import ProfileDir
57 from IPython.core.prompts import PromptManager
57 from IPython.core.prompts import PromptManager
58 from IPython.core.usage import default_banner
58 from IPython.core.usage import default_banner
59 from IPython.testing.skipdoctest import skip_doctest
59 from IPython.testing.skipdoctest import skip_doctest
60 from IPython.utils import PyColorize
60 from IPython.utils import PyColorize
61 from IPython.utils import io
61 from IPython.utils import io
62 from IPython.utils import py3compat
62 from IPython.utils import py3compat
63 from IPython.utils import openpy
63 from IPython.utils import openpy
64 from IPython.utils.decorators import undoc
64 from IPython.utils.decorators import undoc
65 from IPython.utils.io import ask_yes_no
65 from IPython.utils.io import ask_yes_no
66 from IPython.utils.ipstruct import Struct
66 from IPython.utils.ipstruct import Struct
67 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename, ensure_dir_exists
67 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename, ensure_dir_exists
68 from IPython.utils.process import system, getoutput
68 from IPython.utils.process import system, getoutput
69 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
69 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
70 with_metaclass, iteritems)
70 with_metaclass, iteritems)
71 from IPython.utils.strdispatch import StrDispatch
71 from IPython.utils.strdispatch import StrDispatch
72 from IPython.utils.syspathcontext import prepended_to_syspath
72 from IPython.utils.syspathcontext import prepended_to_syspath
73 from IPython.utils.text import (format_screen, LSString, SList,
73 from IPython.utils.text import (format_screen, LSString, SList,
74 DollarFormatter)
74 DollarFormatter)
75 from IPython.utils.traitlets import (Integer, Bool, CBool, CaselessStrEnum, Enum,
75 from IPython.utils.traitlets import (Integer, Bool, CBool, CaselessStrEnum, Enum,
76 List, Unicode, Instance, Type)
76 List, Unicode, Instance, Type)
77 from IPython.utils.warn import warn, error
77 from IPython.utils.warn import warn, error
78 import IPython.core.hooks
78 import IPython.core.hooks
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Globals
81 # Globals
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83
83
84 # compiled regexps for autoindent management
84 # compiled regexps for autoindent management
85 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
85 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
86
86
87 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
88 # Utilities
88 # Utilities
89 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
90
90
91 @undoc
91 @undoc
92 def softspace(file, newvalue):
92 def softspace(file, newvalue):
93 """Copied from code.py, to remove the dependency"""
93 """Copied from code.py, to remove the dependency"""
94
94
95 oldvalue = 0
95 oldvalue = 0
96 try:
96 try:
97 oldvalue = file.softspace
97 oldvalue = file.softspace
98 except AttributeError:
98 except AttributeError:
99 pass
99 pass
100 try:
100 try:
101 file.softspace = newvalue
101 file.softspace = newvalue
102 except (AttributeError, TypeError):
102 except (AttributeError, TypeError):
103 # "attribute-less object" or "read-only attributes"
103 # "attribute-less object" or "read-only attributes"
104 pass
104 pass
105 return oldvalue
105 return oldvalue
106
106
107 @undoc
107 @undoc
108 def no_op(*a, **kw): pass
108 def no_op(*a, **kw): pass
109
109
110 @undoc
110 @undoc
111 class NoOpContext(object):
111 class NoOpContext(object):
112 def __enter__(self): pass
112 def __enter__(self): pass
113 def __exit__(self, type, value, traceback): pass
113 def __exit__(self, type, value, traceback): pass
114 no_op_context = NoOpContext()
114 no_op_context = NoOpContext()
115
115
116 class SpaceInInput(Exception): pass
116 class SpaceInInput(Exception): pass
117
117
118 @undoc
118 @undoc
119 class Bunch: pass
119 class Bunch: pass
120
120
121
121
122 def get_default_colors():
122 def get_default_colors():
123 if sys.platform=='darwin':
123 if sys.platform=='darwin':
124 return "LightBG"
124 return "LightBG"
125 elif os.name=='nt':
125 elif os.name=='nt':
126 return 'Linux'
126 return 'Linux'
127 else:
127 else:
128 return 'Linux'
128 return 'Linux'
129
129
130
130
131 class SeparateUnicode(Unicode):
131 class SeparateUnicode(Unicode):
132 r"""A Unicode subclass to validate separate_in, separate_out, etc.
132 r"""A Unicode subclass to validate separate_in, separate_out, etc.
133
133
134 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
134 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
135 """
135 """
136
136
137 def validate(self, obj, value):
137 def validate(self, obj, value):
138 if value == '0': value = ''
138 if value == '0': value = ''
139 value = value.replace('\\n','\n')
139 value = value.replace('\\n','\n')
140 return super(SeparateUnicode, self).validate(obj, value)
140 return super(SeparateUnicode, self).validate(obj, value)
141
141
142
142
143 class ReadlineNoRecord(object):
143 class ReadlineNoRecord(object):
144 """Context manager to execute some code, then reload readline history
144 """Context manager to execute some code, then reload readline history
145 so that interactive input to the code doesn't appear when pressing up."""
145 so that interactive input to the code doesn't appear when pressing up."""
146 def __init__(self, shell):
146 def __init__(self, shell):
147 self.shell = shell
147 self.shell = shell
148 self._nested_level = 0
148 self._nested_level = 0
149
149
150 def __enter__(self):
150 def __enter__(self):
151 if self._nested_level == 0:
151 if self._nested_level == 0:
152 try:
152 try:
153 self.orig_length = self.current_length()
153 self.orig_length = self.current_length()
154 self.readline_tail = self.get_readline_tail()
154 self.readline_tail = self.get_readline_tail()
155 except (AttributeError, IndexError): # Can fail with pyreadline
155 except (AttributeError, IndexError): # Can fail with pyreadline
156 self.orig_length, self.readline_tail = 999999, []
156 self.orig_length, self.readline_tail = 999999, []
157 self._nested_level += 1
157 self._nested_level += 1
158
158
159 def __exit__(self, type, value, traceback):
159 def __exit__(self, type, value, traceback):
160 self._nested_level -= 1
160 self._nested_level -= 1
161 if self._nested_level == 0:
161 if self._nested_level == 0:
162 # Try clipping the end if it's got longer
162 # Try clipping the end if it's got longer
163 try:
163 try:
164 e = self.current_length() - self.orig_length
164 e = self.current_length() - self.orig_length
165 if e > 0:
165 if e > 0:
166 for _ in range(e):
166 for _ in range(e):
167 self.shell.readline.remove_history_item(self.orig_length)
167 self.shell.readline.remove_history_item(self.orig_length)
168
168
169 # If it still doesn't match, just reload readline history.
169 # If it still doesn't match, just reload readline history.
170 if self.current_length() != self.orig_length \
170 if self.current_length() != self.orig_length \
171 or self.get_readline_tail() != self.readline_tail:
171 or self.get_readline_tail() != self.readline_tail:
172 self.shell.refill_readline_hist()
172 self.shell.refill_readline_hist()
173 except (AttributeError, IndexError):
173 except (AttributeError, IndexError):
174 pass
174 pass
175 # Returning False will cause exceptions to propagate
175 # Returning False will cause exceptions to propagate
176 return False
176 return False
177
177
178 def current_length(self):
178 def current_length(self):
179 return self.shell.readline.get_current_history_length()
179 return self.shell.readline.get_current_history_length()
180
180
181 def get_readline_tail(self, n=10):
181 def get_readline_tail(self, n=10):
182 """Get the last n items in readline history."""
182 """Get the last n items in readline history."""
183 end = self.shell.readline.get_current_history_length() + 1
183 end = self.shell.readline.get_current_history_length() + 1
184 start = max(end-n, 1)
184 start = max(end-n, 1)
185 ghi = self.shell.readline.get_history_item
185 ghi = self.shell.readline.get_history_item
186 return [ghi(x) for x in range(start, end)]
186 return [ghi(x) for x in range(start, end)]
187
187
188
188
189 @undoc
189 @undoc
190 class DummyMod(object):
190 class DummyMod(object):
191 """A dummy module used for IPython's interactive module when
191 """A dummy module used for IPython's interactive module when
192 a namespace must be assigned to the module's __dict__."""
192 a namespace must be assigned to the module's __dict__."""
193 pass
193 pass
194
194
195
195
196 class ExecutionResult(object):
196 class ExecutionResult(object):
197 """The result of a call to :meth:`InteractiveShell.run_cell`
197 """The result of a call to :meth:`InteractiveShell.run_cell`
198
198
199 Stores information about what took place.
199 Stores information about what took place.
200 """
200 """
201 execution_count = None
201 execution_count = None
202 error_before_exec = None
202 error_before_exec = None
203 error_in_exec = None
203 error_in_exec = None
204 result = None
204 result = None
205
205
206 @property
206 @property
207 def success(self):
207 def success(self):
208 return (self.error_before_exec is None) and (self.error_in_exec is None)
208 return (self.error_before_exec is None) and (self.error_in_exec is None)
209
209
210
210
211 class InteractiveShell(SingletonConfigurable):
211 class InteractiveShell(SingletonConfigurable):
212 """An enhanced, interactive shell for Python."""
212 """An enhanced, interactive shell for Python."""
213
213
214 _instance = None
214 _instance = None
215
215
216 ast_transformers = List([], config=True, help=
216 ast_transformers = List([], config=True, help=
217 """
217 """
218 A list of ast.NodeTransformer subclass instances, which will be applied
218 A list of ast.NodeTransformer subclass instances, which will be applied
219 to user input before code is run.
219 to user input before code is run.
220 """
220 """
221 )
221 )
222
222
223 autocall = Enum((0,1,2), default_value=0, config=True, help=
223 autocall = Enum((0,1,2), default_value=0, config=True, help=
224 """
224 """
225 Make IPython automatically call any callable object even if you didn't
225 Make IPython automatically call any callable object even if you didn't
226 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
226 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
227 automatically. The value can be '0' to disable the feature, '1' for
227 automatically. The value can be '0' to disable the feature, '1' for
228 'smart' autocall, where it is not applied if there are no more
228 'smart' autocall, where it is not applied if there are no more
229 arguments on the line, and '2' for 'full' autocall, where all callable
229 arguments on the line, and '2' for 'full' autocall, where all callable
230 objects are automatically called (even if no arguments are present).
230 objects are automatically called (even if no arguments are present).
231 """
231 """
232 )
232 )
233 # TODO: remove all autoindent logic and put into frontends.
233 # TODO: remove all autoindent logic and put into frontends.
234 # We can't do this yet because even runlines uses the autoindent.
234 # We can't do this yet because even runlines uses the autoindent.
235 autoindent = CBool(True, config=True, help=
235 autoindent = CBool(True, config=True, help=
236 """
236 """
237 Autoindent IPython code entered interactively.
237 Autoindent IPython code entered interactively.
238 """
238 """
239 )
239 )
240 automagic = CBool(True, config=True, help=
240 automagic = CBool(True, config=True, help=
241 """
241 """
242 Enable magic commands to be called without the leading %.
242 Enable magic commands to be called without the leading %.
243 """
243 """
244 )
244 )
245
245
246 banner1 = Unicode(default_banner, config=True,
246 banner1 = Unicode(default_banner, config=True,
247 help="""The part of the banner to be printed before the profile"""
247 help="""The part of the banner to be printed before the profile"""
248 )
248 )
249 banner2 = Unicode('', config=True,
249 banner2 = Unicode('', config=True,
250 help="""The part of the banner to be printed after the profile"""
250 help="""The part of the banner to be printed after the profile"""
251 )
251 )
252
252
253 cache_size = Integer(1000, config=True, help=
253 cache_size = Integer(1000, config=True, help=
254 """
254 """
255 Set the size of the output cache. The default is 1000, you can
255 Set the size of the output cache. The default is 1000, you can
256 change it permanently in your config file. Setting it to 0 completely
256 change it permanently in your config file. Setting it to 0 completely
257 disables the caching system, and the minimum value accepted is 20 (if
257 disables the caching system, and the minimum value accepted is 20 (if
258 you provide a value less than 20, it is reset to 0 and a warning is
258 you provide a value less than 20, it is reset to 0 and a warning is
259 issued). This limit is defined because otherwise you'll spend more
259 issued). This limit is defined because otherwise you'll spend more
260 time re-flushing a too small cache than working
260 time re-flushing a too small cache than working
261 """
261 """
262 )
262 )
263 color_info = CBool(True, config=True, help=
263 color_info = CBool(True, config=True, help=
264 """
264 """
265 Use colors for displaying information about objects. Because this
265 Use colors for displaying information about objects. Because this
266 information is passed through a pager (like 'less'), and some pagers
266 information is passed through a pager (like 'less'), and some pagers
267 get confused with color codes, this capability can be turned off.
267 get confused with color codes, this capability can be turned off.
268 """
268 """
269 )
269 )
270 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
270 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
271 default_value=get_default_colors(), config=True,
271 default_value=get_default_colors(), config=True,
272 help="Set the color scheme (NoColor, Linux, or LightBG)."
272 help="Set the color scheme (NoColor, Linux, or LightBG)."
273 )
273 )
274 colors_force = CBool(False, help=
274 colors_force = CBool(False, help=
275 """
275 """
276 Force use of ANSI color codes, regardless of OS and readline
276 Force use of ANSI color codes, regardless of OS and readline
277 availability.
277 availability.
278 """
278 """
279 # FIXME: This is essentially a hack to allow ZMQShell to show colors
279 # FIXME: This is essentially a hack to allow ZMQShell to show colors
280 # without readline on Win32. When the ZMQ formatting system is
280 # without readline on Win32. When the ZMQ formatting system is
281 # refactored, this should be removed.
281 # refactored, this should be removed.
282 )
282 )
283 debug = CBool(False, config=True)
283 debug = CBool(False, config=True)
284 deep_reload = CBool(False, config=True, help=
284 deep_reload = CBool(False, config=True, help=
285 """
285 """
286 Enable deep (recursive) reloading by default. IPython can use the
286 Enable deep (recursive) reloading by default. IPython can use the
287 deep_reload module which reloads changes in modules recursively (it
287 deep_reload module which reloads changes in modules recursively (it
288 replaces the reload() function, so you don't need to change anything to
288 replaces the reload() function, so you don't need to change anything to
289 use it). deep_reload() forces a full reload of modules whose code may
289 use it). deep_reload() forces a full reload of modules whose code may
290 have changed, which the default reload() function does not. When
290 have changed, which the default reload() function does not. When
291 deep_reload is off, IPython will use the normal reload(), but
291 deep_reload is off, IPython will use the normal reload(), but
292 deep_reload will still be available as dreload().
292 deep_reload will still be available as dreload().
293 """
293 """
294 )
294 )
295 disable_failing_post_execute = CBool(False, config=True,
295 disable_failing_post_execute = CBool(False, config=True,
296 help="Don't call post-execute functions that have failed in the past."
296 help="Don't call post-execute functions that have failed in the past."
297 )
297 )
298 display_formatter = Instance(DisplayFormatter)
298 display_formatter = Instance(DisplayFormatter, allow_none=True)
299 displayhook_class = Type(DisplayHook)
299 displayhook_class = Type(DisplayHook, allow_none=True)
300 display_pub_class = Type(DisplayPublisher)
300 display_pub_class = Type(DisplayPublisher, allow_none=True)
301 data_pub_class = None
301 data_pub_class = None
302
302
303 exit_now = CBool(False)
303 exit_now = CBool(False)
304 exiter = Instance(ExitAutocall)
304 exiter = Instance(ExitAutocall, allow_none=True)
305 def _exiter_default(self):
305 def _exiter_default(self):
306 return ExitAutocall(self)
306 return ExitAutocall(self)
307 # Monotonically increasing execution counter
307 # Monotonically increasing execution counter
308 execution_count = Integer(1)
308 execution_count = Integer(1)
309 filename = Unicode("<ipython console>")
309 filename = Unicode("<ipython console>")
310 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
310 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
311
311
312 # Input splitter, to transform input line by line and detect when a block
312 # Input splitter, to transform input line by line and detect when a block
313 # is ready to be executed.
313 # is ready to be executed.
314 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
314 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
315 (), {'line_input_checker': True})
315 (), {'line_input_checker': True})
316
316
317 # This InputSplitter instance is used to transform completed cells before
317 # This InputSplitter instance is used to transform completed cells before
318 # running them. It allows cell magics to contain blank lines.
318 # running them. It allows cell magics to contain blank lines.
319 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
319 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
320 (), {'line_input_checker': False})
320 (), {'line_input_checker': False})
321
321
322 logstart = CBool(False, config=True, help=
322 logstart = CBool(False, config=True, help=
323 """
323 """
324 Start logging to the default log file in overwrite mode.
324 Start logging to the default log file in overwrite mode.
325 Use `logappend` to specify a log file to **append** logs to.
325 Use `logappend` to specify a log file to **append** logs to.
326 """
326 """
327 )
327 )
328 logfile = Unicode('', config=True, help=
328 logfile = Unicode('', config=True, help=
329 """
329 """
330 The name of the logfile to use.
330 The name of the logfile to use.
331 """
331 """
332 )
332 )
333 logappend = Unicode('', config=True, help=
333 logappend = Unicode('', config=True, help=
334 """
334 """
335 Start logging to the given file in append mode.
335 Start logging to the given file in append mode.
336 Use `logfile` to specify a log file to **overwrite** logs to.
336 Use `logfile` to specify a log file to **overwrite** logs to.
337 """
337 """
338 )
338 )
339 object_info_string_level = Enum((0,1,2), default_value=0,
339 object_info_string_level = Enum((0,1,2), default_value=0,
340 config=True)
340 config=True)
341 pdb = CBool(False, config=True, help=
341 pdb = CBool(False, config=True, help=
342 """
342 """
343 Automatically call the pdb debugger after every exception.
343 Automatically call the pdb debugger after every exception.
344 """
344 """
345 )
345 )
346 multiline_history = CBool(sys.platform != 'win32', config=True,
346 multiline_history = CBool(sys.platform != 'win32', config=True,
347 help="Save multi-line entries as one entry in readline history"
347 help="Save multi-line entries as one entry in readline history"
348 )
348 )
349 display_page = Bool(False, config=True,
349 display_page = Bool(False, config=True,
350 help="""If True, anything that would be passed to the pager
350 help="""If True, anything that would be passed to the pager
351 will be displayed as regular output instead."""
351 will be displayed as regular output instead."""
352 )
352 )
353
353
354 # deprecated prompt traits:
354 # deprecated prompt traits:
355
355
356 prompt_in1 = Unicode('In [\\#]: ', config=True,
356 prompt_in1 = Unicode('In [\\#]: ', config=True,
357 help="Deprecated, use PromptManager.in_template")
357 help="Deprecated, use PromptManager.in_template")
358 prompt_in2 = Unicode(' .\\D.: ', config=True,
358 prompt_in2 = Unicode(' .\\D.: ', config=True,
359 help="Deprecated, use PromptManager.in2_template")
359 help="Deprecated, use PromptManager.in2_template")
360 prompt_out = Unicode('Out[\\#]: ', config=True,
360 prompt_out = Unicode('Out[\\#]: ', config=True,
361 help="Deprecated, use PromptManager.out_template")
361 help="Deprecated, use PromptManager.out_template")
362 prompts_pad_left = CBool(True, config=True,
362 prompts_pad_left = CBool(True, config=True,
363 help="Deprecated, use PromptManager.justify")
363 help="Deprecated, use PromptManager.justify")
364
364
365 def _prompt_trait_changed(self, name, old, new):
365 def _prompt_trait_changed(self, name, old, new):
366 table = {
366 table = {
367 'prompt_in1' : 'in_template',
367 'prompt_in1' : 'in_template',
368 'prompt_in2' : 'in2_template',
368 'prompt_in2' : 'in2_template',
369 'prompt_out' : 'out_template',
369 'prompt_out' : 'out_template',
370 'prompts_pad_left' : 'justify',
370 'prompts_pad_left' : 'justify',
371 }
371 }
372 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
372 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
373 name=name, newname=table[name])
373 name=name, newname=table[name])
374 )
374 )
375 # protect against weird cases where self.config may not exist:
375 # protect against weird cases where self.config may not exist:
376 if self.config is not None:
376 if self.config is not None:
377 # propagate to corresponding PromptManager trait
377 # propagate to corresponding PromptManager trait
378 setattr(self.config.PromptManager, table[name], new)
378 setattr(self.config.PromptManager, table[name], new)
379
379
380 _prompt_in1_changed = _prompt_trait_changed
380 _prompt_in1_changed = _prompt_trait_changed
381 _prompt_in2_changed = _prompt_trait_changed
381 _prompt_in2_changed = _prompt_trait_changed
382 _prompt_out_changed = _prompt_trait_changed
382 _prompt_out_changed = _prompt_trait_changed
383 _prompt_pad_left_changed = _prompt_trait_changed
383 _prompt_pad_left_changed = _prompt_trait_changed
384
384
385 show_rewritten_input = CBool(True, config=True,
385 show_rewritten_input = CBool(True, config=True,
386 help="Show rewritten input, e.g. for autocall."
386 help="Show rewritten input, e.g. for autocall."
387 )
387 )
388
388
389 quiet = CBool(False, config=True)
389 quiet = CBool(False, config=True)
390
390
391 history_length = Integer(10000, config=True)
391 history_length = Integer(10000, config=True)
392
392
393 # The readline stuff will eventually be moved to the terminal subclass
393 # The readline stuff will eventually be moved to the terminal subclass
394 # but for now, we can't do that as readline is welded in everywhere.
394 # but for now, we can't do that as readline is welded in everywhere.
395 readline_use = CBool(True, config=True)
395 readline_use = CBool(True, config=True)
396 readline_remove_delims = Unicode('-/~', config=True)
396 readline_remove_delims = Unicode('-/~', config=True)
397 readline_delims = Unicode() # set by init_readline()
397 readline_delims = Unicode() # set by init_readline()
398 # don't use \M- bindings by default, because they
398 # don't use \M- bindings by default, because they
399 # conflict with 8-bit encodings. See gh-58,gh-88
399 # conflict with 8-bit encodings. See gh-58,gh-88
400 readline_parse_and_bind = List([
400 readline_parse_and_bind = List([
401 'tab: complete',
401 'tab: complete',
402 '"\C-l": clear-screen',
402 '"\C-l": clear-screen',
403 'set show-all-if-ambiguous on',
403 'set show-all-if-ambiguous on',
404 '"\C-o": tab-insert',
404 '"\C-o": tab-insert',
405 '"\C-r": reverse-search-history',
405 '"\C-r": reverse-search-history',
406 '"\C-s": forward-search-history',
406 '"\C-s": forward-search-history',
407 '"\C-p": history-search-backward',
407 '"\C-p": history-search-backward',
408 '"\C-n": history-search-forward',
408 '"\C-n": history-search-forward',
409 '"\e[A": history-search-backward',
409 '"\e[A": history-search-backward',
410 '"\e[B": history-search-forward',
410 '"\e[B": history-search-forward',
411 '"\C-k": kill-line',
411 '"\C-k": kill-line',
412 '"\C-u": unix-line-discard',
412 '"\C-u": unix-line-discard',
413 ], config=True)
413 ], config=True)
414
414
415 _custom_readline_config = False
415 _custom_readline_config = False
416
416
417 def _readline_parse_and_bind_changed(self, name, old, new):
417 def _readline_parse_and_bind_changed(self, name, old, new):
418 # notice that readline config is customized
418 # notice that readline config is customized
419 # indicates that it should have higher priority than inputrc
419 # indicates that it should have higher priority than inputrc
420 self._custom_readline_config = True
420 self._custom_readline_config = True
421
421
422 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
422 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
423 default_value='last_expr', config=True,
423 default_value='last_expr', config=True,
424 help="""
424 help="""
425 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
425 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
426 run interactively (displaying output from expressions).""")
426 run interactively (displaying output from expressions).""")
427
427
428 # TODO: this part of prompt management should be moved to the frontends.
428 # TODO: this part of prompt management should be moved to the frontends.
429 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
429 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
430 separate_in = SeparateUnicode('\n', config=True)
430 separate_in = SeparateUnicode('\n', config=True)
431 separate_out = SeparateUnicode('', config=True)
431 separate_out = SeparateUnicode('', config=True)
432 separate_out2 = SeparateUnicode('', config=True)
432 separate_out2 = SeparateUnicode('', config=True)
433 wildcards_case_sensitive = CBool(True, config=True)
433 wildcards_case_sensitive = CBool(True, config=True)
434 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
434 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
435 default_value='Context', config=True)
435 default_value='Context', config=True)
436
436
437 # Subcomponents of InteractiveShell
437 # Subcomponents of InteractiveShell
438 alias_manager = Instance('IPython.core.alias.AliasManager')
438 alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True)
439 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
439 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
440 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
440 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap', allow_none=True)
441 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
441 display_trap = Instance('IPython.core.display_trap.DisplayTrap', allow_none=True)
442 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
442 extension_manager = Instance('IPython.core.extensions.ExtensionManager', allow_none=True)
443 payload_manager = Instance('IPython.core.payload.PayloadManager')
443 payload_manager = Instance('IPython.core.payload.PayloadManager', allow_none=True)
444 history_manager = Instance('IPython.core.history.HistoryAccessorBase')
444 history_manager = Instance('IPython.core.history.HistoryAccessorBase', allow_none=True)
445 magics_manager = Instance('IPython.core.magic.MagicsManager')
445 magics_manager = Instance('IPython.core.magic.MagicsManager', allow_none=True)
446
446
447 profile_dir = Instance('IPython.core.application.ProfileDir')
447 profile_dir = Instance('IPython.core.application.ProfileDir', allow_none=True)
448 @property
448 @property
449 def profile(self):
449 def profile(self):
450 if self.profile_dir is not None:
450 if self.profile_dir is not None:
451 name = os.path.basename(self.profile_dir.location)
451 name = os.path.basename(self.profile_dir.location)
452 return name.replace('profile_','')
452 return name.replace('profile_','')
453
453
454
454
455 # Private interface
455 # Private interface
456 _post_execute = Instance(dict)
456 _post_execute = Instance(dict, allow_none=True)
457
457
458 # Tracks any GUI loop loaded for pylab
458 # Tracks any GUI loop loaded for pylab
459 pylab_gui_select = None
459 pylab_gui_select = None
460
460
461 def __init__(self, ipython_dir=None, profile_dir=None,
461 def __init__(self, ipython_dir=None, profile_dir=None,
462 user_module=None, user_ns=None,
462 user_module=None, user_ns=None,
463 custom_exceptions=((), None), **kwargs):
463 custom_exceptions=((), None), **kwargs):
464
464
465 # This is where traits with a config_key argument are updated
465 # This is where traits with a config_key argument are updated
466 # from the values on config.
466 # from the values on config.
467 super(InteractiveShell, self).__init__(**kwargs)
467 super(InteractiveShell, self).__init__(**kwargs)
468 self.configurables = [self]
468 self.configurables = [self]
469
469
470 # These are relatively independent and stateless
470 # These are relatively independent and stateless
471 self.init_ipython_dir(ipython_dir)
471 self.init_ipython_dir(ipython_dir)
472 self.init_profile_dir(profile_dir)
472 self.init_profile_dir(profile_dir)
473 self.init_instance_attrs()
473 self.init_instance_attrs()
474 self.init_environment()
474 self.init_environment()
475
475
476 # Check if we're in a virtualenv, and set up sys.path.
476 # Check if we're in a virtualenv, and set up sys.path.
477 self.init_virtualenv()
477 self.init_virtualenv()
478
478
479 # Create namespaces (user_ns, user_global_ns, etc.)
479 # Create namespaces (user_ns, user_global_ns, etc.)
480 self.init_create_namespaces(user_module, user_ns)
480 self.init_create_namespaces(user_module, user_ns)
481 # This has to be done after init_create_namespaces because it uses
481 # This has to be done after init_create_namespaces because it uses
482 # something in self.user_ns, but before init_sys_modules, which
482 # something in self.user_ns, but before init_sys_modules, which
483 # is the first thing to modify sys.
483 # is the first thing to modify sys.
484 # TODO: When we override sys.stdout and sys.stderr before this class
484 # TODO: When we override sys.stdout and sys.stderr before this class
485 # is created, we are saving the overridden ones here. Not sure if this
485 # is created, we are saving the overridden ones here. Not sure if this
486 # is what we want to do.
486 # is what we want to do.
487 self.save_sys_module_state()
487 self.save_sys_module_state()
488 self.init_sys_modules()
488 self.init_sys_modules()
489
489
490 # While we're trying to have each part of the code directly access what
490 # While we're trying to have each part of the code directly access what
491 # it needs without keeping redundant references to objects, we have too
491 # it needs without keeping redundant references to objects, we have too
492 # much legacy code that expects ip.db to exist.
492 # much legacy code that expects ip.db to exist.
493 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
493 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
494
494
495 self.init_history()
495 self.init_history()
496 self.init_encoding()
496 self.init_encoding()
497 self.init_prefilter()
497 self.init_prefilter()
498
498
499 self.init_syntax_highlighting()
499 self.init_syntax_highlighting()
500 self.init_hooks()
500 self.init_hooks()
501 self.init_events()
501 self.init_events()
502 self.init_pushd_popd_magic()
502 self.init_pushd_popd_magic()
503 # self.init_traceback_handlers use to be here, but we moved it below
503 # self.init_traceback_handlers use to be here, but we moved it below
504 # because it and init_io have to come after init_readline.
504 # because it and init_io have to come after init_readline.
505 self.init_user_ns()
505 self.init_user_ns()
506 self.init_logger()
506 self.init_logger()
507 self.init_builtins()
507 self.init_builtins()
508
508
509 # The following was in post_config_initialization
509 # The following was in post_config_initialization
510 self.init_inspector()
510 self.init_inspector()
511 # init_readline() must come before init_io(), because init_io uses
511 # init_readline() must come before init_io(), because init_io uses
512 # readline related things.
512 # readline related things.
513 self.init_readline()
513 self.init_readline()
514 # We save this here in case user code replaces raw_input, but it needs
514 # We save this here in case user code replaces raw_input, but it needs
515 # to be after init_readline(), because PyPy's readline works by replacing
515 # to be after init_readline(), because PyPy's readline works by replacing
516 # raw_input.
516 # raw_input.
517 if py3compat.PY3:
517 if py3compat.PY3:
518 self.raw_input_original = input
518 self.raw_input_original = input
519 else:
519 else:
520 self.raw_input_original = raw_input
520 self.raw_input_original = raw_input
521 # init_completer must come after init_readline, because it needs to
521 # init_completer must come after init_readline, because it needs to
522 # know whether readline is present or not system-wide to configure the
522 # know whether readline is present or not system-wide to configure the
523 # completers, since the completion machinery can now operate
523 # completers, since the completion machinery can now operate
524 # independently of readline (e.g. over the network)
524 # independently of readline (e.g. over the network)
525 self.init_completer()
525 self.init_completer()
526 # TODO: init_io() needs to happen before init_traceback handlers
526 # TODO: init_io() needs to happen before init_traceback handlers
527 # because the traceback handlers hardcode the stdout/stderr streams.
527 # because the traceback handlers hardcode the stdout/stderr streams.
528 # This logic in in debugger.Pdb and should eventually be changed.
528 # This logic in in debugger.Pdb and should eventually be changed.
529 self.init_io()
529 self.init_io()
530 self.init_traceback_handlers(custom_exceptions)
530 self.init_traceback_handlers(custom_exceptions)
531 self.init_prompts()
531 self.init_prompts()
532 self.init_display_formatter()
532 self.init_display_formatter()
533 self.init_display_pub()
533 self.init_display_pub()
534 self.init_data_pub()
534 self.init_data_pub()
535 self.init_displayhook()
535 self.init_displayhook()
536 self.init_magics()
536 self.init_magics()
537 self.init_alias()
537 self.init_alias()
538 self.init_logstart()
538 self.init_logstart()
539 self.init_pdb()
539 self.init_pdb()
540 self.init_extension_manager()
540 self.init_extension_manager()
541 self.init_payload()
541 self.init_payload()
542 self.hooks.late_startup_hook()
542 self.hooks.late_startup_hook()
543 self.events.trigger('shell_initialized', self)
543 self.events.trigger('shell_initialized', self)
544 atexit.register(self.atexit_operations)
544 atexit.register(self.atexit_operations)
545
545
546 def get_ipython(self):
546 def get_ipython(self):
547 """Return the currently running IPython instance."""
547 """Return the currently running IPython instance."""
548 return self
548 return self
549
549
550 #-------------------------------------------------------------------------
550 #-------------------------------------------------------------------------
551 # Trait changed handlers
551 # Trait changed handlers
552 #-------------------------------------------------------------------------
552 #-------------------------------------------------------------------------
553
553
554 def _ipython_dir_changed(self, name, new):
554 def _ipython_dir_changed(self, name, new):
555 ensure_dir_exists(new)
555 ensure_dir_exists(new)
556
556
557 def set_autoindent(self,value=None):
557 def set_autoindent(self,value=None):
558 """Set the autoindent flag, checking for readline support.
558 """Set the autoindent flag, checking for readline support.
559
559
560 If called with no arguments, it acts as a toggle."""
560 If called with no arguments, it acts as a toggle."""
561
561
562 if value != 0 and not self.has_readline:
562 if value != 0 and not self.has_readline:
563 if os.name == 'posix':
563 if os.name == 'posix':
564 warn("The auto-indent feature requires the readline library")
564 warn("The auto-indent feature requires the readline library")
565 self.autoindent = 0
565 self.autoindent = 0
566 return
566 return
567 if value is None:
567 if value is None:
568 self.autoindent = not self.autoindent
568 self.autoindent = not self.autoindent
569 else:
569 else:
570 self.autoindent = value
570 self.autoindent = value
571
571
572 #-------------------------------------------------------------------------
572 #-------------------------------------------------------------------------
573 # init_* methods called by __init__
573 # init_* methods called by __init__
574 #-------------------------------------------------------------------------
574 #-------------------------------------------------------------------------
575
575
576 def init_ipython_dir(self, ipython_dir):
576 def init_ipython_dir(self, ipython_dir):
577 if ipython_dir is not None:
577 if ipython_dir is not None:
578 self.ipython_dir = ipython_dir
578 self.ipython_dir = ipython_dir
579 return
579 return
580
580
581 self.ipython_dir = get_ipython_dir()
581 self.ipython_dir = get_ipython_dir()
582
582
583 def init_profile_dir(self, profile_dir):
583 def init_profile_dir(self, profile_dir):
584 if profile_dir is not None:
584 if profile_dir is not None:
585 self.profile_dir = profile_dir
585 self.profile_dir = profile_dir
586 return
586 return
587 self.profile_dir =\
587 self.profile_dir =\
588 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
588 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
589
589
590 def init_instance_attrs(self):
590 def init_instance_attrs(self):
591 self.more = False
591 self.more = False
592
592
593 # command compiler
593 # command compiler
594 self.compile = CachingCompiler()
594 self.compile = CachingCompiler()
595
595
596 # Make an empty namespace, which extension writers can rely on both
596 # Make an empty namespace, which extension writers can rely on both
597 # existing and NEVER being used by ipython itself. This gives them a
597 # existing and NEVER being used by ipython itself. This gives them a
598 # convenient location for storing additional information and state
598 # convenient location for storing additional information and state
599 # their extensions may require, without fear of collisions with other
599 # their extensions may require, without fear of collisions with other
600 # ipython names that may develop later.
600 # ipython names that may develop later.
601 self.meta = Struct()
601 self.meta = Struct()
602
602
603 # Temporary files used for various purposes. Deleted at exit.
603 # Temporary files used for various purposes. Deleted at exit.
604 self.tempfiles = []
604 self.tempfiles = []
605 self.tempdirs = []
605 self.tempdirs = []
606
606
607 # Keep track of readline usage (later set by init_readline)
607 # Keep track of readline usage (later set by init_readline)
608 self.has_readline = False
608 self.has_readline = False
609
609
610 # keep track of where we started running (mainly for crash post-mortem)
610 # keep track of where we started running (mainly for crash post-mortem)
611 # This is not being used anywhere currently.
611 # This is not being used anywhere currently.
612 self.starting_dir = py3compat.getcwd()
612 self.starting_dir = py3compat.getcwd()
613
613
614 # Indentation management
614 # Indentation management
615 self.indent_current_nsp = 0
615 self.indent_current_nsp = 0
616
616
617 # Dict to track post-execution functions that have been registered
617 # Dict to track post-execution functions that have been registered
618 self._post_execute = {}
618 self._post_execute = {}
619
619
620 def init_environment(self):
620 def init_environment(self):
621 """Any changes we need to make to the user's environment."""
621 """Any changes we need to make to the user's environment."""
622 pass
622 pass
623
623
624 def init_encoding(self):
624 def init_encoding(self):
625 # Get system encoding at startup time. Certain terminals (like Emacs
625 # Get system encoding at startup time. Certain terminals (like Emacs
626 # under Win32 have it set to None, and we need to have a known valid
626 # under Win32 have it set to None, and we need to have a known valid
627 # encoding to use in the raw_input() method
627 # encoding to use in the raw_input() method
628 try:
628 try:
629 self.stdin_encoding = sys.stdin.encoding or 'ascii'
629 self.stdin_encoding = sys.stdin.encoding or 'ascii'
630 except AttributeError:
630 except AttributeError:
631 self.stdin_encoding = 'ascii'
631 self.stdin_encoding = 'ascii'
632
632
633 def init_syntax_highlighting(self):
633 def init_syntax_highlighting(self):
634 # Python source parser/formatter for syntax highlighting
634 # Python source parser/formatter for syntax highlighting
635 pyformat = PyColorize.Parser().format
635 pyformat = PyColorize.Parser().format
636 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
636 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
637
637
638 def init_pushd_popd_magic(self):
638 def init_pushd_popd_magic(self):
639 # for pushd/popd management
639 # for pushd/popd management
640 self.home_dir = get_home_dir()
640 self.home_dir = get_home_dir()
641
641
642 self.dir_stack = []
642 self.dir_stack = []
643
643
644 def init_logger(self):
644 def init_logger(self):
645 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
645 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
646 logmode='rotate')
646 logmode='rotate')
647
647
648 def init_logstart(self):
648 def init_logstart(self):
649 """Initialize logging in case it was requested at the command line.
649 """Initialize logging in case it was requested at the command line.
650 """
650 """
651 if self.logappend:
651 if self.logappend:
652 self.magic('logstart %s append' % self.logappend)
652 self.magic('logstart %s append' % self.logappend)
653 elif self.logfile:
653 elif self.logfile:
654 self.magic('logstart %s' % self.logfile)
654 self.magic('logstart %s' % self.logfile)
655 elif self.logstart:
655 elif self.logstart:
656 self.magic('logstart')
656 self.magic('logstart')
657
657
658 def init_builtins(self):
658 def init_builtins(self):
659 # A single, static flag that we set to True. Its presence indicates
659 # A single, static flag that we set to True. Its presence indicates
660 # that an IPython shell has been created, and we make no attempts at
660 # that an IPython shell has been created, and we make no attempts at
661 # removing on exit or representing the existence of more than one
661 # removing on exit or representing the existence of more than one
662 # IPython at a time.
662 # IPython at a time.
663 builtin_mod.__dict__['__IPYTHON__'] = True
663 builtin_mod.__dict__['__IPYTHON__'] = True
664
664
665 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
665 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
666 # manage on enter/exit, but with all our shells it's virtually
666 # manage on enter/exit, but with all our shells it's virtually
667 # impossible to get all the cases right. We're leaving the name in for
667 # impossible to get all the cases right. We're leaving the name in for
668 # those who adapted their codes to check for this flag, but will
668 # those who adapted their codes to check for this flag, but will
669 # eventually remove it after a few more releases.
669 # eventually remove it after a few more releases.
670 builtin_mod.__dict__['__IPYTHON__active'] = \
670 builtin_mod.__dict__['__IPYTHON__active'] = \
671 'Deprecated, check for __IPYTHON__'
671 'Deprecated, check for __IPYTHON__'
672
672
673 self.builtin_trap = BuiltinTrap(shell=self)
673 self.builtin_trap = BuiltinTrap(shell=self)
674
674
675 def init_inspector(self):
675 def init_inspector(self):
676 # Object inspector
676 # Object inspector
677 self.inspector = oinspect.Inspector(oinspect.InspectColors,
677 self.inspector = oinspect.Inspector(oinspect.InspectColors,
678 PyColorize.ANSICodeColors,
678 PyColorize.ANSICodeColors,
679 'NoColor',
679 'NoColor',
680 self.object_info_string_level)
680 self.object_info_string_level)
681
681
682 def init_io(self):
682 def init_io(self):
683 # This will just use sys.stdout and sys.stderr. If you want to
683 # This will just use sys.stdout and sys.stderr. If you want to
684 # override sys.stdout and sys.stderr themselves, you need to do that
684 # override sys.stdout and sys.stderr themselves, you need to do that
685 # *before* instantiating this class, because io holds onto
685 # *before* instantiating this class, because io holds onto
686 # references to the underlying streams.
686 # references to the underlying streams.
687 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
687 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
688 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
688 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
689 else:
689 else:
690 io.stdout = io.IOStream(sys.stdout)
690 io.stdout = io.IOStream(sys.stdout)
691 io.stderr = io.IOStream(sys.stderr)
691 io.stderr = io.IOStream(sys.stderr)
692
692
693 def init_prompts(self):
693 def init_prompts(self):
694 self.prompt_manager = PromptManager(shell=self, parent=self)
694 self.prompt_manager = PromptManager(shell=self, parent=self)
695 self.configurables.append(self.prompt_manager)
695 self.configurables.append(self.prompt_manager)
696 # Set system prompts, so that scripts can decide if they are running
696 # Set system prompts, so that scripts can decide if they are running
697 # interactively.
697 # interactively.
698 sys.ps1 = 'In : '
698 sys.ps1 = 'In : '
699 sys.ps2 = '...: '
699 sys.ps2 = '...: '
700 sys.ps3 = 'Out: '
700 sys.ps3 = 'Out: '
701
701
702 def init_display_formatter(self):
702 def init_display_formatter(self):
703 self.display_formatter = DisplayFormatter(parent=self)
703 self.display_formatter = DisplayFormatter(parent=self)
704 self.configurables.append(self.display_formatter)
704 self.configurables.append(self.display_formatter)
705
705
706 def init_display_pub(self):
706 def init_display_pub(self):
707 self.display_pub = self.display_pub_class(parent=self)
707 self.display_pub = self.display_pub_class(parent=self)
708 self.configurables.append(self.display_pub)
708 self.configurables.append(self.display_pub)
709
709
710 def init_data_pub(self):
710 def init_data_pub(self):
711 if not self.data_pub_class:
711 if not self.data_pub_class:
712 self.data_pub = None
712 self.data_pub = None
713 return
713 return
714 self.data_pub = self.data_pub_class(parent=self)
714 self.data_pub = self.data_pub_class(parent=self)
715 self.configurables.append(self.data_pub)
715 self.configurables.append(self.data_pub)
716
716
717 def init_displayhook(self):
717 def init_displayhook(self):
718 # Initialize displayhook, set in/out prompts and printing system
718 # Initialize displayhook, set in/out prompts and printing system
719 self.displayhook = self.displayhook_class(
719 self.displayhook = self.displayhook_class(
720 parent=self,
720 parent=self,
721 shell=self,
721 shell=self,
722 cache_size=self.cache_size,
722 cache_size=self.cache_size,
723 )
723 )
724 self.configurables.append(self.displayhook)
724 self.configurables.append(self.displayhook)
725 # This is a context manager that installs/revmoes the displayhook at
725 # This is a context manager that installs/revmoes the displayhook at
726 # the appropriate time.
726 # the appropriate time.
727 self.display_trap = DisplayTrap(hook=self.displayhook)
727 self.display_trap = DisplayTrap(hook=self.displayhook)
728
728
729 def init_virtualenv(self):
729 def init_virtualenv(self):
730 """Add a virtualenv to sys.path so the user can import modules from it.
730 """Add a virtualenv to sys.path so the user can import modules from it.
731 This isn't perfect: it doesn't use the Python interpreter with which the
731 This isn't perfect: it doesn't use the Python interpreter with which the
732 virtualenv was built, and it ignores the --no-site-packages option. A
732 virtualenv was built, and it ignores the --no-site-packages option. A
733 warning will appear suggesting the user installs IPython in the
733 warning will appear suggesting the user installs IPython in the
734 virtualenv, but for many cases, it probably works well enough.
734 virtualenv, but for many cases, it probably works well enough.
735
735
736 Adapted from code snippets online.
736 Adapted from code snippets online.
737
737
738 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
738 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
739 """
739 """
740 if 'VIRTUAL_ENV' not in os.environ:
740 if 'VIRTUAL_ENV' not in os.environ:
741 # Not in a virtualenv
741 # Not in a virtualenv
742 return
742 return
743
743
744 # venv detection:
744 # venv detection:
745 # stdlib venv may symlink sys.executable, so we can't use realpath.
745 # stdlib venv may symlink sys.executable, so we can't use realpath.
746 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
746 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
747 # So we just check every item in the symlink tree (generally <= 3)
747 # So we just check every item in the symlink tree (generally <= 3)
748 p = os.path.normcase(sys.executable)
748 p = os.path.normcase(sys.executable)
749 paths = [p]
749 paths = [p]
750 while os.path.islink(p):
750 while os.path.islink(p):
751 p = os.path.normcase(os.path.join(os.path.dirname(p), os.readlink(p)))
751 p = os.path.normcase(os.path.join(os.path.dirname(p), os.readlink(p)))
752 paths.append(p)
752 paths.append(p)
753 p_venv = os.path.normcase(os.environ['VIRTUAL_ENV'])
753 p_venv = os.path.normcase(os.environ['VIRTUAL_ENV'])
754 if any(p.startswith(p_venv) for p in paths):
754 if any(p.startswith(p_venv) for p in paths):
755 # Running properly in the virtualenv, don't need to do anything
755 # Running properly in the virtualenv, don't need to do anything
756 return
756 return
757
757
758 warn("Attempting to work in a virtualenv. If you encounter problems, please "
758 warn("Attempting to work in a virtualenv. If you encounter problems, please "
759 "install IPython inside the virtualenv.")
759 "install IPython inside the virtualenv.")
760 if sys.platform == "win32":
760 if sys.platform == "win32":
761 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
761 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
762 else:
762 else:
763 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
763 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
764 'python%d.%d' % sys.version_info[:2], 'site-packages')
764 'python%d.%d' % sys.version_info[:2], 'site-packages')
765
765
766 import site
766 import site
767 sys.path.insert(0, virtual_env)
767 sys.path.insert(0, virtual_env)
768 site.addsitedir(virtual_env)
768 site.addsitedir(virtual_env)
769
769
770 #-------------------------------------------------------------------------
770 #-------------------------------------------------------------------------
771 # Things related to injections into the sys module
771 # Things related to injections into the sys module
772 #-------------------------------------------------------------------------
772 #-------------------------------------------------------------------------
773
773
774 def save_sys_module_state(self):
774 def save_sys_module_state(self):
775 """Save the state of hooks in the sys module.
775 """Save the state of hooks in the sys module.
776
776
777 This has to be called after self.user_module is created.
777 This has to be called after self.user_module is created.
778 """
778 """
779 self._orig_sys_module_state = {}
779 self._orig_sys_module_state = {}
780 self._orig_sys_module_state['stdin'] = sys.stdin
780 self._orig_sys_module_state['stdin'] = sys.stdin
781 self._orig_sys_module_state['stdout'] = sys.stdout
781 self._orig_sys_module_state['stdout'] = sys.stdout
782 self._orig_sys_module_state['stderr'] = sys.stderr
782 self._orig_sys_module_state['stderr'] = sys.stderr
783 self._orig_sys_module_state['excepthook'] = sys.excepthook
783 self._orig_sys_module_state['excepthook'] = sys.excepthook
784 self._orig_sys_modules_main_name = self.user_module.__name__
784 self._orig_sys_modules_main_name = self.user_module.__name__
785 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
785 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
786
786
787 def restore_sys_module_state(self):
787 def restore_sys_module_state(self):
788 """Restore the state of the sys module."""
788 """Restore the state of the sys module."""
789 try:
789 try:
790 for k, v in iteritems(self._orig_sys_module_state):
790 for k, v in iteritems(self._orig_sys_module_state):
791 setattr(sys, k, v)
791 setattr(sys, k, v)
792 except AttributeError:
792 except AttributeError:
793 pass
793 pass
794 # Reset what what done in self.init_sys_modules
794 # Reset what what done in self.init_sys_modules
795 if self._orig_sys_modules_main_mod is not None:
795 if self._orig_sys_modules_main_mod is not None:
796 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
796 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
797
797
798 #-------------------------------------------------------------------------
798 #-------------------------------------------------------------------------
799 # Things related to the banner
799 # Things related to the banner
800 #-------------------------------------------------------------------------
800 #-------------------------------------------------------------------------
801
801
802 @property
802 @property
803 def banner(self):
803 def banner(self):
804 banner = self.banner1
804 banner = self.banner1
805 if self.profile and self.profile != 'default':
805 if self.profile and self.profile != 'default':
806 banner += '\nIPython profile: %s\n' % self.profile
806 banner += '\nIPython profile: %s\n' % self.profile
807 if self.banner2:
807 if self.banner2:
808 banner += '\n' + self.banner2
808 banner += '\n' + self.banner2
809 return banner
809 return banner
810
810
811 def show_banner(self, banner=None):
811 def show_banner(self, banner=None):
812 if banner is None:
812 if banner is None:
813 banner = self.banner
813 banner = self.banner
814 self.write(banner)
814 self.write(banner)
815
815
816 #-------------------------------------------------------------------------
816 #-------------------------------------------------------------------------
817 # Things related to hooks
817 # Things related to hooks
818 #-------------------------------------------------------------------------
818 #-------------------------------------------------------------------------
819
819
820 def init_hooks(self):
820 def init_hooks(self):
821 # hooks holds pointers used for user-side customizations
821 # hooks holds pointers used for user-side customizations
822 self.hooks = Struct()
822 self.hooks = Struct()
823
823
824 self.strdispatchers = {}
824 self.strdispatchers = {}
825
825
826 # Set all default hooks, defined in the IPython.hooks module.
826 # Set all default hooks, defined in the IPython.hooks module.
827 hooks = IPython.core.hooks
827 hooks = IPython.core.hooks
828 for hook_name in hooks.__all__:
828 for hook_name in hooks.__all__:
829 # default hooks have priority 100, i.e. low; user hooks should have
829 # default hooks have priority 100, i.e. low; user hooks should have
830 # 0-100 priority
830 # 0-100 priority
831 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
831 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
832
832
833 if self.display_page:
833 if self.display_page:
834 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
834 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
835
835
836 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
836 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
837 _warn_deprecated=True):
837 _warn_deprecated=True):
838 """set_hook(name,hook) -> sets an internal IPython hook.
838 """set_hook(name,hook) -> sets an internal IPython hook.
839
839
840 IPython exposes some of its internal API as user-modifiable hooks. By
840 IPython exposes some of its internal API as user-modifiable hooks. By
841 adding your function to one of these hooks, you can modify IPython's
841 adding your function to one of these hooks, you can modify IPython's
842 behavior to call at runtime your own routines."""
842 behavior to call at runtime your own routines."""
843
843
844 # At some point in the future, this should validate the hook before it
844 # At some point in the future, this should validate the hook before it
845 # accepts it. Probably at least check that the hook takes the number
845 # accepts it. Probably at least check that the hook takes the number
846 # of args it's supposed to.
846 # of args it's supposed to.
847
847
848 f = types.MethodType(hook,self)
848 f = types.MethodType(hook,self)
849
849
850 # check if the hook is for strdispatcher first
850 # check if the hook is for strdispatcher first
851 if str_key is not None:
851 if str_key is not None:
852 sdp = self.strdispatchers.get(name, StrDispatch())
852 sdp = self.strdispatchers.get(name, StrDispatch())
853 sdp.add_s(str_key, f, priority )
853 sdp.add_s(str_key, f, priority )
854 self.strdispatchers[name] = sdp
854 self.strdispatchers[name] = sdp
855 return
855 return
856 if re_key is not None:
856 if re_key is not None:
857 sdp = self.strdispatchers.get(name, StrDispatch())
857 sdp = self.strdispatchers.get(name, StrDispatch())
858 sdp.add_re(re.compile(re_key), f, priority )
858 sdp.add_re(re.compile(re_key), f, priority )
859 self.strdispatchers[name] = sdp
859 self.strdispatchers[name] = sdp
860 return
860 return
861
861
862 dp = getattr(self.hooks, name, None)
862 dp = getattr(self.hooks, name, None)
863 if name not in IPython.core.hooks.__all__:
863 if name not in IPython.core.hooks.__all__:
864 print("Warning! Hook '%s' is not one of %s" % \
864 print("Warning! Hook '%s' is not one of %s" % \
865 (name, IPython.core.hooks.__all__ ))
865 (name, IPython.core.hooks.__all__ ))
866
866
867 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
867 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
868 alternative = IPython.core.hooks.deprecated[name]
868 alternative = IPython.core.hooks.deprecated[name]
869 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
869 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
870
870
871 if not dp:
871 if not dp:
872 dp = IPython.core.hooks.CommandChainDispatcher()
872 dp = IPython.core.hooks.CommandChainDispatcher()
873
873
874 try:
874 try:
875 dp.add(f,priority)
875 dp.add(f,priority)
876 except AttributeError:
876 except AttributeError:
877 # it was not commandchain, plain old func - replace
877 # it was not commandchain, plain old func - replace
878 dp = f
878 dp = f
879
879
880 setattr(self.hooks,name, dp)
880 setattr(self.hooks,name, dp)
881
881
882 #-------------------------------------------------------------------------
882 #-------------------------------------------------------------------------
883 # Things related to events
883 # Things related to events
884 #-------------------------------------------------------------------------
884 #-------------------------------------------------------------------------
885
885
886 def init_events(self):
886 def init_events(self):
887 self.events = EventManager(self, available_events)
887 self.events = EventManager(self, available_events)
888
888
889 self.events.register("pre_execute", self._clear_warning_registry)
889 self.events.register("pre_execute", self._clear_warning_registry)
890
890
891 def register_post_execute(self, func):
891 def register_post_execute(self, func):
892 """DEPRECATED: Use ip.events.register('post_run_cell', func)
892 """DEPRECATED: Use ip.events.register('post_run_cell', func)
893
893
894 Register a function for calling after code execution.
894 Register a function for calling after code execution.
895 """
895 """
896 warn("ip.register_post_execute is deprecated, use "
896 warn("ip.register_post_execute is deprecated, use "
897 "ip.events.register('post_run_cell', func) instead.")
897 "ip.events.register('post_run_cell', func) instead.")
898 self.events.register('post_run_cell', func)
898 self.events.register('post_run_cell', func)
899
899
900 def _clear_warning_registry(self):
900 def _clear_warning_registry(self):
901 # clear the warning registry, so that different code blocks with
901 # clear the warning registry, so that different code blocks with
902 # overlapping line number ranges don't cause spurious suppression of
902 # overlapping line number ranges don't cause spurious suppression of
903 # warnings (see gh-6611 for details)
903 # warnings (see gh-6611 for details)
904 if "__warningregistry__" in self.user_global_ns:
904 if "__warningregistry__" in self.user_global_ns:
905 del self.user_global_ns["__warningregistry__"]
905 del self.user_global_ns["__warningregistry__"]
906
906
907 #-------------------------------------------------------------------------
907 #-------------------------------------------------------------------------
908 # Things related to the "main" module
908 # Things related to the "main" module
909 #-------------------------------------------------------------------------
909 #-------------------------------------------------------------------------
910
910
911 def new_main_mod(self, filename, modname):
911 def new_main_mod(self, filename, modname):
912 """Return a new 'main' module object for user code execution.
912 """Return a new 'main' module object for user code execution.
913
913
914 ``filename`` should be the path of the script which will be run in the
914 ``filename`` should be the path of the script which will be run in the
915 module. Requests with the same filename will get the same module, with
915 module. Requests with the same filename will get the same module, with
916 its namespace cleared.
916 its namespace cleared.
917
917
918 ``modname`` should be the module name - normally either '__main__' or
918 ``modname`` should be the module name - normally either '__main__' or
919 the basename of the file without the extension.
919 the basename of the file without the extension.
920
920
921 When scripts are executed via %run, we must keep a reference to their
921 When scripts are executed via %run, we must keep a reference to their
922 __main__ module around so that Python doesn't
922 __main__ module around so that Python doesn't
923 clear it, rendering references to module globals useless.
923 clear it, rendering references to module globals useless.
924
924
925 This method keeps said reference in a private dict, keyed by the
925 This method keeps said reference in a private dict, keyed by the
926 absolute path of the script. This way, for multiple executions of the
926 absolute path of the script. This way, for multiple executions of the
927 same script we only keep one copy of the namespace (the last one),
927 same script we only keep one copy of the namespace (the last one),
928 thus preventing memory leaks from old references while allowing the
928 thus preventing memory leaks from old references while allowing the
929 objects from the last execution to be accessible.
929 objects from the last execution to be accessible.
930 """
930 """
931 filename = os.path.abspath(filename)
931 filename = os.path.abspath(filename)
932 try:
932 try:
933 main_mod = self._main_mod_cache[filename]
933 main_mod = self._main_mod_cache[filename]
934 except KeyError:
934 except KeyError:
935 main_mod = self._main_mod_cache[filename] = types.ModuleType(
935 main_mod = self._main_mod_cache[filename] = types.ModuleType(
936 py3compat.cast_bytes_py2(modname),
936 py3compat.cast_bytes_py2(modname),
937 doc="Module created for script run in IPython")
937 doc="Module created for script run in IPython")
938 else:
938 else:
939 main_mod.__dict__.clear()
939 main_mod.__dict__.clear()
940 main_mod.__name__ = modname
940 main_mod.__name__ = modname
941
941
942 main_mod.__file__ = filename
942 main_mod.__file__ = filename
943 # It seems pydoc (and perhaps others) needs any module instance to
943 # It seems pydoc (and perhaps others) needs any module instance to
944 # implement a __nonzero__ method
944 # implement a __nonzero__ method
945 main_mod.__nonzero__ = lambda : True
945 main_mod.__nonzero__ = lambda : True
946
946
947 return main_mod
947 return main_mod
948
948
949 def clear_main_mod_cache(self):
949 def clear_main_mod_cache(self):
950 """Clear the cache of main modules.
950 """Clear the cache of main modules.
951
951
952 Mainly for use by utilities like %reset.
952 Mainly for use by utilities like %reset.
953
953
954 Examples
954 Examples
955 --------
955 --------
956
956
957 In [15]: import IPython
957 In [15]: import IPython
958
958
959 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
959 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
960
960
961 In [17]: len(_ip._main_mod_cache) > 0
961 In [17]: len(_ip._main_mod_cache) > 0
962 Out[17]: True
962 Out[17]: True
963
963
964 In [18]: _ip.clear_main_mod_cache()
964 In [18]: _ip.clear_main_mod_cache()
965
965
966 In [19]: len(_ip._main_mod_cache) == 0
966 In [19]: len(_ip._main_mod_cache) == 0
967 Out[19]: True
967 Out[19]: True
968 """
968 """
969 self._main_mod_cache.clear()
969 self._main_mod_cache.clear()
970
970
971 #-------------------------------------------------------------------------
971 #-------------------------------------------------------------------------
972 # Things related to debugging
972 # Things related to debugging
973 #-------------------------------------------------------------------------
973 #-------------------------------------------------------------------------
974
974
975 def init_pdb(self):
975 def init_pdb(self):
976 # Set calling of pdb on exceptions
976 # Set calling of pdb on exceptions
977 # self.call_pdb is a property
977 # self.call_pdb is a property
978 self.call_pdb = self.pdb
978 self.call_pdb = self.pdb
979
979
980 def _get_call_pdb(self):
980 def _get_call_pdb(self):
981 return self._call_pdb
981 return self._call_pdb
982
982
983 def _set_call_pdb(self,val):
983 def _set_call_pdb(self,val):
984
984
985 if val not in (0,1,False,True):
985 if val not in (0,1,False,True):
986 raise ValueError('new call_pdb value must be boolean')
986 raise ValueError('new call_pdb value must be boolean')
987
987
988 # store value in instance
988 # store value in instance
989 self._call_pdb = val
989 self._call_pdb = val
990
990
991 # notify the actual exception handlers
991 # notify the actual exception handlers
992 self.InteractiveTB.call_pdb = val
992 self.InteractiveTB.call_pdb = val
993
993
994 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
994 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
995 'Control auto-activation of pdb at exceptions')
995 'Control auto-activation of pdb at exceptions')
996
996
997 def debugger(self,force=False):
997 def debugger(self,force=False):
998 """Call the pydb/pdb debugger.
998 """Call the pydb/pdb debugger.
999
999
1000 Keywords:
1000 Keywords:
1001
1001
1002 - force(False): by default, this routine checks the instance call_pdb
1002 - force(False): by default, this routine checks the instance call_pdb
1003 flag and does not actually invoke the debugger if the flag is false.
1003 flag and does not actually invoke the debugger if the flag is false.
1004 The 'force' option forces the debugger to activate even if the flag
1004 The 'force' option forces the debugger to activate even if the flag
1005 is false.
1005 is false.
1006 """
1006 """
1007
1007
1008 if not (force or self.call_pdb):
1008 if not (force or self.call_pdb):
1009 return
1009 return
1010
1010
1011 if not hasattr(sys,'last_traceback'):
1011 if not hasattr(sys,'last_traceback'):
1012 error('No traceback has been produced, nothing to debug.')
1012 error('No traceback has been produced, nothing to debug.')
1013 return
1013 return
1014
1014
1015 # use pydb if available
1015 # use pydb if available
1016 if debugger.has_pydb:
1016 if debugger.has_pydb:
1017 from pydb import pm
1017 from pydb import pm
1018 else:
1018 else:
1019 # fallback to our internal debugger
1019 # fallback to our internal debugger
1020 pm = lambda : self.InteractiveTB.debugger(force=True)
1020 pm = lambda : self.InteractiveTB.debugger(force=True)
1021
1021
1022 with self.readline_no_record:
1022 with self.readline_no_record:
1023 pm()
1023 pm()
1024
1024
1025 #-------------------------------------------------------------------------
1025 #-------------------------------------------------------------------------
1026 # Things related to IPython's various namespaces
1026 # Things related to IPython's various namespaces
1027 #-------------------------------------------------------------------------
1027 #-------------------------------------------------------------------------
1028 default_user_namespaces = True
1028 default_user_namespaces = True
1029
1029
1030 def init_create_namespaces(self, user_module=None, user_ns=None):
1030 def init_create_namespaces(self, user_module=None, user_ns=None):
1031 # Create the namespace where the user will operate. user_ns is
1031 # Create the namespace where the user will operate. user_ns is
1032 # normally the only one used, and it is passed to the exec calls as
1032 # normally the only one used, and it is passed to the exec calls as
1033 # the locals argument. But we do carry a user_global_ns namespace
1033 # the locals argument. But we do carry a user_global_ns namespace
1034 # given as the exec 'globals' argument, This is useful in embedding
1034 # given as the exec 'globals' argument, This is useful in embedding
1035 # situations where the ipython shell opens in a context where the
1035 # situations where the ipython shell opens in a context where the
1036 # distinction between locals and globals is meaningful. For
1036 # distinction between locals and globals is meaningful. For
1037 # non-embedded contexts, it is just the same object as the user_ns dict.
1037 # non-embedded contexts, it is just the same object as the user_ns dict.
1038
1038
1039 # FIXME. For some strange reason, __builtins__ is showing up at user
1039 # FIXME. For some strange reason, __builtins__ is showing up at user
1040 # level as a dict instead of a module. This is a manual fix, but I
1040 # level as a dict instead of a module. This is a manual fix, but I
1041 # should really track down where the problem is coming from. Alex
1041 # should really track down where the problem is coming from. Alex
1042 # Schmolck reported this problem first.
1042 # Schmolck reported this problem first.
1043
1043
1044 # A useful post by Alex Martelli on this topic:
1044 # A useful post by Alex Martelli on this topic:
1045 # Re: inconsistent value from __builtins__
1045 # Re: inconsistent value from __builtins__
1046 # Von: Alex Martelli <aleaxit@yahoo.com>
1046 # Von: Alex Martelli <aleaxit@yahoo.com>
1047 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1047 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1048 # Gruppen: comp.lang.python
1048 # Gruppen: comp.lang.python
1049
1049
1050 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1050 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1051 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1051 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1052 # > <type 'dict'>
1052 # > <type 'dict'>
1053 # > >>> print type(__builtins__)
1053 # > >>> print type(__builtins__)
1054 # > <type 'module'>
1054 # > <type 'module'>
1055 # > Is this difference in return value intentional?
1055 # > Is this difference in return value intentional?
1056
1056
1057 # Well, it's documented that '__builtins__' can be either a dictionary
1057 # Well, it's documented that '__builtins__' can be either a dictionary
1058 # or a module, and it's been that way for a long time. Whether it's
1058 # or a module, and it's been that way for a long time. Whether it's
1059 # intentional (or sensible), I don't know. In any case, the idea is
1059 # intentional (or sensible), I don't know. In any case, the idea is
1060 # that if you need to access the built-in namespace directly, you
1060 # that if you need to access the built-in namespace directly, you
1061 # should start with "import __builtin__" (note, no 's') which will
1061 # should start with "import __builtin__" (note, no 's') which will
1062 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1062 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1063
1063
1064 # These routines return a properly built module and dict as needed by
1064 # These routines return a properly built module and dict as needed by
1065 # the rest of the code, and can also be used by extension writers to
1065 # the rest of the code, and can also be used by extension writers to
1066 # generate properly initialized namespaces.
1066 # generate properly initialized namespaces.
1067 if (user_ns is not None) or (user_module is not None):
1067 if (user_ns is not None) or (user_module is not None):
1068 self.default_user_namespaces = False
1068 self.default_user_namespaces = False
1069 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1069 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1070
1070
1071 # A record of hidden variables we have added to the user namespace, so
1071 # A record of hidden variables we have added to the user namespace, so
1072 # we can list later only variables defined in actual interactive use.
1072 # we can list later only variables defined in actual interactive use.
1073 self.user_ns_hidden = {}
1073 self.user_ns_hidden = {}
1074
1074
1075 # Now that FakeModule produces a real module, we've run into a nasty
1075 # Now that FakeModule produces a real module, we've run into a nasty
1076 # problem: after script execution (via %run), the module where the user
1076 # problem: after script execution (via %run), the module where the user
1077 # code ran is deleted. Now that this object is a true module (needed
1077 # code ran is deleted. Now that this object is a true module (needed
1078 # so docetst and other tools work correctly), the Python module
1078 # so docetst and other tools work correctly), the Python module
1079 # teardown mechanism runs over it, and sets to None every variable
1079 # teardown mechanism runs over it, and sets to None every variable
1080 # present in that module. Top-level references to objects from the
1080 # present in that module. Top-level references to objects from the
1081 # script survive, because the user_ns is updated with them. However,
1081 # script survive, because the user_ns is updated with them. However,
1082 # calling functions defined in the script that use other things from
1082 # calling functions defined in the script that use other things from
1083 # the script will fail, because the function's closure had references
1083 # the script will fail, because the function's closure had references
1084 # to the original objects, which are now all None. So we must protect
1084 # to the original objects, which are now all None. So we must protect
1085 # these modules from deletion by keeping a cache.
1085 # these modules from deletion by keeping a cache.
1086 #
1086 #
1087 # To avoid keeping stale modules around (we only need the one from the
1087 # To avoid keeping stale modules around (we only need the one from the
1088 # last run), we use a dict keyed with the full path to the script, so
1088 # last run), we use a dict keyed with the full path to the script, so
1089 # only the last version of the module is held in the cache. Note,
1089 # only the last version of the module is held in the cache. Note,
1090 # however, that we must cache the module *namespace contents* (their
1090 # however, that we must cache the module *namespace contents* (their
1091 # __dict__). Because if we try to cache the actual modules, old ones
1091 # __dict__). Because if we try to cache the actual modules, old ones
1092 # (uncached) could be destroyed while still holding references (such as
1092 # (uncached) could be destroyed while still holding references (such as
1093 # those held by GUI objects that tend to be long-lived)>
1093 # those held by GUI objects that tend to be long-lived)>
1094 #
1094 #
1095 # The %reset command will flush this cache. See the cache_main_mod()
1095 # The %reset command will flush this cache. See the cache_main_mod()
1096 # and clear_main_mod_cache() methods for details on use.
1096 # and clear_main_mod_cache() methods for details on use.
1097
1097
1098 # This is the cache used for 'main' namespaces
1098 # This is the cache used for 'main' namespaces
1099 self._main_mod_cache = {}
1099 self._main_mod_cache = {}
1100
1100
1101 # A table holding all the namespaces IPython deals with, so that
1101 # A table holding all the namespaces IPython deals with, so that
1102 # introspection facilities can search easily.
1102 # introspection facilities can search easily.
1103 self.ns_table = {'user_global':self.user_module.__dict__,
1103 self.ns_table = {'user_global':self.user_module.__dict__,
1104 'user_local':self.user_ns,
1104 'user_local':self.user_ns,
1105 'builtin':builtin_mod.__dict__
1105 'builtin':builtin_mod.__dict__
1106 }
1106 }
1107
1107
1108 @property
1108 @property
1109 def user_global_ns(self):
1109 def user_global_ns(self):
1110 return self.user_module.__dict__
1110 return self.user_module.__dict__
1111
1111
1112 def prepare_user_module(self, user_module=None, user_ns=None):
1112 def prepare_user_module(self, user_module=None, user_ns=None):
1113 """Prepare the module and namespace in which user code will be run.
1113 """Prepare the module and namespace in which user code will be run.
1114
1114
1115 When IPython is started normally, both parameters are None: a new module
1115 When IPython is started normally, both parameters are None: a new module
1116 is created automatically, and its __dict__ used as the namespace.
1116 is created automatically, and its __dict__ used as the namespace.
1117
1117
1118 If only user_module is provided, its __dict__ is used as the namespace.
1118 If only user_module is provided, its __dict__ is used as the namespace.
1119 If only user_ns is provided, a dummy module is created, and user_ns
1119 If only user_ns is provided, a dummy module is created, and user_ns
1120 becomes the global namespace. If both are provided (as they may be
1120 becomes the global namespace. If both are provided (as they may be
1121 when embedding), user_ns is the local namespace, and user_module
1121 when embedding), user_ns is the local namespace, and user_module
1122 provides the global namespace.
1122 provides the global namespace.
1123
1123
1124 Parameters
1124 Parameters
1125 ----------
1125 ----------
1126 user_module : module, optional
1126 user_module : module, optional
1127 The current user module in which IPython is being run. If None,
1127 The current user module in which IPython is being run. If None,
1128 a clean module will be created.
1128 a clean module will be created.
1129 user_ns : dict, optional
1129 user_ns : dict, optional
1130 A namespace in which to run interactive commands.
1130 A namespace in which to run interactive commands.
1131
1131
1132 Returns
1132 Returns
1133 -------
1133 -------
1134 A tuple of user_module and user_ns, each properly initialised.
1134 A tuple of user_module and user_ns, each properly initialised.
1135 """
1135 """
1136 if user_module is None and user_ns is not None:
1136 if user_module is None and user_ns is not None:
1137 user_ns.setdefault("__name__", "__main__")
1137 user_ns.setdefault("__name__", "__main__")
1138 user_module = DummyMod()
1138 user_module = DummyMod()
1139 user_module.__dict__ = user_ns
1139 user_module.__dict__ = user_ns
1140
1140
1141 if user_module is None:
1141 if user_module is None:
1142 user_module = types.ModuleType("__main__",
1142 user_module = types.ModuleType("__main__",
1143 doc="Automatically created module for IPython interactive environment")
1143 doc="Automatically created module for IPython interactive environment")
1144
1144
1145 # We must ensure that __builtin__ (without the final 's') is always
1145 # We must ensure that __builtin__ (without the final 's') is always
1146 # available and pointing to the __builtin__ *module*. For more details:
1146 # available and pointing to the __builtin__ *module*. For more details:
1147 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1147 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1148 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1148 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1149 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1149 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1150
1150
1151 if user_ns is None:
1151 if user_ns is None:
1152 user_ns = user_module.__dict__
1152 user_ns = user_module.__dict__
1153
1153
1154 return user_module, user_ns
1154 return user_module, user_ns
1155
1155
1156 def init_sys_modules(self):
1156 def init_sys_modules(self):
1157 # We need to insert into sys.modules something that looks like a
1157 # We need to insert into sys.modules something that looks like a
1158 # module but which accesses the IPython namespace, for shelve and
1158 # module but which accesses the IPython namespace, for shelve and
1159 # pickle to work interactively. Normally they rely on getting
1159 # pickle to work interactively. Normally they rely on getting
1160 # everything out of __main__, but for embedding purposes each IPython
1160 # everything out of __main__, but for embedding purposes each IPython
1161 # instance has its own private namespace, so we can't go shoving
1161 # instance has its own private namespace, so we can't go shoving
1162 # everything into __main__.
1162 # everything into __main__.
1163
1163
1164 # note, however, that we should only do this for non-embedded
1164 # note, however, that we should only do this for non-embedded
1165 # ipythons, which really mimic the __main__.__dict__ with their own
1165 # ipythons, which really mimic the __main__.__dict__ with their own
1166 # namespace. Embedded instances, on the other hand, should not do
1166 # namespace. Embedded instances, on the other hand, should not do
1167 # this because they need to manage the user local/global namespaces
1167 # this because they need to manage the user local/global namespaces
1168 # only, but they live within a 'normal' __main__ (meaning, they
1168 # only, but they live within a 'normal' __main__ (meaning, they
1169 # shouldn't overtake the execution environment of the script they're
1169 # shouldn't overtake the execution environment of the script they're
1170 # embedded in).
1170 # embedded in).
1171
1171
1172 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1172 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1173 main_name = self.user_module.__name__
1173 main_name = self.user_module.__name__
1174 sys.modules[main_name] = self.user_module
1174 sys.modules[main_name] = self.user_module
1175
1175
1176 def init_user_ns(self):
1176 def init_user_ns(self):
1177 """Initialize all user-visible namespaces to their minimum defaults.
1177 """Initialize all user-visible namespaces to their minimum defaults.
1178
1178
1179 Certain history lists are also initialized here, as they effectively
1179 Certain history lists are also initialized here, as they effectively
1180 act as user namespaces.
1180 act as user namespaces.
1181
1181
1182 Notes
1182 Notes
1183 -----
1183 -----
1184 All data structures here are only filled in, they are NOT reset by this
1184 All data structures here are only filled in, they are NOT reset by this
1185 method. If they were not empty before, data will simply be added to
1185 method. If they were not empty before, data will simply be added to
1186 therm.
1186 therm.
1187 """
1187 """
1188 # This function works in two parts: first we put a few things in
1188 # This function works in two parts: first we put a few things in
1189 # user_ns, and we sync that contents into user_ns_hidden so that these
1189 # user_ns, and we sync that contents into user_ns_hidden so that these
1190 # initial variables aren't shown by %who. After the sync, we add the
1190 # initial variables aren't shown by %who. After the sync, we add the
1191 # rest of what we *do* want the user to see with %who even on a new
1191 # rest of what we *do* want the user to see with %who even on a new
1192 # session (probably nothing, so theye really only see their own stuff)
1192 # session (probably nothing, so theye really only see their own stuff)
1193
1193
1194 # The user dict must *always* have a __builtin__ reference to the
1194 # The user dict must *always* have a __builtin__ reference to the
1195 # Python standard __builtin__ namespace, which must be imported.
1195 # Python standard __builtin__ namespace, which must be imported.
1196 # This is so that certain operations in prompt evaluation can be
1196 # This is so that certain operations in prompt evaluation can be
1197 # reliably executed with builtins. Note that we can NOT use
1197 # reliably executed with builtins. Note that we can NOT use
1198 # __builtins__ (note the 's'), because that can either be a dict or a
1198 # __builtins__ (note the 's'), because that can either be a dict or a
1199 # module, and can even mutate at runtime, depending on the context
1199 # module, and can even mutate at runtime, depending on the context
1200 # (Python makes no guarantees on it). In contrast, __builtin__ is
1200 # (Python makes no guarantees on it). In contrast, __builtin__ is
1201 # always a module object, though it must be explicitly imported.
1201 # always a module object, though it must be explicitly imported.
1202
1202
1203 # For more details:
1203 # For more details:
1204 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1204 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1205 ns = dict()
1205 ns = dict()
1206
1206
1207 # make global variables for user access to the histories
1207 # make global variables for user access to the histories
1208 ns['_ih'] = self.history_manager.input_hist_parsed
1208 ns['_ih'] = self.history_manager.input_hist_parsed
1209 ns['_oh'] = self.history_manager.output_hist
1209 ns['_oh'] = self.history_manager.output_hist
1210 ns['_dh'] = self.history_manager.dir_hist
1210 ns['_dh'] = self.history_manager.dir_hist
1211
1211
1212 ns['_sh'] = shadowns
1212 ns['_sh'] = shadowns
1213
1213
1214 # user aliases to input and output histories. These shouldn't show up
1214 # user aliases to input and output histories. These shouldn't show up
1215 # in %who, as they can have very large reprs.
1215 # in %who, as they can have very large reprs.
1216 ns['In'] = self.history_manager.input_hist_parsed
1216 ns['In'] = self.history_manager.input_hist_parsed
1217 ns['Out'] = self.history_manager.output_hist
1217 ns['Out'] = self.history_manager.output_hist
1218
1218
1219 # Store myself as the public api!!!
1219 # Store myself as the public api!!!
1220 ns['get_ipython'] = self.get_ipython
1220 ns['get_ipython'] = self.get_ipython
1221
1221
1222 ns['exit'] = self.exiter
1222 ns['exit'] = self.exiter
1223 ns['quit'] = self.exiter
1223 ns['quit'] = self.exiter
1224
1224
1225 # Sync what we've added so far to user_ns_hidden so these aren't seen
1225 # Sync what we've added so far to user_ns_hidden so these aren't seen
1226 # by %who
1226 # by %who
1227 self.user_ns_hidden.update(ns)
1227 self.user_ns_hidden.update(ns)
1228
1228
1229 # Anything put into ns now would show up in %who. Think twice before
1229 # Anything put into ns now would show up in %who. Think twice before
1230 # putting anything here, as we really want %who to show the user their
1230 # putting anything here, as we really want %who to show the user their
1231 # stuff, not our variables.
1231 # stuff, not our variables.
1232
1232
1233 # Finally, update the real user's namespace
1233 # Finally, update the real user's namespace
1234 self.user_ns.update(ns)
1234 self.user_ns.update(ns)
1235
1235
1236 @property
1236 @property
1237 def all_ns_refs(self):
1237 def all_ns_refs(self):
1238 """Get a list of references to all the namespace dictionaries in which
1238 """Get a list of references to all the namespace dictionaries in which
1239 IPython might store a user-created object.
1239 IPython might store a user-created object.
1240
1240
1241 Note that this does not include the displayhook, which also caches
1241 Note that this does not include the displayhook, which also caches
1242 objects from the output."""
1242 objects from the output."""
1243 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1243 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1244 [m.__dict__ for m in self._main_mod_cache.values()]
1244 [m.__dict__ for m in self._main_mod_cache.values()]
1245
1245
1246 def reset(self, new_session=True):
1246 def reset(self, new_session=True):
1247 """Clear all internal namespaces, and attempt to release references to
1247 """Clear all internal namespaces, and attempt to release references to
1248 user objects.
1248 user objects.
1249
1249
1250 If new_session is True, a new history session will be opened.
1250 If new_session is True, a new history session will be opened.
1251 """
1251 """
1252 # Clear histories
1252 # Clear histories
1253 self.history_manager.reset(new_session)
1253 self.history_manager.reset(new_session)
1254 # Reset counter used to index all histories
1254 # Reset counter used to index all histories
1255 if new_session:
1255 if new_session:
1256 self.execution_count = 1
1256 self.execution_count = 1
1257
1257
1258 # Flush cached output items
1258 # Flush cached output items
1259 if self.displayhook.do_full_cache:
1259 if self.displayhook.do_full_cache:
1260 self.displayhook.flush()
1260 self.displayhook.flush()
1261
1261
1262 # The main execution namespaces must be cleared very carefully,
1262 # The main execution namespaces must be cleared very carefully,
1263 # skipping the deletion of the builtin-related keys, because doing so
1263 # skipping the deletion of the builtin-related keys, because doing so
1264 # would cause errors in many object's __del__ methods.
1264 # would cause errors in many object's __del__ methods.
1265 if self.user_ns is not self.user_global_ns:
1265 if self.user_ns is not self.user_global_ns:
1266 self.user_ns.clear()
1266 self.user_ns.clear()
1267 ns = self.user_global_ns
1267 ns = self.user_global_ns
1268 drop_keys = set(ns.keys())
1268 drop_keys = set(ns.keys())
1269 drop_keys.discard('__builtin__')
1269 drop_keys.discard('__builtin__')
1270 drop_keys.discard('__builtins__')
1270 drop_keys.discard('__builtins__')
1271 drop_keys.discard('__name__')
1271 drop_keys.discard('__name__')
1272 for k in drop_keys:
1272 for k in drop_keys:
1273 del ns[k]
1273 del ns[k]
1274
1274
1275 self.user_ns_hidden.clear()
1275 self.user_ns_hidden.clear()
1276
1276
1277 # Restore the user namespaces to minimal usability
1277 # Restore the user namespaces to minimal usability
1278 self.init_user_ns()
1278 self.init_user_ns()
1279
1279
1280 # Restore the default and user aliases
1280 # Restore the default and user aliases
1281 self.alias_manager.clear_aliases()
1281 self.alias_manager.clear_aliases()
1282 self.alias_manager.init_aliases()
1282 self.alias_manager.init_aliases()
1283
1283
1284 # Flush the private list of module references kept for script
1284 # Flush the private list of module references kept for script
1285 # execution protection
1285 # execution protection
1286 self.clear_main_mod_cache()
1286 self.clear_main_mod_cache()
1287
1287
1288 def del_var(self, varname, by_name=False):
1288 def del_var(self, varname, by_name=False):
1289 """Delete a variable from the various namespaces, so that, as
1289 """Delete a variable from the various namespaces, so that, as
1290 far as possible, we're not keeping any hidden references to it.
1290 far as possible, we're not keeping any hidden references to it.
1291
1291
1292 Parameters
1292 Parameters
1293 ----------
1293 ----------
1294 varname : str
1294 varname : str
1295 The name of the variable to delete.
1295 The name of the variable to delete.
1296 by_name : bool
1296 by_name : bool
1297 If True, delete variables with the given name in each
1297 If True, delete variables with the given name in each
1298 namespace. If False (default), find the variable in the user
1298 namespace. If False (default), find the variable in the user
1299 namespace, and delete references to it.
1299 namespace, and delete references to it.
1300 """
1300 """
1301 if varname in ('__builtin__', '__builtins__'):
1301 if varname in ('__builtin__', '__builtins__'):
1302 raise ValueError("Refusing to delete %s" % varname)
1302 raise ValueError("Refusing to delete %s" % varname)
1303
1303
1304 ns_refs = self.all_ns_refs
1304 ns_refs = self.all_ns_refs
1305
1305
1306 if by_name: # Delete by name
1306 if by_name: # Delete by name
1307 for ns in ns_refs:
1307 for ns in ns_refs:
1308 try:
1308 try:
1309 del ns[varname]
1309 del ns[varname]
1310 except KeyError:
1310 except KeyError:
1311 pass
1311 pass
1312 else: # Delete by object
1312 else: # Delete by object
1313 try:
1313 try:
1314 obj = self.user_ns[varname]
1314 obj = self.user_ns[varname]
1315 except KeyError:
1315 except KeyError:
1316 raise NameError("name '%s' is not defined" % varname)
1316 raise NameError("name '%s' is not defined" % varname)
1317 # Also check in output history
1317 # Also check in output history
1318 ns_refs.append(self.history_manager.output_hist)
1318 ns_refs.append(self.history_manager.output_hist)
1319 for ns in ns_refs:
1319 for ns in ns_refs:
1320 to_delete = [n for n, o in iteritems(ns) if o is obj]
1320 to_delete = [n for n, o in iteritems(ns) if o is obj]
1321 for name in to_delete:
1321 for name in to_delete:
1322 del ns[name]
1322 del ns[name]
1323
1323
1324 # displayhook keeps extra references, but not in a dictionary
1324 # displayhook keeps extra references, but not in a dictionary
1325 for name in ('_', '__', '___'):
1325 for name in ('_', '__', '___'):
1326 if getattr(self.displayhook, name) is obj:
1326 if getattr(self.displayhook, name) is obj:
1327 setattr(self.displayhook, name, None)
1327 setattr(self.displayhook, name, None)
1328
1328
1329 def reset_selective(self, regex=None):
1329 def reset_selective(self, regex=None):
1330 """Clear selective variables from internal namespaces based on a
1330 """Clear selective variables from internal namespaces based on a
1331 specified regular expression.
1331 specified regular expression.
1332
1332
1333 Parameters
1333 Parameters
1334 ----------
1334 ----------
1335 regex : string or compiled pattern, optional
1335 regex : string or compiled pattern, optional
1336 A regular expression pattern that will be used in searching
1336 A regular expression pattern that will be used in searching
1337 variable names in the users namespaces.
1337 variable names in the users namespaces.
1338 """
1338 """
1339 if regex is not None:
1339 if regex is not None:
1340 try:
1340 try:
1341 m = re.compile(regex)
1341 m = re.compile(regex)
1342 except TypeError:
1342 except TypeError:
1343 raise TypeError('regex must be a string or compiled pattern')
1343 raise TypeError('regex must be a string or compiled pattern')
1344 # Search for keys in each namespace that match the given regex
1344 # Search for keys in each namespace that match the given regex
1345 # If a match is found, delete the key/value pair.
1345 # If a match is found, delete the key/value pair.
1346 for ns in self.all_ns_refs:
1346 for ns in self.all_ns_refs:
1347 for var in ns:
1347 for var in ns:
1348 if m.search(var):
1348 if m.search(var):
1349 del ns[var]
1349 del ns[var]
1350
1350
1351 def push(self, variables, interactive=True):
1351 def push(self, variables, interactive=True):
1352 """Inject a group of variables into the IPython user namespace.
1352 """Inject a group of variables into the IPython user namespace.
1353
1353
1354 Parameters
1354 Parameters
1355 ----------
1355 ----------
1356 variables : dict, str or list/tuple of str
1356 variables : dict, str or list/tuple of str
1357 The variables to inject into the user's namespace. If a dict, a
1357 The variables to inject into the user's namespace. If a dict, a
1358 simple update is done. If a str, the string is assumed to have
1358 simple update is done. If a str, the string is assumed to have
1359 variable names separated by spaces. A list/tuple of str can also
1359 variable names separated by spaces. A list/tuple of str can also
1360 be used to give the variable names. If just the variable names are
1360 be used to give the variable names. If just the variable names are
1361 give (list/tuple/str) then the variable values looked up in the
1361 give (list/tuple/str) then the variable values looked up in the
1362 callers frame.
1362 callers frame.
1363 interactive : bool
1363 interactive : bool
1364 If True (default), the variables will be listed with the ``who``
1364 If True (default), the variables will be listed with the ``who``
1365 magic.
1365 magic.
1366 """
1366 """
1367 vdict = None
1367 vdict = None
1368
1368
1369 # We need a dict of name/value pairs to do namespace updates.
1369 # We need a dict of name/value pairs to do namespace updates.
1370 if isinstance(variables, dict):
1370 if isinstance(variables, dict):
1371 vdict = variables
1371 vdict = variables
1372 elif isinstance(variables, string_types+(list, tuple)):
1372 elif isinstance(variables, string_types+(list, tuple)):
1373 if isinstance(variables, string_types):
1373 if isinstance(variables, string_types):
1374 vlist = variables.split()
1374 vlist = variables.split()
1375 else:
1375 else:
1376 vlist = variables
1376 vlist = variables
1377 vdict = {}
1377 vdict = {}
1378 cf = sys._getframe(1)
1378 cf = sys._getframe(1)
1379 for name in vlist:
1379 for name in vlist:
1380 try:
1380 try:
1381 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1381 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1382 except:
1382 except:
1383 print('Could not get variable %s from %s' %
1383 print('Could not get variable %s from %s' %
1384 (name,cf.f_code.co_name))
1384 (name,cf.f_code.co_name))
1385 else:
1385 else:
1386 raise ValueError('variables must be a dict/str/list/tuple')
1386 raise ValueError('variables must be a dict/str/list/tuple')
1387
1387
1388 # Propagate variables to user namespace
1388 # Propagate variables to user namespace
1389 self.user_ns.update(vdict)
1389 self.user_ns.update(vdict)
1390
1390
1391 # And configure interactive visibility
1391 # And configure interactive visibility
1392 user_ns_hidden = self.user_ns_hidden
1392 user_ns_hidden = self.user_ns_hidden
1393 if interactive:
1393 if interactive:
1394 for name in vdict:
1394 for name in vdict:
1395 user_ns_hidden.pop(name, None)
1395 user_ns_hidden.pop(name, None)
1396 else:
1396 else:
1397 user_ns_hidden.update(vdict)
1397 user_ns_hidden.update(vdict)
1398
1398
1399 def drop_by_id(self, variables):
1399 def drop_by_id(self, variables):
1400 """Remove a dict of variables from the user namespace, if they are the
1400 """Remove a dict of variables from the user namespace, if they are the
1401 same as the values in the dictionary.
1401 same as the values in the dictionary.
1402
1402
1403 This is intended for use by extensions: variables that they've added can
1403 This is intended for use by extensions: variables that they've added can
1404 be taken back out if they are unloaded, without removing any that the
1404 be taken back out if they are unloaded, without removing any that the
1405 user has overwritten.
1405 user has overwritten.
1406
1406
1407 Parameters
1407 Parameters
1408 ----------
1408 ----------
1409 variables : dict
1409 variables : dict
1410 A dictionary mapping object names (as strings) to the objects.
1410 A dictionary mapping object names (as strings) to the objects.
1411 """
1411 """
1412 for name, obj in iteritems(variables):
1412 for name, obj in iteritems(variables):
1413 if name in self.user_ns and self.user_ns[name] is obj:
1413 if name in self.user_ns and self.user_ns[name] is obj:
1414 del self.user_ns[name]
1414 del self.user_ns[name]
1415 self.user_ns_hidden.pop(name, None)
1415 self.user_ns_hidden.pop(name, None)
1416
1416
1417 #-------------------------------------------------------------------------
1417 #-------------------------------------------------------------------------
1418 # Things related to object introspection
1418 # Things related to object introspection
1419 #-------------------------------------------------------------------------
1419 #-------------------------------------------------------------------------
1420
1420
1421 def _ofind(self, oname, namespaces=None):
1421 def _ofind(self, oname, namespaces=None):
1422 """Find an object in the available namespaces.
1422 """Find an object in the available namespaces.
1423
1423
1424 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1424 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1425
1425
1426 Has special code to detect magic functions.
1426 Has special code to detect magic functions.
1427 """
1427 """
1428 oname = oname.strip()
1428 oname = oname.strip()
1429 #print '1- oname: <%r>' % oname # dbg
1429 #print '1- oname: <%r>' % oname # dbg
1430 if not oname.startswith(ESC_MAGIC) and \
1430 if not oname.startswith(ESC_MAGIC) and \
1431 not oname.startswith(ESC_MAGIC2) and \
1431 not oname.startswith(ESC_MAGIC2) and \
1432 not py3compat.isidentifier(oname, dotted=True):
1432 not py3compat.isidentifier(oname, dotted=True):
1433 return dict(found=False)
1433 return dict(found=False)
1434
1434
1435 alias_ns = None
1435 alias_ns = None
1436 if namespaces is None:
1436 if namespaces is None:
1437 # Namespaces to search in:
1437 # Namespaces to search in:
1438 # Put them in a list. The order is important so that we
1438 # Put them in a list. The order is important so that we
1439 # find things in the same order that Python finds them.
1439 # find things in the same order that Python finds them.
1440 namespaces = [ ('Interactive', self.user_ns),
1440 namespaces = [ ('Interactive', self.user_ns),
1441 ('Interactive (global)', self.user_global_ns),
1441 ('Interactive (global)', self.user_global_ns),
1442 ('Python builtin', builtin_mod.__dict__),
1442 ('Python builtin', builtin_mod.__dict__),
1443 ]
1443 ]
1444
1444
1445 # initialize results to 'null'
1445 # initialize results to 'null'
1446 found = False; obj = None; ospace = None; ds = None;
1446 found = False; obj = None; ospace = None; ds = None;
1447 ismagic = False; isalias = False; parent = None
1447 ismagic = False; isalias = False; parent = None
1448
1448
1449 # We need to special-case 'print', which as of python2.6 registers as a
1449 # We need to special-case 'print', which as of python2.6 registers as a
1450 # function but should only be treated as one if print_function was
1450 # function but should only be treated as one if print_function was
1451 # loaded with a future import. In this case, just bail.
1451 # loaded with a future import. In this case, just bail.
1452 if (oname == 'print' and not py3compat.PY3 and not \
1452 if (oname == 'print' and not py3compat.PY3 and not \
1453 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1453 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1454 return {'found':found, 'obj':obj, 'namespace':ospace,
1454 return {'found':found, 'obj':obj, 'namespace':ospace,
1455 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1455 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1456
1456
1457 # Look for the given name by splitting it in parts. If the head is
1457 # Look for the given name by splitting it in parts. If the head is
1458 # found, then we look for all the remaining parts as members, and only
1458 # found, then we look for all the remaining parts as members, and only
1459 # declare success if we can find them all.
1459 # declare success if we can find them all.
1460 oname_parts = oname.split('.')
1460 oname_parts = oname.split('.')
1461 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1461 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1462 for nsname,ns in namespaces:
1462 for nsname,ns in namespaces:
1463 try:
1463 try:
1464 obj = ns[oname_head]
1464 obj = ns[oname_head]
1465 except KeyError:
1465 except KeyError:
1466 continue
1466 continue
1467 else:
1467 else:
1468 #print 'oname_rest:', oname_rest # dbg
1468 #print 'oname_rest:', oname_rest # dbg
1469 for idx, part in enumerate(oname_rest):
1469 for idx, part in enumerate(oname_rest):
1470 try:
1470 try:
1471 parent = obj
1471 parent = obj
1472 # The last part is looked up in a special way to avoid
1472 # The last part is looked up in a special way to avoid
1473 # descriptor invocation as it may raise or have side
1473 # descriptor invocation as it may raise or have side
1474 # effects.
1474 # effects.
1475 if idx == len(oname_rest) - 1:
1475 if idx == len(oname_rest) - 1:
1476 obj = self._getattr_property(obj, part)
1476 obj = self._getattr_property(obj, part)
1477 else:
1477 else:
1478 obj = getattr(obj, part)
1478 obj = getattr(obj, part)
1479 except:
1479 except:
1480 # Blanket except b/c some badly implemented objects
1480 # Blanket except b/c some badly implemented objects
1481 # allow __getattr__ to raise exceptions other than
1481 # allow __getattr__ to raise exceptions other than
1482 # AttributeError, which then crashes IPython.
1482 # AttributeError, which then crashes IPython.
1483 break
1483 break
1484 else:
1484 else:
1485 # If we finish the for loop (no break), we got all members
1485 # If we finish the for loop (no break), we got all members
1486 found = True
1486 found = True
1487 ospace = nsname
1487 ospace = nsname
1488 break # namespace loop
1488 break # namespace loop
1489
1489
1490 # Try to see if it's magic
1490 # Try to see if it's magic
1491 if not found:
1491 if not found:
1492 obj = None
1492 obj = None
1493 if oname.startswith(ESC_MAGIC2):
1493 if oname.startswith(ESC_MAGIC2):
1494 oname = oname.lstrip(ESC_MAGIC2)
1494 oname = oname.lstrip(ESC_MAGIC2)
1495 obj = self.find_cell_magic(oname)
1495 obj = self.find_cell_magic(oname)
1496 elif oname.startswith(ESC_MAGIC):
1496 elif oname.startswith(ESC_MAGIC):
1497 oname = oname.lstrip(ESC_MAGIC)
1497 oname = oname.lstrip(ESC_MAGIC)
1498 obj = self.find_line_magic(oname)
1498 obj = self.find_line_magic(oname)
1499 else:
1499 else:
1500 # search without prefix, so run? will find %run?
1500 # search without prefix, so run? will find %run?
1501 obj = self.find_line_magic(oname)
1501 obj = self.find_line_magic(oname)
1502 if obj is None:
1502 if obj is None:
1503 obj = self.find_cell_magic(oname)
1503 obj = self.find_cell_magic(oname)
1504 if obj is not None:
1504 if obj is not None:
1505 found = True
1505 found = True
1506 ospace = 'IPython internal'
1506 ospace = 'IPython internal'
1507 ismagic = True
1507 ismagic = True
1508 isalias = isinstance(obj, Alias)
1508 isalias = isinstance(obj, Alias)
1509
1509
1510 # Last try: special-case some literals like '', [], {}, etc:
1510 # Last try: special-case some literals like '', [], {}, etc:
1511 if not found and oname_head in ["''",'""','[]','{}','()']:
1511 if not found and oname_head in ["''",'""','[]','{}','()']:
1512 obj = eval(oname_head)
1512 obj = eval(oname_head)
1513 found = True
1513 found = True
1514 ospace = 'Interactive'
1514 ospace = 'Interactive'
1515
1515
1516 return {'found':found, 'obj':obj, 'namespace':ospace,
1516 return {'found':found, 'obj':obj, 'namespace':ospace,
1517 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1517 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1518
1518
1519 @staticmethod
1519 @staticmethod
1520 def _getattr_property(obj, attrname):
1520 def _getattr_property(obj, attrname):
1521 """Property-aware getattr to use in object finding.
1521 """Property-aware getattr to use in object finding.
1522
1522
1523 If attrname represents a property, return it unevaluated (in case it has
1523 If attrname represents a property, return it unevaluated (in case it has
1524 side effects or raises an error.
1524 side effects or raises an error.
1525
1525
1526 """
1526 """
1527 if not isinstance(obj, type):
1527 if not isinstance(obj, type):
1528 try:
1528 try:
1529 # `getattr(type(obj), attrname)` is not guaranteed to return
1529 # `getattr(type(obj), attrname)` is not guaranteed to return
1530 # `obj`, but does so for property:
1530 # `obj`, but does so for property:
1531 #
1531 #
1532 # property.__get__(self, None, cls) -> self
1532 # property.__get__(self, None, cls) -> self
1533 #
1533 #
1534 # The universal alternative is to traverse the mro manually
1534 # The universal alternative is to traverse the mro manually
1535 # searching for attrname in class dicts.
1535 # searching for attrname in class dicts.
1536 attr = getattr(type(obj), attrname)
1536 attr = getattr(type(obj), attrname)
1537 except AttributeError:
1537 except AttributeError:
1538 pass
1538 pass
1539 else:
1539 else:
1540 # This relies on the fact that data descriptors (with both
1540 # This relies on the fact that data descriptors (with both
1541 # __get__ & __set__ magic methods) take precedence over
1541 # __get__ & __set__ magic methods) take precedence over
1542 # instance-level attributes:
1542 # instance-level attributes:
1543 #
1543 #
1544 # class A(object):
1544 # class A(object):
1545 # @property
1545 # @property
1546 # def foobar(self): return 123
1546 # def foobar(self): return 123
1547 # a = A()
1547 # a = A()
1548 # a.__dict__['foobar'] = 345
1548 # a.__dict__['foobar'] = 345
1549 # a.foobar # == 123
1549 # a.foobar # == 123
1550 #
1550 #
1551 # So, a property may be returned right away.
1551 # So, a property may be returned right away.
1552 if isinstance(attr, property):
1552 if isinstance(attr, property):
1553 return attr
1553 return attr
1554
1554
1555 # Nothing helped, fall back.
1555 # Nothing helped, fall back.
1556 return getattr(obj, attrname)
1556 return getattr(obj, attrname)
1557
1557
1558 def _object_find(self, oname, namespaces=None):
1558 def _object_find(self, oname, namespaces=None):
1559 """Find an object and return a struct with info about it."""
1559 """Find an object and return a struct with info about it."""
1560 return Struct(self._ofind(oname, namespaces))
1560 return Struct(self._ofind(oname, namespaces))
1561
1561
1562 def _inspect(self, meth, oname, namespaces=None, **kw):
1562 def _inspect(self, meth, oname, namespaces=None, **kw):
1563 """Generic interface to the inspector system.
1563 """Generic interface to the inspector system.
1564
1564
1565 This function is meant to be called by pdef, pdoc & friends."""
1565 This function is meant to be called by pdef, pdoc & friends."""
1566 info = self._object_find(oname, namespaces)
1566 info = self._object_find(oname, namespaces)
1567 if info.found:
1567 if info.found:
1568 pmethod = getattr(self.inspector, meth)
1568 pmethod = getattr(self.inspector, meth)
1569 formatter = format_screen if info.ismagic else None
1569 formatter = format_screen if info.ismagic else None
1570 if meth == 'pdoc':
1570 if meth == 'pdoc':
1571 pmethod(info.obj, oname, formatter)
1571 pmethod(info.obj, oname, formatter)
1572 elif meth == 'pinfo':
1572 elif meth == 'pinfo':
1573 pmethod(info.obj, oname, formatter, info, **kw)
1573 pmethod(info.obj, oname, formatter, info, **kw)
1574 else:
1574 else:
1575 pmethod(info.obj, oname)
1575 pmethod(info.obj, oname)
1576 else:
1576 else:
1577 print('Object `%s` not found.' % oname)
1577 print('Object `%s` not found.' % oname)
1578 return 'not found' # so callers can take other action
1578 return 'not found' # so callers can take other action
1579
1579
1580 def object_inspect(self, oname, detail_level=0):
1580 def object_inspect(self, oname, detail_level=0):
1581 """Get object info about oname"""
1581 """Get object info about oname"""
1582 with self.builtin_trap:
1582 with self.builtin_trap:
1583 info = self._object_find(oname)
1583 info = self._object_find(oname)
1584 if info.found:
1584 if info.found:
1585 return self.inspector.info(info.obj, oname, info=info,
1585 return self.inspector.info(info.obj, oname, info=info,
1586 detail_level=detail_level
1586 detail_level=detail_level
1587 )
1587 )
1588 else:
1588 else:
1589 return oinspect.object_info(name=oname, found=False)
1589 return oinspect.object_info(name=oname, found=False)
1590
1590
1591 def object_inspect_text(self, oname, detail_level=0):
1591 def object_inspect_text(self, oname, detail_level=0):
1592 """Get object info as formatted text"""
1592 """Get object info as formatted text"""
1593 with self.builtin_trap:
1593 with self.builtin_trap:
1594 info = self._object_find(oname)
1594 info = self._object_find(oname)
1595 if info.found:
1595 if info.found:
1596 return self.inspector._format_info(info.obj, oname, info=info,
1596 return self.inspector._format_info(info.obj, oname, info=info,
1597 detail_level=detail_level
1597 detail_level=detail_level
1598 )
1598 )
1599 else:
1599 else:
1600 raise KeyError(oname)
1600 raise KeyError(oname)
1601
1601
1602 #-------------------------------------------------------------------------
1602 #-------------------------------------------------------------------------
1603 # Things related to history management
1603 # Things related to history management
1604 #-------------------------------------------------------------------------
1604 #-------------------------------------------------------------------------
1605
1605
1606 def init_history(self):
1606 def init_history(self):
1607 """Sets up the command history, and starts regular autosaves."""
1607 """Sets up the command history, and starts regular autosaves."""
1608 self.history_manager = HistoryManager(shell=self, parent=self)
1608 self.history_manager = HistoryManager(shell=self, parent=self)
1609 self.configurables.append(self.history_manager)
1609 self.configurables.append(self.history_manager)
1610
1610
1611 #-------------------------------------------------------------------------
1611 #-------------------------------------------------------------------------
1612 # Things related to exception handling and tracebacks (not debugging)
1612 # Things related to exception handling and tracebacks (not debugging)
1613 #-------------------------------------------------------------------------
1613 #-------------------------------------------------------------------------
1614
1614
1615 def init_traceback_handlers(self, custom_exceptions):
1615 def init_traceback_handlers(self, custom_exceptions):
1616 # Syntax error handler.
1616 # Syntax error handler.
1617 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1617 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1618
1618
1619 # The interactive one is initialized with an offset, meaning we always
1619 # The interactive one is initialized with an offset, meaning we always
1620 # want to remove the topmost item in the traceback, which is our own
1620 # want to remove the topmost item in the traceback, which is our own
1621 # internal code. Valid modes: ['Plain','Context','Verbose']
1621 # internal code. Valid modes: ['Plain','Context','Verbose']
1622 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1622 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1623 color_scheme='NoColor',
1623 color_scheme='NoColor',
1624 tb_offset = 1,
1624 tb_offset = 1,
1625 check_cache=check_linecache_ipython)
1625 check_cache=check_linecache_ipython)
1626
1626
1627 # The instance will store a pointer to the system-wide exception hook,
1627 # The instance will store a pointer to the system-wide exception hook,
1628 # so that runtime code (such as magics) can access it. This is because
1628 # so that runtime code (such as magics) can access it. This is because
1629 # during the read-eval loop, it may get temporarily overwritten.
1629 # during the read-eval loop, it may get temporarily overwritten.
1630 self.sys_excepthook = sys.excepthook
1630 self.sys_excepthook = sys.excepthook
1631
1631
1632 # and add any custom exception handlers the user may have specified
1632 # and add any custom exception handlers the user may have specified
1633 self.set_custom_exc(*custom_exceptions)
1633 self.set_custom_exc(*custom_exceptions)
1634
1634
1635 # Set the exception mode
1635 # Set the exception mode
1636 self.InteractiveTB.set_mode(mode=self.xmode)
1636 self.InteractiveTB.set_mode(mode=self.xmode)
1637
1637
1638 def set_custom_exc(self, exc_tuple, handler):
1638 def set_custom_exc(self, exc_tuple, handler):
1639 """set_custom_exc(exc_tuple,handler)
1639 """set_custom_exc(exc_tuple,handler)
1640
1640
1641 Set a custom exception handler, which will be called if any of the
1641 Set a custom exception handler, which will be called if any of the
1642 exceptions in exc_tuple occur in the mainloop (specifically, in the
1642 exceptions in exc_tuple occur in the mainloop (specifically, in the
1643 run_code() method).
1643 run_code() method).
1644
1644
1645 Parameters
1645 Parameters
1646 ----------
1646 ----------
1647
1647
1648 exc_tuple : tuple of exception classes
1648 exc_tuple : tuple of exception classes
1649 A *tuple* of exception classes, for which to call the defined
1649 A *tuple* of exception classes, for which to call the defined
1650 handler. It is very important that you use a tuple, and NOT A
1650 handler. It is very important that you use a tuple, and NOT A
1651 LIST here, because of the way Python's except statement works. If
1651 LIST here, because of the way Python's except statement works. If
1652 you only want to trap a single exception, use a singleton tuple::
1652 you only want to trap a single exception, use a singleton tuple::
1653
1653
1654 exc_tuple == (MyCustomException,)
1654 exc_tuple == (MyCustomException,)
1655
1655
1656 handler : callable
1656 handler : callable
1657 handler must have the following signature::
1657 handler must have the following signature::
1658
1658
1659 def my_handler(self, etype, value, tb, tb_offset=None):
1659 def my_handler(self, etype, value, tb, tb_offset=None):
1660 ...
1660 ...
1661 return structured_traceback
1661 return structured_traceback
1662
1662
1663 Your handler must return a structured traceback (a list of strings),
1663 Your handler must return a structured traceback (a list of strings),
1664 or None.
1664 or None.
1665
1665
1666 This will be made into an instance method (via types.MethodType)
1666 This will be made into an instance method (via types.MethodType)
1667 of IPython itself, and it will be called if any of the exceptions
1667 of IPython itself, and it will be called if any of the exceptions
1668 listed in the exc_tuple are caught. If the handler is None, an
1668 listed in the exc_tuple are caught. If the handler is None, an
1669 internal basic one is used, which just prints basic info.
1669 internal basic one is used, which just prints basic info.
1670
1670
1671 To protect IPython from crashes, if your handler ever raises an
1671 To protect IPython from crashes, if your handler ever raises an
1672 exception or returns an invalid result, it will be immediately
1672 exception or returns an invalid result, it will be immediately
1673 disabled.
1673 disabled.
1674
1674
1675 WARNING: by putting in your own exception handler into IPython's main
1675 WARNING: by putting in your own exception handler into IPython's main
1676 execution loop, you run a very good chance of nasty crashes. This
1676 execution loop, you run a very good chance of nasty crashes. This
1677 facility should only be used if you really know what you are doing."""
1677 facility should only be used if you really know what you are doing."""
1678
1678
1679 assert type(exc_tuple)==type(()) , \
1679 assert type(exc_tuple)==type(()) , \
1680 "The custom exceptions must be given AS A TUPLE."
1680 "The custom exceptions must be given AS A TUPLE."
1681
1681
1682 def dummy_handler(self,etype,value,tb,tb_offset=None):
1682 def dummy_handler(self,etype,value,tb,tb_offset=None):
1683 print('*** Simple custom exception handler ***')
1683 print('*** Simple custom exception handler ***')
1684 print('Exception type :',etype)
1684 print('Exception type :',etype)
1685 print('Exception value:',value)
1685 print('Exception value:',value)
1686 print('Traceback :',tb)
1686 print('Traceback :',tb)
1687 #print 'Source code :','\n'.join(self.buffer)
1687 #print 'Source code :','\n'.join(self.buffer)
1688
1688
1689 def validate_stb(stb):
1689 def validate_stb(stb):
1690 """validate structured traceback return type
1690 """validate structured traceback return type
1691
1691
1692 return type of CustomTB *should* be a list of strings, but allow
1692 return type of CustomTB *should* be a list of strings, but allow
1693 single strings or None, which are harmless.
1693 single strings or None, which are harmless.
1694
1694
1695 This function will *always* return a list of strings,
1695 This function will *always* return a list of strings,
1696 and will raise a TypeError if stb is inappropriate.
1696 and will raise a TypeError if stb is inappropriate.
1697 """
1697 """
1698 msg = "CustomTB must return list of strings, not %r" % stb
1698 msg = "CustomTB must return list of strings, not %r" % stb
1699 if stb is None:
1699 if stb is None:
1700 return []
1700 return []
1701 elif isinstance(stb, string_types):
1701 elif isinstance(stb, string_types):
1702 return [stb]
1702 return [stb]
1703 elif not isinstance(stb, list):
1703 elif not isinstance(stb, list):
1704 raise TypeError(msg)
1704 raise TypeError(msg)
1705 # it's a list
1705 # it's a list
1706 for line in stb:
1706 for line in stb:
1707 # check every element
1707 # check every element
1708 if not isinstance(line, string_types):
1708 if not isinstance(line, string_types):
1709 raise TypeError(msg)
1709 raise TypeError(msg)
1710 return stb
1710 return stb
1711
1711
1712 if handler is None:
1712 if handler is None:
1713 wrapped = dummy_handler
1713 wrapped = dummy_handler
1714 else:
1714 else:
1715 def wrapped(self,etype,value,tb,tb_offset=None):
1715 def wrapped(self,etype,value,tb,tb_offset=None):
1716 """wrap CustomTB handler, to protect IPython from user code
1716 """wrap CustomTB handler, to protect IPython from user code
1717
1717
1718 This makes it harder (but not impossible) for custom exception
1718 This makes it harder (but not impossible) for custom exception
1719 handlers to crash IPython.
1719 handlers to crash IPython.
1720 """
1720 """
1721 try:
1721 try:
1722 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1722 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1723 return validate_stb(stb)
1723 return validate_stb(stb)
1724 except:
1724 except:
1725 # clear custom handler immediately
1725 # clear custom handler immediately
1726 self.set_custom_exc((), None)
1726 self.set_custom_exc((), None)
1727 print("Custom TB Handler failed, unregistering", file=io.stderr)
1727 print("Custom TB Handler failed, unregistering", file=io.stderr)
1728 # show the exception in handler first
1728 # show the exception in handler first
1729 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1729 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1730 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1730 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1731 print("The original exception:", file=io.stdout)
1731 print("The original exception:", file=io.stdout)
1732 stb = self.InteractiveTB.structured_traceback(
1732 stb = self.InteractiveTB.structured_traceback(
1733 (etype,value,tb), tb_offset=tb_offset
1733 (etype,value,tb), tb_offset=tb_offset
1734 )
1734 )
1735 return stb
1735 return stb
1736
1736
1737 self.CustomTB = types.MethodType(wrapped,self)
1737 self.CustomTB = types.MethodType(wrapped,self)
1738 self.custom_exceptions = exc_tuple
1738 self.custom_exceptions = exc_tuple
1739
1739
1740 def excepthook(self, etype, value, tb):
1740 def excepthook(self, etype, value, tb):
1741 """One more defense for GUI apps that call sys.excepthook.
1741 """One more defense for GUI apps that call sys.excepthook.
1742
1742
1743 GUI frameworks like wxPython trap exceptions and call
1743 GUI frameworks like wxPython trap exceptions and call
1744 sys.excepthook themselves. I guess this is a feature that
1744 sys.excepthook themselves. I guess this is a feature that
1745 enables them to keep running after exceptions that would
1745 enables them to keep running after exceptions that would
1746 otherwise kill their mainloop. This is a bother for IPython
1746 otherwise kill their mainloop. This is a bother for IPython
1747 which excepts to catch all of the program exceptions with a try:
1747 which excepts to catch all of the program exceptions with a try:
1748 except: statement.
1748 except: statement.
1749
1749
1750 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1750 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1751 any app directly invokes sys.excepthook, it will look to the user like
1751 any app directly invokes sys.excepthook, it will look to the user like
1752 IPython crashed. In order to work around this, we can disable the
1752 IPython crashed. In order to work around this, we can disable the
1753 CrashHandler and replace it with this excepthook instead, which prints a
1753 CrashHandler and replace it with this excepthook instead, which prints a
1754 regular traceback using our InteractiveTB. In this fashion, apps which
1754 regular traceback using our InteractiveTB. In this fashion, apps which
1755 call sys.excepthook will generate a regular-looking exception from
1755 call sys.excepthook will generate a regular-looking exception from
1756 IPython, and the CrashHandler will only be triggered by real IPython
1756 IPython, and the CrashHandler will only be triggered by real IPython
1757 crashes.
1757 crashes.
1758
1758
1759 This hook should be used sparingly, only in places which are not likely
1759 This hook should be used sparingly, only in places which are not likely
1760 to be true IPython errors.
1760 to be true IPython errors.
1761 """
1761 """
1762 self.showtraceback((etype, value, tb), tb_offset=0)
1762 self.showtraceback((etype, value, tb), tb_offset=0)
1763
1763
1764 def _get_exc_info(self, exc_tuple=None):
1764 def _get_exc_info(self, exc_tuple=None):
1765 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1765 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1766
1766
1767 Ensures sys.last_type,value,traceback hold the exc_info we found,
1767 Ensures sys.last_type,value,traceback hold the exc_info we found,
1768 from whichever source.
1768 from whichever source.
1769
1769
1770 raises ValueError if none of these contain any information
1770 raises ValueError if none of these contain any information
1771 """
1771 """
1772 if exc_tuple is None:
1772 if exc_tuple is None:
1773 etype, value, tb = sys.exc_info()
1773 etype, value, tb = sys.exc_info()
1774 else:
1774 else:
1775 etype, value, tb = exc_tuple
1775 etype, value, tb = exc_tuple
1776
1776
1777 if etype is None:
1777 if etype is None:
1778 if hasattr(sys, 'last_type'):
1778 if hasattr(sys, 'last_type'):
1779 etype, value, tb = sys.last_type, sys.last_value, \
1779 etype, value, tb = sys.last_type, sys.last_value, \
1780 sys.last_traceback
1780 sys.last_traceback
1781
1781
1782 if etype is None:
1782 if etype is None:
1783 raise ValueError("No exception to find")
1783 raise ValueError("No exception to find")
1784
1784
1785 # Now store the exception info in sys.last_type etc.
1785 # Now store the exception info in sys.last_type etc.
1786 # WARNING: these variables are somewhat deprecated and not
1786 # WARNING: these variables are somewhat deprecated and not
1787 # necessarily safe to use in a threaded environment, but tools
1787 # necessarily safe to use in a threaded environment, but tools
1788 # like pdb depend on their existence, so let's set them. If we
1788 # like pdb depend on their existence, so let's set them. If we
1789 # find problems in the field, we'll need to revisit their use.
1789 # find problems in the field, we'll need to revisit their use.
1790 sys.last_type = etype
1790 sys.last_type = etype
1791 sys.last_value = value
1791 sys.last_value = value
1792 sys.last_traceback = tb
1792 sys.last_traceback = tb
1793
1793
1794 return etype, value, tb
1794 return etype, value, tb
1795
1795
1796 def show_usage_error(self, exc):
1796 def show_usage_error(self, exc):
1797 """Show a short message for UsageErrors
1797 """Show a short message for UsageErrors
1798
1798
1799 These are special exceptions that shouldn't show a traceback.
1799 These are special exceptions that shouldn't show a traceback.
1800 """
1800 """
1801 self.write_err("UsageError: %s" % exc)
1801 self.write_err("UsageError: %s" % exc)
1802
1802
1803 def get_exception_only(self, exc_tuple=None):
1803 def get_exception_only(self, exc_tuple=None):
1804 """
1804 """
1805 Return as a string (ending with a newline) the exception that
1805 Return as a string (ending with a newline) the exception that
1806 just occurred, without any traceback.
1806 just occurred, without any traceback.
1807 """
1807 """
1808 etype, value, tb = self._get_exc_info(exc_tuple)
1808 etype, value, tb = self._get_exc_info(exc_tuple)
1809 msg = traceback.format_exception_only(etype, value)
1809 msg = traceback.format_exception_only(etype, value)
1810 return ''.join(msg)
1810 return ''.join(msg)
1811
1811
1812 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1812 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1813 exception_only=False):
1813 exception_only=False):
1814 """Display the exception that just occurred.
1814 """Display the exception that just occurred.
1815
1815
1816 If nothing is known about the exception, this is the method which
1816 If nothing is known about the exception, this is the method which
1817 should be used throughout the code for presenting user tracebacks,
1817 should be used throughout the code for presenting user tracebacks,
1818 rather than directly invoking the InteractiveTB object.
1818 rather than directly invoking the InteractiveTB object.
1819
1819
1820 A specific showsyntaxerror() also exists, but this method can take
1820 A specific showsyntaxerror() also exists, but this method can take
1821 care of calling it if needed, so unless you are explicitly catching a
1821 care of calling it if needed, so unless you are explicitly catching a
1822 SyntaxError exception, don't try to analyze the stack manually and
1822 SyntaxError exception, don't try to analyze the stack manually and
1823 simply call this method."""
1823 simply call this method."""
1824
1824
1825 try:
1825 try:
1826 try:
1826 try:
1827 etype, value, tb = self._get_exc_info(exc_tuple)
1827 etype, value, tb = self._get_exc_info(exc_tuple)
1828 except ValueError:
1828 except ValueError:
1829 self.write_err('No traceback available to show.\n')
1829 self.write_err('No traceback available to show.\n')
1830 return
1830 return
1831
1831
1832 if issubclass(etype, SyntaxError):
1832 if issubclass(etype, SyntaxError):
1833 # Though this won't be called by syntax errors in the input
1833 # Though this won't be called by syntax errors in the input
1834 # line, there may be SyntaxError cases with imported code.
1834 # line, there may be SyntaxError cases with imported code.
1835 self.showsyntaxerror(filename)
1835 self.showsyntaxerror(filename)
1836 elif etype is UsageError:
1836 elif etype is UsageError:
1837 self.show_usage_error(value)
1837 self.show_usage_error(value)
1838 else:
1838 else:
1839 if exception_only:
1839 if exception_only:
1840 stb = ['An exception has occurred, use %tb to see '
1840 stb = ['An exception has occurred, use %tb to see '
1841 'the full traceback.\n']
1841 'the full traceback.\n']
1842 stb.extend(self.InteractiveTB.get_exception_only(etype,
1842 stb.extend(self.InteractiveTB.get_exception_only(etype,
1843 value))
1843 value))
1844 else:
1844 else:
1845 try:
1845 try:
1846 # Exception classes can customise their traceback - we
1846 # Exception classes can customise their traceback - we
1847 # use this in IPython.parallel for exceptions occurring
1847 # use this in IPython.parallel for exceptions occurring
1848 # in the engines. This should return a list of strings.
1848 # in the engines. This should return a list of strings.
1849 stb = value._render_traceback_()
1849 stb = value._render_traceback_()
1850 except Exception:
1850 except Exception:
1851 stb = self.InteractiveTB.structured_traceback(etype,
1851 stb = self.InteractiveTB.structured_traceback(etype,
1852 value, tb, tb_offset=tb_offset)
1852 value, tb, tb_offset=tb_offset)
1853
1853
1854 self._showtraceback(etype, value, stb)
1854 self._showtraceback(etype, value, stb)
1855 if self.call_pdb:
1855 if self.call_pdb:
1856 # drop into debugger
1856 # drop into debugger
1857 self.debugger(force=True)
1857 self.debugger(force=True)
1858 return
1858 return
1859
1859
1860 # Actually show the traceback
1860 # Actually show the traceback
1861 self._showtraceback(etype, value, stb)
1861 self._showtraceback(etype, value, stb)
1862
1862
1863 except KeyboardInterrupt:
1863 except KeyboardInterrupt:
1864 self.write_err('\n' + self.get_exception_only())
1864 self.write_err('\n' + self.get_exception_only())
1865
1865
1866 def _showtraceback(self, etype, evalue, stb):
1866 def _showtraceback(self, etype, evalue, stb):
1867 """Actually show a traceback.
1867 """Actually show a traceback.
1868
1868
1869 Subclasses may override this method to put the traceback on a different
1869 Subclasses may override this method to put the traceback on a different
1870 place, like a side channel.
1870 place, like a side channel.
1871 """
1871 """
1872 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1872 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1873
1873
1874 def showsyntaxerror(self, filename=None):
1874 def showsyntaxerror(self, filename=None):
1875 """Display the syntax error that just occurred.
1875 """Display the syntax error that just occurred.
1876
1876
1877 This doesn't display a stack trace because there isn't one.
1877 This doesn't display a stack trace because there isn't one.
1878
1878
1879 If a filename is given, it is stuffed in the exception instead
1879 If a filename is given, it is stuffed in the exception instead
1880 of what was there before (because Python's parser always uses
1880 of what was there before (because Python's parser always uses
1881 "<string>" when reading from a string).
1881 "<string>" when reading from a string).
1882 """
1882 """
1883 etype, value, last_traceback = self._get_exc_info()
1883 etype, value, last_traceback = self._get_exc_info()
1884
1884
1885 if filename and issubclass(etype, SyntaxError):
1885 if filename and issubclass(etype, SyntaxError):
1886 try:
1886 try:
1887 value.filename = filename
1887 value.filename = filename
1888 except:
1888 except:
1889 # Not the format we expect; leave it alone
1889 # Not the format we expect; leave it alone
1890 pass
1890 pass
1891
1891
1892 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1892 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1893 self._showtraceback(etype, value, stb)
1893 self._showtraceback(etype, value, stb)
1894
1894
1895 # This is overridden in TerminalInteractiveShell to show a message about
1895 # This is overridden in TerminalInteractiveShell to show a message about
1896 # the %paste magic.
1896 # the %paste magic.
1897 def showindentationerror(self):
1897 def showindentationerror(self):
1898 """Called by run_cell when there's an IndentationError in code entered
1898 """Called by run_cell when there's an IndentationError in code entered
1899 at the prompt.
1899 at the prompt.
1900
1900
1901 This is overridden in TerminalInteractiveShell to show a message about
1901 This is overridden in TerminalInteractiveShell to show a message about
1902 the %paste magic."""
1902 the %paste magic."""
1903 self.showsyntaxerror()
1903 self.showsyntaxerror()
1904
1904
1905 #-------------------------------------------------------------------------
1905 #-------------------------------------------------------------------------
1906 # Things related to readline
1906 # Things related to readline
1907 #-------------------------------------------------------------------------
1907 #-------------------------------------------------------------------------
1908
1908
1909 def init_readline(self):
1909 def init_readline(self):
1910 """Command history completion/saving/reloading."""
1910 """Command history completion/saving/reloading."""
1911
1911
1912 if self.readline_use:
1912 if self.readline_use:
1913 import IPython.utils.rlineimpl as readline
1913 import IPython.utils.rlineimpl as readline
1914
1914
1915 self.rl_next_input = None
1915 self.rl_next_input = None
1916 self.rl_do_indent = False
1916 self.rl_do_indent = False
1917
1917
1918 if not self.readline_use or not readline.have_readline:
1918 if not self.readline_use or not readline.have_readline:
1919 self.has_readline = False
1919 self.has_readline = False
1920 self.readline = None
1920 self.readline = None
1921 # Set a number of methods that depend on readline to be no-op
1921 # Set a number of methods that depend on readline to be no-op
1922 self.readline_no_record = no_op_context
1922 self.readline_no_record = no_op_context
1923 self.set_readline_completer = no_op
1923 self.set_readline_completer = no_op
1924 self.set_custom_completer = no_op
1924 self.set_custom_completer = no_op
1925 if self.readline_use:
1925 if self.readline_use:
1926 warn('Readline services not available or not loaded.')
1926 warn('Readline services not available or not loaded.')
1927 else:
1927 else:
1928 self.has_readline = True
1928 self.has_readline = True
1929 self.readline = readline
1929 self.readline = readline
1930 sys.modules['readline'] = readline
1930 sys.modules['readline'] = readline
1931
1931
1932 # Platform-specific configuration
1932 # Platform-specific configuration
1933 if os.name == 'nt':
1933 if os.name == 'nt':
1934 # FIXME - check with Frederick to see if we can harmonize
1934 # FIXME - check with Frederick to see if we can harmonize
1935 # naming conventions with pyreadline to avoid this
1935 # naming conventions with pyreadline to avoid this
1936 # platform-dependent check
1936 # platform-dependent check
1937 self.readline_startup_hook = readline.set_pre_input_hook
1937 self.readline_startup_hook = readline.set_pre_input_hook
1938 else:
1938 else:
1939 self.readline_startup_hook = readline.set_startup_hook
1939 self.readline_startup_hook = readline.set_startup_hook
1940
1940
1941 # Readline config order:
1941 # Readline config order:
1942 # - IPython config (default value)
1942 # - IPython config (default value)
1943 # - custom inputrc
1943 # - custom inputrc
1944 # - IPython config (user customized)
1944 # - IPython config (user customized)
1945
1945
1946 # load IPython config before inputrc if default
1946 # load IPython config before inputrc if default
1947 # skip if libedit because parse_and_bind syntax is different
1947 # skip if libedit because parse_and_bind syntax is different
1948 if not self._custom_readline_config and not readline.uses_libedit:
1948 if not self._custom_readline_config and not readline.uses_libedit:
1949 for rlcommand in self.readline_parse_and_bind:
1949 for rlcommand in self.readline_parse_and_bind:
1950 readline.parse_and_bind(rlcommand)
1950 readline.parse_and_bind(rlcommand)
1951
1951
1952 # Load user's initrc file (readline config)
1952 # Load user's initrc file (readline config)
1953 # Or if libedit is used, load editrc.
1953 # Or if libedit is used, load editrc.
1954 inputrc_name = os.environ.get('INPUTRC')
1954 inputrc_name = os.environ.get('INPUTRC')
1955 if inputrc_name is None:
1955 if inputrc_name is None:
1956 inputrc_name = '.inputrc'
1956 inputrc_name = '.inputrc'
1957 if readline.uses_libedit:
1957 if readline.uses_libedit:
1958 inputrc_name = '.editrc'
1958 inputrc_name = '.editrc'
1959 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1959 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1960 if os.path.isfile(inputrc_name):
1960 if os.path.isfile(inputrc_name):
1961 try:
1961 try:
1962 readline.read_init_file(inputrc_name)
1962 readline.read_init_file(inputrc_name)
1963 except:
1963 except:
1964 warn('Problems reading readline initialization file <%s>'
1964 warn('Problems reading readline initialization file <%s>'
1965 % inputrc_name)
1965 % inputrc_name)
1966
1966
1967 # load IPython config after inputrc if user has customized
1967 # load IPython config after inputrc if user has customized
1968 if self._custom_readline_config:
1968 if self._custom_readline_config:
1969 for rlcommand in self.readline_parse_and_bind:
1969 for rlcommand in self.readline_parse_and_bind:
1970 readline.parse_and_bind(rlcommand)
1970 readline.parse_and_bind(rlcommand)
1971
1971
1972 # Remove some chars from the delimiters list. If we encounter
1972 # Remove some chars from the delimiters list. If we encounter
1973 # unicode chars, discard them.
1973 # unicode chars, discard them.
1974 delims = readline.get_completer_delims()
1974 delims = readline.get_completer_delims()
1975 if not py3compat.PY3:
1975 if not py3compat.PY3:
1976 delims = delims.encode("ascii", "ignore")
1976 delims = delims.encode("ascii", "ignore")
1977 for d in self.readline_remove_delims:
1977 for d in self.readline_remove_delims:
1978 delims = delims.replace(d, "")
1978 delims = delims.replace(d, "")
1979 delims = delims.replace(ESC_MAGIC, '')
1979 delims = delims.replace(ESC_MAGIC, '')
1980 readline.set_completer_delims(delims)
1980 readline.set_completer_delims(delims)
1981 # Store these so we can restore them if something like rpy2 modifies
1981 # Store these so we can restore them if something like rpy2 modifies
1982 # them.
1982 # them.
1983 self.readline_delims = delims
1983 self.readline_delims = delims
1984 # otherwise we end up with a monster history after a while:
1984 # otherwise we end up with a monster history after a while:
1985 readline.set_history_length(self.history_length)
1985 readline.set_history_length(self.history_length)
1986
1986
1987 self.refill_readline_hist()
1987 self.refill_readline_hist()
1988 self.readline_no_record = ReadlineNoRecord(self)
1988 self.readline_no_record = ReadlineNoRecord(self)
1989
1989
1990 # Configure auto-indent for all platforms
1990 # Configure auto-indent for all platforms
1991 self.set_autoindent(self.autoindent)
1991 self.set_autoindent(self.autoindent)
1992
1992
1993 def refill_readline_hist(self):
1993 def refill_readline_hist(self):
1994 # Load the last 1000 lines from history
1994 # Load the last 1000 lines from history
1995 self.readline.clear_history()
1995 self.readline.clear_history()
1996 stdin_encoding = sys.stdin.encoding or "utf-8"
1996 stdin_encoding = sys.stdin.encoding or "utf-8"
1997 last_cell = u""
1997 last_cell = u""
1998 for _, _, cell in self.history_manager.get_tail(1000,
1998 for _, _, cell in self.history_manager.get_tail(1000,
1999 include_latest=True):
1999 include_latest=True):
2000 # Ignore blank lines and consecutive duplicates
2000 # Ignore blank lines and consecutive duplicates
2001 cell = cell.rstrip()
2001 cell = cell.rstrip()
2002 if cell and (cell != last_cell):
2002 if cell and (cell != last_cell):
2003 try:
2003 try:
2004 if self.multiline_history:
2004 if self.multiline_history:
2005 self.readline.add_history(py3compat.unicode_to_str(cell,
2005 self.readline.add_history(py3compat.unicode_to_str(cell,
2006 stdin_encoding))
2006 stdin_encoding))
2007 else:
2007 else:
2008 for line in cell.splitlines():
2008 for line in cell.splitlines():
2009 self.readline.add_history(py3compat.unicode_to_str(line,
2009 self.readline.add_history(py3compat.unicode_to_str(line,
2010 stdin_encoding))
2010 stdin_encoding))
2011 last_cell = cell
2011 last_cell = cell
2012
2012
2013 except TypeError:
2013 except TypeError:
2014 # The history DB can get corrupted so it returns strings
2014 # The history DB can get corrupted so it returns strings
2015 # containing null bytes, which readline objects to.
2015 # containing null bytes, which readline objects to.
2016 continue
2016 continue
2017
2017
2018 @skip_doctest
2018 @skip_doctest
2019 def set_next_input(self, s, replace=False):
2019 def set_next_input(self, s, replace=False):
2020 """ Sets the 'default' input string for the next command line.
2020 """ Sets the 'default' input string for the next command line.
2021
2021
2022 Requires readline.
2022 Requires readline.
2023
2023
2024 Example::
2024 Example::
2025
2025
2026 In [1]: _ip.set_next_input("Hello Word")
2026 In [1]: _ip.set_next_input("Hello Word")
2027 In [2]: Hello Word_ # cursor is here
2027 In [2]: Hello Word_ # cursor is here
2028 """
2028 """
2029 self.rl_next_input = py3compat.cast_bytes_py2(s)
2029 self.rl_next_input = py3compat.cast_bytes_py2(s)
2030
2030
2031 # Maybe move this to the terminal subclass?
2031 # Maybe move this to the terminal subclass?
2032 def pre_readline(self):
2032 def pre_readline(self):
2033 """readline hook to be used at the start of each line.
2033 """readline hook to be used at the start of each line.
2034
2034
2035 Currently it handles auto-indent only."""
2035 Currently it handles auto-indent only."""
2036
2036
2037 if self.rl_do_indent:
2037 if self.rl_do_indent:
2038 self.readline.insert_text(self._indent_current_str())
2038 self.readline.insert_text(self._indent_current_str())
2039 if self.rl_next_input is not None:
2039 if self.rl_next_input is not None:
2040 self.readline.insert_text(self.rl_next_input)
2040 self.readline.insert_text(self.rl_next_input)
2041 self.rl_next_input = None
2041 self.rl_next_input = None
2042
2042
2043 def _indent_current_str(self):
2043 def _indent_current_str(self):
2044 """return the current level of indentation as a string"""
2044 """return the current level of indentation as a string"""
2045 return self.input_splitter.indent_spaces * ' '
2045 return self.input_splitter.indent_spaces * ' '
2046
2046
2047 #-------------------------------------------------------------------------
2047 #-------------------------------------------------------------------------
2048 # Things related to text completion
2048 # Things related to text completion
2049 #-------------------------------------------------------------------------
2049 #-------------------------------------------------------------------------
2050
2050
2051 def init_completer(self):
2051 def init_completer(self):
2052 """Initialize the completion machinery.
2052 """Initialize the completion machinery.
2053
2053
2054 This creates completion machinery that can be used by client code,
2054 This creates completion machinery that can be used by client code,
2055 either interactively in-process (typically triggered by the readline
2055 either interactively in-process (typically triggered by the readline
2056 library), programatically (such as in test suites) or out-of-prcess
2056 library), programatically (such as in test suites) or out-of-prcess
2057 (typically over the network by remote frontends).
2057 (typically over the network by remote frontends).
2058 """
2058 """
2059 from IPython.core.completer import IPCompleter
2059 from IPython.core.completer import IPCompleter
2060 from IPython.core.completerlib import (module_completer,
2060 from IPython.core.completerlib import (module_completer,
2061 magic_run_completer, cd_completer, reset_completer)
2061 magic_run_completer, cd_completer, reset_completer)
2062
2062
2063 self.Completer = IPCompleter(shell=self,
2063 self.Completer = IPCompleter(shell=self,
2064 namespace=self.user_ns,
2064 namespace=self.user_ns,
2065 global_namespace=self.user_global_ns,
2065 global_namespace=self.user_global_ns,
2066 use_readline=self.has_readline,
2066 use_readline=self.has_readline,
2067 parent=self,
2067 parent=self,
2068 )
2068 )
2069 self.configurables.append(self.Completer)
2069 self.configurables.append(self.Completer)
2070
2070
2071 # Add custom completers to the basic ones built into IPCompleter
2071 # Add custom completers to the basic ones built into IPCompleter
2072 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2072 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2073 self.strdispatchers['complete_command'] = sdisp
2073 self.strdispatchers['complete_command'] = sdisp
2074 self.Completer.custom_completers = sdisp
2074 self.Completer.custom_completers = sdisp
2075
2075
2076 self.set_hook('complete_command', module_completer, str_key = 'import')
2076 self.set_hook('complete_command', module_completer, str_key = 'import')
2077 self.set_hook('complete_command', module_completer, str_key = 'from')
2077 self.set_hook('complete_command', module_completer, str_key = 'from')
2078 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2078 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2079 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2079 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2080 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2080 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2081
2081
2082 # Only configure readline if we truly are using readline. IPython can
2082 # Only configure readline if we truly are using readline. IPython can
2083 # do tab-completion over the network, in GUIs, etc, where readline
2083 # do tab-completion over the network, in GUIs, etc, where readline
2084 # itself may be absent
2084 # itself may be absent
2085 if self.has_readline:
2085 if self.has_readline:
2086 self.set_readline_completer()
2086 self.set_readline_completer()
2087
2087
2088 def complete(self, text, line=None, cursor_pos=None):
2088 def complete(self, text, line=None, cursor_pos=None):
2089 """Return the completed text and a list of completions.
2089 """Return the completed text and a list of completions.
2090
2090
2091 Parameters
2091 Parameters
2092 ----------
2092 ----------
2093
2093
2094 text : string
2094 text : string
2095 A string of text to be completed on. It can be given as empty and
2095 A string of text to be completed on. It can be given as empty and
2096 instead a line/position pair are given. In this case, the
2096 instead a line/position pair are given. In this case, the
2097 completer itself will split the line like readline does.
2097 completer itself will split the line like readline does.
2098
2098
2099 line : string, optional
2099 line : string, optional
2100 The complete line that text is part of.
2100 The complete line that text is part of.
2101
2101
2102 cursor_pos : int, optional
2102 cursor_pos : int, optional
2103 The position of the cursor on the input line.
2103 The position of the cursor on the input line.
2104
2104
2105 Returns
2105 Returns
2106 -------
2106 -------
2107 text : string
2107 text : string
2108 The actual text that was completed.
2108 The actual text that was completed.
2109
2109
2110 matches : list
2110 matches : list
2111 A sorted list with all possible completions.
2111 A sorted list with all possible completions.
2112
2112
2113 The optional arguments allow the completion to take more context into
2113 The optional arguments allow the completion to take more context into
2114 account, and are part of the low-level completion API.
2114 account, and are part of the low-level completion API.
2115
2115
2116 This is a wrapper around the completion mechanism, similar to what
2116 This is a wrapper around the completion mechanism, similar to what
2117 readline does at the command line when the TAB key is hit. By
2117 readline does at the command line when the TAB key is hit. By
2118 exposing it as a method, it can be used by other non-readline
2118 exposing it as a method, it can be used by other non-readline
2119 environments (such as GUIs) for text completion.
2119 environments (such as GUIs) for text completion.
2120
2120
2121 Simple usage example:
2121 Simple usage example:
2122
2122
2123 In [1]: x = 'hello'
2123 In [1]: x = 'hello'
2124
2124
2125 In [2]: _ip.complete('x.l')
2125 In [2]: _ip.complete('x.l')
2126 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2126 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2127 """
2127 """
2128
2128
2129 # Inject names into __builtin__ so we can complete on the added names.
2129 # Inject names into __builtin__ so we can complete on the added names.
2130 with self.builtin_trap:
2130 with self.builtin_trap:
2131 return self.Completer.complete(text, line, cursor_pos)
2131 return self.Completer.complete(text, line, cursor_pos)
2132
2132
2133 def set_custom_completer(self, completer, pos=0):
2133 def set_custom_completer(self, completer, pos=0):
2134 """Adds a new custom completer function.
2134 """Adds a new custom completer function.
2135
2135
2136 The position argument (defaults to 0) is the index in the completers
2136 The position argument (defaults to 0) is the index in the completers
2137 list where you want the completer to be inserted."""
2137 list where you want the completer to be inserted."""
2138
2138
2139 newcomp = types.MethodType(completer,self.Completer)
2139 newcomp = types.MethodType(completer,self.Completer)
2140 self.Completer.matchers.insert(pos,newcomp)
2140 self.Completer.matchers.insert(pos,newcomp)
2141
2141
2142 def set_readline_completer(self):
2142 def set_readline_completer(self):
2143 """Reset readline's completer to be our own."""
2143 """Reset readline's completer to be our own."""
2144 self.readline.set_completer(self.Completer.rlcomplete)
2144 self.readline.set_completer(self.Completer.rlcomplete)
2145
2145
2146 def set_completer_frame(self, frame=None):
2146 def set_completer_frame(self, frame=None):
2147 """Set the frame of the completer."""
2147 """Set the frame of the completer."""
2148 if frame:
2148 if frame:
2149 self.Completer.namespace = frame.f_locals
2149 self.Completer.namespace = frame.f_locals
2150 self.Completer.global_namespace = frame.f_globals
2150 self.Completer.global_namespace = frame.f_globals
2151 else:
2151 else:
2152 self.Completer.namespace = self.user_ns
2152 self.Completer.namespace = self.user_ns
2153 self.Completer.global_namespace = self.user_global_ns
2153 self.Completer.global_namespace = self.user_global_ns
2154
2154
2155 #-------------------------------------------------------------------------
2155 #-------------------------------------------------------------------------
2156 # Things related to magics
2156 # Things related to magics
2157 #-------------------------------------------------------------------------
2157 #-------------------------------------------------------------------------
2158
2158
2159 def init_magics(self):
2159 def init_magics(self):
2160 from IPython.core import magics as m
2160 from IPython.core import magics as m
2161 self.magics_manager = magic.MagicsManager(shell=self,
2161 self.magics_manager = magic.MagicsManager(shell=self,
2162 parent=self,
2162 parent=self,
2163 user_magics=m.UserMagics(self))
2163 user_magics=m.UserMagics(self))
2164 self.configurables.append(self.magics_manager)
2164 self.configurables.append(self.magics_manager)
2165
2165
2166 # Expose as public API from the magics manager
2166 # Expose as public API from the magics manager
2167 self.register_magics = self.magics_manager.register
2167 self.register_magics = self.magics_manager.register
2168 self.define_magic = self.magics_manager.define_magic
2168 self.define_magic = self.magics_manager.define_magic
2169
2169
2170 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2170 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2171 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2171 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2172 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2172 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2173 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2173 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2174 )
2174 )
2175
2175
2176 # Register Magic Aliases
2176 # Register Magic Aliases
2177 mman = self.magics_manager
2177 mman = self.magics_manager
2178 # FIXME: magic aliases should be defined by the Magics classes
2178 # FIXME: magic aliases should be defined by the Magics classes
2179 # or in MagicsManager, not here
2179 # or in MagicsManager, not here
2180 mman.register_alias('ed', 'edit')
2180 mman.register_alias('ed', 'edit')
2181 mman.register_alias('hist', 'history')
2181 mman.register_alias('hist', 'history')
2182 mman.register_alias('rep', 'recall')
2182 mman.register_alias('rep', 'recall')
2183 mman.register_alias('SVG', 'svg', 'cell')
2183 mman.register_alias('SVG', 'svg', 'cell')
2184 mman.register_alias('HTML', 'html', 'cell')
2184 mman.register_alias('HTML', 'html', 'cell')
2185 mman.register_alias('file', 'writefile', 'cell')
2185 mman.register_alias('file', 'writefile', 'cell')
2186
2186
2187 # FIXME: Move the color initialization to the DisplayHook, which
2187 # FIXME: Move the color initialization to the DisplayHook, which
2188 # should be split into a prompt manager and displayhook. We probably
2188 # should be split into a prompt manager and displayhook. We probably
2189 # even need a centralize colors management object.
2189 # even need a centralize colors management object.
2190 self.magic('colors %s' % self.colors)
2190 self.magic('colors %s' % self.colors)
2191
2191
2192 # Defined here so that it's included in the documentation
2192 # Defined here so that it's included in the documentation
2193 @functools.wraps(magic.MagicsManager.register_function)
2193 @functools.wraps(magic.MagicsManager.register_function)
2194 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2194 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2195 self.magics_manager.register_function(func,
2195 self.magics_manager.register_function(func,
2196 magic_kind=magic_kind, magic_name=magic_name)
2196 magic_kind=magic_kind, magic_name=magic_name)
2197
2197
2198 def run_line_magic(self, magic_name, line):
2198 def run_line_magic(self, magic_name, line):
2199 """Execute the given line magic.
2199 """Execute the given line magic.
2200
2200
2201 Parameters
2201 Parameters
2202 ----------
2202 ----------
2203 magic_name : str
2203 magic_name : str
2204 Name of the desired magic function, without '%' prefix.
2204 Name of the desired magic function, without '%' prefix.
2205
2205
2206 line : str
2206 line : str
2207 The rest of the input line as a single string.
2207 The rest of the input line as a single string.
2208 """
2208 """
2209 fn = self.find_line_magic(magic_name)
2209 fn = self.find_line_magic(magic_name)
2210 if fn is None:
2210 if fn is None:
2211 cm = self.find_cell_magic(magic_name)
2211 cm = self.find_cell_magic(magic_name)
2212 etpl = "Line magic function `%%%s` not found%s."
2212 etpl = "Line magic function `%%%s` not found%s."
2213 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2213 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2214 'did you mean that instead?)' % magic_name )
2214 'did you mean that instead?)' % magic_name )
2215 error(etpl % (magic_name, extra))
2215 error(etpl % (magic_name, extra))
2216 else:
2216 else:
2217 # Note: this is the distance in the stack to the user's frame.
2217 # Note: this is the distance in the stack to the user's frame.
2218 # This will need to be updated if the internal calling logic gets
2218 # This will need to be updated if the internal calling logic gets
2219 # refactored, or else we'll be expanding the wrong variables.
2219 # refactored, or else we'll be expanding the wrong variables.
2220 stack_depth = 2
2220 stack_depth = 2
2221 magic_arg_s = self.var_expand(line, stack_depth)
2221 magic_arg_s = self.var_expand(line, stack_depth)
2222 # Put magic args in a list so we can call with f(*a) syntax
2222 # Put magic args in a list so we can call with f(*a) syntax
2223 args = [magic_arg_s]
2223 args = [magic_arg_s]
2224 kwargs = {}
2224 kwargs = {}
2225 # Grab local namespace if we need it:
2225 # Grab local namespace if we need it:
2226 if getattr(fn, "needs_local_scope", False):
2226 if getattr(fn, "needs_local_scope", False):
2227 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2227 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2228 with self.builtin_trap:
2228 with self.builtin_trap:
2229 result = fn(*args,**kwargs)
2229 result = fn(*args,**kwargs)
2230 return result
2230 return result
2231
2231
2232 def run_cell_magic(self, magic_name, line, cell):
2232 def run_cell_magic(self, magic_name, line, cell):
2233 """Execute the given cell magic.
2233 """Execute the given cell magic.
2234
2234
2235 Parameters
2235 Parameters
2236 ----------
2236 ----------
2237 magic_name : str
2237 magic_name : str
2238 Name of the desired magic function, without '%' prefix.
2238 Name of the desired magic function, without '%' prefix.
2239
2239
2240 line : str
2240 line : str
2241 The rest of the first input line as a single string.
2241 The rest of the first input line as a single string.
2242
2242
2243 cell : str
2243 cell : str
2244 The body of the cell as a (possibly multiline) string.
2244 The body of the cell as a (possibly multiline) string.
2245 """
2245 """
2246 fn = self.find_cell_magic(magic_name)
2246 fn = self.find_cell_magic(magic_name)
2247 if fn is None:
2247 if fn is None:
2248 lm = self.find_line_magic(magic_name)
2248 lm = self.find_line_magic(magic_name)
2249 etpl = "Cell magic `%%{0}` not found{1}."
2249 etpl = "Cell magic `%%{0}` not found{1}."
2250 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2250 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2251 'did you mean that instead?)'.format(magic_name))
2251 'did you mean that instead?)'.format(magic_name))
2252 error(etpl.format(magic_name, extra))
2252 error(etpl.format(magic_name, extra))
2253 elif cell == '':
2253 elif cell == '':
2254 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2254 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2255 if self.find_line_magic(magic_name) is not None:
2255 if self.find_line_magic(magic_name) is not None:
2256 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2256 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2257 raise UsageError(message)
2257 raise UsageError(message)
2258 else:
2258 else:
2259 # Note: this is the distance in the stack to the user's frame.
2259 # Note: this is the distance in the stack to the user's frame.
2260 # This will need to be updated if the internal calling logic gets
2260 # This will need to be updated if the internal calling logic gets
2261 # refactored, or else we'll be expanding the wrong variables.
2261 # refactored, or else we'll be expanding the wrong variables.
2262 stack_depth = 2
2262 stack_depth = 2
2263 magic_arg_s = self.var_expand(line, stack_depth)
2263 magic_arg_s = self.var_expand(line, stack_depth)
2264 with self.builtin_trap:
2264 with self.builtin_trap:
2265 result = fn(magic_arg_s, cell)
2265 result = fn(magic_arg_s, cell)
2266 return result
2266 return result
2267
2267
2268 def find_line_magic(self, magic_name):
2268 def find_line_magic(self, magic_name):
2269 """Find and return a line magic by name.
2269 """Find and return a line magic by name.
2270
2270
2271 Returns None if the magic isn't found."""
2271 Returns None if the magic isn't found."""
2272 return self.magics_manager.magics['line'].get(magic_name)
2272 return self.magics_manager.magics['line'].get(magic_name)
2273
2273
2274 def find_cell_magic(self, magic_name):
2274 def find_cell_magic(self, magic_name):
2275 """Find and return a cell magic by name.
2275 """Find and return a cell magic by name.
2276
2276
2277 Returns None if the magic isn't found."""
2277 Returns None if the magic isn't found."""
2278 return self.magics_manager.magics['cell'].get(magic_name)
2278 return self.magics_manager.magics['cell'].get(magic_name)
2279
2279
2280 def find_magic(self, magic_name, magic_kind='line'):
2280 def find_magic(self, magic_name, magic_kind='line'):
2281 """Find and return a magic of the given type by name.
2281 """Find and return a magic of the given type by name.
2282
2282
2283 Returns None if the magic isn't found."""
2283 Returns None if the magic isn't found."""
2284 return self.magics_manager.magics[magic_kind].get(magic_name)
2284 return self.magics_manager.magics[magic_kind].get(magic_name)
2285
2285
2286 def magic(self, arg_s):
2286 def magic(self, arg_s):
2287 """DEPRECATED. Use run_line_magic() instead.
2287 """DEPRECATED. Use run_line_magic() instead.
2288
2288
2289 Call a magic function by name.
2289 Call a magic function by name.
2290
2290
2291 Input: a string containing the name of the magic function to call and
2291 Input: a string containing the name of the magic function to call and
2292 any additional arguments to be passed to the magic.
2292 any additional arguments to be passed to the magic.
2293
2293
2294 magic('name -opt foo bar') is equivalent to typing at the ipython
2294 magic('name -opt foo bar') is equivalent to typing at the ipython
2295 prompt:
2295 prompt:
2296
2296
2297 In[1]: %name -opt foo bar
2297 In[1]: %name -opt foo bar
2298
2298
2299 To call a magic without arguments, simply use magic('name').
2299 To call a magic without arguments, simply use magic('name').
2300
2300
2301 This provides a proper Python function to call IPython's magics in any
2301 This provides a proper Python function to call IPython's magics in any
2302 valid Python code you can type at the interpreter, including loops and
2302 valid Python code you can type at the interpreter, including loops and
2303 compound statements.
2303 compound statements.
2304 """
2304 """
2305 # TODO: should we issue a loud deprecation warning here?
2305 # TODO: should we issue a loud deprecation warning here?
2306 magic_name, _, magic_arg_s = arg_s.partition(' ')
2306 magic_name, _, magic_arg_s = arg_s.partition(' ')
2307 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2307 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2308 return self.run_line_magic(magic_name, magic_arg_s)
2308 return self.run_line_magic(magic_name, magic_arg_s)
2309
2309
2310 #-------------------------------------------------------------------------
2310 #-------------------------------------------------------------------------
2311 # Things related to macros
2311 # Things related to macros
2312 #-------------------------------------------------------------------------
2312 #-------------------------------------------------------------------------
2313
2313
2314 def define_macro(self, name, themacro):
2314 def define_macro(self, name, themacro):
2315 """Define a new macro
2315 """Define a new macro
2316
2316
2317 Parameters
2317 Parameters
2318 ----------
2318 ----------
2319 name : str
2319 name : str
2320 The name of the macro.
2320 The name of the macro.
2321 themacro : str or Macro
2321 themacro : str or Macro
2322 The action to do upon invoking the macro. If a string, a new
2322 The action to do upon invoking the macro. If a string, a new
2323 Macro object is created by passing the string to it.
2323 Macro object is created by passing the string to it.
2324 """
2324 """
2325
2325
2326 from IPython.core import macro
2326 from IPython.core import macro
2327
2327
2328 if isinstance(themacro, string_types):
2328 if isinstance(themacro, string_types):
2329 themacro = macro.Macro(themacro)
2329 themacro = macro.Macro(themacro)
2330 if not isinstance(themacro, macro.Macro):
2330 if not isinstance(themacro, macro.Macro):
2331 raise ValueError('A macro must be a string or a Macro instance.')
2331 raise ValueError('A macro must be a string or a Macro instance.')
2332 self.user_ns[name] = themacro
2332 self.user_ns[name] = themacro
2333
2333
2334 #-------------------------------------------------------------------------
2334 #-------------------------------------------------------------------------
2335 # Things related to the running of system commands
2335 # Things related to the running of system commands
2336 #-------------------------------------------------------------------------
2336 #-------------------------------------------------------------------------
2337
2337
2338 def system_piped(self, cmd):
2338 def system_piped(self, cmd):
2339 """Call the given cmd in a subprocess, piping stdout/err
2339 """Call the given cmd in a subprocess, piping stdout/err
2340
2340
2341 Parameters
2341 Parameters
2342 ----------
2342 ----------
2343 cmd : str
2343 cmd : str
2344 Command to execute (can not end in '&', as background processes are
2344 Command to execute (can not end in '&', as background processes are
2345 not supported. Should not be a command that expects input
2345 not supported. Should not be a command that expects input
2346 other than simple text.
2346 other than simple text.
2347 """
2347 """
2348 if cmd.rstrip().endswith('&'):
2348 if cmd.rstrip().endswith('&'):
2349 # this is *far* from a rigorous test
2349 # this is *far* from a rigorous test
2350 # We do not support backgrounding processes because we either use
2350 # We do not support backgrounding processes because we either use
2351 # pexpect or pipes to read from. Users can always just call
2351 # pexpect or pipes to read from. Users can always just call
2352 # os.system() or use ip.system=ip.system_raw
2352 # os.system() or use ip.system=ip.system_raw
2353 # if they really want a background process.
2353 # if they really want a background process.
2354 raise OSError("Background processes not supported.")
2354 raise OSError("Background processes not supported.")
2355
2355
2356 # we explicitly do NOT return the subprocess status code, because
2356 # we explicitly do NOT return the subprocess status code, because
2357 # a non-None value would trigger :func:`sys.displayhook` calls.
2357 # a non-None value would trigger :func:`sys.displayhook` calls.
2358 # Instead, we store the exit_code in user_ns.
2358 # Instead, we store the exit_code in user_ns.
2359 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2359 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2360
2360
2361 def system_raw(self, cmd):
2361 def system_raw(self, cmd):
2362 """Call the given cmd in a subprocess using os.system on Windows or
2362 """Call the given cmd in a subprocess using os.system on Windows or
2363 subprocess.call using the system shell on other platforms.
2363 subprocess.call using the system shell on other platforms.
2364
2364
2365 Parameters
2365 Parameters
2366 ----------
2366 ----------
2367 cmd : str
2367 cmd : str
2368 Command to execute.
2368 Command to execute.
2369 """
2369 """
2370 cmd = self.var_expand(cmd, depth=1)
2370 cmd = self.var_expand(cmd, depth=1)
2371 # protect os.system from UNC paths on Windows, which it can't handle:
2371 # protect os.system from UNC paths on Windows, which it can't handle:
2372 if sys.platform == 'win32':
2372 if sys.platform == 'win32':
2373 from IPython.utils._process_win32 import AvoidUNCPath
2373 from IPython.utils._process_win32 import AvoidUNCPath
2374 with AvoidUNCPath() as path:
2374 with AvoidUNCPath() as path:
2375 if path is not None:
2375 if path is not None:
2376 cmd = '"pushd %s &&"%s' % (path, cmd)
2376 cmd = '"pushd %s &&"%s' % (path, cmd)
2377 cmd = py3compat.unicode_to_str(cmd)
2377 cmd = py3compat.unicode_to_str(cmd)
2378 try:
2378 try:
2379 ec = os.system(cmd)
2379 ec = os.system(cmd)
2380 except KeyboardInterrupt:
2380 except KeyboardInterrupt:
2381 self.write_err('\n' + self.get_exception_only())
2381 self.write_err('\n' + self.get_exception_only())
2382 ec = -2
2382 ec = -2
2383 else:
2383 else:
2384 cmd = py3compat.unicode_to_str(cmd)
2384 cmd = py3compat.unicode_to_str(cmd)
2385 # For posix the result of the subprocess.call() below is an exit
2385 # For posix the result of the subprocess.call() below is an exit
2386 # code, which by convention is zero for success, positive for
2386 # code, which by convention is zero for success, positive for
2387 # program failure. Exit codes above 128 are reserved for signals,
2387 # program failure. Exit codes above 128 are reserved for signals,
2388 # and the formula for converting a signal to an exit code is usually
2388 # and the formula for converting a signal to an exit code is usually
2389 # signal_number+128. To more easily differentiate between exit
2389 # signal_number+128. To more easily differentiate between exit
2390 # codes and signals, ipython uses negative numbers. For instance
2390 # codes and signals, ipython uses negative numbers. For instance
2391 # since control-c is signal 2 but exit code 130, ipython's
2391 # since control-c is signal 2 but exit code 130, ipython's
2392 # _exit_code variable will read -2. Note that some shells like
2392 # _exit_code variable will read -2. Note that some shells like
2393 # csh and fish don't follow sh/bash conventions for exit codes.
2393 # csh and fish don't follow sh/bash conventions for exit codes.
2394 executable = os.environ.get('SHELL', None)
2394 executable = os.environ.get('SHELL', None)
2395 try:
2395 try:
2396 # Use env shell instead of default /bin/sh
2396 # Use env shell instead of default /bin/sh
2397 ec = subprocess.call(cmd, shell=True, executable=executable)
2397 ec = subprocess.call(cmd, shell=True, executable=executable)
2398 except KeyboardInterrupt:
2398 except KeyboardInterrupt:
2399 # intercept control-C; a long traceback is not useful here
2399 # intercept control-C; a long traceback is not useful here
2400 self.write_err('\n' + self.get_exception_only())
2400 self.write_err('\n' + self.get_exception_only())
2401 ec = 130
2401 ec = 130
2402 if ec > 128:
2402 if ec > 128:
2403 ec = -(ec - 128)
2403 ec = -(ec - 128)
2404
2404
2405 # We explicitly do NOT return the subprocess status code, because
2405 # We explicitly do NOT return the subprocess status code, because
2406 # a non-None value would trigger :func:`sys.displayhook` calls.
2406 # a non-None value would trigger :func:`sys.displayhook` calls.
2407 # Instead, we store the exit_code in user_ns. Note the semantics
2407 # Instead, we store the exit_code in user_ns. Note the semantics
2408 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2408 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2409 # but raising SystemExit(_exit_code) will give status 254!
2409 # but raising SystemExit(_exit_code) will give status 254!
2410 self.user_ns['_exit_code'] = ec
2410 self.user_ns['_exit_code'] = ec
2411
2411
2412 # use piped system by default, because it is better behaved
2412 # use piped system by default, because it is better behaved
2413 system = system_piped
2413 system = system_piped
2414
2414
2415 def getoutput(self, cmd, split=True, depth=0):
2415 def getoutput(self, cmd, split=True, depth=0):
2416 """Get output (possibly including stderr) from a subprocess.
2416 """Get output (possibly including stderr) from a subprocess.
2417
2417
2418 Parameters
2418 Parameters
2419 ----------
2419 ----------
2420 cmd : str
2420 cmd : str
2421 Command to execute (can not end in '&', as background processes are
2421 Command to execute (can not end in '&', as background processes are
2422 not supported.
2422 not supported.
2423 split : bool, optional
2423 split : bool, optional
2424 If True, split the output into an IPython SList. Otherwise, an
2424 If True, split the output into an IPython SList. Otherwise, an
2425 IPython LSString is returned. These are objects similar to normal
2425 IPython LSString is returned. These are objects similar to normal
2426 lists and strings, with a few convenience attributes for easier
2426 lists and strings, with a few convenience attributes for easier
2427 manipulation of line-based output. You can use '?' on them for
2427 manipulation of line-based output. You can use '?' on them for
2428 details.
2428 details.
2429 depth : int, optional
2429 depth : int, optional
2430 How many frames above the caller are the local variables which should
2430 How many frames above the caller are the local variables which should
2431 be expanded in the command string? The default (0) assumes that the
2431 be expanded in the command string? The default (0) assumes that the
2432 expansion variables are in the stack frame calling this function.
2432 expansion variables are in the stack frame calling this function.
2433 """
2433 """
2434 if cmd.rstrip().endswith('&'):
2434 if cmd.rstrip().endswith('&'):
2435 # this is *far* from a rigorous test
2435 # this is *far* from a rigorous test
2436 raise OSError("Background processes not supported.")
2436 raise OSError("Background processes not supported.")
2437 out = getoutput(self.var_expand(cmd, depth=depth+1))
2437 out = getoutput(self.var_expand(cmd, depth=depth+1))
2438 if split:
2438 if split:
2439 out = SList(out.splitlines())
2439 out = SList(out.splitlines())
2440 else:
2440 else:
2441 out = LSString(out)
2441 out = LSString(out)
2442 return out
2442 return out
2443
2443
2444 #-------------------------------------------------------------------------
2444 #-------------------------------------------------------------------------
2445 # Things related to aliases
2445 # Things related to aliases
2446 #-------------------------------------------------------------------------
2446 #-------------------------------------------------------------------------
2447
2447
2448 def init_alias(self):
2448 def init_alias(self):
2449 self.alias_manager = AliasManager(shell=self, parent=self)
2449 self.alias_manager = AliasManager(shell=self, parent=self)
2450 self.configurables.append(self.alias_manager)
2450 self.configurables.append(self.alias_manager)
2451
2451
2452 #-------------------------------------------------------------------------
2452 #-------------------------------------------------------------------------
2453 # Things related to extensions
2453 # Things related to extensions
2454 #-------------------------------------------------------------------------
2454 #-------------------------------------------------------------------------
2455
2455
2456 def init_extension_manager(self):
2456 def init_extension_manager(self):
2457 self.extension_manager = ExtensionManager(shell=self, parent=self)
2457 self.extension_manager = ExtensionManager(shell=self, parent=self)
2458 self.configurables.append(self.extension_manager)
2458 self.configurables.append(self.extension_manager)
2459
2459
2460 #-------------------------------------------------------------------------
2460 #-------------------------------------------------------------------------
2461 # Things related to payloads
2461 # Things related to payloads
2462 #-------------------------------------------------------------------------
2462 #-------------------------------------------------------------------------
2463
2463
2464 def init_payload(self):
2464 def init_payload(self):
2465 self.payload_manager = PayloadManager(parent=self)
2465 self.payload_manager = PayloadManager(parent=self)
2466 self.configurables.append(self.payload_manager)
2466 self.configurables.append(self.payload_manager)
2467
2467
2468 #-------------------------------------------------------------------------
2468 #-------------------------------------------------------------------------
2469 # Things related to the prefilter
2469 # Things related to the prefilter
2470 #-------------------------------------------------------------------------
2470 #-------------------------------------------------------------------------
2471
2471
2472 def init_prefilter(self):
2472 def init_prefilter(self):
2473 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2473 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2474 self.configurables.append(self.prefilter_manager)
2474 self.configurables.append(self.prefilter_manager)
2475 # Ultimately this will be refactored in the new interpreter code, but
2475 # Ultimately this will be refactored in the new interpreter code, but
2476 # for now, we should expose the main prefilter method (there's legacy
2476 # for now, we should expose the main prefilter method (there's legacy
2477 # code out there that may rely on this).
2477 # code out there that may rely on this).
2478 self.prefilter = self.prefilter_manager.prefilter_lines
2478 self.prefilter = self.prefilter_manager.prefilter_lines
2479
2479
2480 def auto_rewrite_input(self, cmd):
2480 def auto_rewrite_input(self, cmd):
2481 """Print to the screen the rewritten form of the user's command.
2481 """Print to the screen the rewritten form of the user's command.
2482
2482
2483 This shows visual feedback by rewriting input lines that cause
2483 This shows visual feedback by rewriting input lines that cause
2484 automatic calling to kick in, like::
2484 automatic calling to kick in, like::
2485
2485
2486 /f x
2486 /f x
2487
2487
2488 into::
2488 into::
2489
2489
2490 ------> f(x)
2490 ------> f(x)
2491
2491
2492 after the user's input prompt. This helps the user understand that the
2492 after the user's input prompt. This helps the user understand that the
2493 input line was transformed automatically by IPython.
2493 input line was transformed automatically by IPython.
2494 """
2494 """
2495 if not self.show_rewritten_input:
2495 if not self.show_rewritten_input:
2496 return
2496 return
2497
2497
2498 rw = self.prompt_manager.render('rewrite') + cmd
2498 rw = self.prompt_manager.render('rewrite') + cmd
2499
2499
2500 try:
2500 try:
2501 # plain ascii works better w/ pyreadline, on some machines, so
2501 # plain ascii works better w/ pyreadline, on some machines, so
2502 # we use it and only print uncolored rewrite if we have unicode
2502 # we use it and only print uncolored rewrite if we have unicode
2503 rw = str(rw)
2503 rw = str(rw)
2504 print(rw, file=io.stdout)
2504 print(rw, file=io.stdout)
2505 except UnicodeEncodeError:
2505 except UnicodeEncodeError:
2506 print("------> " + cmd)
2506 print("------> " + cmd)
2507
2507
2508 #-------------------------------------------------------------------------
2508 #-------------------------------------------------------------------------
2509 # Things related to extracting values/expressions from kernel and user_ns
2509 # Things related to extracting values/expressions from kernel and user_ns
2510 #-------------------------------------------------------------------------
2510 #-------------------------------------------------------------------------
2511
2511
2512 def _user_obj_error(self):
2512 def _user_obj_error(self):
2513 """return simple exception dict
2513 """return simple exception dict
2514
2514
2515 for use in user_expressions
2515 for use in user_expressions
2516 """
2516 """
2517
2517
2518 etype, evalue, tb = self._get_exc_info()
2518 etype, evalue, tb = self._get_exc_info()
2519 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2519 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2520
2520
2521 exc_info = {
2521 exc_info = {
2522 u'status' : 'error',
2522 u'status' : 'error',
2523 u'traceback' : stb,
2523 u'traceback' : stb,
2524 u'ename' : unicode_type(etype.__name__),
2524 u'ename' : unicode_type(etype.__name__),
2525 u'evalue' : py3compat.safe_unicode(evalue),
2525 u'evalue' : py3compat.safe_unicode(evalue),
2526 }
2526 }
2527
2527
2528 return exc_info
2528 return exc_info
2529
2529
2530 def _format_user_obj(self, obj):
2530 def _format_user_obj(self, obj):
2531 """format a user object to display dict
2531 """format a user object to display dict
2532
2532
2533 for use in user_expressions
2533 for use in user_expressions
2534 """
2534 """
2535
2535
2536 data, md = self.display_formatter.format(obj)
2536 data, md = self.display_formatter.format(obj)
2537 value = {
2537 value = {
2538 'status' : 'ok',
2538 'status' : 'ok',
2539 'data' : data,
2539 'data' : data,
2540 'metadata' : md,
2540 'metadata' : md,
2541 }
2541 }
2542 return value
2542 return value
2543
2543
2544 def user_expressions(self, expressions):
2544 def user_expressions(self, expressions):
2545 """Evaluate a dict of expressions in the user's namespace.
2545 """Evaluate a dict of expressions in the user's namespace.
2546
2546
2547 Parameters
2547 Parameters
2548 ----------
2548 ----------
2549 expressions : dict
2549 expressions : dict
2550 A dict with string keys and string values. The expression values
2550 A dict with string keys and string values. The expression values
2551 should be valid Python expressions, each of which will be evaluated
2551 should be valid Python expressions, each of which will be evaluated
2552 in the user namespace.
2552 in the user namespace.
2553
2553
2554 Returns
2554 Returns
2555 -------
2555 -------
2556 A dict, keyed like the input expressions dict, with the rich mime-typed
2556 A dict, keyed like the input expressions dict, with the rich mime-typed
2557 display_data of each value.
2557 display_data of each value.
2558 """
2558 """
2559 out = {}
2559 out = {}
2560 user_ns = self.user_ns
2560 user_ns = self.user_ns
2561 global_ns = self.user_global_ns
2561 global_ns = self.user_global_ns
2562
2562
2563 for key, expr in iteritems(expressions):
2563 for key, expr in iteritems(expressions):
2564 try:
2564 try:
2565 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2565 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2566 except:
2566 except:
2567 value = self._user_obj_error()
2567 value = self._user_obj_error()
2568 out[key] = value
2568 out[key] = value
2569 return out
2569 return out
2570
2570
2571 #-------------------------------------------------------------------------
2571 #-------------------------------------------------------------------------
2572 # Things related to the running of code
2572 # Things related to the running of code
2573 #-------------------------------------------------------------------------
2573 #-------------------------------------------------------------------------
2574
2574
2575 def ex(self, cmd):
2575 def ex(self, cmd):
2576 """Execute a normal python statement in user namespace."""
2576 """Execute a normal python statement in user namespace."""
2577 with self.builtin_trap:
2577 with self.builtin_trap:
2578 exec(cmd, self.user_global_ns, self.user_ns)
2578 exec(cmd, self.user_global_ns, self.user_ns)
2579
2579
2580 def ev(self, expr):
2580 def ev(self, expr):
2581 """Evaluate python expression expr in user namespace.
2581 """Evaluate python expression expr in user namespace.
2582
2582
2583 Returns the result of evaluation
2583 Returns the result of evaluation
2584 """
2584 """
2585 with self.builtin_trap:
2585 with self.builtin_trap:
2586 return eval(expr, self.user_global_ns, self.user_ns)
2586 return eval(expr, self.user_global_ns, self.user_ns)
2587
2587
2588 def safe_execfile(self, fname, *where, **kw):
2588 def safe_execfile(self, fname, *where, **kw):
2589 """A safe version of the builtin execfile().
2589 """A safe version of the builtin execfile().
2590
2590
2591 This version will never throw an exception, but instead print
2591 This version will never throw an exception, but instead print
2592 helpful error messages to the screen. This only works on pure
2592 helpful error messages to the screen. This only works on pure
2593 Python files with the .py extension.
2593 Python files with the .py extension.
2594
2594
2595 Parameters
2595 Parameters
2596 ----------
2596 ----------
2597 fname : string
2597 fname : string
2598 The name of the file to be executed.
2598 The name of the file to be executed.
2599 where : tuple
2599 where : tuple
2600 One or two namespaces, passed to execfile() as (globals,locals).
2600 One or two namespaces, passed to execfile() as (globals,locals).
2601 If only one is given, it is passed as both.
2601 If only one is given, it is passed as both.
2602 exit_ignore : bool (False)
2602 exit_ignore : bool (False)
2603 If True, then silence SystemExit for non-zero status (it is always
2603 If True, then silence SystemExit for non-zero status (it is always
2604 silenced for zero status, as it is so common).
2604 silenced for zero status, as it is so common).
2605 raise_exceptions : bool (False)
2605 raise_exceptions : bool (False)
2606 If True raise exceptions everywhere. Meant for testing.
2606 If True raise exceptions everywhere. Meant for testing.
2607 shell_futures : bool (False)
2607 shell_futures : bool (False)
2608 If True, the code will share future statements with the interactive
2608 If True, the code will share future statements with the interactive
2609 shell. It will both be affected by previous __future__ imports, and
2609 shell. It will both be affected by previous __future__ imports, and
2610 any __future__ imports in the code will affect the shell. If False,
2610 any __future__ imports in the code will affect the shell. If False,
2611 __future__ imports are not shared in either direction.
2611 __future__ imports are not shared in either direction.
2612
2612
2613 """
2613 """
2614 kw.setdefault('exit_ignore', False)
2614 kw.setdefault('exit_ignore', False)
2615 kw.setdefault('raise_exceptions', False)
2615 kw.setdefault('raise_exceptions', False)
2616 kw.setdefault('shell_futures', False)
2616 kw.setdefault('shell_futures', False)
2617
2617
2618 fname = os.path.abspath(os.path.expanduser(fname))
2618 fname = os.path.abspath(os.path.expanduser(fname))
2619
2619
2620 # Make sure we can open the file
2620 # Make sure we can open the file
2621 try:
2621 try:
2622 with open(fname) as thefile:
2622 with open(fname) as thefile:
2623 pass
2623 pass
2624 except:
2624 except:
2625 warn('Could not open file <%s> for safe execution.' % fname)
2625 warn('Could not open file <%s> for safe execution.' % fname)
2626 return
2626 return
2627
2627
2628 # Find things also in current directory. This is needed to mimic the
2628 # Find things also in current directory. This is needed to mimic the
2629 # behavior of running a script from the system command line, where
2629 # behavior of running a script from the system command line, where
2630 # Python inserts the script's directory into sys.path
2630 # Python inserts the script's directory into sys.path
2631 dname = os.path.dirname(fname)
2631 dname = os.path.dirname(fname)
2632
2632
2633 with prepended_to_syspath(dname):
2633 with prepended_to_syspath(dname):
2634 try:
2634 try:
2635 glob, loc = (where + (None, ))[:2]
2635 glob, loc = (where + (None, ))[:2]
2636 py3compat.execfile(
2636 py3compat.execfile(
2637 fname, glob, loc,
2637 fname, glob, loc,
2638 self.compile if kw['shell_futures'] else None)
2638 self.compile if kw['shell_futures'] else None)
2639 except SystemExit as status:
2639 except SystemExit as status:
2640 # If the call was made with 0 or None exit status (sys.exit(0)
2640 # If the call was made with 0 or None exit status (sys.exit(0)
2641 # or sys.exit() ), don't bother showing a traceback, as both of
2641 # or sys.exit() ), don't bother showing a traceback, as both of
2642 # these are considered normal by the OS:
2642 # these are considered normal by the OS:
2643 # > python -c'import sys;sys.exit(0)'; echo $?
2643 # > python -c'import sys;sys.exit(0)'; echo $?
2644 # 0
2644 # 0
2645 # > python -c'import sys;sys.exit()'; echo $?
2645 # > python -c'import sys;sys.exit()'; echo $?
2646 # 0
2646 # 0
2647 # For other exit status, we show the exception unless
2647 # For other exit status, we show the exception unless
2648 # explicitly silenced, but only in short form.
2648 # explicitly silenced, but only in short form.
2649 if kw['raise_exceptions']:
2649 if kw['raise_exceptions']:
2650 raise
2650 raise
2651 if status.code and not kw['exit_ignore']:
2651 if status.code and not kw['exit_ignore']:
2652 self.showtraceback(exception_only=True)
2652 self.showtraceback(exception_only=True)
2653 except:
2653 except:
2654 if kw['raise_exceptions']:
2654 if kw['raise_exceptions']:
2655 raise
2655 raise
2656 # tb offset is 2 because we wrap execfile
2656 # tb offset is 2 because we wrap execfile
2657 self.showtraceback(tb_offset=2)
2657 self.showtraceback(tb_offset=2)
2658
2658
2659 def safe_execfile_ipy(self, fname, shell_futures=False):
2659 def safe_execfile_ipy(self, fname, shell_futures=False):
2660 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2660 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2661
2661
2662 Parameters
2662 Parameters
2663 ----------
2663 ----------
2664 fname : str
2664 fname : str
2665 The name of the file to execute. The filename must have a
2665 The name of the file to execute. The filename must have a
2666 .ipy or .ipynb extension.
2666 .ipy or .ipynb extension.
2667 shell_futures : bool (False)
2667 shell_futures : bool (False)
2668 If True, the code will share future statements with the interactive
2668 If True, the code will share future statements with the interactive
2669 shell. It will both be affected by previous __future__ imports, and
2669 shell. It will both be affected by previous __future__ imports, and
2670 any __future__ imports in the code will affect the shell. If False,
2670 any __future__ imports in the code will affect the shell. If False,
2671 __future__ imports are not shared in either direction.
2671 __future__ imports are not shared in either direction.
2672 """
2672 """
2673 fname = os.path.abspath(os.path.expanduser(fname))
2673 fname = os.path.abspath(os.path.expanduser(fname))
2674
2674
2675 # Make sure we can open the file
2675 # Make sure we can open the file
2676 try:
2676 try:
2677 with open(fname) as thefile:
2677 with open(fname) as thefile:
2678 pass
2678 pass
2679 except:
2679 except:
2680 warn('Could not open file <%s> for safe execution.' % fname)
2680 warn('Could not open file <%s> for safe execution.' % fname)
2681 return
2681 return
2682
2682
2683 # Find things also in current directory. This is needed to mimic the
2683 # Find things also in current directory. This is needed to mimic the
2684 # behavior of running a script from the system command line, where
2684 # behavior of running a script from the system command line, where
2685 # Python inserts the script's directory into sys.path
2685 # Python inserts the script's directory into sys.path
2686 dname = os.path.dirname(fname)
2686 dname = os.path.dirname(fname)
2687
2687
2688 def get_cells():
2688 def get_cells():
2689 """generator for sequence of code blocks to run"""
2689 """generator for sequence of code blocks to run"""
2690 if fname.endswith('.ipynb'):
2690 if fname.endswith('.ipynb'):
2691 from IPython.nbformat import read
2691 from IPython.nbformat import read
2692 with io_open(fname) as f:
2692 with io_open(fname) as f:
2693 nb = read(f, as_version=4)
2693 nb = read(f, as_version=4)
2694 if not nb.cells:
2694 if not nb.cells:
2695 return
2695 return
2696 for cell in nb.cells:
2696 for cell in nb.cells:
2697 if cell.cell_type == 'code':
2697 if cell.cell_type == 'code':
2698 yield cell.source
2698 yield cell.source
2699 else:
2699 else:
2700 with open(fname) as f:
2700 with open(fname) as f:
2701 yield f.read()
2701 yield f.read()
2702
2702
2703 with prepended_to_syspath(dname):
2703 with prepended_to_syspath(dname):
2704 try:
2704 try:
2705 for cell in get_cells():
2705 for cell in get_cells():
2706 # self.run_cell currently captures all exceptions
2706 # self.run_cell currently captures all exceptions
2707 # raised in user code. It would be nice if there were
2707 # raised in user code. It would be nice if there were
2708 # versions of run_cell that did raise, so
2708 # versions of run_cell that did raise, so
2709 # we could catch the errors.
2709 # we could catch the errors.
2710 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2710 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
2711 if not result.success:
2711 if not result.success:
2712 break
2712 break
2713 except:
2713 except:
2714 self.showtraceback()
2714 self.showtraceback()
2715 warn('Unknown failure executing file: <%s>' % fname)
2715 warn('Unknown failure executing file: <%s>' % fname)
2716
2716
2717 def safe_run_module(self, mod_name, where):
2717 def safe_run_module(self, mod_name, where):
2718 """A safe version of runpy.run_module().
2718 """A safe version of runpy.run_module().
2719
2719
2720 This version will never throw an exception, but instead print
2720 This version will never throw an exception, but instead print
2721 helpful error messages to the screen.
2721 helpful error messages to the screen.
2722
2722
2723 `SystemExit` exceptions with status code 0 or None are ignored.
2723 `SystemExit` exceptions with status code 0 or None are ignored.
2724
2724
2725 Parameters
2725 Parameters
2726 ----------
2726 ----------
2727 mod_name : string
2727 mod_name : string
2728 The name of the module to be executed.
2728 The name of the module to be executed.
2729 where : dict
2729 where : dict
2730 The globals namespace.
2730 The globals namespace.
2731 """
2731 """
2732 try:
2732 try:
2733 try:
2733 try:
2734 where.update(
2734 where.update(
2735 runpy.run_module(str(mod_name), run_name="__main__",
2735 runpy.run_module(str(mod_name), run_name="__main__",
2736 alter_sys=True)
2736 alter_sys=True)
2737 )
2737 )
2738 except SystemExit as status:
2738 except SystemExit as status:
2739 if status.code:
2739 if status.code:
2740 raise
2740 raise
2741 except:
2741 except:
2742 self.showtraceback()
2742 self.showtraceback()
2743 warn('Unknown failure executing module: <%s>' % mod_name)
2743 warn('Unknown failure executing module: <%s>' % mod_name)
2744
2744
2745 def _run_cached_cell_magic(self, magic_name, line):
2745 def _run_cached_cell_magic(self, magic_name, line):
2746 """Special method to call a cell magic with the data stored in self.
2746 """Special method to call a cell magic with the data stored in self.
2747 """
2747 """
2748 cell = self._current_cell_magic_body
2748 cell = self._current_cell_magic_body
2749 self._current_cell_magic_body = None
2749 self._current_cell_magic_body = None
2750 return self.run_cell_magic(magic_name, line, cell)
2750 return self.run_cell_magic(magic_name, line, cell)
2751
2751
2752 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2752 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2753 """Run a complete IPython cell.
2753 """Run a complete IPython cell.
2754
2754
2755 Parameters
2755 Parameters
2756 ----------
2756 ----------
2757 raw_cell : str
2757 raw_cell : str
2758 The code (including IPython code such as %magic functions) to run.
2758 The code (including IPython code such as %magic functions) to run.
2759 store_history : bool
2759 store_history : bool
2760 If True, the raw and translated cell will be stored in IPython's
2760 If True, the raw and translated cell will be stored in IPython's
2761 history. For user code calling back into IPython's machinery, this
2761 history. For user code calling back into IPython's machinery, this
2762 should be set to False.
2762 should be set to False.
2763 silent : bool
2763 silent : bool
2764 If True, avoid side-effects, such as implicit displayhooks and
2764 If True, avoid side-effects, such as implicit displayhooks and
2765 and logging. silent=True forces store_history=False.
2765 and logging. silent=True forces store_history=False.
2766 shell_futures : bool
2766 shell_futures : bool
2767 If True, the code will share future statements with the interactive
2767 If True, the code will share future statements with the interactive
2768 shell. It will both be affected by previous __future__ imports, and
2768 shell. It will both be affected by previous __future__ imports, and
2769 any __future__ imports in the code will affect the shell. If False,
2769 any __future__ imports in the code will affect the shell. If False,
2770 __future__ imports are not shared in either direction.
2770 __future__ imports are not shared in either direction.
2771
2771
2772 Returns
2772 Returns
2773 -------
2773 -------
2774 result : :class:`ExecutionResult`
2774 result : :class:`ExecutionResult`
2775 """
2775 """
2776 result = ExecutionResult()
2776 result = ExecutionResult()
2777
2777
2778 if (not raw_cell) or raw_cell.isspace():
2778 if (not raw_cell) or raw_cell.isspace():
2779 return result
2779 return result
2780
2780
2781 if silent:
2781 if silent:
2782 store_history = False
2782 store_history = False
2783
2783
2784 if store_history:
2784 if store_history:
2785 result.execution_count = self.execution_count
2785 result.execution_count = self.execution_count
2786
2786
2787 def error_before_exec(value):
2787 def error_before_exec(value):
2788 result.error_before_exec = value
2788 result.error_before_exec = value
2789 return result
2789 return result
2790
2790
2791 self.events.trigger('pre_execute')
2791 self.events.trigger('pre_execute')
2792 if not silent:
2792 if not silent:
2793 self.events.trigger('pre_run_cell')
2793 self.events.trigger('pre_run_cell')
2794
2794
2795 # If any of our input transformation (input_transformer_manager or
2795 # If any of our input transformation (input_transformer_manager or
2796 # prefilter_manager) raises an exception, we store it in this variable
2796 # prefilter_manager) raises an exception, we store it in this variable
2797 # so that we can display the error after logging the input and storing
2797 # so that we can display the error after logging the input and storing
2798 # it in the history.
2798 # it in the history.
2799 preprocessing_exc_tuple = None
2799 preprocessing_exc_tuple = None
2800 try:
2800 try:
2801 # Static input transformations
2801 # Static input transformations
2802 cell = self.input_transformer_manager.transform_cell(raw_cell)
2802 cell = self.input_transformer_manager.transform_cell(raw_cell)
2803 except SyntaxError:
2803 except SyntaxError:
2804 preprocessing_exc_tuple = sys.exc_info()
2804 preprocessing_exc_tuple = sys.exc_info()
2805 cell = raw_cell # cell has to exist so it can be stored/logged
2805 cell = raw_cell # cell has to exist so it can be stored/logged
2806 else:
2806 else:
2807 if len(cell.splitlines()) == 1:
2807 if len(cell.splitlines()) == 1:
2808 # Dynamic transformations - only applied for single line commands
2808 # Dynamic transformations - only applied for single line commands
2809 with self.builtin_trap:
2809 with self.builtin_trap:
2810 try:
2810 try:
2811 # use prefilter_lines to handle trailing newlines
2811 # use prefilter_lines to handle trailing newlines
2812 # restore trailing newline for ast.parse
2812 # restore trailing newline for ast.parse
2813 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2813 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2814 except Exception:
2814 except Exception:
2815 # don't allow prefilter errors to crash IPython
2815 # don't allow prefilter errors to crash IPython
2816 preprocessing_exc_tuple = sys.exc_info()
2816 preprocessing_exc_tuple = sys.exc_info()
2817
2817
2818 # Store raw and processed history
2818 # Store raw and processed history
2819 if store_history:
2819 if store_history:
2820 self.history_manager.store_inputs(self.execution_count,
2820 self.history_manager.store_inputs(self.execution_count,
2821 cell, raw_cell)
2821 cell, raw_cell)
2822 if not silent:
2822 if not silent:
2823 self.logger.log(cell, raw_cell)
2823 self.logger.log(cell, raw_cell)
2824
2824
2825 # Display the exception if input processing failed.
2825 # Display the exception if input processing failed.
2826 if preprocessing_exc_tuple is not None:
2826 if preprocessing_exc_tuple is not None:
2827 self.showtraceback(preprocessing_exc_tuple)
2827 self.showtraceback(preprocessing_exc_tuple)
2828 if store_history:
2828 if store_history:
2829 self.execution_count += 1
2829 self.execution_count += 1
2830 return error_before_exec(preprocessing_exc_tuple[2])
2830 return error_before_exec(preprocessing_exc_tuple[2])
2831
2831
2832 # Our own compiler remembers the __future__ environment. If we want to
2832 # Our own compiler remembers the __future__ environment. If we want to
2833 # run code with a separate __future__ environment, use the default
2833 # run code with a separate __future__ environment, use the default
2834 # compiler
2834 # compiler
2835 compiler = self.compile if shell_futures else CachingCompiler()
2835 compiler = self.compile if shell_futures else CachingCompiler()
2836
2836
2837 with self.builtin_trap:
2837 with self.builtin_trap:
2838 cell_name = self.compile.cache(cell, self.execution_count)
2838 cell_name = self.compile.cache(cell, self.execution_count)
2839
2839
2840 with self.display_trap:
2840 with self.display_trap:
2841 # Compile to bytecode
2841 # Compile to bytecode
2842 try:
2842 try:
2843 code_ast = compiler.ast_parse(cell, filename=cell_name)
2843 code_ast = compiler.ast_parse(cell, filename=cell_name)
2844 except IndentationError as e:
2844 except IndentationError as e:
2845 self.showindentationerror()
2845 self.showindentationerror()
2846 if store_history:
2846 if store_history:
2847 self.execution_count += 1
2847 self.execution_count += 1
2848 return error_before_exec(e)
2848 return error_before_exec(e)
2849 except (OverflowError, SyntaxError, ValueError, TypeError,
2849 except (OverflowError, SyntaxError, ValueError, TypeError,
2850 MemoryError) as e:
2850 MemoryError) as e:
2851 self.showsyntaxerror()
2851 self.showsyntaxerror()
2852 if store_history:
2852 if store_history:
2853 self.execution_count += 1
2853 self.execution_count += 1
2854 return error_before_exec(e)
2854 return error_before_exec(e)
2855
2855
2856 # Apply AST transformations
2856 # Apply AST transformations
2857 try:
2857 try:
2858 code_ast = self.transform_ast(code_ast)
2858 code_ast = self.transform_ast(code_ast)
2859 except InputRejected as e:
2859 except InputRejected as e:
2860 self.showtraceback()
2860 self.showtraceback()
2861 if store_history:
2861 if store_history:
2862 self.execution_count += 1
2862 self.execution_count += 1
2863 return error_before_exec(e)
2863 return error_before_exec(e)
2864
2864
2865 # Give the displayhook a reference to our ExecutionResult so it
2865 # Give the displayhook a reference to our ExecutionResult so it
2866 # can fill in the output value.
2866 # can fill in the output value.
2867 self.displayhook.exec_result = result
2867 self.displayhook.exec_result = result
2868
2868
2869 # Execute the user code
2869 # Execute the user code
2870 interactivity = "none" if silent else self.ast_node_interactivity
2870 interactivity = "none" if silent else self.ast_node_interactivity
2871 self.run_ast_nodes(code_ast.body, cell_name,
2871 self.run_ast_nodes(code_ast.body, cell_name,
2872 interactivity=interactivity, compiler=compiler, result=result)
2872 interactivity=interactivity, compiler=compiler, result=result)
2873
2873
2874 # Reset this so later displayed values do not modify the
2874 # Reset this so later displayed values do not modify the
2875 # ExecutionResult
2875 # ExecutionResult
2876 self.displayhook.exec_result = None
2876 self.displayhook.exec_result = None
2877
2877
2878 self.events.trigger('post_execute')
2878 self.events.trigger('post_execute')
2879 if not silent:
2879 if not silent:
2880 self.events.trigger('post_run_cell')
2880 self.events.trigger('post_run_cell')
2881
2881
2882 if store_history:
2882 if store_history:
2883 # Write output to the database. Does nothing unless
2883 # Write output to the database. Does nothing unless
2884 # history output logging is enabled.
2884 # history output logging is enabled.
2885 self.history_manager.store_output(self.execution_count)
2885 self.history_manager.store_output(self.execution_count)
2886 # Each cell is a *single* input, regardless of how many lines it has
2886 # Each cell is a *single* input, regardless of how many lines it has
2887 self.execution_count += 1
2887 self.execution_count += 1
2888
2888
2889 return result
2889 return result
2890
2890
2891 def transform_ast(self, node):
2891 def transform_ast(self, node):
2892 """Apply the AST transformations from self.ast_transformers
2892 """Apply the AST transformations from self.ast_transformers
2893
2893
2894 Parameters
2894 Parameters
2895 ----------
2895 ----------
2896 node : ast.Node
2896 node : ast.Node
2897 The root node to be transformed. Typically called with the ast.Module
2897 The root node to be transformed. Typically called with the ast.Module
2898 produced by parsing user input.
2898 produced by parsing user input.
2899
2899
2900 Returns
2900 Returns
2901 -------
2901 -------
2902 An ast.Node corresponding to the node it was called with. Note that it
2902 An ast.Node corresponding to the node it was called with. Note that it
2903 may also modify the passed object, so don't rely on references to the
2903 may also modify the passed object, so don't rely on references to the
2904 original AST.
2904 original AST.
2905 """
2905 """
2906 for transformer in self.ast_transformers:
2906 for transformer in self.ast_transformers:
2907 try:
2907 try:
2908 node = transformer.visit(node)
2908 node = transformer.visit(node)
2909 except InputRejected:
2909 except InputRejected:
2910 # User-supplied AST transformers can reject an input by raising
2910 # User-supplied AST transformers can reject an input by raising
2911 # an InputRejected. Short-circuit in this case so that we
2911 # an InputRejected. Short-circuit in this case so that we
2912 # don't unregister the transform.
2912 # don't unregister the transform.
2913 raise
2913 raise
2914 except Exception:
2914 except Exception:
2915 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2915 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2916 self.ast_transformers.remove(transformer)
2916 self.ast_transformers.remove(transformer)
2917
2917
2918 if self.ast_transformers:
2918 if self.ast_transformers:
2919 ast.fix_missing_locations(node)
2919 ast.fix_missing_locations(node)
2920 return node
2920 return node
2921
2921
2922
2922
2923 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2923 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2924 compiler=compile, result=None):
2924 compiler=compile, result=None):
2925 """Run a sequence of AST nodes. The execution mode depends on the
2925 """Run a sequence of AST nodes. The execution mode depends on the
2926 interactivity parameter.
2926 interactivity parameter.
2927
2927
2928 Parameters
2928 Parameters
2929 ----------
2929 ----------
2930 nodelist : list
2930 nodelist : list
2931 A sequence of AST nodes to run.
2931 A sequence of AST nodes to run.
2932 cell_name : str
2932 cell_name : str
2933 Will be passed to the compiler as the filename of the cell. Typically
2933 Will be passed to the compiler as the filename of the cell. Typically
2934 the value returned by ip.compile.cache(cell).
2934 the value returned by ip.compile.cache(cell).
2935 interactivity : str
2935 interactivity : str
2936 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2936 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2937 run interactively (displaying output from expressions). 'last_expr'
2937 run interactively (displaying output from expressions). 'last_expr'
2938 will run the last node interactively only if it is an expression (i.e.
2938 will run the last node interactively only if it is an expression (i.e.
2939 expressions in loops or other blocks are not displayed. Other values
2939 expressions in loops or other blocks are not displayed. Other values
2940 for this parameter will raise a ValueError.
2940 for this parameter will raise a ValueError.
2941 compiler : callable
2941 compiler : callable
2942 A function with the same interface as the built-in compile(), to turn
2942 A function with the same interface as the built-in compile(), to turn
2943 the AST nodes into code objects. Default is the built-in compile().
2943 the AST nodes into code objects. Default is the built-in compile().
2944 result : ExecutionResult, optional
2944 result : ExecutionResult, optional
2945 An object to store exceptions that occur during execution.
2945 An object to store exceptions that occur during execution.
2946
2946
2947 Returns
2947 Returns
2948 -------
2948 -------
2949 True if an exception occurred while running code, False if it finished
2949 True if an exception occurred while running code, False if it finished
2950 running.
2950 running.
2951 """
2951 """
2952 if not nodelist:
2952 if not nodelist:
2953 return
2953 return
2954
2954
2955 if interactivity == 'last_expr':
2955 if interactivity == 'last_expr':
2956 if isinstance(nodelist[-1], ast.Expr):
2956 if isinstance(nodelist[-1], ast.Expr):
2957 interactivity = "last"
2957 interactivity = "last"
2958 else:
2958 else:
2959 interactivity = "none"
2959 interactivity = "none"
2960
2960
2961 if interactivity == 'none':
2961 if interactivity == 'none':
2962 to_run_exec, to_run_interactive = nodelist, []
2962 to_run_exec, to_run_interactive = nodelist, []
2963 elif interactivity == 'last':
2963 elif interactivity == 'last':
2964 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2964 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2965 elif interactivity == 'all':
2965 elif interactivity == 'all':
2966 to_run_exec, to_run_interactive = [], nodelist
2966 to_run_exec, to_run_interactive = [], nodelist
2967 else:
2967 else:
2968 raise ValueError("Interactivity was %r" % interactivity)
2968 raise ValueError("Interactivity was %r" % interactivity)
2969
2969
2970 exec_count = self.execution_count
2970 exec_count = self.execution_count
2971
2971
2972 try:
2972 try:
2973 for i, node in enumerate(to_run_exec):
2973 for i, node in enumerate(to_run_exec):
2974 mod = ast.Module([node])
2974 mod = ast.Module([node])
2975 code = compiler(mod, cell_name, "exec")
2975 code = compiler(mod, cell_name, "exec")
2976 if self.run_code(code, result):
2976 if self.run_code(code, result):
2977 return True
2977 return True
2978
2978
2979 for i, node in enumerate(to_run_interactive):
2979 for i, node in enumerate(to_run_interactive):
2980 mod = ast.Interactive([node])
2980 mod = ast.Interactive([node])
2981 code = compiler(mod, cell_name, "single")
2981 code = compiler(mod, cell_name, "single")
2982 if self.run_code(code, result):
2982 if self.run_code(code, result):
2983 return True
2983 return True
2984
2984
2985 # Flush softspace
2985 # Flush softspace
2986 if softspace(sys.stdout, 0):
2986 if softspace(sys.stdout, 0):
2987 print()
2987 print()
2988
2988
2989 except:
2989 except:
2990 # It's possible to have exceptions raised here, typically by
2990 # It's possible to have exceptions raised here, typically by
2991 # compilation of odd code (such as a naked 'return' outside a
2991 # compilation of odd code (such as a naked 'return' outside a
2992 # function) that did parse but isn't valid. Typically the exception
2992 # function) that did parse but isn't valid. Typically the exception
2993 # is a SyntaxError, but it's safest just to catch anything and show
2993 # is a SyntaxError, but it's safest just to catch anything and show
2994 # the user a traceback.
2994 # the user a traceback.
2995
2995
2996 # We do only one try/except outside the loop to minimize the impact
2996 # We do only one try/except outside the loop to minimize the impact
2997 # on runtime, and also because if any node in the node list is
2997 # on runtime, and also because if any node in the node list is
2998 # broken, we should stop execution completely.
2998 # broken, we should stop execution completely.
2999 if result:
2999 if result:
3000 result.error_before_exec = sys.exc_info()[1]
3000 result.error_before_exec = sys.exc_info()[1]
3001 self.showtraceback()
3001 self.showtraceback()
3002 return True
3002 return True
3003
3003
3004 return False
3004 return False
3005
3005
3006 def run_code(self, code_obj, result=None):
3006 def run_code(self, code_obj, result=None):
3007 """Execute a code object.
3007 """Execute a code object.
3008
3008
3009 When an exception occurs, self.showtraceback() is called to display a
3009 When an exception occurs, self.showtraceback() is called to display a
3010 traceback.
3010 traceback.
3011
3011
3012 Parameters
3012 Parameters
3013 ----------
3013 ----------
3014 code_obj : code object
3014 code_obj : code object
3015 A compiled code object, to be executed
3015 A compiled code object, to be executed
3016 result : ExecutionResult, optional
3016 result : ExecutionResult, optional
3017 An object to store exceptions that occur during execution.
3017 An object to store exceptions that occur during execution.
3018
3018
3019 Returns
3019 Returns
3020 -------
3020 -------
3021 False : successful execution.
3021 False : successful execution.
3022 True : an error occurred.
3022 True : an error occurred.
3023 """
3023 """
3024 # Set our own excepthook in case the user code tries to call it
3024 # Set our own excepthook in case the user code tries to call it
3025 # directly, so that the IPython crash handler doesn't get triggered
3025 # directly, so that the IPython crash handler doesn't get triggered
3026 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3026 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
3027
3027
3028 # we save the original sys.excepthook in the instance, in case config
3028 # we save the original sys.excepthook in the instance, in case config
3029 # code (such as magics) needs access to it.
3029 # code (such as magics) needs access to it.
3030 self.sys_excepthook = old_excepthook
3030 self.sys_excepthook = old_excepthook
3031 outflag = 1 # happens in more places, so it's easier as default
3031 outflag = 1 # happens in more places, so it's easier as default
3032 try:
3032 try:
3033 try:
3033 try:
3034 self.hooks.pre_run_code_hook()
3034 self.hooks.pre_run_code_hook()
3035 #rprint('Running code', repr(code_obj)) # dbg
3035 #rprint('Running code', repr(code_obj)) # dbg
3036 exec(code_obj, self.user_global_ns, self.user_ns)
3036 exec(code_obj, self.user_global_ns, self.user_ns)
3037 finally:
3037 finally:
3038 # Reset our crash handler in place
3038 # Reset our crash handler in place
3039 sys.excepthook = old_excepthook
3039 sys.excepthook = old_excepthook
3040 except SystemExit as e:
3040 except SystemExit as e:
3041 if result is not None:
3041 if result is not None:
3042 result.error_in_exec = e
3042 result.error_in_exec = e
3043 self.showtraceback(exception_only=True)
3043 self.showtraceback(exception_only=True)
3044 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
3044 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
3045 except self.custom_exceptions:
3045 except self.custom_exceptions:
3046 etype, value, tb = sys.exc_info()
3046 etype, value, tb = sys.exc_info()
3047 if result is not None:
3047 if result is not None:
3048 result.error_in_exec = value
3048 result.error_in_exec = value
3049 self.CustomTB(etype, value, tb)
3049 self.CustomTB(etype, value, tb)
3050 except:
3050 except:
3051 if result is not None:
3051 if result is not None:
3052 result.error_in_exec = sys.exc_info()[1]
3052 result.error_in_exec = sys.exc_info()[1]
3053 self.showtraceback()
3053 self.showtraceback()
3054 else:
3054 else:
3055 outflag = 0
3055 outflag = 0
3056 return outflag
3056 return outflag
3057
3057
3058 # For backwards compatibility
3058 # For backwards compatibility
3059 runcode = run_code
3059 runcode = run_code
3060
3060
3061 #-------------------------------------------------------------------------
3061 #-------------------------------------------------------------------------
3062 # Things related to GUI support and pylab
3062 # Things related to GUI support and pylab
3063 #-------------------------------------------------------------------------
3063 #-------------------------------------------------------------------------
3064
3064
3065 def enable_gui(self, gui=None):
3065 def enable_gui(self, gui=None):
3066 raise NotImplementedError('Implement enable_gui in a subclass')
3066 raise NotImplementedError('Implement enable_gui in a subclass')
3067
3067
3068 def enable_matplotlib(self, gui=None):
3068 def enable_matplotlib(self, gui=None):
3069 """Enable interactive matplotlib and inline figure support.
3069 """Enable interactive matplotlib and inline figure support.
3070
3070
3071 This takes the following steps:
3071 This takes the following steps:
3072
3072
3073 1. select the appropriate eventloop and matplotlib backend
3073 1. select the appropriate eventloop and matplotlib backend
3074 2. set up matplotlib for interactive use with that backend
3074 2. set up matplotlib for interactive use with that backend
3075 3. configure formatters for inline figure display
3075 3. configure formatters for inline figure display
3076 4. enable the selected gui eventloop
3076 4. enable the selected gui eventloop
3077
3077
3078 Parameters
3078 Parameters
3079 ----------
3079 ----------
3080 gui : optional, string
3080 gui : optional, string
3081 If given, dictates the choice of matplotlib GUI backend to use
3081 If given, dictates the choice of matplotlib GUI backend to use
3082 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3082 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3083 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3083 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3084 matplotlib (as dictated by the matplotlib build-time options plus the
3084 matplotlib (as dictated by the matplotlib build-time options plus the
3085 user's matplotlibrc configuration file). Note that not all backends
3085 user's matplotlibrc configuration file). Note that not all backends
3086 make sense in all contexts, for example a terminal ipython can't
3086 make sense in all contexts, for example a terminal ipython can't
3087 display figures inline.
3087 display figures inline.
3088 """
3088 """
3089 from IPython.core import pylabtools as pt
3089 from IPython.core import pylabtools as pt
3090 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3090 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3091
3091
3092 if gui != 'inline':
3092 if gui != 'inline':
3093 # If we have our first gui selection, store it
3093 # If we have our first gui selection, store it
3094 if self.pylab_gui_select is None:
3094 if self.pylab_gui_select is None:
3095 self.pylab_gui_select = gui
3095 self.pylab_gui_select = gui
3096 # Otherwise if they are different
3096 # Otherwise if they are different
3097 elif gui != self.pylab_gui_select:
3097 elif gui != self.pylab_gui_select:
3098 print ('Warning: Cannot change to a different GUI toolkit: %s.'
3098 print ('Warning: Cannot change to a different GUI toolkit: %s.'
3099 ' Using %s instead.' % (gui, self.pylab_gui_select))
3099 ' Using %s instead.' % (gui, self.pylab_gui_select))
3100 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3100 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3101
3101
3102 pt.activate_matplotlib(backend)
3102 pt.activate_matplotlib(backend)
3103 pt.configure_inline_support(self, backend)
3103 pt.configure_inline_support(self, backend)
3104
3104
3105 # Now we must activate the gui pylab wants to use, and fix %run to take
3105 # Now we must activate the gui pylab wants to use, and fix %run to take
3106 # plot updates into account
3106 # plot updates into account
3107 self.enable_gui(gui)
3107 self.enable_gui(gui)
3108 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3108 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3109 pt.mpl_runner(self.safe_execfile)
3109 pt.mpl_runner(self.safe_execfile)
3110
3110
3111 return gui, backend
3111 return gui, backend
3112
3112
3113 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3113 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3114 """Activate pylab support at runtime.
3114 """Activate pylab support at runtime.
3115
3115
3116 This turns on support for matplotlib, preloads into the interactive
3116 This turns on support for matplotlib, preloads into the interactive
3117 namespace all of numpy and pylab, and configures IPython to correctly
3117 namespace all of numpy and pylab, and configures IPython to correctly
3118 interact with the GUI event loop. The GUI backend to be used can be
3118 interact with the GUI event loop. The GUI backend to be used can be
3119 optionally selected with the optional ``gui`` argument.
3119 optionally selected with the optional ``gui`` argument.
3120
3120
3121 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3121 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3122
3122
3123 Parameters
3123 Parameters
3124 ----------
3124 ----------
3125 gui : optional, string
3125 gui : optional, string
3126 If given, dictates the choice of matplotlib GUI backend to use
3126 If given, dictates the choice of matplotlib GUI backend to use
3127 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3127 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3128 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3128 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3129 matplotlib (as dictated by the matplotlib build-time options plus the
3129 matplotlib (as dictated by the matplotlib build-time options plus the
3130 user's matplotlibrc configuration file). Note that not all backends
3130 user's matplotlibrc configuration file). Note that not all backends
3131 make sense in all contexts, for example a terminal ipython can't
3131 make sense in all contexts, for example a terminal ipython can't
3132 display figures inline.
3132 display figures inline.
3133 import_all : optional, bool, default: True
3133 import_all : optional, bool, default: True
3134 Whether to do `from numpy import *` and `from pylab import *`
3134 Whether to do `from numpy import *` and `from pylab import *`
3135 in addition to module imports.
3135 in addition to module imports.
3136 welcome_message : deprecated
3136 welcome_message : deprecated
3137 This argument is ignored, no welcome message will be displayed.
3137 This argument is ignored, no welcome message will be displayed.
3138 """
3138 """
3139 from IPython.core.pylabtools import import_pylab
3139 from IPython.core.pylabtools import import_pylab
3140
3140
3141 gui, backend = self.enable_matplotlib(gui)
3141 gui, backend = self.enable_matplotlib(gui)
3142
3142
3143 # We want to prevent the loading of pylab to pollute the user's
3143 # We want to prevent the loading of pylab to pollute the user's
3144 # namespace as shown by the %who* magics, so we execute the activation
3144 # namespace as shown by the %who* magics, so we execute the activation
3145 # code in an empty namespace, and we update *both* user_ns and
3145 # code in an empty namespace, and we update *both* user_ns and
3146 # user_ns_hidden with this information.
3146 # user_ns_hidden with this information.
3147 ns = {}
3147 ns = {}
3148 import_pylab(ns, import_all)
3148 import_pylab(ns, import_all)
3149 # warn about clobbered names
3149 # warn about clobbered names
3150 ignored = set(["__builtins__"])
3150 ignored = set(["__builtins__"])
3151 both = set(ns).intersection(self.user_ns).difference(ignored)
3151 both = set(ns).intersection(self.user_ns).difference(ignored)
3152 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3152 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3153 self.user_ns.update(ns)
3153 self.user_ns.update(ns)
3154 self.user_ns_hidden.update(ns)
3154 self.user_ns_hidden.update(ns)
3155 return gui, backend, clobbered
3155 return gui, backend, clobbered
3156
3156
3157 #-------------------------------------------------------------------------
3157 #-------------------------------------------------------------------------
3158 # Utilities
3158 # Utilities
3159 #-------------------------------------------------------------------------
3159 #-------------------------------------------------------------------------
3160
3160
3161 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3161 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3162 """Expand python variables in a string.
3162 """Expand python variables in a string.
3163
3163
3164 The depth argument indicates how many frames above the caller should
3164 The depth argument indicates how many frames above the caller should
3165 be walked to look for the local namespace where to expand variables.
3165 be walked to look for the local namespace where to expand variables.
3166
3166
3167 The global namespace for expansion is always the user's interactive
3167 The global namespace for expansion is always the user's interactive
3168 namespace.
3168 namespace.
3169 """
3169 """
3170 ns = self.user_ns.copy()
3170 ns = self.user_ns.copy()
3171 try:
3171 try:
3172 frame = sys._getframe(depth+1)
3172 frame = sys._getframe(depth+1)
3173 except ValueError:
3173 except ValueError:
3174 # This is thrown if there aren't that many frames on the stack,
3174 # This is thrown if there aren't that many frames on the stack,
3175 # e.g. if a script called run_line_magic() directly.
3175 # e.g. if a script called run_line_magic() directly.
3176 pass
3176 pass
3177 else:
3177 else:
3178 ns.update(frame.f_locals)
3178 ns.update(frame.f_locals)
3179
3179
3180 try:
3180 try:
3181 # We have to use .vformat() here, because 'self' is a valid and common
3181 # We have to use .vformat() here, because 'self' is a valid and common
3182 # name, and expanding **ns for .format() would make it collide with
3182 # name, and expanding **ns for .format() would make it collide with
3183 # the 'self' argument of the method.
3183 # the 'self' argument of the method.
3184 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3184 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3185 except Exception:
3185 except Exception:
3186 # if formatter couldn't format, just let it go untransformed
3186 # if formatter couldn't format, just let it go untransformed
3187 pass
3187 pass
3188 return cmd
3188 return cmd
3189
3189
3190 def mktempfile(self, data=None, prefix='ipython_edit_'):
3190 def mktempfile(self, data=None, prefix='ipython_edit_'):
3191 """Make a new tempfile and return its filename.
3191 """Make a new tempfile and return its filename.
3192
3192
3193 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3193 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3194 but it registers the created filename internally so ipython cleans it up
3194 but it registers the created filename internally so ipython cleans it up
3195 at exit time.
3195 at exit time.
3196
3196
3197 Optional inputs:
3197 Optional inputs:
3198
3198
3199 - data(None): if data is given, it gets written out to the temp file
3199 - data(None): if data is given, it gets written out to the temp file
3200 immediately, and the file is closed again."""
3200 immediately, and the file is closed again."""
3201
3201
3202 dirname = tempfile.mkdtemp(prefix=prefix)
3202 dirname = tempfile.mkdtemp(prefix=prefix)
3203 self.tempdirs.append(dirname)
3203 self.tempdirs.append(dirname)
3204
3204
3205 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3205 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3206 os.close(handle) # On Windows, there can only be one open handle on a file
3206 os.close(handle) # On Windows, there can only be one open handle on a file
3207 self.tempfiles.append(filename)
3207 self.tempfiles.append(filename)
3208
3208
3209 if data:
3209 if data:
3210 tmp_file = open(filename,'w')
3210 tmp_file = open(filename,'w')
3211 tmp_file.write(data)
3211 tmp_file.write(data)
3212 tmp_file.close()
3212 tmp_file.close()
3213 return filename
3213 return filename
3214
3214
3215 # TODO: This should be removed when Term is refactored.
3215 # TODO: This should be removed when Term is refactored.
3216 def write(self,data):
3216 def write(self,data):
3217 """Write a string to the default output"""
3217 """Write a string to the default output"""
3218 io.stdout.write(data)
3218 io.stdout.write(data)
3219
3219
3220 # TODO: This should be removed when Term is refactored.
3220 # TODO: This should be removed when Term is refactored.
3221 def write_err(self,data):
3221 def write_err(self,data):
3222 """Write a string to the default error output"""
3222 """Write a string to the default error output"""
3223 io.stderr.write(data)
3223 io.stderr.write(data)
3224
3224
3225 def ask_yes_no(self, prompt, default=None):
3225 def ask_yes_no(self, prompt, default=None):
3226 if self.quiet:
3226 if self.quiet:
3227 return True
3227 return True
3228 return ask_yes_no(prompt,default)
3228 return ask_yes_no(prompt,default)
3229
3229
3230 def show_usage(self):
3230 def show_usage(self):
3231 """Show a usage message"""
3231 """Show a usage message"""
3232 page.page(IPython.core.usage.interactive_usage)
3232 page.page(IPython.core.usage.interactive_usage)
3233
3233
3234 def extract_input_lines(self, range_str, raw=False):
3234 def extract_input_lines(self, range_str, raw=False):
3235 """Return as a string a set of input history slices.
3235 """Return as a string a set of input history slices.
3236
3236
3237 Parameters
3237 Parameters
3238 ----------
3238 ----------
3239 range_str : string
3239 range_str : string
3240 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3240 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3241 since this function is for use by magic functions which get their
3241 since this function is for use by magic functions which get their
3242 arguments as strings. The number before the / is the session
3242 arguments as strings. The number before the / is the session
3243 number: ~n goes n back from the current session.
3243 number: ~n goes n back from the current session.
3244
3244
3245 raw : bool, optional
3245 raw : bool, optional
3246 By default, the processed input is used. If this is true, the raw
3246 By default, the processed input is used. If this is true, the raw
3247 input history is used instead.
3247 input history is used instead.
3248
3248
3249 Notes
3249 Notes
3250 -----
3250 -----
3251
3251
3252 Slices can be described with two notations:
3252 Slices can be described with two notations:
3253
3253
3254 * ``N:M`` -> standard python form, means including items N...(M-1).
3254 * ``N:M`` -> standard python form, means including items N...(M-1).
3255 * ``N-M`` -> include items N..M (closed endpoint).
3255 * ``N-M`` -> include items N..M (closed endpoint).
3256 """
3256 """
3257 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3257 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3258 return "\n".join(x for _, _, x in lines)
3258 return "\n".join(x for _, _, x in lines)
3259
3259
3260 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3260 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3261 """Get a code string from history, file, url, or a string or macro.
3261 """Get a code string from history, file, url, or a string or macro.
3262
3262
3263 This is mainly used by magic functions.
3263 This is mainly used by magic functions.
3264
3264
3265 Parameters
3265 Parameters
3266 ----------
3266 ----------
3267
3267
3268 target : str
3268 target : str
3269
3269
3270 A string specifying code to retrieve. This will be tried respectively
3270 A string specifying code to retrieve. This will be tried respectively
3271 as: ranges of input history (see %history for syntax), url,
3271 as: ranges of input history (see %history for syntax), url,
3272 correspnding .py file, filename, or an expression evaluating to a
3272 correspnding .py file, filename, or an expression evaluating to a
3273 string or Macro in the user namespace.
3273 string or Macro in the user namespace.
3274
3274
3275 raw : bool
3275 raw : bool
3276 If true (default), retrieve raw history. Has no effect on the other
3276 If true (default), retrieve raw history. Has no effect on the other
3277 retrieval mechanisms.
3277 retrieval mechanisms.
3278
3278
3279 py_only : bool (default False)
3279 py_only : bool (default False)
3280 Only try to fetch python code, do not try alternative methods to decode file
3280 Only try to fetch python code, do not try alternative methods to decode file
3281 if unicode fails.
3281 if unicode fails.
3282
3282
3283 Returns
3283 Returns
3284 -------
3284 -------
3285 A string of code.
3285 A string of code.
3286
3286
3287 ValueError is raised if nothing is found, and TypeError if it evaluates
3287 ValueError is raised if nothing is found, and TypeError if it evaluates
3288 to an object of another type. In each case, .args[0] is a printable
3288 to an object of another type. In each case, .args[0] is a printable
3289 message.
3289 message.
3290 """
3290 """
3291 code = self.extract_input_lines(target, raw=raw) # Grab history
3291 code = self.extract_input_lines(target, raw=raw) # Grab history
3292 if code:
3292 if code:
3293 return code
3293 return code
3294 utarget = unquote_filename(target)
3294 utarget = unquote_filename(target)
3295 try:
3295 try:
3296 if utarget.startswith(('http://', 'https://')):
3296 if utarget.startswith(('http://', 'https://')):
3297 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3297 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3298 except UnicodeDecodeError:
3298 except UnicodeDecodeError:
3299 if not py_only :
3299 if not py_only :
3300 # Deferred import
3300 # Deferred import
3301 try:
3301 try:
3302 from urllib.request import urlopen # Py3
3302 from urllib.request import urlopen # Py3
3303 except ImportError:
3303 except ImportError:
3304 from urllib import urlopen
3304 from urllib import urlopen
3305 response = urlopen(target)
3305 response = urlopen(target)
3306 return response.read().decode('latin1')
3306 return response.read().decode('latin1')
3307 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3307 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3308
3308
3309 potential_target = [target]
3309 potential_target = [target]
3310 try :
3310 try :
3311 potential_target.insert(0,get_py_filename(target))
3311 potential_target.insert(0,get_py_filename(target))
3312 except IOError:
3312 except IOError:
3313 pass
3313 pass
3314
3314
3315 for tgt in potential_target :
3315 for tgt in potential_target :
3316 if os.path.isfile(tgt): # Read file
3316 if os.path.isfile(tgt): # Read file
3317 try :
3317 try :
3318 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3318 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3319 except UnicodeDecodeError :
3319 except UnicodeDecodeError :
3320 if not py_only :
3320 if not py_only :
3321 with io_open(tgt,'r', encoding='latin1') as f :
3321 with io_open(tgt,'r', encoding='latin1') as f :
3322 return f.read()
3322 return f.read()
3323 raise ValueError(("'%s' seem to be unreadable.") % target)
3323 raise ValueError(("'%s' seem to be unreadable.") % target)
3324 elif os.path.isdir(os.path.expanduser(tgt)):
3324 elif os.path.isdir(os.path.expanduser(tgt)):
3325 raise ValueError("'%s' is a directory, not a regular file." % target)
3325 raise ValueError("'%s' is a directory, not a regular file." % target)
3326
3326
3327 if search_ns:
3327 if search_ns:
3328 # Inspect namespace to load object source
3328 # Inspect namespace to load object source
3329 object_info = self.object_inspect(target, detail_level=1)
3329 object_info = self.object_inspect(target, detail_level=1)
3330 if object_info['found'] and object_info['source']:
3330 if object_info['found'] and object_info['source']:
3331 return object_info['source']
3331 return object_info['source']
3332
3332
3333 try: # User namespace
3333 try: # User namespace
3334 codeobj = eval(target, self.user_ns)
3334 codeobj = eval(target, self.user_ns)
3335 except Exception:
3335 except Exception:
3336 raise ValueError(("'%s' was not found in history, as a file, url, "
3336 raise ValueError(("'%s' was not found in history, as a file, url, "
3337 "nor in the user namespace.") % target)
3337 "nor in the user namespace.") % target)
3338
3338
3339 if isinstance(codeobj, string_types):
3339 if isinstance(codeobj, string_types):
3340 return codeobj
3340 return codeobj
3341 elif isinstance(codeobj, Macro):
3341 elif isinstance(codeobj, Macro):
3342 return codeobj.value
3342 return codeobj.value
3343
3343
3344 raise TypeError("%s is neither a string nor a macro." % target,
3344 raise TypeError("%s is neither a string nor a macro." % target,
3345 codeobj)
3345 codeobj)
3346
3346
3347 #-------------------------------------------------------------------------
3347 #-------------------------------------------------------------------------
3348 # Things related to IPython exiting
3348 # Things related to IPython exiting
3349 #-------------------------------------------------------------------------
3349 #-------------------------------------------------------------------------
3350 def atexit_operations(self):
3350 def atexit_operations(self):
3351 """This will be executed at the time of exit.
3351 """This will be executed at the time of exit.
3352
3352
3353 Cleanup operations and saving of persistent data that is done
3353 Cleanup operations and saving of persistent data that is done
3354 unconditionally by IPython should be performed here.
3354 unconditionally by IPython should be performed here.
3355
3355
3356 For things that may depend on startup flags or platform specifics (such
3356 For things that may depend on startup flags or platform specifics (such
3357 as having readline or not), register a separate atexit function in the
3357 as having readline or not), register a separate atexit function in the
3358 code that has the appropriate information, rather than trying to
3358 code that has the appropriate information, rather than trying to
3359 clutter
3359 clutter
3360 """
3360 """
3361 # Close the history session (this stores the end time and line count)
3361 # Close the history session (this stores the end time and line count)
3362 # this must be *before* the tempfile cleanup, in case of temporary
3362 # this must be *before* the tempfile cleanup, in case of temporary
3363 # history db
3363 # history db
3364 self.history_manager.end_session()
3364 self.history_manager.end_session()
3365
3365
3366 # Cleanup all tempfiles and folders left around
3366 # Cleanup all tempfiles and folders left around
3367 for tfile in self.tempfiles:
3367 for tfile in self.tempfiles:
3368 try:
3368 try:
3369 os.unlink(tfile)
3369 os.unlink(tfile)
3370 except OSError:
3370 except OSError:
3371 pass
3371 pass
3372
3372
3373 for tdir in self.tempdirs:
3373 for tdir in self.tempdirs:
3374 try:
3374 try:
3375 os.rmdir(tdir)
3375 os.rmdir(tdir)
3376 except OSError:
3376 except OSError:
3377 pass
3377 pass
3378
3378
3379 # Clear all user namespaces to release all references cleanly.
3379 # Clear all user namespaces to release all references cleanly.
3380 self.reset(new_session=False)
3380 self.reset(new_session=False)
3381
3381
3382 # Run user hooks
3382 # Run user hooks
3383 self.hooks.shutdown_hook()
3383 self.hooks.shutdown_hook()
3384
3384
3385 def cleanup(self):
3385 def cleanup(self):
3386 self.restore_sys_module_state()
3386 self.restore_sys_module_state()
3387
3387
3388
3388
3389 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3389 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3390 """An abstract base class for InteractiveShell."""
3390 """An abstract base class for InteractiveShell."""
3391
3391
3392 InteractiveShellABC.register(InteractiveShell)
3392 InteractiveShellABC.register(InteractiveShell)
@@ -1,702 +1,702 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 from __future__ import print_function
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
8 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10
10
11 # 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
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Stdlib
18 # Stdlib
19 import os
19 import os
20 import re
20 import re
21 import sys
21 import sys
22 import types
22 import types
23 from getopt import getopt, GetoptError
23 from getopt import getopt, GetoptError
24
24
25 # Our own
25 # Our own
26 from IPython.config.configurable import Configurable
26 from IPython.config.configurable import Configurable
27 from IPython.core import oinspect
27 from IPython.core import oinspect
28 from IPython.core.error import UsageError
28 from IPython.core.error import UsageError
29 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
29 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
30 from decorator import decorator
30 from decorator import decorator
31 from IPython.utils.ipstruct import Struct
31 from IPython.utils.ipstruct import Struct
32 from IPython.utils.process import arg_split
32 from IPython.utils.process import arg_split
33 from IPython.utils.py3compat import string_types, iteritems
33 from IPython.utils.py3compat import string_types, iteritems
34 from IPython.utils.text import dedent
34 from IPython.utils.text import dedent
35 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
35 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
36 from IPython.utils.warn import error
36 from IPython.utils.warn import error
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Globals
39 # Globals
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 # A dict we'll use for each class that has magics, used as temporary storage to
42 # A dict we'll use for each class that has magics, used as temporary storage to
43 # pass information between the @line/cell_magic method decorators and the
43 # pass information between the @line/cell_magic method decorators and the
44 # @magics_class class decorator, because the method decorators have no
44 # @magics_class class decorator, because the method decorators have no
45 # access to the class when they run. See for more details:
45 # access to the class when they run. See for more details:
46 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
46 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
47
47
48 magics = dict(line={}, cell={})
48 magics = dict(line={}, cell={})
49
49
50 magic_kinds = ('line', 'cell')
50 magic_kinds = ('line', 'cell')
51 magic_spec = ('line', 'cell', 'line_cell')
51 magic_spec = ('line', 'cell', 'line_cell')
52 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
52 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Utility classes and functions
55 # Utility classes and functions
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58 class Bunch: pass
58 class Bunch: pass
59
59
60
60
61 def on_off(tag):
61 def on_off(tag):
62 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
62 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
63 return ['OFF','ON'][tag]
63 return ['OFF','ON'][tag]
64
64
65
65
66 def compress_dhist(dh):
66 def compress_dhist(dh):
67 """Compress a directory history into a new one with at most 20 entries.
67 """Compress a directory history into a new one with at most 20 entries.
68
68
69 Return a new list made from the first and last 10 elements of dhist after
69 Return a new list made from the first and last 10 elements of dhist after
70 removal of duplicates.
70 removal of duplicates.
71 """
71 """
72 head, tail = dh[:-10], dh[-10:]
72 head, tail = dh[:-10], dh[-10:]
73
73
74 newhead = []
74 newhead = []
75 done = set()
75 done = set()
76 for h in head:
76 for h in head:
77 if h in done:
77 if h in done:
78 continue
78 continue
79 newhead.append(h)
79 newhead.append(h)
80 done.add(h)
80 done.add(h)
81
81
82 return newhead + tail
82 return newhead + tail
83
83
84
84
85 def needs_local_scope(func):
85 def needs_local_scope(func):
86 """Decorator to mark magic functions which need to local scope to run."""
86 """Decorator to mark magic functions which need to local scope to run."""
87 func.needs_local_scope = True
87 func.needs_local_scope = True
88 return func
88 return func
89
89
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91 # Class and method decorators for registering magics
91 # Class and method decorators for registering magics
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93
93
94 def magics_class(cls):
94 def magics_class(cls):
95 """Class decorator for all subclasses of the main Magics class.
95 """Class decorator for all subclasses of the main Magics class.
96
96
97 Any class that subclasses Magics *must* also apply this decorator, to
97 Any class that subclasses Magics *must* also apply this decorator, to
98 ensure that all the methods that have been decorated as line/cell magics
98 ensure that all the methods that have been decorated as line/cell magics
99 get correctly registered in the class instance. This is necessary because
99 get correctly registered in the class instance. This is necessary because
100 when method decorators run, the class does not exist yet, so they
100 when method decorators run, the class does not exist yet, so they
101 temporarily store their information into a module global. Application of
101 temporarily store their information into a module global. Application of
102 this class decorator copies that global data to the class instance and
102 this class decorator copies that global data to the class instance and
103 clears the global.
103 clears the global.
104
104
105 Obviously, this mechanism is not thread-safe, which means that the
105 Obviously, this mechanism is not thread-safe, which means that the
106 *creation* of subclasses of Magic should only be done in a single-thread
106 *creation* of subclasses of Magic should only be done in a single-thread
107 context. Instantiation of the classes has no restrictions. Given that
107 context. Instantiation of the classes has no restrictions. Given that
108 these classes are typically created at IPython startup time and before user
108 these classes are typically created at IPython startup time and before user
109 application code becomes active, in practice this should not pose any
109 application code becomes active, in practice this should not pose any
110 problems.
110 problems.
111 """
111 """
112 cls.registered = True
112 cls.registered = True
113 cls.magics = dict(line = magics['line'],
113 cls.magics = dict(line = magics['line'],
114 cell = magics['cell'])
114 cell = magics['cell'])
115 magics['line'] = {}
115 magics['line'] = {}
116 magics['cell'] = {}
116 magics['cell'] = {}
117 return cls
117 return cls
118
118
119
119
120 def record_magic(dct, magic_kind, magic_name, func):
120 def record_magic(dct, magic_kind, magic_name, func):
121 """Utility function to store a function as a magic of a specific kind.
121 """Utility function to store a function as a magic of a specific kind.
122
122
123 Parameters
123 Parameters
124 ----------
124 ----------
125 dct : dict
125 dct : dict
126 A dictionary with 'line' and 'cell' subdicts.
126 A dictionary with 'line' and 'cell' subdicts.
127
127
128 magic_kind : str
128 magic_kind : str
129 Kind of magic to be stored.
129 Kind of magic to be stored.
130
130
131 magic_name : str
131 magic_name : str
132 Key to store the magic as.
132 Key to store the magic as.
133
133
134 func : function
134 func : function
135 Callable object to store.
135 Callable object to store.
136 """
136 """
137 if magic_kind == 'line_cell':
137 if magic_kind == 'line_cell':
138 dct['line'][magic_name] = dct['cell'][magic_name] = func
138 dct['line'][magic_name] = dct['cell'][magic_name] = func
139 else:
139 else:
140 dct[magic_kind][magic_name] = func
140 dct[magic_kind][magic_name] = func
141
141
142
142
143 def validate_type(magic_kind):
143 def validate_type(magic_kind):
144 """Ensure that the given magic_kind is valid.
144 """Ensure that the given magic_kind is valid.
145
145
146 Check that the given magic_kind is one of the accepted spec types (stored
146 Check that the given magic_kind is one of the accepted spec types (stored
147 in the global `magic_spec`), raise ValueError otherwise.
147 in the global `magic_spec`), raise ValueError otherwise.
148 """
148 """
149 if magic_kind not in magic_spec:
149 if magic_kind not in magic_spec:
150 raise ValueError('magic_kind must be one of %s, %s given' %
150 raise ValueError('magic_kind must be one of %s, %s given' %
151 magic_kinds, magic_kind)
151 magic_kinds, magic_kind)
152
152
153
153
154 # The docstrings for the decorator below will be fairly similar for the two
154 # The docstrings for the decorator below will be fairly similar for the two
155 # types (method and function), so we generate them here once and reuse the
155 # types (method and function), so we generate them here once and reuse the
156 # templates below.
156 # templates below.
157 _docstring_template = \
157 _docstring_template = \
158 """Decorate the given {0} as {1} magic.
158 """Decorate the given {0} as {1} magic.
159
159
160 The decorator can be used with or without arguments, as follows.
160 The decorator can be used with or without arguments, as follows.
161
161
162 i) without arguments: it will create a {1} magic named as the {0} being
162 i) without arguments: it will create a {1} magic named as the {0} being
163 decorated::
163 decorated::
164
164
165 @deco
165 @deco
166 def foo(...)
166 def foo(...)
167
167
168 will create a {1} magic named `foo`.
168 will create a {1} magic named `foo`.
169
169
170 ii) with one string argument: which will be used as the actual name of the
170 ii) with one string argument: which will be used as the actual name of the
171 resulting magic::
171 resulting magic::
172
172
173 @deco('bar')
173 @deco('bar')
174 def foo(...)
174 def foo(...)
175
175
176 will create a {1} magic named `bar`.
176 will create a {1} magic named `bar`.
177 """
177 """
178
178
179 # These two are decorator factories. While they are conceptually very similar,
179 # These two are decorator factories. While they are conceptually very similar,
180 # there are enough differences in the details that it's simpler to have them
180 # there are enough differences in the details that it's simpler to have them
181 # written as completely standalone functions rather than trying to share code
181 # written as completely standalone functions rather than trying to share code
182 # and make a single one with convoluted logic.
182 # and make a single one with convoluted logic.
183
183
184 def _method_magic_marker(magic_kind):
184 def _method_magic_marker(magic_kind):
185 """Decorator factory for methods in Magics subclasses.
185 """Decorator factory for methods in Magics subclasses.
186 """
186 """
187
187
188 validate_type(magic_kind)
188 validate_type(magic_kind)
189
189
190 # This is a closure to capture the magic_kind. We could also use a class,
190 # This is a closure to capture the magic_kind. We could also use a class,
191 # but it's overkill for just that one bit of state.
191 # but it's overkill for just that one bit of state.
192 def magic_deco(arg):
192 def magic_deco(arg):
193 call = lambda f, *a, **k: f(*a, **k)
193 call = lambda f, *a, **k: f(*a, **k)
194
194
195 if callable(arg):
195 if callable(arg):
196 # "Naked" decorator call (just @foo, no args)
196 # "Naked" decorator call (just @foo, no args)
197 func = arg
197 func = arg
198 name = func.__name__
198 name = func.__name__
199 retval = decorator(call, func)
199 retval = decorator(call, func)
200 record_magic(magics, magic_kind, name, name)
200 record_magic(magics, magic_kind, name, name)
201 elif isinstance(arg, string_types):
201 elif isinstance(arg, string_types):
202 # Decorator called with arguments (@foo('bar'))
202 # Decorator called with arguments (@foo('bar'))
203 name = arg
203 name = arg
204 def mark(func, *a, **kw):
204 def mark(func, *a, **kw):
205 record_magic(magics, magic_kind, name, func.__name__)
205 record_magic(magics, magic_kind, name, func.__name__)
206 return decorator(call, func)
206 return decorator(call, func)
207 retval = mark
207 retval = mark
208 else:
208 else:
209 raise TypeError("Decorator can only be called with "
209 raise TypeError("Decorator can only be called with "
210 "string or function")
210 "string or function")
211 return retval
211 return retval
212
212
213 # Ensure the resulting decorator has a usable docstring
213 # Ensure the resulting decorator has a usable docstring
214 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
214 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
215 return magic_deco
215 return magic_deco
216
216
217
217
218 def _function_magic_marker(magic_kind):
218 def _function_magic_marker(magic_kind):
219 """Decorator factory for standalone functions.
219 """Decorator factory for standalone functions.
220 """
220 """
221 validate_type(magic_kind)
221 validate_type(magic_kind)
222
222
223 # This is a closure to capture the magic_kind. We could also use a class,
223 # This is a closure to capture the magic_kind. We could also use a class,
224 # but it's overkill for just that one bit of state.
224 # but it's overkill for just that one bit of state.
225 def magic_deco(arg):
225 def magic_deco(arg):
226 call = lambda f, *a, **k: f(*a, **k)
226 call = lambda f, *a, **k: f(*a, **k)
227
227
228 # Find get_ipython() in the caller's namespace
228 # Find get_ipython() in the caller's namespace
229 caller = sys._getframe(1)
229 caller = sys._getframe(1)
230 for ns in ['f_locals', 'f_globals', 'f_builtins']:
230 for ns in ['f_locals', 'f_globals', 'f_builtins']:
231 get_ipython = getattr(caller, ns).get('get_ipython')
231 get_ipython = getattr(caller, ns).get('get_ipython')
232 if get_ipython is not None:
232 if get_ipython is not None:
233 break
233 break
234 else:
234 else:
235 raise NameError('Decorator can only run in context where '
235 raise NameError('Decorator can only run in context where '
236 '`get_ipython` exists')
236 '`get_ipython` exists')
237
237
238 ip = get_ipython()
238 ip = get_ipython()
239
239
240 if callable(arg):
240 if callable(arg):
241 # "Naked" decorator call (just @foo, no args)
241 # "Naked" decorator call (just @foo, no args)
242 func = arg
242 func = arg
243 name = func.__name__
243 name = func.__name__
244 ip.register_magic_function(func, magic_kind, name)
244 ip.register_magic_function(func, magic_kind, name)
245 retval = decorator(call, func)
245 retval = decorator(call, func)
246 elif isinstance(arg, string_types):
246 elif isinstance(arg, string_types):
247 # Decorator called with arguments (@foo('bar'))
247 # Decorator called with arguments (@foo('bar'))
248 name = arg
248 name = arg
249 def mark(func, *a, **kw):
249 def mark(func, *a, **kw):
250 ip.register_magic_function(func, magic_kind, name)
250 ip.register_magic_function(func, magic_kind, name)
251 return decorator(call, func)
251 return decorator(call, func)
252 retval = mark
252 retval = mark
253 else:
253 else:
254 raise TypeError("Decorator can only be called with "
254 raise TypeError("Decorator can only be called with "
255 "string or function")
255 "string or function")
256 return retval
256 return retval
257
257
258 # Ensure the resulting decorator has a usable docstring
258 # Ensure the resulting decorator has a usable docstring
259 ds = _docstring_template.format('function', magic_kind)
259 ds = _docstring_template.format('function', magic_kind)
260
260
261 ds += dedent("""
261 ds += dedent("""
262 Note: this decorator can only be used in a context where IPython is already
262 Note: this decorator can only be used in a context where IPython is already
263 active, so that the `get_ipython()` call succeeds. You can therefore use
263 active, so that the `get_ipython()` call succeeds. You can therefore use
264 it in your startup files loaded after IPython initializes, but *not* in the
264 it in your startup files loaded after IPython initializes, but *not* in the
265 IPython configuration file itself, which is executed before IPython is
265 IPython configuration file itself, which is executed before IPython is
266 fully up and running. Any file located in the `startup` subdirectory of
266 fully up and running. Any file located in the `startup` subdirectory of
267 your configuration profile will be OK in this sense.
267 your configuration profile will be OK in this sense.
268 """)
268 """)
269
269
270 magic_deco.__doc__ = ds
270 magic_deco.__doc__ = ds
271 return magic_deco
271 return magic_deco
272
272
273
273
274 # Create the actual decorators for public use
274 # Create the actual decorators for public use
275
275
276 # These three are used to decorate methods in class definitions
276 # These three are used to decorate methods in class definitions
277 line_magic = _method_magic_marker('line')
277 line_magic = _method_magic_marker('line')
278 cell_magic = _method_magic_marker('cell')
278 cell_magic = _method_magic_marker('cell')
279 line_cell_magic = _method_magic_marker('line_cell')
279 line_cell_magic = _method_magic_marker('line_cell')
280
280
281 # These three decorate standalone functions and perform the decoration
281 # These three decorate standalone functions and perform the decoration
282 # immediately. They can only run where get_ipython() works
282 # immediately. They can only run where get_ipython() works
283 register_line_magic = _function_magic_marker('line')
283 register_line_magic = _function_magic_marker('line')
284 register_cell_magic = _function_magic_marker('cell')
284 register_cell_magic = _function_magic_marker('cell')
285 register_line_cell_magic = _function_magic_marker('line_cell')
285 register_line_cell_magic = _function_magic_marker('line_cell')
286
286
287 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
288 # Core Magic classes
288 # Core Magic classes
289 #-----------------------------------------------------------------------------
289 #-----------------------------------------------------------------------------
290
290
291 class MagicsManager(Configurable):
291 class MagicsManager(Configurable):
292 """Object that handles all magic-related functionality for IPython.
292 """Object that handles all magic-related functionality for IPython.
293 """
293 """
294 # Non-configurable class attributes
294 # Non-configurable class attributes
295
295
296 # A two-level dict, first keyed by magic type, then by magic function, and
296 # A two-level dict, first keyed by magic type, then by magic function, and
297 # holding the actual callable object as value. This is the dict used for
297 # holding the actual callable object as value. This is the dict used for
298 # magic function dispatch
298 # magic function dispatch
299 magics = Dict
299 magics = Dict
300
300
301 # A registry of the original objects that we've been given holding magics.
301 # A registry of the original objects that we've been given holding magics.
302 registry = Dict
302 registry = Dict
303
303
304 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
304 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
305
305
306 auto_magic = Bool(True, config=True, help=
306 auto_magic = Bool(True, config=True, help=
307 "Automatically call line magics without requiring explicit % prefix")
307 "Automatically call line magics without requiring explicit % prefix")
308
308
309 def _auto_magic_changed(self, name, value):
309 def _auto_magic_changed(self, name, value):
310 self.shell.automagic = value
310 self.shell.automagic = value
311
311
312 _auto_status = [
312 _auto_status = [
313 'Automagic is OFF, % prefix IS needed for line magics.',
313 'Automagic is OFF, % prefix IS needed for line magics.',
314 'Automagic is ON, % prefix IS NOT needed for line magics.']
314 'Automagic is ON, % prefix IS NOT needed for line magics.']
315
315
316 user_magics = Instance('IPython.core.magics.UserMagics')
316 user_magics = Instance('IPython.core.magics.UserMagics', allow_none=True)
317
317
318 def __init__(self, shell=None, config=None, user_magics=None, **traits):
318 def __init__(self, shell=None, config=None, user_magics=None, **traits):
319
319
320 super(MagicsManager, self).__init__(shell=shell, config=config,
320 super(MagicsManager, self).__init__(shell=shell, config=config,
321 user_magics=user_magics, **traits)
321 user_magics=user_magics, **traits)
322 self.magics = dict(line={}, cell={})
322 self.magics = dict(line={}, cell={})
323 # Let's add the user_magics to the registry for uniformity, so *all*
323 # Let's add the user_magics to the registry for uniformity, so *all*
324 # registered magic containers can be found there.
324 # registered magic containers can be found there.
325 self.registry[user_magics.__class__.__name__] = user_magics
325 self.registry[user_magics.__class__.__name__] = user_magics
326
326
327 def auto_status(self):
327 def auto_status(self):
328 """Return descriptive string with automagic status."""
328 """Return descriptive string with automagic status."""
329 return self._auto_status[self.auto_magic]
329 return self._auto_status[self.auto_magic]
330
330
331 def lsmagic(self):
331 def lsmagic(self):
332 """Return a dict of currently available magic functions.
332 """Return a dict of currently available magic functions.
333
333
334 The return dict has the keys 'line' and 'cell', corresponding to the
334 The return dict has the keys 'line' and 'cell', corresponding to the
335 two types of magics we support. Each value is a list of names.
335 two types of magics we support. Each value is a list of names.
336 """
336 """
337 return self.magics
337 return self.magics
338
338
339 def lsmagic_docs(self, brief=False, missing=''):
339 def lsmagic_docs(self, brief=False, missing=''):
340 """Return dict of documentation of magic functions.
340 """Return dict of documentation of magic functions.
341
341
342 The return dict has the keys 'line' and 'cell', corresponding to the
342 The return dict has the keys 'line' and 'cell', corresponding to the
343 two types of magics we support. Each value is a dict keyed by magic
343 two types of magics we support. Each value is a dict keyed by magic
344 name whose value is the function docstring. If a docstring is
344 name whose value is the function docstring. If a docstring is
345 unavailable, the value of `missing` is used instead.
345 unavailable, the value of `missing` is used instead.
346
346
347 If brief is True, only the first line of each docstring will be returned.
347 If brief is True, only the first line of each docstring will be returned.
348 """
348 """
349 docs = {}
349 docs = {}
350 for m_type in self.magics:
350 for m_type in self.magics:
351 m_docs = {}
351 m_docs = {}
352 for m_name, m_func in iteritems(self.magics[m_type]):
352 for m_name, m_func in iteritems(self.magics[m_type]):
353 if m_func.__doc__:
353 if m_func.__doc__:
354 if brief:
354 if brief:
355 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
355 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
356 else:
356 else:
357 m_docs[m_name] = m_func.__doc__.rstrip()
357 m_docs[m_name] = m_func.__doc__.rstrip()
358 else:
358 else:
359 m_docs[m_name] = missing
359 m_docs[m_name] = missing
360 docs[m_type] = m_docs
360 docs[m_type] = m_docs
361 return docs
361 return docs
362
362
363 def register(self, *magic_objects):
363 def register(self, *magic_objects):
364 """Register one or more instances of Magics.
364 """Register one or more instances of Magics.
365
365
366 Take one or more classes or instances of classes that subclass the main
366 Take one or more classes or instances of classes that subclass the main
367 `core.Magic` class, and register them with IPython to use the magic
367 `core.Magic` class, and register them with IPython to use the magic
368 functions they provide. The registration process will then ensure that
368 functions they provide. The registration process will then ensure that
369 any methods that have decorated to provide line and/or cell magics will
369 any methods that have decorated to provide line and/or cell magics will
370 be recognized with the `%x`/`%%x` syntax as a line/cell magic
370 be recognized with the `%x`/`%%x` syntax as a line/cell magic
371 respectively.
371 respectively.
372
372
373 If classes are given, they will be instantiated with the default
373 If classes are given, they will be instantiated with the default
374 constructor. If your classes need a custom constructor, you should
374 constructor. If your classes need a custom constructor, you should
375 instanitate them first and pass the instance.
375 instanitate them first and pass the instance.
376
376
377 The provided arguments can be an arbitrary mix of classes and instances.
377 The provided arguments can be an arbitrary mix of classes and instances.
378
378
379 Parameters
379 Parameters
380 ----------
380 ----------
381 magic_objects : one or more classes or instances
381 magic_objects : one or more classes or instances
382 """
382 """
383 # Start by validating them to ensure they have all had their magic
383 # Start by validating them to ensure they have all had their magic
384 # methods registered at the instance level
384 # methods registered at the instance level
385 for m in magic_objects:
385 for m in magic_objects:
386 if not m.registered:
386 if not m.registered:
387 raise ValueError("Class of magics %r was constructed without "
387 raise ValueError("Class of magics %r was constructed without "
388 "the @register_magics class decorator")
388 "the @register_magics class decorator")
389 if type(m) in (type, MetaHasTraits):
389 if type(m) in (type, MetaHasTraits):
390 # If we're given an uninstantiated class
390 # If we're given an uninstantiated class
391 m = m(shell=self.shell)
391 m = m(shell=self.shell)
392
392
393 # Now that we have an instance, we can register it and update the
393 # Now that we have an instance, we can register it and update the
394 # table of callables
394 # table of callables
395 self.registry[m.__class__.__name__] = m
395 self.registry[m.__class__.__name__] = m
396 for mtype in magic_kinds:
396 for mtype in magic_kinds:
397 self.magics[mtype].update(m.magics[mtype])
397 self.magics[mtype].update(m.magics[mtype])
398
398
399 def register_function(self, func, magic_kind='line', magic_name=None):
399 def register_function(self, func, magic_kind='line', magic_name=None):
400 """Expose a standalone function as magic function for IPython.
400 """Expose a standalone function as magic function for IPython.
401
401
402 This will create an IPython magic (line, cell or both) from a
402 This will create an IPython magic (line, cell or both) from a
403 standalone function. The functions should have the following
403 standalone function. The functions should have the following
404 signatures:
404 signatures:
405
405
406 * For line magics: `def f(line)`
406 * For line magics: `def f(line)`
407 * For cell magics: `def f(line, cell)`
407 * For cell magics: `def f(line, cell)`
408 * For a function that does both: `def f(line, cell=None)`
408 * For a function that does both: `def f(line, cell=None)`
409
409
410 In the latter case, the function will be called with `cell==None` when
410 In the latter case, the function will be called with `cell==None` when
411 invoked as `%f`, and with cell as a string when invoked as `%%f`.
411 invoked as `%f`, and with cell as a string when invoked as `%%f`.
412
412
413 Parameters
413 Parameters
414 ----------
414 ----------
415 func : callable
415 func : callable
416 Function to be registered as a magic.
416 Function to be registered as a magic.
417
417
418 magic_kind : str
418 magic_kind : str
419 Kind of magic, one of 'line', 'cell' or 'line_cell'
419 Kind of magic, one of 'line', 'cell' or 'line_cell'
420
420
421 magic_name : optional str
421 magic_name : optional str
422 If given, the name the magic will have in the IPython namespace. By
422 If given, the name the magic will have in the IPython namespace. By
423 default, the name of the function itself is used.
423 default, the name of the function itself is used.
424 """
424 """
425
425
426 # Create the new method in the user_magics and register it in the
426 # Create the new method in the user_magics and register it in the
427 # global table
427 # global table
428 validate_type(magic_kind)
428 validate_type(magic_kind)
429 magic_name = func.__name__ if magic_name is None else magic_name
429 magic_name = func.__name__ if magic_name is None else magic_name
430 setattr(self.user_magics, magic_name, func)
430 setattr(self.user_magics, magic_name, func)
431 record_magic(self.magics, magic_kind, magic_name, func)
431 record_magic(self.magics, magic_kind, magic_name, func)
432
432
433 def define_magic(self, name, func):
433 def define_magic(self, name, func):
434 """[Deprecated] Expose own function as magic function for IPython.
434 """[Deprecated] Expose own function as magic function for IPython.
435
435
436 Example::
436 Example::
437
437
438 def foo_impl(self, parameter_s=''):
438 def foo_impl(self, parameter_s=''):
439 'My very own magic!. (Use docstrings, IPython reads them).'
439 'My very own magic!. (Use docstrings, IPython reads them).'
440 print 'Magic function. Passed parameter is between < >:'
440 print 'Magic function. Passed parameter is between < >:'
441 print '<%s>' % parameter_s
441 print '<%s>' % parameter_s
442 print 'The self object is:', self
442 print 'The self object is:', self
443
443
444 ip.define_magic('foo',foo_impl)
444 ip.define_magic('foo',foo_impl)
445 """
445 """
446 meth = types.MethodType(func, self.user_magics)
446 meth = types.MethodType(func, self.user_magics)
447 setattr(self.user_magics, name, meth)
447 setattr(self.user_magics, name, meth)
448 record_magic(self.magics, 'line', name, meth)
448 record_magic(self.magics, 'line', name, meth)
449
449
450 def register_alias(self, alias_name, magic_name, magic_kind='line'):
450 def register_alias(self, alias_name, magic_name, magic_kind='line'):
451 """Register an alias to a magic function.
451 """Register an alias to a magic function.
452
452
453 The alias is an instance of :class:`MagicAlias`, which holds the
453 The alias is an instance of :class:`MagicAlias`, which holds the
454 name and kind of the magic it should call. Binding is done at
454 name and kind of the magic it should call. Binding is done at
455 call time, so if the underlying magic function is changed the alias
455 call time, so if the underlying magic function is changed the alias
456 will call the new function.
456 will call the new function.
457
457
458 Parameters
458 Parameters
459 ----------
459 ----------
460 alias_name : str
460 alias_name : str
461 The name of the magic to be registered.
461 The name of the magic to be registered.
462
462
463 magic_name : str
463 magic_name : str
464 The name of an existing magic.
464 The name of an existing magic.
465
465
466 magic_kind : str
466 magic_kind : str
467 Kind of magic, one of 'line' or 'cell'
467 Kind of magic, one of 'line' or 'cell'
468 """
468 """
469
469
470 # `validate_type` is too permissive, as it allows 'line_cell'
470 # `validate_type` is too permissive, as it allows 'line_cell'
471 # which we do not handle.
471 # which we do not handle.
472 if magic_kind not in magic_kinds:
472 if magic_kind not in magic_kinds:
473 raise ValueError('magic_kind must be one of %s, %s given' %
473 raise ValueError('magic_kind must be one of %s, %s given' %
474 magic_kinds, magic_kind)
474 magic_kinds, magic_kind)
475
475
476 alias = MagicAlias(self.shell, magic_name, magic_kind)
476 alias = MagicAlias(self.shell, magic_name, magic_kind)
477 setattr(self.user_magics, alias_name, alias)
477 setattr(self.user_magics, alias_name, alias)
478 record_magic(self.magics, magic_kind, alias_name, alias)
478 record_magic(self.magics, magic_kind, alias_name, alias)
479
479
480 # Key base class that provides the central functionality for magics.
480 # Key base class that provides the central functionality for magics.
481
481
482
482
483 class Magics(Configurable):
483 class Magics(Configurable):
484 """Base class for implementing magic functions.
484 """Base class for implementing magic functions.
485
485
486 Shell functions which can be reached as %function_name. All magic
486 Shell functions which can be reached as %function_name. All magic
487 functions should accept a string, which they can parse for their own
487 functions should accept a string, which they can parse for their own
488 needs. This can make some functions easier to type, eg `%cd ../`
488 needs. This can make some functions easier to type, eg `%cd ../`
489 vs. `%cd("../")`
489 vs. `%cd("../")`
490
490
491 Classes providing magic functions need to subclass this class, and they
491 Classes providing magic functions need to subclass this class, and they
492 MUST:
492 MUST:
493
493
494 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
494 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
495 individual methods as magic functions, AND
495 individual methods as magic functions, AND
496
496
497 - Use the class decorator `@magics_class` to ensure that the magic
497 - Use the class decorator `@magics_class` to ensure that the magic
498 methods are properly registered at the instance level upon instance
498 methods are properly registered at the instance level upon instance
499 initialization.
499 initialization.
500
500
501 See :mod:`magic_functions` for examples of actual implementation classes.
501 See :mod:`magic_functions` for examples of actual implementation classes.
502 """
502 """
503 # Dict holding all command-line options for each magic.
503 # Dict holding all command-line options for each magic.
504 options_table = None
504 options_table = None
505 # Dict for the mapping of magic names to methods, set by class decorator
505 # Dict for the mapping of magic names to methods, set by class decorator
506 magics = None
506 magics = None
507 # Flag to check that the class decorator was properly applied
507 # Flag to check that the class decorator was properly applied
508 registered = False
508 registered = False
509 # Instance of IPython shell
509 # Instance of IPython shell
510 shell = None
510 shell = None
511
511
512 def __init__(self, shell=None, **kwargs):
512 def __init__(self, shell=None, **kwargs):
513 if not(self.__class__.registered):
513 if not(self.__class__.registered):
514 raise ValueError('Magics subclass without registration - '
514 raise ValueError('Magics subclass without registration - '
515 'did you forget to apply @magics_class?')
515 'did you forget to apply @magics_class?')
516 if shell is not None:
516 if shell is not None:
517 if hasattr(shell, 'configurables'):
517 if hasattr(shell, 'configurables'):
518 shell.configurables.append(self)
518 shell.configurables.append(self)
519 if hasattr(shell, 'config'):
519 if hasattr(shell, 'config'):
520 kwargs.setdefault('parent', shell)
520 kwargs.setdefault('parent', shell)
521 kwargs['shell'] = shell
521 kwargs['shell'] = shell
522
522
523 self.shell = shell
523 self.shell = shell
524 self.options_table = {}
524 self.options_table = {}
525 # The method decorators are run when the instance doesn't exist yet, so
525 # The method decorators are run when the instance doesn't exist yet, so
526 # they can only record the names of the methods they are supposed to
526 # they can only record the names of the methods they are supposed to
527 # grab. Only now, that the instance exists, can we create the proper
527 # grab. Only now, that the instance exists, can we create the proper
528 # mapping to bound methods. So we read the info off the original names
528 # mapping to bound methods. So we read the info off the original names
529 # table and replace each method name by the actual bound method.
529 # table and replace each method name by the actual bound method.
530 # But we mustn't clobber the *class* mapping, in case of multiple instances.
530 # But we mustn't clobber the *class* mapping, in case of multiple instances.
531 class_magics = self.magics
531 class_magics = self.magics
532 self.magics = {}
532 self.magics = {}
533 for mtype in magic_kinds:
533 for mtype in magic_kinds:
534 tab = self.magics[mtype] = {}
534 tab = self.magics[mtype] = {}
535 cls_tab = class_magics[mtype]
535 cls_tab = class_magics[mtype]
536 for magic_name, meth_name in iteritems(cls_tab):
536 for magic_name, meth_name in iteritems(cls_tab):
537 if isinstance(meth_name, string_types):
537 if isinstance(meth_name, string_types):
538 # it's a method name, grab it
538 # it's a method name, grab it
539 tab[magic_name] = getattr(self, meth_name)
539 tab[magic_name] = getattr(self, meth_name)
540 else:
540 else:
541 # it's the real thing
541 # it's the real thing
542 tab[magic_name] = meth_name
542 tab[magic_name] = meth_name
543 # Configurable **needs** to be initiated at the end or the config
543 # Configurable **needs** to be initiated at the end or the config
544 # magics get screwed up.
544 # magics get screwed up.
545 super(Magics, self).__init__(**kwargs)
545 super(Magics, self).__init__(**kwargs)
546
546
547 def arg_err(self,func):
547 def arg_err(self,func):
548 """Print docstring if incorrect arguments were passed"""
548 """Print docstring if incorrect arguments were passed"""
549 print('Error in arguments:')
549 print('Error in arguments:')
550 print(oinspect.getdoc(func))
550 print(oinspect.getdoc(func))
551
551
552 def format_latex(self, strng):
552 def format_latex(self, strng):
553 """Format a string for latex inclusion."""
553 """Format a string for latex inclusion."""
554
554
555 # Characters that need to be escaped for latex:
555 # Characters that need to be escaped for latex:
556 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
556 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
557 # Magic command names as headers:
557 # Magic command names as headers:
558 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
558 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
559 re.MULTILINE)
559 re.MULTILINE)
560 # Magic commands
560 # Magic commands
561 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
561 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
562 re.MULTILINE)
562 re.MULTILINE)
563 # Paragraph continue
563 # Paragraph continue
564 par_re = re.compile(r'\\$',re.MULTILINE)
564 par_re = re.compile(r'\\$',re.MULTILINE)
565
565
566 # The "\n" symbol
566 # The "\n" symbol
567 newline_re = re.compile(r'\\n')
567 newline_re = re.compile(r'\\n')
568
568
569 # Now build the string for output:
569 # Now build the string for output:
570 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
570 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
571 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
571 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
572 strng)
572 strng)
573 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
573 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
574 strng = par_re.sub(r'\\\\',strng)
574 strng = par_re.sub(r'\\\\',strng)
575 strng = escape_re.sub(r'\\\1',strng)
575 strng = escape_re.sub(r'\\\1',strng)
576 strng = newline_re.sub(r'\\textbackslash{}n',strng)
576 strng = newline_re.sub(r'\\textbackslash{}n',strng)
577 return strng
577 return strng
578
578
579 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
579 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
580 """Parse options passed to an argument string.
580 """Parse options passed to an argument string.
581
581
582 The interface is similar to that of :func:`getopt.getopt`, but it
582 The interface is similar to that of :func:`getopt.getopt`, but it
583 returns a :class:`~IPython.utils.struct.Struct` with the options as keys
583 returns a :class:`~IPython.utils.struct.Struct` with the options as keys
584 and the stripped argument string still as a string.
584 and the stripped argument string still as a string.
585
585
586 arg_str is quoted as a true sys.argv vector by using shlex.split.
586 arg_str is quoted as a true sys.argv vector by using shlex.split.
587 This allows us to easily expand variables, glob files, quote
587 This allows us to easily expand variables, glob files, quote
588 arguments, etc.
588 arguments, etc.
589
589
590 Parameters
590 Parameters
591 ----------
591 ----------
592
592
593 arg_str : str
593 arg_str : str
594 The arguments to parse.
594 The arguments to parse.
595
595
596 opt_str : str
596 opt_str : str
597 The options specification.
597 The options specification.
598
598
599 mode : str, default 'string'
599 mode : str, default 'string'
600 If given as 'list', the argument string is returned as a list (split
600 If given as 'list', the argument string is returned as a list (split
601 on whitespace) instead of a string.
601 on whitespace) instead of a string.
602
602
603 list_all : bool, default False
603 list_all : bool, default False
604 Put all option values in lists. Normally only options
604 Put all option values in lists. Normally only options
605 appearing more than once are put in a list.
605 appearing more than once are put in a list.
606
606
607 posix : bool, default True
607 posix : bool, default True
608 Whether to split the input line in POSIX mode or not, as per the
608 Whether to split the input line in POSIX mode or not, as per the
609 conventions outlined in the :mod:`shlex` module from the standard
609 conventions outlined in the :mod:`shlex` module from the standard
610 library.
610 library.
611 """
611 """
612
612
613 # inject default options at the beginning of the input line
613 # inject default options at the beginning of the input line
614 caller = sys._getframe(1).f_code.co_name
614 caller = sys._getframe(1).f_code.co_name
615 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
615 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
616
616
617 mode = kw.get('mode','string')
617 mode = kw.get('mode','string')
618 if mode not in ['string','list']:
618 if mode not in ['string','list']:
619 raise ValueError('incorrect mode given: %s' % mode)
619 raise ValueError('incorrect mode given: %s' % mode)
620 # Get options
620 # Get options
621 list_all = kw.get('list_all',0)
621 list_all = kw.get('list_all',0)
622 posix = kw.get('posix', os.name == 'posix')
622 posix = kw.get('posix', os.name == 'posix')
623 strict = kw.get('strict', True)
623 strict = kw.get('strict', True)
624
624
625 # Check if we have more than one argument to warrant extra processing:
625 # Check if we have more than one argument to warrant extra processing:
626 odict = {} # Dictionary with options
626 odict = {} # Dictionary with options
627 args = arg_str.split()
627 args = arg_str.split()
628 if len(args) >= 1:
628 if len(args) >= 1:
629 # If the list of inputs only has 0 or 1 thing in it, there's no
629 # If the list of inputs only has 0 or 1 thing in it, there's no
630 # need to look for options
630 # need to look for options
631 argv = arg_split(arg_str, posix, strict)
631 argv = arg_split(arg_str, posix, strict)
632 # Do regular option processing
632 # Do regular option processing
633 try:
633 try:
634 opts,args = getopt(argv, opt_str, long_opts)
634 opts,args = getopt(argv, opt_str, long_opts)
635 except GetoptError as e:
635 except GetoptError as e:
636 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
636 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
637 " ".join(long_opts)))
637 " ".join(long_opts)))
638 for o,a in opts:
638 for o,a in opts:
639 if o.startswith('--'):
639 if o.startswith('--'):
640 o = o[2:]
640 o = o[2:]
641 else:
641 else:
642 o = o[1:]
642 o = o[1:]
643 try:
643 try:
644 odict[o].append(a)
644 odict[o].append(a)
645 except AttributeError:
645 except AttributeError:
646 odict[o] = [odict[o],a]
646 odict[o] = [odict[o],a]
647 except KeyError:
647 except KeyError:
648 if list_all:
648 if list_all:
649 odict[o] = [a]
649 odict[o] = [a]
650 else:
650 else:
651 odict[o] = a
651 odict[o] = a
652
652
653 # Prepare opts,args for return
653 # Prepare opts,args for return
654 opts = Struct(odict)
654 opts = Struct(odict)
655 if mode == 'string':
655 if mode == 'string':
656 args = ' '.join(args)
656 args = ' '.join(args)
657
657
658 return opts,args
658 return opts,args
659
659
660 def default_option(self, fn, optstr):
660 def default_option(self, fn, optstr):
661 """Make an entry in the options_table for fn, with value optstr"""
661 """Make an entry in the options_table for fn, with value optstr"""
662
662
663 if fn not in self.lsmagic():
663 if fn not in self.lsmagic():
664 error("%s is not a magic function" % fn)
664 error("%s is not a magic function" % fn)
665 self.options_table[fn] = optstr
665 self.options_table[fn] = optstr
666
666
667
667
668 class MagicAlias(object):
668 class MagicAlias(object):
669 """An alias to another magic function.
669 """An alias to another magic function.
670
670
671 An alias is determined by its magic name and magic kind. Lookup
671 An alias is determined by its magic name and magic kind. Lookup
672 is done at call time, so if the underlying magic changes the alias
672 is done at call time, so if the underlying magic changes the alias
673 will call the new function.
673 will call the new function.
674
674
675 Use the :meth:`MagicsManager.register_alias` method or the
675 Use the :meth:`MagicsManager.register_alias` method or the
676 `%alias_magic` magic function to create and register a new alias.
676 `%alias_magic` magic function to create and register a new alias.
677 """
677 """
678 def __init__(self, shell, magic_name, magic_kind):
678 def __init__(self, shell, magic_name, magic_kind):
679 self.shell = shell
679 self.shell = shell
680 self.magic_name = magic_name
680 self.magic_name = magic_name
681 self.magic_kind = magic_kind
681 self.magic_kind = magic_kind
682
682
683 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
683 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
684 self.__doc__ = "Alias for `%s`." % self.pretty_target
684 self.__doc__ = "Alias for `%s`." % self.pretty_target
685
685
686 self._in_call = False
686 self._in_call = False
687
687
688 def __call__(self, *args, **kwargs):
688 def __call__(self, *args, **kwargs):
689 """Call the magic alias."""
689 """Call the magic alias."""
690 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
690 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
691 if fn is None:
691 if fn is None:
692 raise UsageError("Magic `%s` not found." % self.pretty_target)
692 raise UsageError("Magic `%s` not found." % self.pretty_target)
693
693
694 # Protect against infinite recursion.
694 # Protect against infinite recursion.
695 if self._in_call:
695 if self._in_call:
696 raise UsageError("Infinite recursion detected; "
696 raise UsageError("Infinite recursion detected; "
697 "magic aliases cannot call themselves.")
697 "magic aliases cannot call themselves.")
698 self._in_call = True
698 self._in_call = True
699 try:
699 try:
700 return fn(*args, **kwargs)
700 return fn(*args, **kwargs)
701 finally:
701 finally:
702 self._in_call = False
702 self._in_call = False
@@ -1,715 +1,715 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Prefiltering components.
3 Prefiltering components.
4
4
5 Prefilters transform user input before it is exec'd by Python. These
5 Prefilters transform user input before it is exec'd by Python. These
6 transforms are used to implement additional syntax such as !ls and %magic.
6 transforms are used to implement additional syntax such as !ls and %magic.
7
7
8 Authors:
8 Authors:
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Dan Milstein
12 * Dan Milstein
13 * Ville Vainio
13 * Ville Vainio
14 """
14 """
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008-2011 The IPython Development Team
17 # Copyright (C) 2008-2011 The IPython Development Team
18 #
18 #
19 # Distributed under the terms of the BSD License. The full license is in
19 # Distributed under the terms of the BSD License. The full license is in
20 # the file COPYING, distributed as part of this software.
20 # the file COPYING, distributed as part of this software.
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Imports
24 # Imports
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 from keyword import iskeyword
27 from keyword import iskeyword
28 import re
28 import re
29
29
30 from IPython.core.autocall import IPyAutocall
30 from IPython.core.autocall import IPyAutocall
31 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
32 from IPython.core.inputsplitter import (
32 from IPython.core.inputsplitter import (
33 ESC_MAGIC,
33 ESC_MAGIC,
34 ESC_QUOTE,
34 ESC_QUOTE,
35 ESC_QUOTE2,
35 ESC_QUOTE2,
36 ESC_PAREN,
36 ESC_PAREN,
37 )
37 )
38 from IPython.core.macro import Macro
38 from IPython.core.macro import Macro
39 from IPython.core.splitinput import LineInfo
39 from IPython.core.splitinput import LineInfo
40
40
41 from IPython.utils.traitlets import (
41 from IPython.utils.traitlets import (
42 List, Integer, Unicode, CBool, Bool, Instance, CRegExp
42 List, Integer, Unicode, CBool, Bool, Instance, CRegExp
43 )
43 )
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Global utilities, errors and constants
46 # Global utilities, errors and constants
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49
49
50 class PrefilterError(Exception):
50 class PrefilterError(Exception):
51 pass
51 pass
52
52
53
53
54 # RegExp to identify potential function names
54 # RegExp to identify potential function names
55 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
55 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
56
56
57 # RegExp to exclude strings with this start from autocalling. In
57 # RegExp to exclude strings with this start from autocalling. In
58 # particular, all binary operators should be excluded, so that if foo is
58 # particular, all binary operators should be excluded, so that if foo is
59 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
59 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
60 # characters '!=()' don't need to be checked for, as the checkPythonChars
60 # characters '!=()' don't need to be checked for, as the checkPythonChars
61 # routine explicitely does so, to catch direct calls and rebindings of
61 # routine explicitely does so, to catch direct calls and rebindings of
62 # existing names.
62 # existing names.
63
63
64 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
64 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
65 # it affects the rest of the group in square brackets.
65 # it affects the rest of the group in square brackets.
66 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
66 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
67 r'|^is |^not |^in |^and |^or ')
67 r'|^is |^not |^in |^and |^or ')
68
68
69 # try to catch also methods for stuff in lists/tuples/dicts: off
69 # try to catch also methods for stuff in lists/tuples/dicts: off
70 # (experimental). For this to work, the line_split regexp would need
70 # (experimental). For this to work, the line_split regexp would need
71 # to be modified so it wouldn't break things at '['. That line is
71 # to be modified so it wouldn't break things at '['. That line is
72 # nasty enough that I shouldn't change it until I can test it _well_.
72 # nasty enough that I shouldn't change it until I can test it _well_.
73 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
73 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
74
74
75
75
76 # Handler Check Utilities
76 # Handler Check Utilities
77 def is_shadowed(identifier, ip):
77 def is_shadowed(identifier, ip):
78 """Is the given identifier defined in one of the namespaces which shadow
78 """Is the given identifier defined in one of the namespaces which shadow
79 the alias and magic namespaces? Note that an identifier is different
79 the alias and magic namespaces? Note that an identifier is different
80 than ifun, because it can not contain a '.' character."""
80 than ifun, because it can not contain a '.' character."""
81 # This is much safer than calling ofind, which can change state
81 # This is much safer than calling ofind, which can change state
82 return (identifier in ip.user_ns \
82 return (identifier in ip.user_ns \
83 or identifier in ip.user_global_ns \
83 or identifier in ip.user_global_ns \
84 or identifier in ip.ns_table['builtin']\
84 or identifier in ip.ns_table['builtin']\
85 or iskeyword(identifier))
85 or iskeyword(identifier))
86
86
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Main Prefilter manager
89 # Main Prefilter manager
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92
92
93 class PrefilterManager(Configurable):
93 class PrefilterManager(Configurable):
94 """Main prefilter component.
94 """Main prefilter component.
95
95
96 The IPython prefilter is run on all user input before it is run. The
96 The IPython prefilter is run on all user input before it is run. The
97 prefilter consumes lines of input and produces transformed lines of
97 prefilter consumes lines of input and produces transformed lines of
98 input.
98 input.
99
99
100 The iplementation consists of two phases:
100 The iplementation consists of two phases:
101
101
102 1. Transformers
102 1. Transformers
103 2. Checkers and handlers
103 2. Checkers and handlers
104
104
105 Over time, we plan on deprecating the checkers and handlers and doing
105 Over time, we plan on deprecating the checkers and handlers and doing
106 everything in the transformers.
106 everything in the transformers.
107
107
108 The transformers are instances of :class:`PrefilterTransformer` and have
108 The transformers are instances of :class:`PrefilterTransformer` and have
109 a single method :meth:`transform` that takes a line and returns a
109 a single method :meth:`transform` that takes a line and returns a
110 transformed line. The transformation can be accomplished using any
110 transformed line. The transformation can be accomplished using any
111 tool, but our current ones use regular expressions for speed.
111 tool, but our current ones use regular expressions for speed.
112
112
113 After all the transformers have been run, the line is fed to the checkers,
113 After all the transformers have been run, the line is fed to the checkers,
114 which are instances of :class:`PrefilterChecker`. The line is passed to
114 which are instances of :class:`PrefilterChecker`. The line is passed to
115 the :meth:`check` method, which either returns `None` or a
115 the :meth:`check` method, which either returns `None` or a
116 :class:`PrefilterHandler` instance. If `None` is returned, the other
116 :class:`PrefilterHandler` instance. If `None` is returned, the other
117 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
117 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
118 the line is passed to the :meth:`handle` method of the returned
118 the line is passed to the :meth:`handle` method of the returned
119 handler and no further checkers are tried.
119 handler and no further checkers are tried.
120
120
121 Both transformers and checkers have a `priority` attribute, that determines
121 Both transformers and checkers have a `priority` attribute, that determines
122 the order in which they are called. Smaller priorities are tried first.
122 the order in which they are called. Smaller priorities are tried first.
123
123
124 Both transformers and checkers also have `enabled` attribute, which is
124 Both transformers and checkers also have `enabled` attribute, which is
125 a boolean that determines if the instance is used.
125 a boolean that determines if the instance is used.
126
126
127 Users or developers can change the priority or enabled attribute of
127 Users or developers can change the priority or enabled attribute of
128 transformers or checkers, but they must call the :meth:`sort_checkers`
128 transformers or checkers, but they must call the :meth:`sort_checkers`
129 or :meth:`sort_transformers` method after changing the priority.
129 or :meth:`sort_transformers` method after changing the priority.
130 """
130 """
131
131
132 multi_line_specials = CBool(True, config=True)
132 multi_line_specials = CBool(True, config=True)
133 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
133 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
134
134
135 def __init__(self, shell=None, **kwargs):
135 def __init__(self, shell=None, **kwargs):
136 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
136 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
137 self.shell = shell
137 self.shell = shell
138 self.init_transformers()
138 self.init_transformers()
139 self.init_handlers()
139 self.init_handlers()
140 self.init_checkers()
140 self.init_checkers()
141
141
142 #-------------------------------------------------------------------------
142 #-------------------------------------------------------------------------
143 # API for managing transformers
143 # API for managing transformers
144 #-------------------------------------------------------------------------
144 #-------------------------------------------------------------------------
145
145
146 def init_transformers(self):
146 def init_transformers(self):
147 """Create the default transformers."""
147 """Create the default transformers."""
148 self._transformers = []
148 self._transformers = []
149 for transformer_cls in _default_transformers:
149 for transformer_cls in _default_transformers:
150 transformer_cls(
150 transformer_cls(
151 shell=self.shell, prefilter_manager=self, parent=self
151 shell=self.shell, prefilter_manager=self, parent=self
152 )
152 )
153
153
154 def sort_transformers(self):
154 def sort_transformers(self):
155 """Sort the transformers by priority.
155 """Sort the transformers by priority.
156
156
157 This must be called after the priority of a transformer is changed.
157 This must be called after the priority of a transformer is changed.
158 The :meth:`register_transformer` method calls this automatically.
158 The :meth:`register_transformer` method calls this automatically.
159 """
159 """
160 self._transformers.sort(key=lambda x: x.priority)
160 self._transformers.sort(key=lambda x: x.priority)
161
161
162 @property
162 @property
163 def transformers(self):
163 def transformers(self):
164 """Return a list of checkers, sorted by priority."""
164 """Return a list of checkers, sorted by priority."""
165 return self._transformers
165 return self._transformers
166
166
167 def register_transformer(self, transformer):
167 def register_transformer(self, transformer):
168 """Register a transformer instance."""
168 """Register a transformer instance."""
169 if transformer not in self._transformers:
169 if transformer not in self._transformers:
170 self._transformers.append(transformer)
170 self._transformers.append(transformer)
171 self.sort_transformers()
171 self.sort_transformers()
172
172
173 def unregister_transformer(self, transformer):
173 def unregister_transformer(self, transformer):
174 """Unregister a transformer instance."""
174 """Unregister a transformer instance."""
175 if transformer in self._transformers:
175 if transformer in self._transformers:
176 self._transformers.remove(transformer)
176 self._transformers.remove(transformer)
177
177
178 #-------------------------------------------------------------------------
178 #-------------------------------------------------------------------------
179 # API for managing checkers
179 # API for managing checkers
180 #-------------------------------------------------------------------------
180 #-------------------------------------------------------------------------
181
181
182 def init_checkers(self):
182 def init_checkers(self):
183 """Create the default checkers."""
183 """Create the default checkers."""
184 self._checkers = []
184 self._checkers = []
185 for checker in _default_checkers:
185 for checker in _default_checkers:
186 checker(
186 checker(
187 shell=self.shell, prefilter_manager=self, parent=self
187 shell=self.shell, prefilter_manager=self, parent=self
188 )
188 )
189
189
190 def sort_checkers(self):
190 def sort_checkers(self):
191 """Sort the checkers by priority.
191 """Sort the checkers by priority.
192
192
193 This must be called after the priority of a checker is changed.
193 This must be called after the priority of a checker is changed.
194 The :meth:`register_checker` method calls this automatically.
194 The :meth:`register_checker` method calls this automatically.
195 """
195 """
196 self._checkers.sort(key=lambda x: x.priority)
196 self._checkers.sort(key=lambda x: x.priority)
197
197
198 @property
198 @property
199 def checkers(self):
199 def checkers(self):
200 """Return a list of checkers, sorted by priority."""
200 """Return a list of checkers, sorted by priority."""
201 return self._checkers
201 return self._checkers
202
202
203 def register_checker(self, checker):
203 def register_checker(self, checker):
204 """Register a checker instance."""
204 """Register a checker instance."""
205 if checker not in self._checkers:
205 if checker not in self._checkers:
206 self._checkers.append(checker)
206 self._checkers.append(checker)
207 self.sort_checkers()
207 self.sort_checkers()
208
208
209 def unregister_checker(self, checker):
209 def unregister_checker(self, checker):
210 """Unregister a checker instance."""
210 """Unregister a checker instance."""
211 if checker in self._checkers:
211 if checker in self._checkers:
212 self._checkers.remove(checker)
212 self._checkers.remove(checker)
213
213
214 #-------------------------------------------------------------------------
214 #-------------------------------------------------------------------------
215 # API for managing handlers
215 # API for managing handlers
216 #-------------------------------------------------------------------------
216 #-------------------------------------------------------------------------
217
217
218 def init_handlers(self):
218 def init_handlers(self):
219 """Create the default handlers."""
219 """Create the default handlers."""
220 self._handlers = {}
220 self._handlers = {}
221 self._esc_handlers = {}
221 self._esc_handlers = {}
222 for handler in _default_handlers:
222 for handler in _default_handlers:
223 handler(
223 handler(
224 shell=self.shell, prefilter_manager=self, parent=self
224 shell=self.shell, prefilter_manager=self, parent=self
225 )
225 )
226
226
227 @property
227 @property
228 def handlers(self):
228 def handlers(self):
229 """Return a dict of all the handlers."""
229 """Return a dict of all the handlers."""
230 return self._handlers
230 return self._handlers
231
231
232 def register_handler(self, name, handler, esc_strings):
232 def register_handler(self, name, handler, esc_strings):
233 """Register a handler instance by name with esc_strings."""
233 """Register a handler instance by name with esc_strings."""
234 self._handlers[name] = handler
234 self._handlers[name] = handler
235 for esc_str in esc_strings:
235 for esc_str in esc_strings:
236 self._esc_handlers[esc_str] = handler
236 self._esc_handlers[esc_str] = handler
237
237
238 def unregister_handler(self, name, handler, esc_strings):
238 def unregister_handler(self, name, handler, esc_strings):
239 """Unregister a handler instance by name with esc_strings."""
239 """Unregister a handler instance by name with esc_strings."""
240 try:
240 try:
241 del self._handlers[name]
241 del self._handlers[name]
242 except KeyError:
242 except KeyError:
243 pass
243 pass
244 for esc_str in esc_strings:
244 for esc_str in esc_strings:
245 h = self._esc_handlers.get(esc_str)
245 h = self._esc_handlers.get(esc_str)
246 if h is handler:
246 if h is handler:
247 del self._esc_handlers[esc_str]
247 del self._esc_handlers[esc_str]
248
248
249 def get_handler_by_name(self, name):
249 def get_handler_by_name(self, name):
250 """Get a handler by its name."""
250 """Get a handler by its name."""
251 return self._handlers.get(name)
251 return self._handlers.get(name)
252
252
253 def get_handler_by_esc(self, esc_str):
253 def get_handler_by_esc(self, esc_str):
254 """Get a handler by its escape string."""
254 """Get a handler by its escape string."""
255 return self._esc_handlers.get(esc_str)
255 return self._esc_handlers.get(esc_str)
256
256
257 #-------------------------------------------------------------------------
257 #-------------------------------------------------------------------------
258 # Main prefiltering API
258 # Main prefiltering API
259 #-------------------------------------------------------------------------
259 #-------------------------------------------------------------------------
260
260
261 def prefilter_line_info(self, line_info):
261 def prefilter_line_info(self, line_info):
262 """Prefilter a line that has been converted to a LineInfo object.
262 """Prefilter a line that has been converted to a LineInfo object.
263
263
264 This implements the checker/handler part of the prefilter pipe.
264 This implements the checker/handler part of the prefilter pipe.
265 """
265 """
266 # print "prefilter_line_info: ", line_info
266 # print "prefilter_line_info: ", line_info
267 handler = self.find_handler(line_info)
267 handler = self.find_handler(line_info)
268 return handler.handle(line_info)
268 return handler.handle(line_info)
269
269
270 def find_handler(self, line_info):
270 def find_handler(self, line_info):
271 """Find a handler for the line_info by trying checkers."""
271 """Find a handler for the line_info by trying checkers."""
272 for checker in self.checkers:
272 for checker in self.checkers:
273 if checker.enabled:
273 if checker.enabled:
274 handler = checker.check(line_info)
274 handler = checker.check(line_info)
275 if handler:
275 if handler:
276 return handler
276 return handler
277 return self.get_handler_by_name('normal')
277 return self.get_handler_by_name('normal')
278
278
279 def transform_line(self, line, continue_prompt):
279 def transform_line(self, line, continue_prompt):
280 """Calls the enabled transformers in order of increasing priority."""
280 """Calls the enabled transformers in order of increasing priority."""
281 for transformer in self.transformers:
281 for transformer in self.transformers:
282 if transformer.enabled:
282 if transformer.enabled:
283 line = transformer.transform(line, continue_prompt)
283 line = transformer.transform(line, continue_prompt)
284 return line
284 return line
285
285
286 def prefilter_line(self, line, continue_prompt=False):
286 def prefilter_line(self, line, continue_prompt=False):
287 """Prefilter a single input line as text.
287 """Prefilter a single input line as text.
288
288
289 This method prefilters a single line of text by calling the
289 This method prefilters a single line of text by calling the
290 transformers and then the checkers/handlers.
290 transformers and then the checkers/handlers.
291 """
291 """
292
292
293 # print "prefilter_line: ", line, continue_prompt
293 # print "prefilter_line: ", line, continue_prompt
294 # All handlers *must* return a value, even if it's blank ('').
294 # All handlers *must* return a value, even if it's blank ('').
295
295
296 # save the line away in case we crash, so the post-mortem handler can
296 # save the line away in case we crash, so the post-mortem handler can
297 # record it
297 # record it
298 self.shell._last_input_line = line
298 self.shell._last_input_line = line
299
299
300 if not line:
300 if not line:
301 # Return immediately on purely empty lines, so that if the user
301 # Return immediately on purely empty lines, so that if the user
302 # previously typed some whitespace that started a continuation
302 # previously typed some whitespace that started a continuation
303 # prompt, he can break out of that loop with just an empty line.
303 # prompt, he can break out of that loop with just an empty line.
304 # This is how the default python prompt works.
304 # This is how the default python prompt works.
305 return ''
305 return ''
306
306
307 # At this point, we invoke our transformers.
307 # At this point, we invoke our transformers.
308 if not continue_prompt or (continue_prompt and self.multi_line_specials):
308 if not continue_prompt or (continue_prompt and self.multi_line_specials):
309 line = self.transform_line(line, continue_prompt)
309 line = self.transform_line(line, continue_prompt)
310
310
311 # Now we compute line_info for the checkers and handlers
311 # Now we compute line_info for the checkers and handlers
312 line_info = LineInfo(line, continue_prompt)
312 line_info = LineInfo(line, continue_prompt)
313
313
314 # the input history needs to track even empty lines
314 # the input history needs to track even empty lines
315 stripped = line.strip()
315 stripped = line.strip()
316
316
317 normal_handler = self.get_handler_by_name('normal')
317 normal_handler = self.get_handler_by_name('normal')
318 if not stripped:
318 if not stripped:
319 return normal_handler.handle(line_info)
319 return normal_handler.handle(line_info)
320
320
321 # special handlers are only allowed for single line statements
321 # special handlers are only allowed for single line statements
322 if continue_prompt and not self.multi_line_specials:
322 if continue_prompt and not self.multi_line_specials:
323 return normal_handler.handle(line_info)
323 return normal_handler.handle(line_info)
324
324
325 prefiltered = self.prefilter_line_info(line_info)
325 prefiltered = self.prefilter_line_info(line_info)
326 # print "prefiltered line: %r" % prefiltered
326 # print "prefiltered line: %r" % prefiltered
327 return prefiltered
327 return prefiltered
328
328
329 def prefilter_lines(self, lines, continue_prompt=False):
329 def prefilter_lines(self, lines, continue_prompt=False):
330 """Prefilter multiple input lines of text.
330 """Prefilter multiple input lines of text.
331
331
332 This is the main entry point for prefiltering multiple lines of
332 This is the main entry point for prefiltering multiple lines of
333 input. This simply calls :meth:`prefilter_line` for each line of
333 input. This simply calls :meth:`prefilter_line` for each line of
334 input.
334 input.
335
335
336 This covers cases where there are multiple lines in the user entry,
336 This covers cases where there are multiple lines in the user entry,
337 which is the case when the user goes back to a multiline history
337 which is the case when the user goes back to a multiline history
338 entry and presses enter.
338 entry and presses enter.
339 """
339 """
340 llines = lines.rstrip('\n').split('\n')
340 llines = lines.rstrip('\n').split('\n')
341 # We can get multiple lines in one shot, where multiline input 'blends'
341 # We can get multiple lines in one shot, where multiline input 'blends'
342 # into one line, in cases like recalling from the readline history
342 # into one line, in cases like recalling from the readline history
343 # buffer. We need to make sure that in such cases, we correctly
343 # buffer. We need to make sure that in such cases, we correctly
344 # communicate downstream which line is first and which are continuation
344 # communicate downstream which line is first and which are continuation
345 # ones.
345 # ones.
346 if len(llines) > 1:
346 if len(llines) > 1:
347 out = '\n'.join([self.prefilter_line(line, lnum>0)
347 out = '\n'.join([self.prefilter_line(line, lnum>0)
348 for lnum, line in enumerate(llines) ])
348 for lnum, line in enumerate(llines) ])
349 else:
349 else:
350 out = self.prefilter_line(llines[0], continue_prompt)
350 out = self.prefilter_line(llines[0], continue_prompt)
351
351
352 return out
352 return out
353
353
354 #-----------------------------------------------------------------------------
354 #-----------------------------------------------------------------------------
355 # Prefilter transformers
355 # Prefilter transformers
356 #-----------------------------------------------------------------------------
356 #-----------------------------------------------------------------------------
357
357
358
358
359 class PrefilterTransformer(Configurable):
359 class PrefilterTransformer(Configurable):
360 """Transform a line of user input."""
360 """Transform a line of user input."""
361
361
362 priority = Integer(100, config=True)
362 priority = Integer(100, config=True)
363 # Transformers don't currently use shell or prefilter_manager, but as we
363 # Transformers don't currently use shell or prefilter_manager, but as we
364 # move away from checkers and handlers, they will need them.
364 # move away from checkers and handlers, they will need them.
365 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
365 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
366 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
366 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
367 enabled = Bool(True, config=True)
367 enabled = Bool(True, config=True)
368
368
369 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
369 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
370 super(PrefilterTransformer, self).__init__(
370 super(PrefilterTransformer, self).__init__(
371 shell=shell, prefilter_manager=prefilter_manager, **kwargs
371 shell=shell, prefilter_manager=prefilter_manager, **kwargs
372 )
372 )
373 self.prefilter_manager.register_transformer(self)
373 self.prefilter_manager.register_transformer(self)
374
374
375 def transform(self, line, continue_prompt):
375 def transform(self, line, continue_prompt):
376 """Transform a line, returning the new one."""
376 """Transform a line, returning the new one."""
377 return None
377 return None
378
378
379 def __repr__(self):
379 def __repr__(self):
380 return "<%s(priority=%r, enabled=%r)>" % (
380 return "<%s(priority=%r, enabled=%r)>" % (
381 self.__class__.__name__, self.priority, self.enabled)
381 self.__class__.__name__, self.priority, self.enabled)
382
382
383
383
384 #-----------------------------------------------------------------------------
384 #-----------------------------------------------------------------------------
385 # Prefilter checkers
385 # Prefilter checkers
386 #-----------------------------------------------------------------------------
386 #-----------------------------------------------------------------------------
387
387
388
388
389 class PrefilterChecker(Configurable):
389 class PrefilterChecker(Configurable):
390 """Inspect an input line and return a handler for that line."""
390 """Inspect an input line and return a handler for that line."""
391
391
392 priority = Integer(100, config=True)
392 priority = Integer(100, config=True)
393 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
393 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
394 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
394 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
395 enabled = Bool(True, config=True)
395 enabled = Bool(True, config=True)
396
396
397 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
397 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
398 super(PrefilterChecker, self).__init__(
398 super(PrefilterChecker, self).__init__(
399 shell=shell, prefilter_manager=prefilter_manager, **kwargs
399 shell=shell, prefilter_manager=prefilter_manager, **kwargs
400 )
400 )
401 self.prefilter_manager.register_checker(self)
401 self.prefilter_manager.register_checker(self)
402
402
403 def check(self, line_info):
403 def check(self, line_info):
404 """Inspect line_info and return a handler instance or None."""
404 """Inspect line_info and return a handler instance or None."""
405 return None
405 return None
406
406
407 def __repr__(self):
407 def __repr__(self):
408 return "<%s(priority=%r, enabled=%r)>" % (
408 return "<%s(priority=%r, enabled=%r)>" % (
409 self.__class__.__name__, self.priority, self.enabled)
409 self.__class__.__name__, self.priority, self.enabled)
410
410
411
411
412 class EmacsChecker(PrefilterChecker):
412 class EmacsChecker(PrefilterChecker):
413
413
414 priority = Integer(100, config=True)
414 priority = Integer(100, config=True)
415 enabled = Bool(False, config=True)
415 enabled = Bool(False, config=True)
416
416
417 def check(self, line_info):
417 def check(self, line_info):
418 "Emacs ipython-mode tags certain input lines."
418 "Emacs ipython-mode tags certain input lines."
419 if line_info.line.endswith('# PYTHON-MODE'):
419 if line_info.line.endswith('# PYTHON-MODE'):
420 return self.prefilter_manager.get_handler_by_name('emacs')
420 return self.prefilter_manager.get_handler_by_name('emacs')
421 else:
421 else:
422 return None
422 return None
423
423
424
424
425 class MacroChecker(PrefilterChecker):
425 class MacroChecker(PrefilterChecker):
426
426
427 priority = Integer(250, config=True)
427 priority = Integer(250, config=True)
428
428
429 def check(self, line_info):
429 def check(self, line_info):
430 obj = self.shell.user_ns.get(line_info.ifun)
430 obj = self.shell.user_ns.get(line_info.ifun)
431 if isinstance(obj, Macro):
431 if isinstance(obj, Macro):
432 return self.prefilter_manager.get_handler_by_name('macro')
432 return self.prefilter_manager.get_handler_by_name('macro')
433 else:
433 else:
434 return None
434 return None
435
435
436
436
437 class IPyAutocallChecker(PrefilterChecker):
437 class IPyAutocallChecker(PrefilterChecker):
438
438
439 priority = Integer(300, config=True)
439 priority = Integer(300, config=True)
440
440
441 def check(self, line_info):
441 def check(self, line_info):
442 "Instances of IPyAutocall in user_ns get autocalled immediately"
442 "Instances of IPyAutocall in user_ns get autocalled immediately"
443 obj = self.shell.user_ns.get(line_info.ifun, None)
443 obj = self.shell.user_ns.get(line_info.ifun, None)
444 if isinstance(obj, IPyAutocall):
444 if isinstance(obj, IPyAutocall):
445 obj.set_ip(self.shell)
445 obj.set_ip(self.shell)
446 return self.prefilter_manager.get_handler_by_name('auto')
446 return self.prefilter_manager.get_handler_by_name('auto')
447 else:
447 else:
448 return None
448 return None
449
449
450
450
451 class AssignmentChecker(PrefilterChecker):
451 class AssignmentChecker(PrefilterChecker):
452
452
453 priority = Integer(600, config=True)
453 priority = Integer(600, config=True)
454
454
455 def check(self, line_info):
455 def check(self, line_info):
456 """Check to see if user is assigning to a var for the first time, in
456 """Check to see if user is assigning to a var for the first time, in
457 which case we want to avoid any sort of automagic / autocall games.
457 which case we want to avoid any sort of automagic / autocall games.
458
458
459 This allows users to assign to either alias or magic names true python
459 This allows users to assign to either alias or magic names true python
460 variables (the magic/alias systems always take second seat to true
460 variables (the magic/alias systems always take second seat to true
461 python code). E.g. ls='hi', or ls,that=1,2"""
461 python code). E.g. ls='hi', or ls,that=1,2"""
462 if line_info.the_rest:
462 if line_info.the_rest:
463 if line_info.the_rest[0] in '=,':
463 if line_info.the_rest[0] in '=,':
464 return self.prefilter_manager.get_handler_by_name('normal')
464 return self.prefilter_manager.get_handler_by_name('normal')
465 else:
465 else:
466 return None
466 return None
467
467
468
468
469 class AutoMagicChecker(PrefilterChecker):
469 class AutoMagicChecker(PrefilterChecker):
470
470
471 priority = Integer(700, config=True)
471 priority = Integer(700, config=True)
472
472
473 def check(self, line_info):
473 def check(self, line_info):
474 """If the ifun is magic, and automagic is on, run it. Note: normal,
474 """If the ifun is magic, and automagic is on, run it. Note: normal,
475 non-auto magic would already have been triggered via '%' in
475 non-auto magic would already have been triggered via '%' in
476 check_esc_chars. This just checks for automagic. Also, before
476 check_esc_chars. This just checks for automagic. Also, before
477 triggering the magic handler, make sure that there is nothing in the
477 triggering the magic handler, make sure that there is nothing in the
478 user namespace which could shadow it."""
478 user namespace which could shadow it."""
479 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
479 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
480 return None
480 return None
481
481
482 # We have a likely magic method. Make sure we should actually call it.
482 # We have a likely magic method. Make sure we should actually call it.
483 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
483 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
484 return None
484 return None
485
485
486 head = line_info.ifun.split('.',1)[0]
486 head = line_info.ifun.split('.',1)[0]
487 if is_shadowed(head, self.shell):
487 if is_shadowed(head, self.shell):
488 return None
488 return None
489
489
490 return self.prefilter_manager.get_handler_by_name('magic')
490 return self.prefilter_manager.get_handler_by_name('magic')
491
491
492
492
493 class PythonOpsChecker(PrefilterChecker):
493 class PythonOpsChecker(PrefilterChecker):
494
494
495 priority = Integer(900, config=True)
495 priority = Integer(900, config=True)
496
496
497 def check(self, line_info):
497 def check(self, line_info):
498 """If the 'rest' of the line begins with a function call or pretty much
498 """If the 'rest' of the line begins with a function call or pretty much
499 any python operator, we should simply execute the line (regardless of
499 any python operator, we should simply execute the line (regardless of
500 whether or not there's a possible autocall expansion). This avoids
500 whether or not there's a possible autocall expansion). This avoids
501 spurious (and very confusing) geattr() accesses."""
501 spurious (and very confusing) geattr() accesses."""
502 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
502 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
503 return self.prefilter_manager.get_handler_by_name('normal')
503 return self.prefilter_manager.get_handler_by_name('normal')
504 else:
504 else:
505 return None
505 return None
506
506
507
507
508 class AutocallChecker(PrefilterChecker):
508 class AutocallChecker(PrefilterChecker):
509
509
510 priority = Integer(1000, config=True)
510 priority = Integer(1000, config=True)
511
511
512 function_name_regexp = CRegExp(re_fun_name, config=True,
512 function_name_regexp = CRegExp(re_fun_name, config=True,
513 help="RegExp to identify potential function names.")
513 help="RegExp to identify potential function names.")
514 exclude_regexp = CRegExp(re_exclude_auto, config=True,
514 exclude_regexp = CRegExp(re_exclude_auto, config=True,
515 help="RegExp to exclude strings with this start from autocalling.")
515 help="RegExp to exclude strings with this start from autocalling.")
516
516
517 def check(self, line_info):
517 def check(self, line_info):
518 "Check if the initial word/function is callable and autocall is on."
518 "Check if the initial word/function is callable and autocall is on."
519 if not self.shell.autocall:
519 if not self.shell.autocall:
520 return None
520 return None
521
521
522 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
522 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
523 if not oinfo['found']:
523 if not oinfo['found']:
524 return None
524 return None
525
525
526 if callable(oinfo['obj']) \
526 if callable(oinfo['obj']) \
527 and (not self.exclude_regexp.match(line_info.the_rest)) \
527 and (not self.exclude_regexp.match(line_info.the_rest)) \
528 and self.function_name_regexp.match(line_info.ifun):
528 and self.function_name_regexp.match(line_info.ifun):
529 return self.prefilter_manager.get_handler_by_name('auto')
529 return self.prefilter_manager.get_handler_by_name('auto')
530 else:
530 else:
531 return None
531 return None
532
532
533
533
534 #-----------------------------------------------------------------------------
534 #-----------------------------------------------------------------------------
535 # Prefilter handlers
535 # Prefilter handlers
536 #-----------------------------------------------------------------------------
536 #-----------------------------------------------------------------------------
537
537
538
538
539 class PrefilterHandler(Configurable):
539 class PrefilterHandler(Configurable):
540
540
541 handler_name = Unicode('normal')
541 handler_name = Unicode('normal')
542 esc_strings = List([])
542 esc_strings = List([])
543 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
543 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
544 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
544 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
545
545
546 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
546 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
547 super(PrefilterHandler, self).__init__(
547 super(PrefilterHandler, self).__init__(
548 shell=shell, prefilter_manager=prefilter_manager, **kwargs
548 shell=shell, prefilter_manager=prefilter_manager, **kwargs
549 )
549 )
550 self.prefilter_manager.register_handler(
550 self.prefilter_manager.register_handler(
551 self.handler_name,
551 self.handler_name,
552 self,
552 self,
553 self.esc_strings
553 self.esc_strings
554 )
554 )
555
555
556 def handle(self, line_info):
556 def handle(self, line_info):
557 # print "normal: ", line_info
557 # print "normal: ", line_info
558 """Handle normal input lines. Use as a template for handlers."""
558 """Handle normal input lines. Use as a template for handlers."""
559
559
560 # With autoindent on, we need some way to exit the input loop, and I
560 # With autoindent on, we need some way to exit the input loop, and I
561 # don't want to force the user to have to backspace all the way to
561 # don't want to force the user to have to backspace all the way to
562 # clear the line. The rule will be in this case, that either two
562 # clear the line. The rule will be in this case, that either two
563 # lines of pure whitespace in a row, or a line of pure whitespace but
563 # lines of pure whitespace in a row, or a line of pure whitespace but
564 # of a size different to the indent level, will exit the input loop.
564 # of a size different to the indent level, will exit the input loop.
565 line = line_info.line
565 line = line_info.line
566 continue_prompt = line_info.continue_prompt
566 continue_prompt = line_info.continue_prompt
567
567
568 if (continue_prompt and
568 if (continue_prompt and
569 self.shell.autoindent and
569 self.shell.autoindent and
570 line.isspace() and
570 line.isspace() and
571 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
571 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
572 line = ''
572 line = ''
573
573
574 return line
574 return line
575
575
576 def __str__(self):
576 def __str__(self):
577 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
577 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
578
578
579
579
580 class MacroHandler(PrefilterHandler):
580 class MacroHandler(PrefilterHandler):
581 handler_name = Unicode("macro")
581 handler_name = Unicode("macro")
582
582
583 def handle(self, line_info):
583 def handle(self, line_info):
584 obj = self.shell.user_ns.get(line_info.ifun)
584 obj = self.shell.user_ns.get(line_info.ifun)
585 pre_space = line_info.pre_whitespace
585 pre_space = line_info.pre_whitespace
586 line_sep = "\n" + pre_space
586 line_sep = "\n" + pre_space
587 return pre_space + line_sep.join(obj.value.splitlines())
587 return pre_space + line_sep.join(obj.value.splitlines())
588
588
589
589
590 class MagicHandler(PrefilterHandler):
590 class MagicHandler(PrefilterHandler):
591
591
592 handler_name = Unicode('magic')
592 handler_name = Unicode('magic')
593 esc_strings = List([ESC_MAGIC])
593 esc_strings = List([ESC_MAGIC])
594
594
595 def handle(self, line_info):
595 def handle(self, line_info):
596 """Execute magic functions."""
596 """Execute magic functions."""
597 ifun = line_info.ifun
597 ifun = line_info.ifun
598 the_rest = line_info.the_rest
598 the_rest = line_info.the_rest
599 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
599 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
600 (ifun + " " + the_rest))
600 (ifun + " " + the_rest))
601 return cmd
601 return cmd
602
602
603
603
604 class AutoHandler(PrefilterHandler):
604 class AutoHandler(PrefilterHandler):
605
605
606 handler_name = Unicode('auto')
606 handler_name = Unicode('auto')
607 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
607 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
608
608
609 def handle(self, line_info):
609 def handle(self, line_info):
610 """Handle lines which can be auto-executed, quoting if requested."""
610 """Handle lines which can be auto-executed, quoting if requested."""
611 line = line_info.line
611 line = line_info.line
612 ifun = line_info.ifun
612 ifun = line_info.ifun
613 the_rest = line_info.the_rest
613 the_rest = line_info.the_rest
614 pre = line_info.pre
614 pre = line_info.pre
615 esc = line_info.esc
615 esc = line_info.esc
616 continue_prompt = line_info.continue_prompt
616 continue_prompt = line_info.continue_prompt
617 obj = line_info.ofind(self.shell)['obj']
617 obj = line_info.ofind(self.shell)['obj']
618 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
618 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
619
619
620 # This should only be active for single-line input!
620 # This should only be active for single-line input!
621 if continue_prompt:
621 if continue_prompt:
622 return line
622 return line
623
623
624 force_auto = isinstance(obj, IPyAutocall)
624 force_auto = isinstance(obj, IPyAutocall)
625
625
626 # User objects sometimes raise exceptions on attribute access other
626 # User objects sometimes raise exceptions on attribute access other
627 # than AttributeError (we've seen it in the past), so it's safest to be
627 # than AttributeError (we've seen it in the past), so it's safest to be
628 # ultra-conservative here and catch all.
628 # ultra-conservative here and catch all.
629 try:
629 try:
630 auto_rewrite = obj.rewrite
630 auto_rewrite = obj.rewrite
631 except Exception:
631 except Exception:
632 auto_rewrite = True
632 auto_rewrite = True
633
633
634 if esc == ESC_QUOTE:
634 if esc == ESC_QUOTE:
635 # Auto-quote splitting on whitespace
635 # Auto-quote splitting on whitespace
636 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
636 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
637 elif esc == ESC_QUOTE2:
637 elif esc == ESC_QUOTE2:
638 # Auto-quote whole string
638 # Auto-quote whole string
639 newcmd = '%s("%s")' % (ifun,the_rest)
639 newcmd = '%s("%s")' % (ifun,the_rest)
640 elif esc == ESC_PAREN:
640 elif esc == ESC_PAREN:
641 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
641 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
642 else:
642 else:
643 # Auto-paren.
643 # Auto-paren.
644 if force_auto:
644 if force_auto:
645 # Don't rewrite if it is already a call.
645 # Don't rewrite if it is already a call.
646 do_rewrite = not the_rest.startswith('(')
646 do_rewrite = not the_rest.startswith('(')
647 else:
647 else:
648 if not the_rest:
648 if not the_rest:
649 # We only apply it to argument-less calls if the autocall
649 # We only apply it to argument-less calls if the autocall
650 # parameter is set to 2.
650 # parameter is set to 2.
651 do_rewrite = (self.shell.autocall >= 2)
651 do_rewrite = (self.shell.autocall >= 2)
652 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
652 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
653 # Don't autocall in this case: item access for an object
653 # Don't autocall in this case: item access for an object
654 # which is BOTH callable and implements __getitem__.
654 # which is BOTH callable and implements __getitem__.
655 do_rewrite = False
655 do_rewrite = False
656 else:
656 else:
657 do_rewrite = True
657 do_rewrite = True
658
658
659 # Figure out the rewritten command
659 # Figure out the rewritten command
660 if do_rewrite:
660 if do_rewrite:
661 if the_rest.endswith(';'):
661 if the_rest.endswith(';'):
662 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
662 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
663 else:
663 else:
664 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
664 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
665 else:
665 else:
666 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
666 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
667 return normal_handler.handle(line_info)
667 return normal_handler.handle(line_info)
668
668
669 # Display the rewritten call
669 # Display the rewritten call
670 if auto_rewrite:
670 if auto_rewrite:
671 self.shell.auto_rewrite_input(newcmd)
671 self.shell.auto_rewrite_input(newcmd)
672
672
673 return newcmd
673 return newcmd
674
674
675
675
676 class EmacsHandler(PrefilterHandler):
676 class EmacsHandler(PrefilterHandler):
677
677
678 handler_name = Unicode('emacs')
678 handler_name = Unicode('emacs')
679 esc_strings = List([])
679 esc_strings = List([])
680
680
681 def handle(self, line_info):
681 def handle(self, line_info):
682 """Handle input lines marked by python-mode."""
682 """Handle input lines marked by python-mode."""
683
683
684 # Currently, nothing is done. Later more functionality can be added
684 # Currently, nothing is done. Later more functionality can be added
685 # here if needed.
685 # here if needed.
686
686
687 # The input cache shouldn't be updated
687 # The input cache shouldn't be updated
688 return line_info.line
688 return line_info.line
689
689
690
690
691 #-----------------------------------------------------------------------------
691 #-----------------------------------------------------------------------------
692 # Defaults
692 # Defaults
693 #-----------------------------------------------------------------------------
693 #-----------------------------------------------------------------------------
694
694
695
695
696 _default_transformers = [
696 _default_transformers = [
697 ]
697 ]
698
698
699 _default_checkers = [
699 _default_checkers = [
700 EmacsChecker,
700 EmacsChecker,
701 MacroChecker,
701 MacroChecker,
702 IPyAutocallChecker,
702 IPyAutocallChecker,
703 AssignmentChecker,
703 AssignmentChecker,
704 AutoMagicChecker,
704 AutoMagicChecker,
705 PythonOpsChecker,
705 PythonOpsChecker,
706 AutocallChecker
706 AutocallChecker
707 ]
707 ]
708
708
709 _default_handlers = [
709 _default_handlers = [
710 PrefilterHandler,
710 PrefilterHandler,
711 MacroHandler,
711 MacroHandler,
712 MagicHandler,
712 MagicHandler,
713 AutoHandler,
713 AutoHandler,
714 EmacsHandler
714 EmacsHandler
715 ]
715 ]
@@ -1,442 +1,442 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Classes for handling input/output prompts.
2 """Classes for handling input/output prompts.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian Granger
7 * Brian Granger
8 * Thomas Kluyver
8 * Thomas Kluyver
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
13 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
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 import os
23 import os
24 import re
24 import re
25 import socket
25 import socket
26 import sys
26 import sys
27 import time
27 import time
28
28
29 from string import Formatter
29 from string import Formatter
30
30
31 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
32 from IPython.core import release
32 from IPython.core import release
33 from IPython.utils import coloransi, py3compat
33 from IPython.utils import coloransi, py3compat
34 from IPython.utils.traitlets import (Unicode, Instance, Dict, Bool, Int)
34 from IPython.utils.traitlets import (Unicode, Instance, Dict, Bool, Int)
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Color schemes for prompts
37 # Color schemes for prompts
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 InputColors = coloransi.InputTermColors # just a shorthand
40 InputColors = coloransi.InputTermColors # just a shorthand
41 Colors = coloransi.TermColors # just a shorthand
41 Colors = coloransi.TermColors # just a shorthand
42
42
43 color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors())
43 color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors())
44
44
45 PColNoColors = coloransi.ColorScheme(
45 PColNoColors = coloransi.ColorScheme(
46 'NoColor',
46 'NoColor',
47 in_prompt = InputColors.NoColor, # Input prompt
47 in_prompt = InputColors.NoColor, # Input prompt
48 in_number = InputColors.NoColor, # Input prompt number
48 in_number = InputColors.NoColor, # Input prompt number
49 in_prompt2 = InputColors.NoColor, # Continuation prompt
49 in_prompt2 = InputColors.NoColor, # Continuation prompt
50 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
50 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
51
51
52 out_prompt = Colors.NoColor, # Output prompt
52 out_prompt = Colors.NoColor, # Output prompt
53 out_number = Colors.NoColor, # Output prompt number
53 out_number = Colors.NoColor, # Output prompt number
54
54
55 normal = Colors.NoColor # color off (usu. Colors.Normal)
55 normal = Colors.NoColor # color off (usu. Colors.Normal)
56 )
56 )
57
57
58 # make some schemes as instances so we can copy them for modification easily:
58 # make some schemes as instances so we can copy them for modification easily:
59 PColLinux = coloransi.ColorScheme(
59 PColLinux = coloransi.ColorScheme(
60 'Linux',
60 'Linux',
61 in_prompt = InputColors.Green,
61 in_prompt = InputColors.Green,
62 in_number = InputColors.LightGreen,
62 in_number = InputColors.LightGreen,
63 in_prompt2 = InputColors.Green,
63 in_prompt2 = InputColors.Green,
64 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
64 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
65
65
66 out_prompt = Colors.Red,
66 out_prompt = Colors.Red,
67 out_number = Colors.LightRed,
67 out_number = Colors.LightRed,
68
68
69 normal = Colors.Normal
69 normal = Colors.Normal
70 )
70 )
71
71
72 # Slightly modified Linux for light backgrounds
72 # Slightly modified Linux for light backgrounds
73 PColLightBG = PColLinux.copy('LightBG')
73 PColLightBG = PColLinux.copy('LightBG')
74
74
75 PColLightBG.colors.update(
75 PColLightBG.colors.update(
76 in_prompt = InputColors.Blue,
76 in_prompt = InputColors.Blue,
77 in_number = InputColors.LightBlue,
77 in_number = InputColors.LightBlue,
78 in_prompt2 = InputColors.Blue
78 in_prompt2 = InputColors.Blue
79 )
79 )
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Utilities
82 # Utilities
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 class LazyEvaluate(object):
85 class LazyEvaluate(object):
86 """This is used for formatting strings with values that need to be updated
86 """This is used for formatting strings with values that need to be updated
87 at that time, such as the current time or working directory."""
87 at that time, such as the current time or working directory."""
88 def __init__(self, func, *args, **kwargs):
88 def __init__(self, func, *args, **kwargs):
89 self.func = func
89 self.func = func
90 self.args = args
90 self.args = args
91 self.kwargs = kwargs
91 self.kwargs = kwargs
92
92
93 def __call__(self, **kwargs):
93 def __call__(self, **kwargs):
94 self.kwargs.update(kwargs)
94 self.kwargs.update(kwargs)
95 return self.func(*self.args, **self.kwargs)
95 return self.func(*self.args, **self.kwargs)
96
96
97 def __str__(self):
97 def __str__(self):
98 return str(self())
98 return str(self())
99
99
100 def __unicode__(self):
100 def __unicode__(self):
101 return py3compat.unicode_type(self())
101 return py3compat.unicode_type(self())
102
102
103 def __format__(self, format_spec):
103 def __format__(self, format_spec):
104 return format(self(), format_spec)
104 return format(self(), format_spec)
105
105
106 def multiple_replace(dict, text):
106 def multiple_replace(dict, text):
107 """ Replace in 'text' all occurences of any key in the given
107 """ Replace in 'text' all occurences of any key in the given
108 dictionary by its corresponding value. Returns the new string."""
108 dictionary by its corresponding value. Returns the new string."""
109
109
110 # Function by Xavier Defrang, originally found at:
110 # Function by Xavier Defrang, originally found at:
111 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
111 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
112
112
113 # Create a regular expression from the dictionary keys
113 # Create a regular expression from the dictionary keys
114 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
114 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
115 # For each match, look-up corresponding value in dictionary
115 # For each match, look-up corresponding value in dictionary
116 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
116 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
117
117
118 #-----------------------------------------------------------------------------
118 #-----------------------------------------------------------------------------
119 # Special characters that can be used in prompt templates, mainly bash-like
119 # Special characters that can be used in prompt templates, mainly bash-like
120 #-----------------------------------------------------------------------------
120 #-----------------------------------------------------------------------------
121
121
122 # If $HOME isn't defined (Windows), make it an absurd string so that it can
122 # If $HOME isn't defined (Windows), make it an absurd string so that it can
123 # never be expanded out into '~'. Basically anything which can never be a
123 # never be expanded out into '~'. Basically anything which can never be a
124 # reasonable directory name will do, we just want the $HOME -> '~' operation
124 # reasonable directory name will do, we just want the $HOME -> '~' operation
125 # to become a no-op. We pre-compute $HOME here so it's not done on every
125 # to become a no-op. We pre-compute $HOME here so it's not done on every
126 # prompt call.
126 # prompt call.
127
127
128 # FIXME:
128 # FIXME:
129
129
130 # - This should be turned into a class which does proper namespace management,
130 # - This should be turned into a class which does proper namespace management,
131 # since the prompt specials need to be evaluated in a certain namespace.
131 # since the prompt specials need to be evaluated in a certain namespace.
132 # Currently it's just globals, which need to be managed manually by code
132 # Currently it's just globals, which need to be managed manually by code
133 # below.
133 # below.
134
134
135 # - I also need to split up the color schemes from the prompt specials
135 # - I also need to split up the color schemes from the prompt specials
136 # somehow. I don't have a clean design for that quite yet.
136 # somehow. I don't have a clean design for that quite yet.
137
137
138 HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~"))
138 HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~"))
139
139
140 # This is needed on FreeBSD, and maybe other systems which symlink /home to
140 # This is needed on FreeBSD, and maybe other systems which symlink /home to
141 # /usr/home, but retain the $HOME variable as pointing to /home
141 # /usr/home, but retain the $HOME variable as pointing to /home
142 HOME = os.path.realpath(HOME)
142 HOME = os.path.realpath(HOME)
143
143
144 # We precompute a few more strings here for the prompt_specials, which are
144 # We precompute a few more strings here for the prompt_specials, which are
145 # fixed once ipython starts. This reduces the runtime overhead of computing
145 # fixed once ipython starts. This reduces the runtime overhead of computing
146 # prompt strings.
146 # prompt strings.
147 USER = py3compat.str_to_unicode(os.environ.get("USER",''))
147 USER = py3compat.str_to_unicode(os.environ.get("USER",''))
148 HOSTNAME = py3compat.str_to_unicode(socket.gethostname())
148 HOSTNAME = py3compat.str_to_unicode(socket.gethostname())
149 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
149 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
150
150
151 # IronPython doesn't currently have os.getuid() even if
151 # IronPython doesn't currently have os.getuid() even if
152 # os.name == 'posix'; 2/8/2014
152 # os.name == 'posix'; 2/8/2014
153 ROOT_SYMBOL = "#" if (os.name=='nt' or sys.platform=='cli' or os.getuid()==0) else "$"
153 ROOT_SYMBOL = "#" if (os.name=='nt' or sys.platform=='cli' or os.getuid()==0) else "$"
154
154
155 prompt_abbreviations = {
155 prompt_abbreviations = {
156 # Prompt/history count
156 # Prompt/history count
157 '%n' : '{color.number}' '{count}' '{color.prompt}',
157 '%n' : '{color.number}' '{count}' '{color.prompt}',
158 r'\#': '{color.number}' '{count}' '{color.prompt}',
158 r'\#': '{color.number}' '{count}' '{color.prompt}',
159 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
159 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
160 # can get numbers displayed in whatever color they want.
160 # can get numbers displayed in whatever color they want.
161 r'\N': '{count}',
161 r'\N': '{count}',
162
162
163 # Prompt/history count, with the actual digits replaced by dots. Used
163 # Prompt/history count, with the actual digits replaced by dots. Used
164 # mainly in continuation prompts (prompt_in2)
164 # mainly in continuation prompts (prompt_in2)
165 r'\D': '{dots}',
165 r'\D': '{dots}',
166
166
167 # Current time
167 # Current time
168 r'\T' : '{time}',
168 r'\T' : '{time}',
169 # Current working directory
169 # Current working directory
170 r'\w': '{cwd}',
170 r'\w': '{cwd}',
171 # Basename of current working directory.
171 # Basename of current working directory.
172 # (use os.sep to make this portable across OSes)
172 # (use os.sep to make this portable across OSes)
173 r'\W' : '{cwd_last}',
173 r'\W' : '{cwd_last}',
174 # These X<N> are an extension to the normal bash prompts. They return
174 # These X<N> are an extension to the normal bash prompts. They return
175 # N terms of the path, after replacing $HOME with '~'
175 # N terms of the path, after replacing $HOME with '~'
176 r'\X0': '{cwd_x[0]}',
176 r'\X0': '{cwd_x[0]}',
177 r'\X1': '{cwd_x[1]}',
177 r'\X1': '{cwd_x[1]}',
178 r'\X2': '{cwd_x[2]}',
178 r'\X2': '{cwd_x[2]}',
179 r'\X3': '{cwd_x[3]}',
179 r'\X3': '{cwd_x[3]}',
180 r'\X4': '{cwd_x[4]}',
180 r'\X4': '{cwd_x[4]}',
181 r'\X5': '{cwd_x[5]}',
181 r'\X5': '{cwd_x[5]}',
182 # Y<N> are similar to X<N>, but they show '~' if it's the directory
182 # Y<N> are similar to X<N>, but they show '~' if it's the directory
183 # N+1 in the list. Somewhat like %cN in tcsh.
183 # N+1 in the list. Somewhat like %cN in tcsh.
184 r'\Y0': '{cwd_y[0]}',
184 r'\Y0': '{cwd_y[0]}',
185 r'\Y1': '{cwd_y[1]}',
185 r'\Y1': '{cwd_y[1]}',
186 r'\Y2': '{cwd_y[2]}',
186 r'\Y2': '{cwd_y[2]}',
187 r'\Y3': '{cwd_y[3]}',
187 r'\Y3': '{cwd_y[3]}',
188 r'\Y4': '{cwd_y[4]}',
188 r'\Y4': '{cwd_y[4]}',
189 r'\Y5': '{cwd_y[5]}',
189 r'\Y5': '{cwd_y[5]}',
190 # Hostname up to first .
190 # Hostname up to first .
191 r'\h': HOSTNAME_SHORT,
191 r'\h': HOSTNAME_SHORT,
192 # Full hostname
192 # Full hostname
193 r'\H': HOSTNAME,
193 r'\H': HOSTNAME,
194 # Username of current user
194 # Username of current user
195 r'\u': USER,
195 r'\u': USER,
196 # Escaped '\'
196 # Escaped '\'
197 '\\\\': '\\',
197 '\\\\': '\\',
198 # Newline
198 # Newline
199 r'\n': '\n',
199 r'\n': '\n',
200 # Carriage return
200 # Carriage return
201 r'\r': '\r',
201 r'\r': '\r',
202 # Release version
202 # Release version
203 r'\v': release.version,
203 r'\v': release.version,
204 # Root symbol ($ or #)
204 # Root symbol ($ or #)
205 r'\$': ROOT_SYMBOL,
205 r'\$': ROOT_SYMBOL,
206 }
206 }
207
207
208 #-----------------------------------------------------------------------------
208 #-----------------------------------------------------------------------------
209 # More utilities
209 # More utilities
210 #-----------------------------------------------------------------------------
210 #-----------------------------------------------------------------------------
211
211
212 def cwd_filt(depth):
212 def cwd_filt(depth):
213 """Return the last depth elements of the current working directory.
213 """Return the last depth elements of the current working directory.
214
214
215 $HOME is always replaced with '~'.
215 $HOME is always replaced with '~'.
216 If depth==0, the full path is returned."""
216 If depth==0, the full path is returned."""
217
217
218 cwd = py3compat.getcwd().replace(HOME,"~")
218 cwd = py3compat.getcwd().replace(HOME,"~")
219 out = os.sep.join(cwd.split(os.sep)[-depth:])
219 out = os.sep.join(cwd.split(os.sep)[-depth:])
220 return out or os.sep
220 return out or os.sep
221
221
222 def cwd_filt2(depth):
222 def cwd_filt2(depth):
223 """Return the last depth elements of the current working directory.
223 """Return the last depth elements of the current working directory.
224
224
225 $HOME is always replaced with '~'.
225 $HOME is always replaced with '~'.
226 If depth==0, the full path is returned."""
226 If depth==0, the full path is returned."""
227
227
228 full_cwd = py3compat.getcwd()
228 full_cwd = py3compat.getcwd()
229 cwd = full_cwd.replace(HOME,"~").split(os.sep)
229 cwd = full_cwd.replace(HOME,"~").split(os.sep)
230 if '~' in cwd and len(cwd) == depth+1:
230 if '~' in cwd and len(cwd) == depth+1:
231 depth += 1
231 depth += 1
232 drivepart = ''
232 drivepart = ''
233 if sys.platform == 'win32' and len(cwd) > depth:
233 if sys.platform == 'win32' and len(cwd) > depth:
234 drivepart = os.path.splitdrive(full_cwd)[0]
234 drivepart = os.path.splitdrive(full_cwd)[0]
235 out = drivepart + '/'.join(cwd[-depth:])
235 out = drivepart + '/'.join(cwd[-depth:])
236
236
237 return out or os.sep
237 return out or os.sep
238
238
239 #-----------------------------------------------------------------------------
239 #-----------------------------------------------------------------------------
240 # Prompt classes
240 # Prompt classes
241 #-----------------------------------------------------------------------------
241 #-----------------------------------------------------------------------------
242
242
243 lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"),
243 lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"),
244 'cwd': LazyEvaluate(py3compat.getcwd),
244 'cwd': LazyEvaluate(py3compat.getcwd),
245 'cwd_last': LazyEvaluate(lambda: py3compat.getcwd().split(os.sep)[-1]),
245 'cwd_last': LazyEvaluate(lambda: py3compat.getcwd().split(os.sep)[-1]),
246 'cwd_x': [LazyEvaluate(lambda: py3compat.getcwd().replace(HOME,"~"))] +\
246 'cwd_x': [LazyEvaluate(lambda: py3compat.getcwd().replace(HOME,"~"))] +\
247 [LazyEvaluate(cwd_filt, x) for x in range(1,6)],
247 [LazyEvaluate(cwd_filt, x) for x in range(1,6)],
248 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
248 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
249 }
249 }
250
250
251 def _lenlastline(s):
251 def _lenlastline(s):
252 """Get the length of the last line. More intelligent than
252 """Get the length of the last line. More intelligent than
253 len(s.splitlines()[-1]).
253 len(s.splitlines()[-1]).
254 """
254 """
255 if not s or s.endswith(('\n', '\r')):
255 if not s or s.endswith(('\n', '\r')):
256 return 0
256 return 0
257 return len(s.splitlines()[-1])
257 return len(s.splitlines()[-1])
258
258
259
259
260 class UserNSFormatter(Formatter):
260 class UserNSFormatter(Formatter):
261 """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution"""
261 """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution"""
262 def __init__(self, shell):
262 def __init__(self, shell):
263 self.shell = shell
263 self.shell = shell
264
264
265 def get_value(self, key, args, kwargs):
265 def get_value(self, key, args, kwargs):
266 # try regular formatting first:
266 # try regular formatting first:
267 try:
267 try:
268 return Formatter.get_value(self, key, args, kwargs)
268 return Formatter.get_value(self, key, args, kwargs)
269 except Exception:
269 except Exception:
270 pass
270 pass
271 # next, look in user_ns and builtins:
271 # next, look in user_ns and builtins:
272 for container in (self.shell.user_ns, __builtins__):
272 for container in (self.shell.user_ns, __builtins__):
273 if key in container:
273 if key in container:
274 return container[key]
274 return container[key]
275 # nothing found, put error message in its place
275 # nothing found, put error message in its place
276 return "<ERROR: '%s' not found>" % key
276 return "<ERROR: '%s' not found>" % key
277
277
278
278
279 class PromptManager(Configurable):
279 class PromptManager(Configurable):
280 """This is the primary interface for producing IPython's prompts."""
280 """This is the primary interface for producing IPython's prompts."""
281 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
281 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
282
282
283 color_scheme_table = Instance(coloransi.ColorSchemeTable)
283 color_scheme_table = Instance(coloransi.ColorSchemeTable, allow_none=True)
284 color_scheme = Unicode('Linux', config=True)
284 color_scheme = Unicode('Linux', config=True)
285 def _color_scheme_changed(self, name, new_value):
285 def _color_scheme_changed(self, name, new_value):
286 self.color_scheme_table.set_active_scheme(new_value)
286 self.color_scheme_table.set_active_scheme(new_value)
287 for pname in ['in', 'in2', 'out', 'rewrite']:
287 for pname in ['in', 'in2', 'out', 'rewrite']:
288 # We need to recalculate the number of invisible characters
288 # We need to recalculate the number of invisible characters
289 self.update_prompt(pname)
289 self.update_prompt(pname)
290
290
291 lazy_evaluate_fields = Dict(help="""
291 lazy_evaluate_fields = Dict(help="""
292 This maps field names used in the prompt templates to functions which
292 This maps field names used in the prompt templates to functions which
293 will be called when the prompt is rendered. This allows us to include
293 will be called when the prompt is rendered. This allows us to include
294 things like the current time in the prompts. Functions are only called
294 things like the current time in the prompts. Functions are only called
295 if they are used in the prompt.
295 if they are used in the prompt.
296 """)
296 """)
297 def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()
297 def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()
298
298
299 in_template = Unicode('In [\\#]: ', config=True,
299 in_template = Unicode('In [\\#]: ', config=True,
300 help="Input prompt. '\\#' will be transformed to the prompt number")
300 help="Input prompt. '\\#' will be transformed to the prompt number")
301 in2_template = Unicode(' .\\D.: ', config=True,
301 in2_template = Unicode(' .\\D.: ', config=True,
302 help="Continuation prompt.")
302 help="Continuation prompt.")
303 out_template = Unicode('Out[\\#]: ', config=True,
303 out_template = Unicode('Out[\\#]: ', config=True,
304 help="Output prompt. '\\#' will be transformed to the prompt number")
304 help="Output prompt. '\\#' will be transformed to the prompt number")
305
305
306 justify = Bool(True, config=True, help="""
306 justify = Bool(True, config=True, help="""
307 If True (default), each prompt will be right-aligned with the
307 If True (default), each prompt will be right-aligned with the
308 preceding one.
308 preceding one.
309 """)
309 """)
310
310
311 # We actually store the expanded templates here:
311 # We actually store the expanded templates here:
312 templates = Dict()
312 templates = Dict()
313
313
314 # The number of characters in the last prompt rendered, not including
314 # The number of characters in the last prompt rendered, not including
315 # colour characters.
315 # colour characters.
316 width = Int()
316 width = Int()
317 txtwidth = Int() # Not including right-justification
317 txtwidth = Int() # Not including right-justification
318
318
319 # The number of characters in each prompt which don't contribute to width
319 # The number of characters in each prompt which don't contribute to width
320 invisible_chars = Dict()
320 invisible_chars = Dict()
321 def _invisible_chars_default(self):
321 def _invisible_chars_default(self):
322 return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}
322 return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}
323
323
324 def __init__(self, shell, **kwargs):
324 def __init__(self, shell, **kwargs):
325 super(PromptManager, self).__init__(shell=shell, **kwargs)
325 super(PromptManager, self).__init__(shell=shell, **kwargs)
326
326
327 # Prepare colour scheme table
327 # Prepare colour scheme table
328 self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors,
328 self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors,
329 PColLinux, PColLightBG], self.color_scheme)
329 PColLinux, PColLightBG], self.color_scheme)
330
330
331 self._formatter = UserNSFormatter(shell)
331 self._formatter = UserNSFormatter(shell)
332 # Prepare templates & numbers of invisible characters
332 # Prepare templates & numbers of invisible characters
333 self.update_prompt('in', self.in_template)
333 self.update_prompt('in', self.in_template)
334 self.update_prompt('in2', self.in2_template)
334 self.update_prompt('in2', self.in2_template)
335 self.update_prompt('out', self.out_template)
335 self.update_prompt('out', self.out_template)
336 self.update_prompt('rewrite')
336 self.update_prompt('rewrite')
337 self.on_trait_change(self._update_prompt_trait, ['in_template',
337 self.on_trait_change(self._update_prompt_trait, ['in_template',
338 'in2_template', 'out_template'])
338 'in2_template', 'out_template'])
339
339
340 def update_prompt(self, name, new_template=None):
340 def update_prompt(self, name, new_template=None):
341 """This is called when a prompt template is updated. It processes
341 """This is called when a prompt template is updated. It processes
342 abbreviations used in the prompt template (like \#) and calculates how
342 abbreviations used in the prompt template (like \#) and calculates how
343 many invisible characters (ANSI colour escapes) the resulting prompt
343 many invisible characters (ANSI colour escapes) the resulting prompt
344 contains.
344 contains.
345
345
346 It is also called for each prompt on changing the colour scheme. In both
346 It is also called for each prompt on changing the colour scheme. In both
347 cases, traitlets should take care of calling this automatically.
347 cases, traitlets should take care of calling this automatically.
348 """
348 """
349 if new_template is not None:
349 if new_template is not None:
350 self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
350 self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
351 # We count invisible characters (colour escapes) on the last line of the
351 # We count invisible characters (colour escapes) on the last line of the
352 # prompt, to calculate the width for lining up subsequent prompts.
352 # prompt, to calculate the width for lining up subsequent prompts.
353 invis_chars = _lenlastline(self._render(name, color=True)) - \
353 invis_chars = _lenlastline(self._render(name, color=True)) - \
354 _lenlastline(self._render(name, color=False))
354 _lenlastline(self._render(name, color=False))
355 self.invisible_chars[name] = invis_chars
355 self.invisible_chars[name] = invis_chars
356
356
357 def _update_prompt_trait(self, traitname, new_template):
357 def _update_prompt_trait(self, traitname, new_template):
358 name = traitname[:-9] # Cut off '_template'
358 name = traitname[:-9] # Cut off '_template'
359 self.update_prompt(name, new_template)
359 self.update_prompt(name, new_template)
360
360
361 def _render(self, name, color=True, **kwargs):
361 def _render(self, name, color=True, **kwargs):
362 """Render but don't justify, or update the width or txtwidth attributes.
362 """Render but don't justify, or update the width or txtwidth attributes.
363 """
363 """
364 if name == 'rewrite':
364 if name == 'rewrite':
365 return self._render_rewrite(color=color)
365 return self._render_rewrite(color=color)
366
366
367 if color:
367 if color:
368 scheme = self.color_scheme_table.active_colors
368 scheme = self.color_scheme_table.active_colors
369 if name=='out':
369 if name=='out':
370 colors = color_lists['normal']
370 colors = color_lists['normal']
371 colors.number, colors.prompt, colors.normal = \
371 colors.number, colors.prompt, colors.normal = \
372 scheme.out_number, scheme.out_prompt, scheme.normal
372 scheme.out_number, scheme.out_prompt, scheme.normal
373 else:
373 else:
374 colors = color_lists['inp']
374 colors = color_lists['inp']
375 colors.number, colors.prompt, colors.normal = \
375 colors.number, colors.prompt, colors.normal = \
376 scheme.in_number, scheme.in_prompt, scheme.in_normal
376 scheme.in_number, scheme.in_prompt, scheme.in_normal
377 if name=='in2':
377 if name=='in2':
378 colors.prompt = scheme.in_prompt2
378 colors.prompt = scheme.in_prompt2
379 else:
379 else:
380 # No color
380 # No color
381 colors = color_lists['nocolor']
381 colors = color_lists['nocolor']
382 colors.number, colors.prompt, colors.normal = '', '', ''
382 colors.number, colors.prompt, colors.normal = '', '', ''
383
383
384 count = self.shell.execution_count # Shorthand
384 count = self.shell.execution_count # Shorthand
385 # Build the dictionary to be passed to string formatting
385 # Build the dictionary to be passed to string formatting
386 fmtargs = dict(color=colors, count=count,
386 fmtargs = dict(color=colors, count=count,
387 dots="."*len(str(count)),
387 dots="."*len(str(count)),
388 width=self.width, txtwidth=self.txtwidth )
388 width=self.width, txtwidth=self.txtwidth )
389 fmtargs.update(self.lazy_evaluate_fields)
389 fmtargs.update(self.lazy_evaluate_fields)
390 fmtargs.update(kwargs)
390 fmtargs.update(kwargs)
391
391
392 # Prepare the prompt
392 # Prepare the prompt
393 prompt = colors.prompt + self.templates[name] + colors.normal
393 prompt = colors.prompt + self.templates[name] + colors.normal
394
394
395 # Fill in required fields
395 # Fill in required fields
396 return self._formatter.format(prompt, **fmtargs)
396 return self._formatter.format(prompt, **fmtargs)
397
397
398 def _render_rewrite(self, color=True):
398 def _render_rewrite(self, color=True):
399 """Render the ---> rewrite prompt."""
399 """Render the ---> rewrite prompt."""
400 if color:
400 if color:
401 scheme = self.color_scheme_table.active_colors
401 scheme = self.color_scheme_table.active_colors
402 # We need a non-input version of these escapes
402 # We need a non-input version of these escapes
403 color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
403 color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
404 color_normal = scheme.normal
404 color_normal = scheme.normal
405 else:
405 else:
406 color_prompt, color_normal = '', ''
406 color_prompt, color_normal = '', ''
407
407
408 return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal
408 return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal
409
409
410 def render(self, name, color=True, just=None, **kwargs):
410 def render(self, name, color=True, just=None, **kwargs):
411 """
411 """
412 Render the selected prompt.
412 Render the selected prompt.
413
413
414 Parameters
414 Parameters
415 ----------
415 ----------
416 name : str
416 name : str
417 Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
417 Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
418 color : bool
418 color : bool
419 If True (default), include ANSI escape sequences for a coloured prompt.
419 If True (default), include ANSI escape sequences for a coloured prompt.
420 just : bool
420 just : bool
421 If True, justify the prompt to the width of the last prompt. The
421 If True, justify the prompt to the width of the last prompt. The
422 default is stored in self.justify.
422 default is stored in self.justify.
423 **kwargs :
423 **kwargs :
424 Additional arguments will be passed to the string formatting operation,
424 Additional arguments will be passed to the string formatting operation,
425 so they can override the values that would otherwise fill in the
425 so they can override the values that would otherwise fill in the
426 template.
426 template.
427
427
428 Returns
428 Returns
429 -------
429 -------
430 A string containing the rendered prompt.
430 A string containing the rendered prompt.
431 """
431 """
432 res = self._render(name, color=color, **kwargs)
432 res = self._render(name, color=color, **kwargs)
433
433
434 # Handle justification of prompt
434 # Handle justification of prompt
435 invis_chars = self.invisible_chars[name] if color else 0
435 invis_chars = self.invisible_chars[name] if color else 0
436 self.txtwidth = _lenlastline(res) - invis_chars
436 self.txtwidth = _lenlastline(res) - invis_chars
437 just = self.justify if (just is None) else just
437 just = self.justify if (just is None) else just
438 # If the prompt spans more than one line, don't try to justify it:
438 # If the prompt spans more than one line, don't try to justify it:
439 if just and name != 'in' and ('\n' not in res) and ('\r' not in res):
439 if just and name != 'in' and ('\n' not in res) and ('\r' not in res):
440 res = res.rjust(self.width + invis_chars)
440 res = res.rjust(self.width + invis_chars)
441 self.width = _lenlastline(res) - invis_chars
441 self.width = _lenlastline(res) - invis_chars
442 return res
442 return res
@@ -1,432 +1,433 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
6
7 # Copyright (c) IPython Development Team.
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9
9
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 import glob
13 import glob
14 import os
14 import os
15 import sys
15 import sys
16
16
17 from IPython.config.application import boolean_flag
17 from IPython.config.application import boolean_flag
18 from IPython.config.configurable import Configurable
18 from IPython.config.configurable import Configurable
19 from IPython.config.loader import Config
19 from IPython.config.loader import Config
20 from IPython.core import pylabtools
20 from IPython.core import pylabtools
21 from IPython.utils import py3compat
21 from IPython.utils import py3compat
22 from IPython.utils.contexts import preserve_keys
22 from IPython.utils.contexts import preserve_keys
23 from IPython.utils.path import filefind
23 from IPython.utils.path import filefind
24 from IPython.utils.traitlets import (
24 from IPython.utils.traitlets import (
25 Unicode, Instance, List, Bool, CaselessStrEnum
25 Unicode, Instance, List, Bool, CaselessStrEnum
26 )
26 )
27 from IPython.lib.inputhook import guis
27 from IPython.lib.inputhook import guis
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Aliases and Flags
30 # Aliases and Flags
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
33 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
34
34
35 backend_keys = sorted(pylabtools.backends.keys())
35 backend_keys = sorted(pylabtools.backends.keys())
36 backend_keys.insert(0, 'auto')
36 backend_keys.insert(0, 'auto')
37
37
38 shell_flags = {}
38 shell_flags = {}
39
39
40 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
40 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
41 addflag('autoindent', 'InteractiveShell.autoindent',
41 addflag('autoindent', 'InteractiveShell.autoindent',
42 'Turn on autoindenting.', 'Turn off autoindenting.'
42 'Turn on autoindenting.', 'Turn off autoindenting.'
43 )
43 )
44 addflag('automagic', 'InteractiveShell.automagic',
44 addflag('automagic', 'InteractiveShell.automagic',
45 """Turn on the auto calling of magic commands. Type %%magic at the
45 """Turn on the auto calling of magic commands. Type %%magic at the
46 IPython prompt for more information.""",
46 IPython prompt for more information.""",
47 'Turn off the auto calling of magic commands.'
47 'Turn off the auto calling of magic commands.'
48 )
48 )
49 addflag('pdb', 'InteractiveShell.pdb',
49 addflag('pdb', 'InteractiveShell.pdb',
50 "Enable auto calling the pdb debugger after every exception.",
50 "Enable auto calling the pdb debugger after every exception.",
51 "Disable auto calling the pdb debugger after every exception."
51 "Disable auto calling the pdb debugger after every exception."
52 )
52 )
53 # pydb flag doesn't do any config, as core.debugger switches on import,
53 # pydb flag doesn't do any config, as core.debugger switches on import,
54 # which is before parsing. This just allows the flag to be passed.
54 # which is before parsing. This just allows the flag to be passed.
55 shell_flags.update(dict(
55 shell_flags.update(dict(
56 pydb = ({},
56 pydb = ({},
57 """Use the third party 'pydb' package as debugger, instead of pdb.
57 """Use the third party 'pydb' package as debugger, instead of pdb.
58 Requires that pydb is installed."""
58 Requires that pydb is installed."""
59 )
59 )
60 ))
60 ))
61 addflag('pprint', 'PlainTextFormatter.pprint',
61 addflag('pprint', 'PlainTextFormatter.pprint',
62 "Enable auto pretty printing of results.",
62 "Enable auto pretty printing of results.",
63 "Disable auto pretty printing of results."
63 "Disable auto pretty printing of results."
64 )
64 )
65 addflag('color-info', 'InteractiveShell.color_info',
65 addflag('color-info', 'InteractiveShell.color_info',
66 """IPython can display information about objects via a set of functions,
66 """IPython can display information about objects via a set of functions,
67 and optionally can use colors for this, syntax highlighting
67 and optionally can use colors for this, syntax highlighting
68 source code and various other elements. This is on by default, but can cause
68 source code and various other elements. This is on by default, but can cause
69 problems with some pagers. If you see such problems, you can disable the
69 problems with some pagers. If you see such problems, you can disable the
70 colours.""",
70 colours.""",
71 "Disable using colors for info related things."
71 "Disable using colors for info related things."
72 )
72 )
73 addflag('deep-reload', 'InteractiveShell.deep_reload',
73 addflag('deep-reload', 'InteractiveShell.deep_reload',
74 """Enable deep (recursive) reloading by default. IPython can use the
74 """Enable deep (recursive) reloading by default. IPython can use the
75 deep_reload module which reloads changes in modules recursively (it
75 deep_reload module which reloads changes in modules recursively (it
76 replaces the reload() function, so you don't need to change anything to
76 replaces the reload() function, so you don't need to change anything to
77 use it). deep_reload() forces a full reload of modules whose code may
77 use it). deep_reload() forces a full reload of modules whose code may
78 have changed, which the default reload() function does not. When
78 have changed, which the default reload() function does not. When
79 deep_reload is off, IPython will use the normal reload(), but
79 deep_reload is off, IPython will use the normal reload(), but
80 deep_reload will still be available as dreload(). This feature is off
80 deep_reload will still be available as dreload(). This feature is off
81 by default [which means that you have both normal reload() and
81 by default [which means that you have both normal reload() and
82 dreload()].""",
82 dreload()].""",
83 "Disable deep (recursive) reloading by default."
83 "Disable deep (recursive) reloading by default."
84 )
84 )
85 nosep_config = Config()
85 nosep_config = Config()
86 nosep_config.InteractiveShell.separate_in = ''
86 nosep_config.InteractiveShell.separate_in = ''
87 nosep_config.InteractiveShell.separate_out = ''
87 nosep_config.InteractiveShell.separate_out = ''
88 nosep_config.InteractiveShell.separate_out2 = ''
88 nosep_config.InteractiveShell.separate_out2 = ''
89
89
90 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
90 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
91 shell_flags['pylab'] = (
91 shell_flags['pylab'] = (
92 {'InteractiveShellApp' : {'pylab' : 'auto'}},
92 {'InteractiveShellApp' : {'pylab' : 'auto'}},
93 """Pre-load matplotlib and numpy for interactive use with
93 """Pre-load matplotlib and numpy for interactive use with
94 the default matplotlib backend."""
94 the default matplotlib backend."""
95 )
95 )
96 shell_flags['matplotlib'] = (
96 shell_flags['matplotlib'] = (
97 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
97 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
98 """Configure matplotlib for interactive use with
98 """Configure matplotlib for interactive use with
99 the default matplotlib backend."""
99 the default matplotlib backend."""
100 )
100 )
101
101
102 # it's possible we don't want short aliases for *all* of these:
102 # it's possible we don't want short aliases for *all* of these:
103 shell_aliases = dict(
103 shell_aliases = dict(
104 autocall='InteractiveShell.autocall',
104 autocall='InteractiveShell.autocall',
105 colors='InteractiveShell.colors',
105 colors='InteractiveShell.colors',
106 logfile='InteractiveShell.logfile',
106 logfile='InteractiveShell.logfile',
107 logappend='InteractiveShell.logappend',
107 logappend='InteractiveShell.logappend',
108 c='InteractiveShellApp.code_to_run',
108 c='InteractiveShellApp.code_to_run',
109 m='InteractiveShellApp.module_to_run',
109 m='InteractiveShellApp.module_to_run',
110 ext='InteractiveShellApp.extra_extension',
110 ext='InteractiveShellApp.extra_extension',
111 gui='InteractiveShellApp.gui',
111 gui='InteractiveShellApp.gui',
112 pylab='InteractiveShellApp.pylab',
112 pylab='InteractiveShellApp.pylab',
113 matplotlib='InteractiveShellApp.matplotlib',
113 matplotlib='InteractiveShellApp.matplotlib',
114 )
114 )
115 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
115 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
116
116
117 #-----------------------------------------------------------------------------
117 #-----------------------------------------------------------------------------
118 # Main classes and functions
118 # Main classes and functions
119 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
120
120
121 class InteractiveShellApp(Configurable):
121 class InteractiveShellApp(Configurable):
122 """A Mixin for applications that start InteractiveShell instances.
122 """A Mixin for applications that start InteractiveShell instances.
123
123
124 Provides configurables for loading extensions and executing files
124 Provides configurables for loading extensions and executing files
125 as part of configuring a Shell environment.
125 as part of configuring a Shell environment.
126
126
127 The following methods should be called by the :meth:`initialize` method
127 The following methods should be called by the :meth:`initialize` method
128 of the subclass:
128 of the subclass:
129
129
130 - :meth:`init_path`
130 - :meth:`init_path`
131 - :meth:`init_shell` (to be implemented by the subclass)
131 - :meth:`init_shell` (to be implemented by the subclass)
132 - :meth:`init_gui_pylab`
132 - :meth:`init_gui_pylab`
133 - :meth:`init_extensions`
133 - :meth:`init_extensions`
134 - :meth:`init_code`
134 - :meth:`init_code`
135 """
135 """
136 extensions = List(Unicode, config=True,
136 extensions = List(Unicode, config=True,
137 help="A list of dotted module names of IPython extensions to load."
137 help="A list of dotted module names of IPython extensions to load."
138 )
138 )
139 extra_extension = Unicode('', config=True,
139 extra_extension = Unicode('', config=True,
140 help="dotted module name of an IPython extension to load."
140 help="dotted module name of an IPython extension to load."
141 )
141 )
142
142
143 reraise_ipython_extension_failures = Bool(
143 reraise_ipython_extension_failures = Bool(
144 False,
144 False,
145 config=True,
145 config=True,
146 help="Reraise exceptions encountered loading IPython extensions?",
146 help="Reraise exceptions encountered loading IPython extensions?",
147 )
147 )
148
148
149 # Extensions that are always loaded (not configurable)
149 # Extensions that are always loaded (not configurable)
150 default_extensions = List(Unicode, [u'storemagic'], config=False)
150 default_extensions = List(Unicode, [u'storemagic'], config=False)
151
151
152 hide_initial_ns = Bool(True, config=True,
152 hide_initial_ns = Bool(True, config=True,
153 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
153 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
154 be hidden from tools like %who?"""
154 be hidden from tools like %who?"""
155 )
155 )
156
156
157 exec_files = List(Unicode, config=True,
157 exec_files = List(Unicode, config=True,
158 help="""List of files to run at IPython startup."""
158 help="""List of files to run at IPython startup."""
159 )
159 )
160 exec_PYTHONSTARTUP = Bool(True, config=True,
160 exec_PYTHONSTARTUP = Bool(True, config=True,
161 help="""Run the file referenced by the PYTHONSTARTUP environment
161 help="""Run the file referenced by the PYTHONSTARTUP environment
162 variable at IPython startup."""
162 variable at IPython startup."""
163 )
163 )
164 file_to_run = Unicode('', config=True,
164 file_to_run = Unicode('', config=True,
165 help="""A file to be run""")
165 help="""A file to be run""")
166
166
167 exec_lines = List(Unicode, config=True,
167 exec_lines = List(Unicode, config=True,
168 help="""lines of code to run at IPython startup."""
168 help="""lines of code to run at IPython startup."""
169 )
169 )
170 code_to_run = Unicode('', config=True,
170 code_to_run = Unicode('', config=True,
171 help="Execute the given command string."
171 help="Execute the given command string."
172 )
172 )
173 module_to_run = Unicode('', config=True,
173 module_to_run = Unicode('', config=True,
174 help="Run the module as a script."
174 help="Run the module as a script."
175 )
175 )
176 gui = CaselessStrEnum(gui_keys, config=True, allow_none=True,
176 gui = CaselessStrEnum(gui_keys, config=True, allow_none=True,
177 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
177 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
178 )
178 )
179 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
179 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
180 config=True,
180 config=True,
181 help="""Configure matplotlib for interactive use with
181 help="""Configure matplotlib for interactive use with
182 the default matplotlib backend."""
182 the default matplotlib backend."""
183 )
183 )
184 pylab = CaselessStrEnum(backend_keys, allow_none=True,
184 pylab = CaselessStrEnum(backend_keys, allow_none=True,
185 config=True,
185 config=True,
186 help="""Pre-load matplotlib and numpy for interactive use,
186 help="""Pre-load matplotlib and numpy for interactive use,
187 selecting a particular matplotlib backend and loop integration.
187 selecting a particular matplotlib backend and loop integration.
188 """
188 """
189 )
189 )
190 pylab_import_all = Bool(True, config=True,
190 pylab_import_all = Bool(True, config=True,
191 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
191 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
192 and an ``import *`` is done from numpy and pylab, when using pylab mode.
192 and an ``import *`` is done from numpy and pylab, when using pylab mode.
193
193
194 When False, pylab mode should not import any names into the user namespace.
194 When False, pylab mode should not import any names into the user namespace.
195 """
195 """
196 )
196 )
197 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
197 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
198 allow_none=True)
198
199
199 user_ns = Instance(dict, args=None, allow_none=True)
200 user_ns = Instance(dict, args=None, allow_none=True)
200 def _user_ns_changed(self, name, old, new):
201 def _user_ns_changed(self, name, old, new):
201 if self.shell is not None:
202 if self.shell is not None:
202 self.shell.user_ns = new
203 self.shell.user_ns = new
203 self.shell.init_user_ns()
204 self.shell.init_user_ns()
204
205
205 def init_path(self):
206 def init_path(self):
206 """Add current working directory, '', to sys.path"""
207 """Add current working directory, '', to sys.path"""
207 if sys.path[0] != '':
208 if sys.path[0] != '':
208 sys.path.insert(0, '')
209 sys.path.insert(0, '')
209
210
210 def init_shell(self):
211 def init_shell(self):
211 raise NotImplementedError("Override in subclasses")
212 raise NotImplementedError("Override in subclasses")
212
213
213 def init_gui_pylab(self):
214 def init_gui_pylab(self):
214 """Enable GUI event loop integration, taking pylab into account."""
215 """Enable GUI event loop integration, taking pylab into account."""
215 enable = False
216 enable = False
216 shell = self.shell
217 shell = self.shell
217 if self.pylab:
218 if self.pylab:
218 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
219 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
219 key = self.pylab
220 key = self.pylab
220 elif self.matplotlib:
221 elif self.matplotlib:
221 enable = shell.enable_matplotlib
222 enable = shell.enable_matplotlib
222 key = self.matplotlib
223 key = self.matplotlib
223 elif self.gui:
224 elif self.gui:
224 enable = shell.enable_gui
225 enable = shell.enable_gui
225 key = self.gui
226 key = self.gui
226
227
227 if not enable:
228 if not enable:
228 return
229 return
229
230
230 try:
231 try:
231 r = enable(key)
232 r = enable(key)
232 except ImportError:
233 except ImportError:
233 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
234 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
234 self.shell.showtraceback()
235 self.shell.showtraceback()
235 return
236 return
236 except Exception:
237 except Exception:
237 self.log.warn("GUI event loop or pylab initialization failed")
238 self.log.warn("GUI event loop or pylab initialization failed")
238 self.shell.showtraceback()
239 self.shell.showtraceback()
239 return
240 return
240
241
241 if isinstance(r, tuple):
242 if isinstance(r, tuple):
242 gui, backend = r[:2]
243 gui, backend = r[:2]
243 self.log.info("Enabling GUI event loop integration, "
244 self.log.info("Enabling GUI event loop integration, "
244 "eventloop=%s, matplotlib=%s", gui, backend)
245 "eventloop=%s, matplotlib=%s", gui, backend)
245 if key == "auto":
246 if key == "auto":
246 print("Using matplotlib backend: %s" % backend)
247 print("Using matplotlib backend: %s" % backend)
247 else:
248 else:
248 gui = r
249 gui = r
249 self.log.info("Enabling GUI event loop integration, "
250 self.log.info("Enabling GUI event loop integration, "
250 "eventloop=%s", gui)
251 "eventloop=%s", gui)
251
252
252 def init_extensions(self):
253 def init_extensions(self):
253 """Load all IPython extensions in IPythonApp.extensions.
254 """Load all IPython extensions in IPythonApp.extensions.
254
255
255 This uses the :meth:`ExtensionManager.load_extensions` to load all
256 This uses the :meth:`ExtensionManager.load_extensions` to load all
256 the extensions listed in ``self.extensions``.
257 the extensions listed in ``self.extensions``.
257 """
258 """
258 try:
259 try:
259 self.log.debug("Loading IPython extensions...")
260 self.log.debug("Loading IPython extensions...")
260 extensions = self.default_extensions + self.extensions
261 extensions = self.default_extensions + self.extensions
261 if self.extra_extension:
262 if self.extra_extension:
262 extensions.append(self.extra_extension)
263 extensions.append(self.extra_extension)
263 for ext in extensions:
264 for ext in extensions:
264 try:
265 try:
265 self.log.info("Loading IPython extension: %s" % ext)
266 self.log.info("Loading IPython extension: %s" % ext)
266 self.shell.extension_manager.load_extension(ext)
267 self.shell.extension_manager.load_extension(ext)
267 except:
268 except:
268 if self.reraise_ipython_extension_failures:
269 if self.reraise_ipython_extension_failures:
269 raise
270 raise
270 msg = ("Error in loading extension: {ext}\n"
271 msg = ("Error in loading extension: {ext}\n"
271 "Check your config files in {location}".format(
272 "Check your config files in {location}".format(
272 ext=ext,
273 ext=ext,
273 location=self.profile_dir.location
274 location=self.profile_dir.location
274 ))
275 ))
275 self.log.warn(msg, exc_info=True)
276 self.log.warn(msg, exc_info=True)
276 except:
277 except:
277 if self.reraise_ipython_extension_failures:
278 if self.reraise_ipython_extension_failures:
278 raise
279 raise
279 self.log.warn("Unknown error in loading extensions:", exc_info=True)
280 self.log.warn("Unknown error in loading extensions:", exc_info=True)
280
281
281 def init_code(self):
282 def init_code(self):
282 """run the pre-flight code, specified via exec_lines"""
283 """run the pre-flight code, specified via exec_lines"""
283 self._run_startup_files()
284 self._run_startup_files()
284 self._run_exec_lines()
285 self._run_exec_lines()
285 self._run_exec_files()
286 self._run_exec_files()
286
287
287 # Hide variables defined here from %who etc.
288 # Hide variables defined here from %who etc.
288 if self.hide_initial_ns:
289 if self.hide_initial_ns:
289 self.shell.user_ns_hidden.update(self.shell.user_ns)
290 self.shell.user_ns_hidden.update(self.shell.user_ns)
290
291
291 # command-line execution (ipython -i script.py, ipython -m module)
292 # command-line execution (ipython -i script.py, ipython -m module)
292 # should *not* be excluded from %whos
293 # should *not* be excluded from %whos
293 self._run_cmd_line_code()
294 self._run_cmd_line_code()
294 self._run_module()
295 self._run_module()
295
296
296 # flush output, so itwon't be attached to the first cell
297 # flush output, so itwon't be attached to the first cell
297 sys.stdout.flush()
298 sys.stdout.flush()
298 sys.stderr.flush()
299 sys.stderr.flush()
299
300
300 def _run_exec_lines(self):
301 def _run_exec_lines(self):
301 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
302 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
302 if not self.exec_lines:
303 if not self.exec_lines:
303 return
304 return
304 try:
305 try:
305 self.log.debug("Running code from IPythonApp.exec_lines...")
306 self.log.debug("Running code from IPythonApp.exec_lines...")
306 for line in self.exec_lines:
307 for line in self.exec_lines:
307 try:
308 try:
308 self.log.info("Running code in user namespace: %s" %
309 self.log.info("Running code in user namespace: %s" %
309 line)
310 line)
310 self.shell.run_cell(line, store_history=False)
311 self.shell.run_cell(line, store_history=False)
311 except:
312 except:
312 self.log.warn("Error in executing line in user "
313 self.log.warn("Error in executing line in user "
313 "namespace: %s" % line)
314 "namespace: %s" % line)
314 self.shell.showtraceback()
315 self.shell.showtraceback()
315 except:
316 except:
316 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
317 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
317 self.shell.showtraceback()
318 self.shell.showtraceback()
318
319
319 def _exec_file(self, fname, shell_futures=False):
320 def _exec_file(self, fname, shell_futures=False):
320 try:
321 try:
321 full_filename = filefind(fname, [u'.', self.ipython_dir])
322 full_filename = filefind(fname, [u'.', self.ipython_dir])
322 except IOError as e:
323 except IOError as e:
323 self.log.warn("File not found: %r"%fname)
324 self.log.warn("File not found: %r"%fname)
324 return
325 return
325 # Make sure that the running script gets a proper sys.argv as if it
326 # Make sure that the running script gets a proper sys.argv as if it
326 # were run from a system shell.
327 # were run from a system shell.
327 save_argv = sys.argv
328 save_argv = sys.argv
328 sys.argv = [full_filename] + self.extra_args[1:]
329 sys.argv = [full_filename] + self.extra_args[1:]
329 # protect sys.argv from potential unicode strings on Python 2:
330 # protect sys.argv from potential unicode strings on Python 2:
330 if not py3compat.PY3:
331 if not py3compat.PY3:
331 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
332 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
332 try:
333 try:
333 if os.path.isfile(full_filename):
334 if os.path.isfile(full_filename):
334 self.log.info("Running file in user namespace: %s" %
335 self.log.info("Running file in user namespace: %s" %
335 full_filename)
336 full_filename)
336 # Ensure that __file__ is always defined to match Python
337 # Ensure that __file__ is always defined to match Python
337 # behavior.
338 # behavior.
338 with preserve_keys(self.shell.user_ns, '__file__'):
339 with preserve_keys(self.shell.user_ns, '__file__'):
339 self.shell.user_ns['__file__'] = fname
340 self.shell.user_ns['__file__'] = fname
340 if full_filename.endswith('.ipy'):
341 if full_filename.endswith('.ipy'):
341 self.shell.safe_execfile_ipy(full_filename,
342 self.shell.safe_execfile_ipy(full_filename,
342 shell_futures=shell_futures)
343 shell_futures=shell_futures)
343 else:
344 else:
344 # default to python, even without extension
345 # default to python, even without extension
345 self.shell.safe_execfile(full_filename,
346 self.shell.safe_execfile(full_filename,
346 self.shell.user_ns,
347 self.shell.user_ns,
347 shell_futures=shell_futures)
348 shell_futures=shell_futures)
348 finally:
349 finally:
349 sys.argv = save_argv
350 sys.argv = save_argv
350
351
351 def _run_startup_files(self):
352 def _run_startup_files(self):
352 """Run files from profile startup directory"""
353 """Run files from profile startup directory"""
353 startup_dir = self.profile_dir.startup_dir
354 startup_dir = self.profile_dir.startup_dir
354 startup_files = []
355 startup_files = []
355
356
356 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
357 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
357 not (self.file_to_run or self.code_to_run or self.module_to_run):
358 not (self.file_to_run or self.code_to_run or self.module_to_run):
358 python_startup = os.environ['PYTHONSTARTUP']
359 python_startup = os.environ['PYTHONSTARTUP']
359 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
360 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
360 try:
361 try:
361 self._exec_file(python_startup)
362 self._exec_file(python_startup)
362 except:
363 except:
363 self.log.warn("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
364 self.log.warn("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
364 self.shell.showtraceback()
365 self.shell.showtraceback()
365 finally:
366 finally:
366 # Many PYTHONSTARTUP files set up the readline completions,
367 # Many PYTHONSTARTUP files set up the readline completions,
367 # but this is often at odds with IPython's own completions.
368 # but this is often at odds with IPython's own completions.
368 # Do not allow PYTHONSTARTUP to set up readline.
369 # Do not allow PYTHONSTARTUP to set up readline.
369 if self.shell.has_readline:
370 if self.shell.has_readline:
370 self.shell.set_readline_completer()
371 self.shell.set_readline_completer()
371
372
372 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
373 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
373 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
374 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
374 if not startup_files:
375 if not startup_files:
375 return
376 return
376
377
377 self.log.debug("Running startup files from %s...", startup_dir)
378 self.log.debug("Running startup files from %s...", startup_dir)
378 try:
379 try:
379 for fname in sorted(startup_files):
380 for fname in sorted(startup_files):
380 self._exec_file(fname)
381 self._exec_file(fname)
381 except:
382 except:
382 self.log.warn("Unknown error in handling startup files:")
383 self.log.warn("Unknown error in handling startup files:")
383 self.shell.showtraceback()
384 self.shell.showtraceback()
384
385
385 def _run_exec_files(self):
386 def _run_exec_files(self):
386 """Run files from IPythonApp.exec_files"""
387 """Run files from IPythonApp.exec_files"""
387 if not self.exec_files:
388 if not self.exec_files:
388 return
389 return
389
390
390 self.log.debug("Running files in IPythonApp.exec_files...")
391 self.log.debug("Running files in IPythonApp.exec_files...")
391 try:
392 try:
392 for fname in self.exec_files:
393 for fname in self.exec_files:
393 self._exec_file(fname)
394 self._exec_file(fname)
394 except:
395 except:
395 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
396 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
396 self.shell.showtraceback()
397 self.shell.showtraceback()
397
398
398 def _run_cmd_line_code(self):
399 def _run_cmd_line_code(self):
399 """Run code or file specified at the command-line"""
400 """Run code or file specified at the command-line"""
400 if self.code_to_run:
401 if self.code_to_run:
401 line = self.code_to_run
402 line = self.code_to_run
402 try:
403 try:
403 self.log.info("Running code given at command line (c=): %s" %
404 self.log.info("Running code given at command line (c=): %s" %
404 line)
405 line)
405 self.shell.run_cell(line, store_history=False)
406 self.shell.run_cell(line, store_history=False)
406 except:
407 except:
407 self.log.warn("Error in executing line in user namespace: %s" %
408 self.log.warn("Error in executing line in user namespace: %s" %
408 line)
409 line)
409 self.shell.showtraceback()
410 self.shell.showtraceback()
410
411
411 # Like Python itself, ignore the second if the first of these is present
412 # Like Python itself, ignore the second if the first of these is present
412 elif self.file_to_run:
413 elif self.file_to_run:
413 fname = self.file_to_run
414 fname = self.file_to_run
414 try:
415 try:
415 self._exec_file(fname, shell_futures=True)
416 self._exec_file(fname, shell_futures=True)
416 except:
417 except:
417 self.log.warn("Error in executing file in user namespace: %s" %
418 self.log.warn("Error in executing file in user namespace: %s" %
418 fname)
419 fname)
419 self.shell.showtraceback()
420 self.shell.showtraceback()
420
421
421 def _run_module(self):
422 def _run_module(self):
422 """Run module specified at the command-line."""
423 """Run module specified at the command-line."""
423 if self.module_to_run:
424 if self.module_to_run:
424 # Make sure that the module gets a proper sys.argv as if it were
425 # Make sure that the module gets a proper sys.argv as if it were
425 # run using `python -m`.
426 # run using `python -m`.
426 save_argv = sys.argv
427 save_argv = sys.argv
427 sys.argv = [sys.executable] + self.extra_args
428 sys.argv = [sys.executable] + self.extra_args
428 try:
429 try:
429 self.shell.safe_run_module(self.module_to_run,
430 self.shell.safe_run_module(self.module_to_run,
430 self.shell.user_ns)
431 self.shell.user_ns)
431 finally:
432 finally:
432 sys.argv = save_argv
433 sys.argv = save_argv
@@ -1,1127 +1,1127 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 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import base64
9 import base64
10 import datetime
10 import datetime
11 import errno
11 import errno
12 import importlib
12 import importlib
13 import io
13 import io
14 import json
14 import json
15 import logging
15 import logging
16 import os
16 import os
17 import random
17 import random
18 import re
18 import re
19 import select
19 import select
20 import signal
20 import signal
21 import socket
21 import socket
22 import sys
22 import sys
23 import threading
23 import threading
24 import webbrowser
24 import webbrowser
25
25
26
26
27 # check for pyzmq
27 # check for pyzmq
28 from IPython.utils.zmqrelated import check_for_zmq
28 from IPython.utils.zmqrelated import check_for_zmq
29 check_for_zmq('13', 'IPython.html')
29 check_for_zmq('13', 'IPython.html')
30
30
31 from jinja2 import Environment, FileSystemLoader
31 from jinja2 import Environment, FileSystemLoader
32
32
33 # Install the pyzmq ioloop. This has to be done before anything else from
33 # Install the pyzmq ioloop. This has to be done before anything else from
34 # tornado is imported.
34 # tornado is imported.
35 from zmq.eventloop import ioloop
35 from zmq.eventloop import ioloop
36 ioloop.install()
36 ioloop.install()
37
37
38 # check for tornado 3.1.0
38 # check for tornado 3.1.0
39 msg = "The IPython Notebook requires tornado >= 4.0"
39 msg = "The IPython Notebook requires tornado >= 4.0"
40 try:
40 try:
41 import tornado
41 import tornado
42 except ImportError:
42 except ImportError:
43 raise ImportError(msg)
43 raise ImportError(msg)
44 try:
44 try:
45 version_info = tornado.version_info
45 version_info = tornado.version_info
46 except AttributeError:
46 except AttributeError:
47 raise ImportError(msg + ", but you have < 1.1.0")
47 raise ImportError(msg + ", but you have < 1.1.0")
48 if version_info < (4,0):
48 if version_info < (4,0):
49 raise ImportError(msg + ", but you have %s" % tornado.version)
49 raise ImportError(msg + ", but you have %s" % tornado.version)
50
50
51 from tornado import httpserver
51 from tornado import httpserver
52 from tornado import web
52 from tornado import web
53 from tornado.log import LogFormatter, app_log, access_log, gen_log
53 from tornado.log import LogFormatter, app_log, access_log, gen_log
54
54
55 from IPython.html import (
55 from IPython.html import (
56 DEFAULT_STATIC_FILES_PATH,
56 DEFAULT_STATIC_FILES_PATH,
57 DEFAULT_TEMPLATE_PATH_LIST,
57 DEFAULT_TEMPLATE_PATH_LIST,
58 )
58 )
59 from .base.handlers import Template404
59 from .base.handlers import Template404
60 from .log import log_request
60 from .log import log_request
61 from .services.kernels.kernelmanager import MappingKernelManager
61 from .services.kernels.kernelmanager import MappingKernelManager
62 from .services.config import ConfigManager
62 from .services.config import ConfigManager
63 from .services.contents.manager import ContentsManager
63 from .services.contents.manager import ContentsManager
64 from .services.contents.filemanager import FileContentsManager
64 from .services.contents.filemanager import FileContentsManager
65 from .services.clusters.clustermanager import ClusterManager
65 from .services.clusters.clustermanager import ClusterManager
66 from .services.sessions.sessionmanager import SessionManager
66 from .services.sessions.sessionmanager import SessionManager
67
67
68 from .auth.login import LoginHandler
68 from .auth.login import LoginHandler
69 from .auth.logout import LogoutHandler
69 from .auth.logout import LogoutHandler
70 from .base.handlers import IPythonHandler, FileFindHandler
70 from .base.handlers import IPythonHandler, FileFindHandler
71
71
72 from IPython.config import Config
72 from IPython.config import Config
73 from IPython.config.application import catch_config_error, boolean_flag
73 from IPython.config.application import catch_config_error, boolean_flag
74 from IPython.core.application import (
74 from IPython.core.application import (
75 BaseIPythonApplication, base_flags, base_aliases,
75 BaseIPythonApplication, base_flags, base_aliases,
76 )
76 )
77 from IPython.core.profiledir import ProfileDir
77 from IPython.core.profiledir import ProfileDir
78 from IPython.kernel import KernelManager
78 from IPython.kernel import KernelManager
79 from IPython.kernel.kernelspec import KernelSpecManager
79 from IPython.kernel.kernelspec import KernelSpecManager
80 from IPython.kernel.zmq.session import Session
80 from IPython.kernel.zmq.session import Session
81 from IPython.nbformat.sign import NotebookNotary
81 from IPython.nbformat.sign import NotebookNotary
82 from IPython.utils.importstring import import_item
82 from IPython.utils.importstring import import_item
83 from IPython.utils import submodule
83 from IPython.utils import submodule
84 from IPython.utils.process import check_pid
84 from IPython.utils.process import check_pid
85 from IPython.utils.traitlets import (
85 from IPython.utils.traitlets import (
86 Dict, Unicode, Integer, List, Bool, Bytes, Instance,
86 Dict, Unicode, Integer, List, Bool, Bytes, Instance,
87 TraitError, Type,
87 TraitError, Type,
88 )
88 )
89 from IPython.utils import py3compat
89 from IPython.utils import py3compat
90 from IPython.utils.path import filefind, get_ipython_dir
90 from IPython.utils.path import filefind, get_ipython_dir
91 from IPython.utils.sysinfo import get_sys_info
91 from IPython.utils.sysinfo import get_sys_info
92
92
93 from .nbextensions import SYSTEM_NBEXTENSIONS_DIRS
93 from .nbextensions import SYSTEM_NBEXTENSIONS_DIRS
94 from .utils import url_path_join
94 from .utils import url_path_join
95
95
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 # Module globals
97 # Module globals
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99
99
100 _examples = """
100 _examples = """
101 ipython notebook # start the notebook
101 ipython notebook # start the notebook
102 ipython notebook --profile=sympy # use the sympy profile
102 ipython notebook --profile=sympy # use the sympy profile
103 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
103 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
104 """
104 """
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Helper functions
107 # Helper functions
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 def random_ports(port, n):
110 def random_ports(port, n):
111 """Generate a list of n random ports near the given port.
111 """Generate a list of n random ports near the given port.
112
112
113 The first 5 ports will be sequential, and the remaining n-5 will be
113 The first 5 ports will be sequential, and the remaining n-5 will be
114 randomly selected in the range [port-2*n, port+2*n].
114 randomly selected in the range [port-2*n, port+2*n].
115 """
115 """
116 for i in range(min(5, n)):
116 for i in range(min(5, n)):
117 yield port + i
117 yield port + i
118 for i in range(n-5):
118 for i in range(n-5):
119 yield max(1, port + random.randint(-2*n, 2*n))
119 yield max(1, port + random.randint(-2*n, 2*n))
120
120
121 def load_handlers(name):
121 def load_handlers(name):
122 """Load the (URL pattern, handler) tuples for each component."""
122 """Load the (URL pattern, handler) tuples for each component."""
123 name = 'IPython.html.' + name
123 name = 'IPython.html.' + name
124 mod = __import__(name, fromlist=['default_handlers'])
124 mod = __import__(name, fromlist=['default_handlers'])
125 return mod.default_handlers
125 return mod.default_handlers
126
126
127 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
128 # The Tornado web application
128 # The Tornado web application
129 #-----------------------------------------------------------------------------
129 #-----------------------------------------------------------------------------
130
130
131 class NotebookWebApplication(web.Application):
131 class NotebookWebApplication(web.Application):
132
132
133 def __init__(self, ipython_app, kernel_manager, contents_manager,
133 def __init__(self, ipython_app, kernel_manager, contents_manager,
134 cluster_manager, session_manager, kernel_spec_manager,
134 cluster_manager, session_manager, kernel_spec_manager,
135 config_manager, log,
135 config_manager, log,
136 base_url, default_url, settings_overrides, jinja_env_options):
136 base_url, default_url, settings_overrides, jinja_env_options):
137
137
138 settings = self.init_settings(
138 settings = self.init_settings(
139 ipython_app, kernel_manager, contents_manager, cluster_manager,
139 ipython_app, kernel_manager, contents_manager, cluster_manager,
140 session_manager, kernel_spec_manager, config_manager, log, base_url,
140 session_manager, kernel_spec_manager, config_manager, log, base_url,
141 default_url, settings_overrides, jinja_env_options)
141 default_url, settings_overrides, jinja_env_options)
142 handlers = self.init_handlers(settings)
142 handlers = self.init_handlers(settings)
143
143
144 super(NotebookWebApplication, self).__init__(handlers, **settings)
144 super(NotebookWebApplication, self).__init__(handlers, **settings)
145
145
146 def init_settings(self, ipython_app, kernel_manager, contents_manager,
146 def init_settings(self, ipython_app, kernel_manager, contents_manager,
147 cluster_manager, session_manager, kernel_spec_manager,
147 cluster_manager, session_manager, kernel_spec_manager,
148 config_manager,
148 config_manager,
149 log, base_url, default_url, settings_overrides,
149 log, base_url, default_url, settings_overrides,
150 jinja_env_options=None):
150 jinja_env_options=None):
151
151
152 _template_path = settings_overrides.get(
152 _template_path = settings_overrides.get(
153 "template_path",
153 "template_path",
154 ipython_app.template_file_path,
154 ipython_app.template_file_path,
155 )
155 )
156 if isinstance(_template_path, str):
156 if isinstance(_template_path, str):
157 _template_path = (_template_path,)
157 _template_path = (_template_path,)
158 template_path = [os.path.expanduser(path) for path in _template_path]
158 template_path = [os.path.expanduser(path) for path in _template_path]
159
159
160 jenv_opt = jinja_env_options if jinja_env_options else {}
160 jenv_opt = jinja_env_options if jinja_env_options else {}
161 env = Environment(loader=FileSystemLoader(template_path), **jenv_opt)
161 env = Environment(loader=FileSystemLoader(template_path), **jenv_opt)
162
162
163 sys_info = get_sys_info()
163 sys_info = get_sys_info()
164 if sys_info['commit_source'] == 'repository':
164 if sys_info['commit_source'] == 'repository':
165 # don't cache (rely on 304) when working from master
165 # don't cache (rely on 304) when working from master
166 version_hash = ''
166 version_hash = ''
167 else:
167 else:
168 # reset the cache on server restart
168 # reset the cache on server restart
169 version_hash = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
169 version_hash = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
170
170
171 settings = dict(
171 settings = dict(
172 # basics
172 # basics
173 log_function=log_request,
173 log_function=log_request,
174 base_url=base_url,
174 base_url=base_url,
175 default_url=default_url,
175 default_url=default_url,
176 template_path=template_path,
176 template_path=template_path,
177 static_path=ipython_app.static_file_path,
177 static_path=ipython_app.static_file_path,
178 static_handler_class = FileFindHandler,
178 static_handler_class = FileFindHandler,
179 static_url_prefix = url_path_join(base_url,'/static/'),
179 static_url_prefix = url_path_join(base_url,'/static/'),
180 static_handler_args = {
180 static_handler_args = {
181 # don't cache custom.js
181 # don't cache custom.js
182 'no_cache_paths': [url_path_join(base_url, 'static', 'custom')],
182 'no_cache_paths': [url_path_join(base_url, 'static', 'custom')],
183 },
183 },
184 version_hash=version_hash,
184 version_hash=version_hash,
185
185
186 # authentication
186 # authentication
187 cookie_secret=ipython_app.cookie_secret,
187 cookie_secret=ipython_app.cookie_secret,
188 login_url=url_path_join(base_url,'/login'),
188 login_url=url_path_join(base_url,'/login'),
189 login_handler_class=ipython_app.login_handler_class,
189 login_handler_class=ipython_app.login_handler_class,
190 logout_handler_class=ipython_app.logout_handler_class,
190 logout_handler_class=ipython_app.logout_handler_class,
191 password=ipython_app.password,
191 password=ipython_app.password,
192
192
193 # managers
193 # managers
194 kernel_manager=kernel_manager,
194 kernel_manager=kernel_manager,
195 contents_manager=contents_manager,
195 contents_manager=contents_manager,
196 cluster_manager=cluster_manager,
196 cluster_manager=cluster_manager,
197 session_manager=session_manager,
197 session_manager=session_manager,
198 kernel_spec_manager=kernel_spec_manager,
198 kernel_spec_manager=kernel_spec_manager,
199 config_manager=config_manager,
199 config_manager=config_manager,
200
200
201 # IPython stuff
201 # IPython stuff
202 nbextensions_path=ipython_app.nbextensions_path,
202 nbextensions_path=ipython_app.nbextensions_path,
203 websocket_url=ipython_app.websocket_url,
203 websocket_url=ipython_app.websocket_url,
204 mathjax_url=ipython_app.mathjax_url,
204 mathjax_url=ipython_app.mathjax_url,
205 config=ipython_app.config,
205 config=ipython_app.config,
206 jinja2_env=env,
206 jinja2_env=env,
207 terminals_available=False, # Set later if terminals are available
207 terminals_available=False, # Set later if terminals are available
208 )
208 )
209
209
210 # allow custom overrides for the tornado web app.
210 # allow custom overrides for the tornado web app.
211 settings.update(settings_overrides)
211 settings.update(settings_overrides)
212 return settings
212 return settings
213
213
214 def init_handlers(self, settings):
214 def init_handlers(self, settings):
215 """Load the (URL pattern, handler) tuples for each component."""
215 """Load the (URL pattern, handler) tuples for each component."""
216
216
217 # Order matters. The first handler to match the URL will handle the request.
217 # Order matters. The first handler to match the URL will handle the request.
218 handlers = []
218 handlers = []
219 handlers.extend(load_handlers('tree.handlers'))
219 handlers.extend(load_handlers('tree.handlers'))
220 handlers.extend([(r"/login", settings['login_handler_class'])])
220 handlers.extend([(r"/login", settings['login_handler_class'])])
221 handlers.extend([(r"/logout", settings['logout_handler_class'])])
221 handlers.extend([(r"/logout", settings['logout_handler_class'])])
222 handlers.extend(load_handlers('files.handlers'))
222 handlers.extend(load_handlers('files.handlers'))
223 handlers.extend(load_handlers('notebook.handlers'))
223 handlers.extend(load_handlers('notebook.handlers'))
224 handlers.extend(load_handlers('nbconvert.handlers'))
224 handlers.extend(load_handlers('nbconvert.handlers'))
225 handlers.extend(load_handlers('kernelspecs.handlers'))
225 handlers.extend(load_handlers('kernelspecs.handlers'))
226 handlers.extend(load_handlers('edit.handlers'))
226 handlers.extend(load_handlers('edit.handlers'))
227 handlers.extend(load_handlers('services.config.handlers'))
227 handlers.extend(load_handlers('services.config.handlers'))
228 handlers.extend(load_handlers('services.kernels.handlers'))
228 handlers.extend(load_handlers('services.kernels.handlers'))
229 handlers.extend(load_handlers('services.contents.handlers'))
229 handlers.extend(load_handlers('services.contents.handlers'))
230 handlers.extend(load_handlers('services.clusters.handlers'))
230 handlers.extend(load_handlers('services.clusters.handlers'))
231 handlers.extend(load_handlers('services.sessions.handlers'))
231 handlers.extend(load_handlers('services.sessions.handlers'))
232 handlers.extend(load_handlers('services.nbconvert.handlers'))
232 handlers.extend(load_handlers('services.nbconvert.handlers'))
233 handlers.extend(load_handlers('services.kernelspecs.handlers'))
233 handlers.extend(load_handlers('services.kernelspecs.handlers'))
234 handlers.extend(load_handlers('services.security.handlers'))
234 handlers.extend(load_handlers('services.security.handlers'))
235 handlers.append(
235 handlers.append(
236 (r"/nbextensions/(.*)", FileFindHandler, {
236 (r"/nbextensions/(.*)", FileFindHandler, {
237 'path': settings['nbextensions_path'],
237 'path': settings['nbextensions_path'],
238 'no_cache_paths': ['/'], # don't cache anything in nbextensions
238 'no_cache_paths': ['/'], # don't cache anything in nbextensions
239 }),
239 }),
240 )
240 )
241 # register base handlers last
241 # register base handlers last
242 handlers.extend(load_handlers('base.handlers'))
242 handlers.extend(load_handlers('base.handlers'))
243 # set the URL that will be redirected from `/`
243 # set the URL that will be redirected from `/`
244 handlers.append(
244 handlers.append(
245 (r'/?', web.RedirectHandler, {
245 (r'/?', web.RedirectHandler, {
246 'url' : settings['default_url'],
246 'url' : settings['default_url'],
247 'permanent': False, # want 302, not 301
247 'permanent': False, # want 302, not 301
248 })
248 })
249 )
249 )
250 # prepend base_url onto the patterns that we match
250 # prepend base_url onto the patterns that we match
251 new_handlers = []
251 new_handlers = []
252 for handler in handlers:
252 for handler in handlers:
253 pattern = url_path_join(settings['base_url'], handler[0])
253 pattern = url_path_join(settings['base_url'], handler[0])
254 new_handler = tuple([pattern] + list(handler[1:]))
254 new_handler = tuple([pattern] + list(handler[1:]))
255 new_handlers.append(new_handler)
255 new_handlers.append(new_handler)
256 # add 404 on the end, which will catch everything that falls through
256 # add 404 on the end, which will catch everything that falls through
257 new_handlers.append((r'(.*)', Template404))
257 new_handlers.append((r'(.*)', Template404))
258 return new_handlers
258 return new_handlers
259
259
260
260
261 class NbserverListApp(BaseIPythonApplication):
261 class NbserverListApp(BaseIPythonApplication):
262
262
263 description="List currently running notebook servers in this profile."
263 description="List currently running notebook servers in this profile."
264
264
265 flags = dict(
265 flags = dict(
266 json=({'NbserverListApp': {'json': True}},
266 json=({'NbserverListApp': {'json': True}},
267 "Produce machine-readable JSON output."),
267 "Produce machine-readable JSON output."),
268 )
268 )
269
269
270 json = Bool(False, config=True,
270 json = Bool(False, config=True,
271 help="If True, each line of output will be a JSON object with the "
271 help="If True, each line of output will be a JSON object with the "
272 "details from the server info file.")
272 "details from the server info file.")
273
273
274 def start(self):
274 def start(self):
275 if not self.json:
275 if not self.json:
276 print("Currently running servers:")
276 print("Currently running servers:")
277 for serverinfo in list_running_servers(self.profile):
277 for serverinfo in list_running_servers(self.profile):
278 if self.json:
278 if self.json:
279 print(json.dumps(serverinfo))
279 print(json.dumps(serverinfo))
280 else:
280 else:
281 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
281 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
282
282
283 #-----------------------------------------------------------------------------
283 #-----------------------------------------------------------------------------
284 # Aliases and Flags
284 # Aliases and Flags
285 #-----------------------------------------------------------------------------
285 #-----------------------------------------------------------------------------
286
286
287 flags = dict(base_flags)
287 flags = dict(base_flags)
288 flags['no-browser']=(
288 flags['no-browser']=(
289 {'NotebookApp' : {'open_browser' : False}},
289 {'NotebookApp' : {'open_browser' : False}},
290 "Don't open the notebook in a browser after startup."
290 "Don't open the notebook in a browser after startup."
291 )
291 )
292 flags['pylab']=(
292 flags['pylab']=(
293 {'NotebookApp' : {'pylab' : 'warn'}},
293 {'NotebookApp' : {'pylab' : 'warn'}},
294 "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib."
294 "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib."
295 )
295 )
296 flags['no-mathjax']=(
296 flags['no-mathjax']=(
297 {'NotebookApp' : {'enable_mathjax' : False}},
297 {'NotebookApp' : {'enable_mathjax' : False}},
298 """Disable MathJax
298 """Disable MathJax
299
299
300 MathJax is the javascript library IPython uses to render math/LaTeX. It is
300 MathJax is the javascript library IPython uses to render math/LaTeX. It is
301 very large, so you may want to disable it if you have a slow internet
301 very large, so you may want to disable it if you have a slow internet
302 connection, or for offline use of the notebook.
302 connection, or for offline use of the notebook.
303
303
304 When disabled, equations etc. will appear as their untransformed TeX source.
304 When disabled, equations etc. will appear as their untransformed TeX source.
305 """
305 """
306 )
306 )
307
307
308 # Add notebook manager flags
308 # Add notebook manager flags
309 flags.update(boolean_flag('script', 'FileContentsManager.save_script',
309 flags.update(boolean_flag('script', 'FileContentsManager.save_script',
310 'DEPRECATED, IGNORED',
310 'DEPRECATED, IGNORED',
311 'DEPRECATED, IGNORED'))
311 'DEPRECATED, IGNORED'))
312
312
313 aliases = dict(base_aliases)
313 aliases = dict(base_aliases)
314
314
315 aliases.update({
315 aliases.update({
316 'ip': 'NotebookApp.ip',
316 'ip': 'NotebookApp.ip',
317 'port': 'NotebookApp.port',
317 'port': 'NotebookApp.port',
318 'port-retries': 'NotebookApp.port_retries',
318 'port-retries': 'NotebookApp.port_retries',
319 'transport': 'KernelManager.transport',
319 'transport': 'KernelManager.transport',
320 'keyfile': 'NotebookApp.keyfile',
320 'keyfile': 'NotebookApp.keyfile',
321 'certfile': 'NotebookApp.certfile',
321 'certfile': 'NotebookApp.certfile',
322 'notebook-dir': 'NotebookApp.notebook_dir',
322 'notebook-dir': 'NotebookApp.notebook_dir',
323 'browser': 'NotebookApp.browser',
323 'browser': 'NotebookApp.browser',
324 'pylab': 'NotebookApp.pylab',
324 'pylab': 'NotebookApp.pylab',
325 })
325 })
326
326
327 #-----------------------------------------------------------------------------
327 #-----------------------------------------------------------------------------
328 # NotebookApp
328 # NotebookApp
329 #-----------------------------------------------------------------------------
329 #-----------------------------------------------------------------------------
330
330
331 class NotebookApp(BaseIPythonApplication):
331 class NotebookApp(BaseIPythonApplication):
332
332
333 name = 'ipython-notebook'
333 name = 'ipython-notebook'
334
334
335 description = """
335 description = """
336 The IPython HTML Notebook.
336 The IPython HTML Notebook.
337
337
338 This launches a Tornado based HTML Notebook Server that serves up an
338 This launches a Tornado based HTML Notebook Server that serves up an
339 HTML5/Javascript Notebook client.
339 HTML5/Javascript Notebook client.
340 """
340 """
341 examples = _examples
341 examples = _examples
342 aliases = aliases
342 aliases = aliases
343 flags = flags
343 flags = flags
344
344
345 classes = [
345 classes = [
346 KernelManager, ProfileDir, Session, MappingKernelManager,
346 KernelManager, ProfileDir, Session, MappingKernelManager,
347 ContentsManager, FileContentsManager, NotebookNotary,
347 ContentsManager, FileContentsManager, NotebookNotary,
348 KernelSpecManager,
348 KernelSpecManager,
349 ]
349 ]
350 flags = Dict(flags)
350 flags = Dict(flags)
351 aliases = Dict(aliases)
351 aliases = Dict(aliases)
352
352
353 subcommands = dict(
353 subcommands = dict(
354 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
354 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
355 )
355 )
356
356
357 _log_formatter_cls = LogFormatter
357 _log_formatter_cls = LogFormatter
358
358
359 def _log_level_default(self):
359 def _log_level_default(self):
360 return logging.INFO
360 return logging.INFO
361
361
362 def _log_datefmt_default(self):
362 def _log_datefmt_default(self):
363 """Exclude date from default date format"""
363 """Exclude date from default date format"""
364 return "%H:%M:%S"
364 return "%H:%M:%S"
365
365
366 def _log_format_default(self):
366 def _log_format_default(self):
367 """override default log format to include time"""
367 """override default log format to include time"""
368 return u"%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s]%(end_color)s %(message)s"
368 return u"%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s]%(end_color)s %(message)s"
369
369
370 # create requested profiles by default, if they don't exist:
370 # create requested profiles by default, if they don't exist:
371 auto_create = Bool(True)
371 auto_create = Bool(True)
372
372
373 # file to be opened in the notebook server
373 # file to be opened in the notebook server
374 file_to_run = Unicode('', config=True)
374 file_to_run = Unicode('', config=True)
375
375
376 # Network related information
376 # Network related information
377
377
378 allow_origin = Unicode('', config=True,
378 allow_origin = Unicode('', config=True,
379 help="""Set the Access-Control-Allow-Origin header
379 help="""Set the Access-Control-Allow-Origin header
380
380
381 Use '*' to allow any origin to access your server.
381 Use '*' to allow any origin to access your server.
382
382
383 Takes precedence over allow_origin_pat.
383 Takes precedence over allow_origin_pat.
384 """
384 """
385 )
385 )
386
386
387 allow_origin_pat = Unicode('', config=True,
387 allow_origin_pat = Unicode('', config=True,
388 help="""Use a regular expression for the Access-Control-Allow-Origin header
388 help="""Use a regular expression for the Access-Control-Allow-Origin header
389
389
390 Requests from an origin matching the expression will get replies with:
390 Requests from an origin matching the expression will get replies with:
391
391
392 Access-Control-Allow-Origin: origin
392 Access-Control-Allow-Origin: origin
393
393
394 where `origin` is the origin of the request.
394 where `origin` is the origin of the request.
395
395
396 Ignored if allow_origin is set.
396 Ignored if allow_origin is set.
397 """
397 """
398 )
398 )
399
399
400 allow_credentials = Bool(False, config=True,
400 allow_credentials = Bool(False, config=True,
401 help="Set the Access-Control-Allow-Credentials: true header"
401 help="Set the Access-Control-Allow-Credentials: true header"
402 )
402 )
403
403
404 default_url = Unicode('/tree', config=True,
404 default_url = Unicode('/tree', config=True,
405 help="The default URL to redirect to from `/`"
405 help="The default URL to redirect to from `/`"
406 )
406 )
407
407
408 ip = Unicode('localhost', config=True,
408 ip = Unicode('localhost', config=True,
409 help="The IP address the notebook server will listen on."
409 help="The IP address the notebook server will listen on."
410 )
410 )
411 def _ip_default(self):
411 def _ip_default(self):
412 """Return localhost if available, 127.0.0.1 otherwise.
412 """Return localhost if available, 127.0.0.1 otherwise.
413
413
414 On some (horribly broken) systems, localhost cannot be bound.
414 On some (horribly broken) systems, localhost cannot be bound.
415 """
415 """
416 s = socket.socket()
416 s = socket.socket()
417 try:
417 try:
418 s.bind(('localhost', 0))
418 s.bind(('localhost', 0))
419 except socket.error as e:
419 except socket.error as e:
420 self.log.warn("Cannot bind to localhost, using 127.0.0.1 as default ip\n%s", e)
420 self.log.warn("Cannot bind to localhost, using 127.0.0.1 as default ip\n%s", e)
421 return '127.0.0.1'
421 return '127.0.0.1'
422 else:
422 else:
423 s.close()
423 s.close()
424 return 'localhost'
424 return 'localhost'
425
425
426 def _ip_changed(self, name, old, new):
426 def _ip_changed(self, name, old, new):
427 if new == u'*': self.ip = u''
427 if new == u'*': self.ip = u''
428
428
429 port = Integer(8888, config=True,
429 port = Integer(8888, config=True,
430 help="The port the notebook server will listen on."
430 help="The port the notebook server will listen on."
431 )
431 )
432 port_retries = Integer(50, config=True,
432 port_retries = Integer(50, config=True,
433 help="The number of additional ports to try if the specified port is not available."
433 help="The number of additional ports to try if the specified port is not available."
434 )
434 )
435
435
436 certfile = Unicode(u'', config=True,
436 certfile = Unicode(u'', config=True,
437 help="""The full path to an SSL/TLS certificate file."""
437 help="""The full path to an SSL/TLS certificate file."""
438 )
438 )
439
439
440 keyfile = Unicode(u'', config=True,
440 keyfile = Unicode(u'', config=True,
441 help="""The full path to a private key file for usage with SSL/TLS."""
441 help="""The full path to a private key file for usage with SSL/TLS."""
442 )
442 )
443
443
444 cookie_secret_file = Unicode(config=True,
444 cookie_secret_file = Unicode(config=True,
445 help="""The file where the cookie secret is stored."""
445 help="""The file where the cookie secret is stored."""
446 )
446 )
447 def _cookie_secret_file_default(self):
447 def _cookie_secret_file_default(self):
448 if self.profile_dir is None:
448 if self.profile_dir is None:
449 return ''
449 return ''
450 return os.path.join(self.profile_dir.security_dir, 'notebook_cookie_secret')
450 return os.path.join(self.profile_dir.security_dir, 'notebook_cookie_secret')
451
451
452 cookie_secret = Bytes(b'', config=True,
452 cookie_secret = Bytes(b'', config=True,
453 help="""The random bytes used to secure cookies.
453 help="""The random bytes used to secure cookies.
454 By default this is a new random number every time you start the Notebook.
454 By default this is a new random number every time you start the Notebook.
455 Set it to a value in a config file to enable logins to persist across server sessions.
455 Set it to a value in a config file to enable logins to persist across server sessions.
456
456
457 Note: Cookie secrets should be kept private, do not share config files with
457 Note: Cookie secrets should be kept private, do not share config files with
458 cookie_secret stored in plaintext (you can read the value from a file).
458 cookie_secret stored in plaintext (you can read the value from a file).
459 """
459 """
460 )
460 )
461 def _cookie_secret_default(self):
461 def _cookie_secret_default(self):
462 if os.path.exists(self.cookie_secret_file):
462 if os.path.exists(self.cookie_secret_file):
463 with io.open(self.cookie_secret_file, 'rb') as f:
463 with io.open(self.cookie_secret_file, 'rb') as f:
464 return f.read()
464 return f.read()
465 else:
465 else:
466 secret = base64.encodestring(os.urandom(1024))
466 secret = base64.encodestring(os.urandom(1024))
467 self._write_cookie_secret_file(secret)
467 self._write_cookie_secret_file(secret)
468 return secret
468 return secret
469
469
470 def _write_cookie_secret_file(self, secret):
470 def _write_cookie_secret_file(self, secret):
471 """write my secret to my secret_file"""
471 """write my secret to my secret_file"""
472 self.log.info("Writing notebook server cookie secret to %s", self.cookie_secret_file)
472 self.log.info("Writing notebook server cookie secret to %s", self.cookie_secret_file)
473 with io.open(self.cookie_secret_file, 'wb') as f:
473 with io.open(self.cookie_secret_file, 'wb') as f:
474 f.write(secret)
474 f.write(secret)
475 try:
475 try:
476 os.chmod(self.cookie_secret_file, 0o600)
476 os.chmod(self.cookie_secret_file, 0o600)
477 except OSError:
477 except OSError:
478 self.log.warn(
478 self.log.warn(
479 "Could not set permissions on %s",
479 "Could not set permissions on %s",
480 self.cookie_secret_file
480 self.cookie_secret_file
481 )
481 )
482
482
483 password = Unicode(u'', config=True,
483 password = Unicode(u'', config=True,
484 help="""Hashed password to use for web authentication.
484 help="""Hashed password to use for web authentication.
485
485
486 To generate, type in a python/IPython shell:
486 To generate, type in a python/IPython shell:
487
487
488 from IPython.lib import passwd; passwd()
488 from IPython.lib import passwd; passwd()
489
489
490 The string should be of the form type:salt:hashed-password.
490 The string should be of the form type:salt:hashed-password.
491 """
491 """
492 )
492 )
493
493
494 open_browser = Bool(True, config=True,
494 open_browser = Bool(True, config=True,
495 help="""Whether to open in a browser after starting.
495 help="""Whether to open in a browser after starting.
496 The specific browser used is platform dependent and
496 The specific browser used is platform dependent and
497 determined by the python standard library `webbrowser`
497 determined by the python standard library `webbrowser`
498 module, unless it is overridden using the --browser
498 module, unless it is overridden using the --browser
499 (NotebookApp.browser) configuration option.
499 (NotebookApp.browser) configuration option.
500 """)
500 """)
501
501
502 browser = Unicode(u'', config=True,
502 browser = Unicode(u'', config=True,
503 help="""Specify what command to use to invoke a web
503 help="""Specify what command to use to invoke a web
504 browser when opening the notebook. If not specified, the
504 browser when opening the notebook. If not specified, the
505 default browser will be determined by the `webbrowser`
505 default browser will be determined by the `webbrowser`
506 standard library module, which allows setting of the
506 standard library module, which allows setting of the
507 BROWSER environment variable to override it.
507 BROWSER environment variable to override it.
508 """)
508 """)
509
509
510 webapp_settings = Dict(config=True,
510 webapp_settings = Dict(config=True,
511 help="DEPRECATED, use tornado_settings"
511 help="DEPRECATED, use tornado_settings"
512 )
512 )
513 def _webapp_settings_changed(self, name, old, new):
513 def _webapp_settings_changed(self, name, old, new):
514 self.log.warn("\n webapp_settings is deprecated, use tornado_settings.\n")
514 self.log.warn("\n webapp_settings is deprecated, use tornado_settings.\n")
515 self.tornado_settings = new
515 self.tornado_settings = new
516
516
517 tornado_settings = Dict(config=True,
517 tornado_settings = Dict(config=True,
518 help="Supply overrides for the tornado.web.Application that the "
518 help="Supply overrides for the tornado.web.Application that the "
519 "IPython notebook uses.")
519 "IPython notebook uses.")
520
520
521 ssl_options = Dict(config=True,
521 ssl_options = Dict(config=True,
522 help="""Supply SSL options for the tornado HTTPServer.
522 help="""Supply SSL options for the tornado HTTPServer.
523 See the tornado docs for details.""")
523 See the tornado docs for details.""")
524
524
525 jinja_environment_options = Dict(config=True,
525 jinja_environment_options = Dict(config=True,
526 help="Supply extra arguments that will be passed to Jinja environment.")
526 help="Supply extra arguments that will be passed to Jinja environment.")
527
527
528 enable_mathjax = Bool(True, config=True,
528 enable_mathjax = Bool(True, config=True,
529 help="""Whether to enable MathJax for typesetting math/TeX
529 help="""Whether to enable MathJax for typesetting math/TeX
530
530
531 MathJax is the javascript library IPython uses to render math/LaTeX. It is
531 MathJax is the javascript library IPython uses to render math/LaTeX. It is
532 very large, so you may want to disable it if you have a slow internet
532 very large, so you may want to disable it if you have a slow internet
533 connection, or for offline use of the notebook.
533 connection, or for offline use of the notebook.
534
534
535 When disabled, equations etc. will appear as their untransformed TeX source.
535 When disabled, equations etc. will appear as their untransformed TeX source.
536 """
536 """
537 )
537 )
538 def _enable_mathjax_changed(self, name, old, new):
538 def _enable_mathjax_changed(self, name, old, new):
539 """set mathjax url to empty if mathjax is disabled"""
539 """set mathjax url to empty if mathjax is disabled"""
540 if not new:
540 if not new:
541 self.mathjax_url = u''
541 self.mathjax_url = u''
542
542
543 base_url = Unicode('/', config=True,
543 base_url = Unicode('/', config=True,
544 help='''The base URL for the notebook server.
544 help='''The base URL for the notebook server.
545
545
546 Leading and trailing slashes can be omitted,
546 Leading and trailing slashes can be omitted,
547 and will automatically be added.
547 and will automatically be added.
548 ''')
548 ''')
549 def _base_url_changed(self, name, old, new):
549 def _base_url_changed(self, name, old, new):
550 if not new.startswith('/'):
550 if not new.startswith('/'):
551 self.base_url = '/'+new
551 self.base_url = '/'+new
552 elif not new.endswith('/'):
552 elif not new.endswith('/'):
553 self.base_url = new+'/'
553 self.base_url = new+'/'
554
554
555 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
555 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
556 def _base_project_url_changed(self, name, old, new):
556 def _base_project_url_changed(self, name, old, new):
557 self.log.warn("base_project_url is deprecated, use base_url")
557 self.log.warn("base_project_url is deprecated, use base_url")
558 self.base_url = new
558 self.base_url = new
559
559
560 extra_static_paths = List(Unicode, config=True,
560 extra_static_paths = List(Unicode, config=True,
561 help="""Extra paths to search for serving static files.
561 help="""Extra paths to search for serving static files.
562
562
563 This allows adding javascript/css to be available from the notebook server machine,
563 This allows adding javascript/css to be available from the notebook server machine,
564 or overriding individual files in the IPython"""
564 or overriding individual files in the IPython"""
565 )
565 )
566 def _extra_static_paths_default(self):
566 def _extra_static_paths_default(self):
567 return [os.path.join(self.profile_dir.location, 'static')]
567 return [os.path.join(self.profile_dir.location, 'static')]
568
568
569 @property
569 @property
570 def static_file_path(self):
570 def static_file_path(self):
571 """return extra paths + the default location"""
571 """return extra paths + the default location"""
572 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
572 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
573
573
574 extra_template_paths = List(Unicode, config=True,
574 extra_template_paths = List(Unicode, config=True,
575 help="""Extra paths to search for serving jinja templates.
575 help="""Extra paths to search for serving jinja templates.
576
576
577 Can be used to override templates from IPython.html.templates."""
577 Can be used to override templates from IPython.html.templates."""
578 )
578 )
579 def _extra_template_paths_default(self):
579 def _extra_template_paths_default(self):
580 return []
580 return []
581
581
582 @property
582 @property
583 def template_file_path(self):
583 def template_file_path(self):
584 """return extra paths + the default locations"""
584 """return extra paths + the default locations"""
585 return self.extra_template_paths + DEFAULT_TEMPLATE_PATH_LIST
585 return self.extra_template_paths + DEFAULT_TEMPLATE_PATH_LIST
586
586
587 extra_nbextensions_path = List(Unicode, config=True,
587 extra_nbextensions_path = List(Unicode, config=True,
588 help="""extra paths to look for Javascript notebook extensions"""
588 help="""extra paths to look for Javascript notebook extensions"""
589 )
589 )
590
590
591 @property
591 @property
592 def nbextensions_path(self):
592 def nbextensions_path(self):
593 """The path to look for Javascript notebook extensions"""
593 """The path to look for Javascript notebook extensions"""
594 return self.extra_nbextensions_path + [os.path.join(get_ipython_dir(), 'nbextensions')] + SYSTEM_NBEXTENSIONS_DIRS
594 return self.extra_nbextensions_path + [os.path.join(get_ipython_dir(), 'nbextensions')] + SYSTEM_NBEXTENSIONS_DIRS
595
595
596 websocket_url = Unicode("", config=True,
596 websocket_url = Unicode("", config=True,
597 help="""The base URL for websockets,
597 help="""The base URL for websockets,
598 if it differs from the HTTP server (hint: it almost certainly doesn't).
598 if it differs from the HTTP server (hint: it almost certainly doesn't).
599
599
600 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
600 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
601 """
601 """
602 )
602 )
603 mathjax_url = Unicode("", config=True,
603 mathjax_url = Unicode("", config=True,
604 help="""The url for MathJax.js."""
604 help="""The url for MathJax.js."""
605 )
605 )
606 def _mathjax_url_default(self):
606 def _mathjax_url_default(self):
607 if not self.enable_mathjax:
607 if not self.enable_mathjax:
608 return u''
608 return u''
609 static_url_prefix = self.tornado_settings.get("static_url_prefix",
609 static_url_prefix = self.tornado_settings.get("static_url_prefix",
610 url_path_join(self.base_url, "static")
610 url_path_join(self.base_url, "static")
611 )
611 )
612
612
613 # try local mathjax, either in nbextensions/mathjax or static/mathjax
613 # try local mathjax, either in nbextensions/mathjax or static/mathjax
614 for (url_prefix, search_path) in [
614 for (url_prefix, search_path) in [
615 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
615 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
616 (static_url_prefix, self.static_file_path),
616 (static_url_prefix, self.static_file_path),
617 ]:
617 ]:
618 self.log.debug("searching for local mathjax in %s", search_path)
618 self.log.debug("searching for local mathjax in %s", search_path)
619 try:
619 try:
620 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
620 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
621 except IOError:
621 except IOError:
622 continue
622 continue
623 else:
623 else:
624 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
624 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
625 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
625 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
626 return url
626 return url
627
627
628 # no local mathjax, serve from CDN
628 # no local mathjax, serve from CDN
629 url = u"https://cdn.mathjax.org/mathjax/latest/MathJax.js"
629 url = u"https://cdn.mathjax.org/mathjax/latest/MathJax.js"
630 self.log.info("Using MathJax from CDN: %s", url)
630 self.log.info("Using MathJax from CDN: %s", url)
631 return url
631 return url
632
632
633 def _mathjax_url_changed(self, name, old, new):
633 def _mathjax_url_changed(self, name, old, new):
634 if new and not self.enable_mathjax:
634 if new and not self.enable_mathjax:
635 # enable_mathjax=False overrides mathjax_url
635 # enable_mathjax=False overrides mathjax_url
636 self.mathjax_url = u''
636 self.mathjax_url = u''
637 else:
637 else:
638 self.log.info("Using MathJax: %s", new)
638 self.log.info("Using MathJax: %s", new)
639
639
640 contents_manager_class = Type(
640 contents_manager_class = Type(
641 default_value=FileContentsManager,
641 default_value=FileContentsManager,
642 klass=ContentsManager,
642 klass=ContentsManager,
643 config=True,
643 config=True,
644 help='The notebook manager class to use.'
644 help='The notebook manager class to use.'
645 )
645 )
646 kernel_manager_class = Type(
646 kernel_manager_class = Type(
647 default_value=MappingKernelManager,
647 default_value=MappingKernelManager,
648 config=True,
648 config=True,
649 help='The kernel manager class to use.'
649 help='The kernel manager class to use.'
650 )
650 )
651 session_manager_class = Type(
651 session_manager_class = Type(
652 default_value=SessionManager,
652 default_value=SessionManager,
653 config=True,
653 config=True,
654 help='The session manager class to use.'
654 help='The session manager class to use.'
655 )
655 )
656 cluster_manager_class = Type(
656 cluster_manager_class = Type(
657 default_value=ClusterManager,
657 default_value=ClusterManager,
658 config=True,
658 config=True,
659 help='The cluster manager class to use.'
659 help='The cluster manager class to use.'
660 )
660 )
661
661
662 config_manager_class = Type(
662 config_manager_class = Type(
663 default_value=ConfigManager,
663 default_value=ConfigManager,
664 config = True,
664 config = True,
665 help='The config manager class to use'
665 help='The config manager class to use'
666 )
666 )
667
667
668 kernel_spec_manager = Instance(KernelSpecManager)
668 kernel_spec_manager = Instance(KernelSpecManager, allow_none=True)
669
669
670 kernel_spec_manager_class = Type(
670 kernel_spec_manager_class = Type(
671 default_value=KernelSpecManager,
671 default_value=KernelSpecManager,
672 config=True,
672 config=True,
673 help="""
673 help="""
674 The kernel spec manager class to use. Should be a subclass
674 The kernel spec manager class to use. Should be a subclass
675 of `IPython.kernel.kernelspec.KernelSpecManager`.
675 of `IPython.kernel.kernelspec.KernelSpecManager`.
676
676
677 The Api of KernelSpecManager is provisional and might change
677 The Api of KernelSpecManager is provisional and might change
678 without warning between this version of IPython and the next stable one.
678 without warning between this version of IPython and the next stable one.
679 """
679 """
680 )
680 )
681
681
682 login_handler_class = Type(
682 login_handler_class = Type(
683 default_value=LoginHandler,
683 default_value=LoginHandler,
684 klass=web.RequestHandler,
684 klass=web.RequestHandler,
685 config=True,
685 config=True,
686 help='The login handler class to use.',
686 help='The login handler class to use.',
687 )
687 )
688
688
689 logout_handler_class = Type(
689 logout_handler_class = Type(
690 default_value=LogoutHandler,
690 default_value=LogoutHandler,
691 klass=web.RequestHandler,
691 klass=web.RequestHandler,
692 config=True,
692 config=True,
693 help='The logout handler class to use.',
693 help='The logout handler class to use.',
694 )
694 )
695
695
696 trust_xheaders = Bool(False, config=True,
696 trust_xheaders = Bool(False, config=True,
697 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
697 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
698 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
698 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
699 )
699 )
700
700
701 info_file = Unicode()
701 info_file = Unicode()
702
702
703 def _info_file_default(self):
703 def _info_file_default(self):
704 info_file = "nbserver-%s.json"%os.getpid()
704 info_file = "nbserver-%s.json"%os.getpid()
705 return os.path.join(self.profile_dir.security_dir, info_file)
705 return os.path.join(self.profile_dir.security_dir, info_file)
706
706
707 pylab = Unicode('disabled', config=True,
707 pylab = Unicode('disabled', config=True,
708 help="""
708 help="""
709 DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.
709 DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.
710 """
710 """
711 )
711 )
712 def _pylab_changed(self, name, old, new):
712 def _pylab_changed(self, name, old, new):
713 """when --pylab is specified, display a warning and exit"""
713 """when --pylab is specified, display a warning and exit"""
714 if new != 'warn':
714 if new != 'warn':
715 backend = ' %s' % new
715 backend = ' %s' % new
716 else:
716 else:
717 backend = ''
717 backend = ''
718 self.log.error("Support for specifying --pylab on the command line has been removed.")
718 self.log.error("Support for specifying --pylab on the command line has been removed.")
719 self.log.error(
719 self.log.error(
720 "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself.".format(backend)
720 "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself.".format(backend)
721 )
721 )
722 self.exit(1)
722 self.exit(1)
723
723
724 notebook_dir = Unicode(config=True,
724 notebook_dir = Unicode(config=True,
725 help="The directory to use for notebooks and kernels."
725 help="The directory to use for notebooks and kernels."
726 )
726 )
727
727
728 def _notebook_dir_default(self):
728 def _notebook_dir_default(self):
729 if self.file_to_run:
729 if self.file_to_run:
730 return os.path.dirname(os.path.abspath(self.file_to_run))
730 return os.path.dirname(os.path.abspath(self.file_to_run))
731 else:
731 else:
732 return py3compat.getcwd()
732 return py3compat.getcwd()
733
733
734 def _notebook_dir_changed(self, name, old, new):
734 def _notebook_dir_changed(self, name, old, new):
735 """Do a bit of validation of the notebook dir."""
735 """Do a bit of validation of the notebook dir."""
736 if not os.path.isabs(new):
736 if not os.path.isabs(new):
737 # If we receive a non-absolute path, make it absolute.
737 # If we receive a non-absolute path, make it absolute.
738 self.notebook_dir = os.path.abspath(new)
738 self.notebook_dir = os.path.abspath(new)
739 return
739 return
740 if not os.path.isdir(new):
740 if not os.path.isdir(new):
741 raise TraitError("No such notebook dir: %r" % new)
741 raise TraitError("No such notebook dir: %r" % new)
742
742
743 # setting App.notebook_dir implies setting notebook and kernel dirs as well
743 # setting App.notebook_dir implies setting notebook and kernel dirs as well
744 self.config.FileContentsManager.root_dir = new
744 self.config.FileContentsManager.root_dir = new
745 self.config.MappingKernelManager.root_dir = new
745 self.config.MappingKernelManager.root_dir = new
746
746
747 server_extensions = List(Unicode(), config=True,
747 server_extensions = List(Unicode(), config=True,
748 help=("Python modules to load as notebook server extensions. "
748 help=("Python modules to load as notebook server extensions. "
749 "This is an experimental API, and may change in future releases.")
749 "This is an experimental API, and may change in future releases.")
750 )
750 )
751
751
752 reraise_server_extension_failures = Bool(
752 reraise_server_extension_failures = Bool(
753 False,
753 False,
754 config=True,
754 config=True,
755 help="Reraise exceptions encountered loading server extensions?",
755 help="Reraise exceptions encountered loading server extensions?",
756 )
756 )
757
757
758 def parse_command_line(self, argv=None):
758 def parse_command_line(self, argv=None):
759 super(NotebookApp, self).parse_command_line(argv)
759 super(NotebookApp, self).parse_command_line(argv)
760
760
761 if self.extra_args:
761 if self.extra_args:
762 arg0 = self.extra_args[0]
762 arg0 = self.extra_args[0]
763 f = os.path.abspath(arg0)
763 f = os.path.abspath(arg0)
764 self.argv.remove(arg0)
764 self.argv.remove(arg0)
765 if not os.path.exists(f):
765 if not os.path.exists(f):
766 self.log.critical("No such file or directory: %s", f)
766 self.log.critical("No such file or directory: %s", f)
767 self.exit(1)
767 self.exit(1)
768
768
769 # Use config here, to ensure that it takes higher priority than
769 # Use config here, to ensure that it takes higher priority than
770 # anything that comes from the profile.
770 # anything that comes from the profile.
771 c = Config()
771 c = Config()
772 if os.path.isdir(f):
772 if os.path.isdir(f):
773 c.NotebookApp.notebook_dir = f
773 c.NotebookApp.notebook_dir = f
774 elif os.path.isfile(f):
774 elif os.path.isfile(f):
775 c.NotebookApp.file_to_run = f
775 c.NotebookApp.file_to_run = f
776 self.update_config(c)
776 self.update_config(c)
777
777
778 def init_configurables(self):
778 def init_configurables(self):
779 self.kernel_spec_manager = self.kernel_spec_manager_class(
779 self.kernel_spec_manager = self.kernel_spec_manager_class(
780 parent=self,
780 parent=self,
781 ipython_dir=self.ipython_dir,
781 ipython_dir=self.ipython_dir,
782 )
782 )
783 self.kernel_manager = self.kernel_manager_class(
783 self.kernel_manager = self.kernel_manager_class(
784 parent=self,
784 parent=self,
785 log=self.log,
785 log=self.log,
786 connection_dir=self.profile_dir.security_dir,
786 connection_dir=self.profile_dir.security_dir,
787 )
787 )
788 self.contents_manager = self.contents_manager_class(
788 self.contents_manager = self.contents_manager_class(
789 parent=self,
789 parent=self,
790 log=self.log,
790 log=self.log,
791 )
791 )
792 self.session_manager = self.session_manager_class(
792 self.session_manager = self.session_manager_class(
793 parent=self,
793 parent=self,
794 log=self.log,
794 log=self.log,
795 kernel_manager=self.kernel_manager,
795 kernel_manager=self.kernel_manager,
796 contents_manager=self.contents_manager,
796 contents_manager=self.contents_manager,
797 )
797 )
798 self.cluster_manager = self.cluster_manager_class(
798 self.cluster_manager = self.cluster_manager_class(
799 parent=self,
799 parent=self,
800 log=self.log,
800 log=self.log,
801 )
801 )
802
802
803 self.config_manager = self.config_manager_class(
803 self.config_manager = self.config_manager_class(
804 parent=self,
804 parent=self,
805 log=self.log,
805 log=self.log,
806 profile_dir=self.profile_dir.location,
806 profile_dir=self.profile_dir.location,
807 )
807 )
808
808
809 def init_logging(self):
809 def init_logging(self):
810 # This prevents double log messages because tornado use a root logger that
810 # This prevents double log messages because tornado use a root logger that
811 # self.log is a child of. The logging module dipatches log messages to a log
811 # self.log is a child of. The logging module dipatches log messages to a log
812 # and all of its ancenstors until propagate is set to False.
812 # and all of its ancenstors until propagate is set to False.
813 self.log.propagate = False
813 self.log.propagate = False
814
814
815 for log in app_log, access_log, gen_log:
815 for log in app_log, access_log, gen_log:
816 # consistent log output name (NotebookApp instead of tornado.access, etc.)
816 # consistent log output name (NotebookApp instead of tornado.access, etc.)
817 log.name = self.log.name
817 log.name = self.log.name
818 # hook up tornado 3's loggers to our app handlers
818 # hook up tornado 3's loggers to our app handlers
819 logger = logging.getLogger('tornado')
819 logger = logging.getLogger('tornado')
820 logger.propagate = True
820 logger.propagate = True
821 logger.parent = self.log
821 logger.parent = self.log
822 logger.setLevel(self.log.level)
822 logger.setLevel(self.log.level)
823
823
824 def init_webapp(self):
824 def init_webapp(self):
825 """initialize tornado webapp and httpserver"""
825 """initialize tornado webapp and httpserver"""
826 self.tornado_settings['allow_origin'] = self.allow_origin
826 self.tornado_settings['allow_origin'] = self.allow_origin
827 if self.allow_origin_pat:
827 if self.allow_origin_pat:
828 self.tornado_settings['allow_origin_pat'] = re.compile(self.allow_origin_pat)
828 self.tornado_settings['allow_origin_pat'] = re.compile(self.allow_origin_pat)
829 self.tornado_settings['allow_credentials'] = self.allow_credentials
829 self.tornado_settings['allow_credentials'] = self.allow_credentials
830 # ensure default_url starts with base_url
830 # ensure default_url starts with base_url
831 if not self.default_url.startswith(self.base_url):
831 if not self.default_url.startswith(self.base_url):
832 self.default_url = url_path_join(self.base_url, self.default_url)
832 self.default_url = url_path_join(self.base_url, self.default_url)
833
833
834 self.web_app = NotebookWebApplication(
834 self.web_app = NotebookWebApplication(
835 self, self.kernel_manager, self.contents_manager,
835 self, self.kernel_manager, self.contents_manager,
836 self.cluster_manager, self.session_manager, self.kernel_spec_manager,
836 self.cluster_manager, self.session_manager, self.kernel_spec_manager,
837 self.config_manager,
837 self.config_manager,
838 self.log, self.base_url, self.default_url, self.tornado_settings,
838 self.log, self.base_url, self.default_url, self.tornado_settings,
839 self.jinja_environment_options
839 self.jinja_environment_options
840 )
840 )
841 ssl_options = self.ssl_options
841 ssl_options = self.ssl_options
842 if self.certfile:
842 if self.certfile:
843 ssl_options['certfile'] = self.certfile
843 ssl_options['certfile'] = self.certfile
844 if self.keyfile:
844 if self.keyfile:
845 ssl_options['keyfile'] = self.keyfile
845 ssl_options['keyfile'] = self.keyfile
846 if not ssl_options:
846 if not ssl_options:
847 # None indicates no SSL config
847 # None indicates no SSL config
848 ssl_options = None
848 ssl_options = None
849 self.login_handler_class.validate_security(self, ssl_options=ssl_options)
849 self.login_handler_class.validate_security(self, ssl_options=ssl_options)
850 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
850 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
851 xheaders=self.trust_xheaders)
851 xheaders=self.trust_xheaders)
852
852
853 success = None
853 success = None
854 for port in random_ports(self.port, self.port_retries+1):
854 for port in random_ports(self.port, self.port_retries+1):
855 try:
855 try:
856 self.http_server.listen(port, self.ip)
856 self.http_server.listen(port, self.ip)
857 except socket.error as e:
857 except socket.error as e:
858 if e.errno == errno.EADDRINUSE:
858 if e.errno == errno.EADDRINUSE:
859 self.log.info('The port %i is already in use, trying another random port.' % port)
859 self.log.info('The port %i is already in use, trying another random port.' % port)
860 continue
860 continue
861 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
861 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
862 self.log.warn("Permission to listen on port %i denied" % port)
862 self.log.warn("Permission to listen on port %i denied" % port)
863 continue
863 continue
864 else:
864 else:
865 raise
865 raise
866 else:
866 else:
867 self.port = port
867 self.port = port
868 success = True
868 success = True
869 break
869 break
870 if not success:
870 if not success:
871 self.log.critical('ERROR: the notebook server could not be started because '
871 self.log.critical('ERROR: the notebook server could not be started because '
872 'no available port could be found.')
872 'no available port could be found.')
873 self.exit(1)
873 self.exit(1)
874
874
875 @property
875 @property
876 def display_url(self):
876 def display_url(self):
877 ip = self.ip if self.ip else '[all ip addresses on your system]'
877 ip = self.ip if self.ip else '[all ip addresses on your system]'
878 return self._url(ip)
878 return self._url(ip)
879
879
880 @property
880 @property
881 def connection_url(self):
881 def connection_url(self):
882 ip = self.ip if self.ip else 'localhost'
882 ip = self.ip if self.ip else 'localhost'
883 return self._url(ip)
883 return self._url(ip)
884
884
885 def _url(self, ip):
885 def _url(self, ip):
886 proto = 'https' if self.certfile else 'http'
886 proto = 'https' if self.certfile else 'http'
887 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
887 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
888
888
889 def init_terminals(self):
889 def init_terminals(self):
890 try:
890 try:
891 from .terminal import initialize
891 from .terminal import initialize
892 initialize(self.web_app)
892 initialize(self.web_app)
893 self.web_app.settings['terminals_available'] = True
893 self.web_app.settings['terminals_available'] = True
894 except ImportError as e:
894 except ImportError as e:
895 log = self.log.debug if sys.platform == 'win32' else self.log.warn
895 log = self.log.debug if sys.platform == 'win32' else self.log.warn
896 log("Terminals not available (error was %s)", e)
896 log("Terminals not available (error was %s)", e)
897
897
898 def init_signal(self):
898 def init_signal(self):
899 if not sys.platform.startswith('win'):
899 if not sys.platform.startswith('win'):
900 signal.signal(signal.SIGINT, self._handle_sigint)
900 signal.signal(signal.SIGINT, self._handle_sigint)
901 signal.signal(signal.SIGTERM, self._signal_stop)
901 signal.signal(signal.SIGTERM, self._signal_stop)
902 if hasattr(signal, 'SIGUSR1'):
902 if hasattr(signal, 'SIGUSR1'):
903 # Windows doesn't support SIGUSR1
903 # Windows doesn't support SIGUSR1
904 signal.signal(signal.SIGUSR1, self._signal_info)
904 signal.signal(signal.SIGUSR1, self._signal_info)
905 if hasattr(signal, 'SIGINFO'):
905 if hasattr(signal, 'SIGINFO'):
906 # only on BSD-based systems
906 # only on BSD-based systems
907 signal.signal(signal.SIGINFO, self._signal_info)
907 signal.signal(signal.SIGINFO, self._signal_info)
908
908
909 def _handle_sigint(self, sig, frame):
909 def _handle_sigint(self, sig, frame):
910 """SIGINT handler spawns confirmation dialog"""
910 """SIGINT handler spawns confirmation dialog"""
911 # register more forceful signal handler for ^C^C case
911 # register more forceful signal handler for ^C^C case
912 signal.signal(signal.SIGINT, self._signal_stop)
912 signal.signal(signal.SIGINT, self._signal_stop)
913 # request confirmation dialog in bg thread, to avoid
913 # request confirmation dialog in bg thread, to avoid
914 # blocking the App
914 # blocking the App
915 thread = threading.Thread(target=self._confirm_exit)
915 thread = threading.Thread(target=self._confirm_exit)
916 thread.daemon = True
916 thread.daemon = True
917 thread.start()
917 thread.start()
918
918
919 def _restore_sigint_handler(self):
919 def _restore_sigint_handler(self):
920 """callback for restoring original SIGINT handler"""
920 """callback for restoring original SIGINT handler"""
921 signal.signal(signal.SIGINT, self._handle_sigint)
921 signal.signal(signal.SIGINT, self._handle_sigint)
922
922
923 def _confirm_exit(self):
923 def _confirm_exit(self):
924 """confirm shutdown on ^C
924 """confirm shutdown on ^C
925
925
926 A second ^C, or answering 'y' within 5s will cause shutdown,
926 A second ^C, or answering 'y' within 5s will cause shutdown,
927 otherwise original SIGINT handler will be restored.
927 otherwise original SIGINT handler will be restored.
928
928
929 This doesn't work on Windows.
929 This doesn't work on Windows.
930 """
930 """
931 info = self.log.info
931 info = self.log.info
932 info('interrupted')
932 info('interrupted')
933 print(self.notebook_info())
933 print(self.notebook_info())
934 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
934 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
935 sys.stdout.flush()
935 sys.stdout.flush()
936 r,w,x = select.select([sys.stdin], [], [], 5)
936 r,w,x = select.select([sys.stdin], [], [], 5)
937 if r:
937 if r:
938 line = sys.stdin.readline()
938 line = sys.stdin.readline()
939 if line.lower().startswith('y') and 'n' not in line.lower():
939 if line.lower().startswith('y') and 'n' not in line.lower():
940 self.log.critical("Shutdown confirmed")
940 self.log.critical("Shutdown confirmed")
941 ioloop.IOLoop.current().stop()
941 ioloop.IOLoop.current().stop()
942 return
942 return
943 else:
943 else:
944 print("No answer for 5s:", end=' ')
944 print("No answer for 5s:", end=' ')
945 print("resuming operation...")
945 print("resuming operation...")
946 # no answer, or answer is no:
946 # no answer, or answer is no:
947 # set it back to original SIGINT handler
947 # set it back to original SIGINT handler
948 # use IOLoop.add_callback because signal.signal must be called
948 # use IOLoop.add_callback because signal.signal must be called
949 # from main thread
949 # from main thread
950 ioloop.IOLoop.current().add_callback(self._restore_sigint_handler)
950 ioloop.IOLoop.current().add_callback(self._restore_sigint_handler)
951
951
952 def _signal_stop(self, sig, frame):
952 def _signal_stop(self, sig, frame):
953 self.log.critical("received signal %s, stopping", sig)
953 self.log.critical("received signal %s, stopping", sig)
954 ioloop.IOLoop.current().stop()
954 ioloop.IOLoop.current().stop()
955
955
956 def _signal_info(self, sig, frame):
956 def _signal_info(self, sig, frame):
957 print(self.notebook_info())
957 print(self.notebook_info())
958
958
959 def init_components(self):
959 def init_components(self):
960 """Check the components submodule, and warn if it's unclean"""
960 """Check the components submodule, and warn if it's unclean"""
961 status = submodule.check_submodule_status()
961 status = submodule.check_submodule_status()
962 if status == 'missing':
962 if status == 'missing':
963 self.log.warn("components submodule missing, running `git submodule update`")
963 self.log.warn("components submodule missing, running `git submodule update`")
964 submodule.update_submodules(submodule.ipython_parent())
964 submodule.update_submodules(submodule.ipython_parent())
965 elif status == 'unclean':
965 elif status == 'unclean':
966 self.log.warn("components submodule unclean, you may see 404s on static/components")
966 self.log.warn("components submodule unclean, you may see 404s on static/components")
967 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
967 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
968
968
969 def init_server_extensions(self):
969 def init_server_extensions(self):
970 """Load any extensions specified by config.
970 """Load any extensions specified by config.
971
971
972 Import the module, then call the load_jupyter_server_extension function,
972 Import the module, then call the load_jupyter_server_extension function,
973 if one exists.
973 if one exists.
974
974
975 The extension API is experimental, and may change in future releases.
975 The extension API is experimental, and may change in future releases.
976 """
976 """
977 for modulename in self.server_extensions:
977 for modulename in self.server_extensions:
978 try:
978 try:
979 mod = importlib.import_module(modulename)
979 mod = importlib.import_module(modulename)
980 func = getattr(mod, 'load_jupyter_server_extension', None)
980 func = getattr(mod, 'load_jupyter_server_extension', None)
981 if func is not None:
981 if func is not None:
982 func(self)
982 func(self)
983 except Exception:
983 except Exception:
984 if self.reraise_server_extension_failures:
984 if self.reraise_server_extension_failures:
985 raise
985 raise
986 self.log.warn("Error loading server extension %s", modulename,
986 self.log.warn("Error loading server extension %s", modulename,
987 exc_info=True)
987 exc_info=True)
988
988
989 @catch_config_error
989 @catch_config_error
990 def initialize(self, argv=None):
990 def initialize(self, argv=None):
991 super(NotebookApp, self).initialize(argv)
991 super(NotebookApp, self).initialize(argv)
992 self.init_logging()
992 self.init_logging()
993 self.init_configurables()
993 self.init_configurables()
994 self.init_components()
994 self.init_components()
995 self.init_webapp()
995 self.init_webapp()
996 self.init_terminals()
996 self.init_terminals()
997 self.init_signal()
997 self.init_signal()
998 self.init_server_extensions()
998 self.init_server_extensions()
999
999
1000 def cleanup_kernels(self):
1000 def cleanup_kernels(self):
1001 """Shutdown all kernels.
1001 """Shutdown all kernels.
1002
1002
1003 The kernels will shutdown themselves when this process no longer exists,
1003 The kernels will shutdown themselves when this process no longer exists,
1004 but explicit shutdown allows the KernelManagers to cleanup the connection files.
1004 but explicit shutdown allows the KernelManagers to cleanup the connection files.
1005 """
1005 """
1006 self.log.info('Shutting down kernels')
1006 self.log.info('Shutting down kernels')
1007 self.kernel_manager.shutdown_all()
1007 self.kernel_manager.shutdown_all()
1008
1008
1009 def notebook_info(self):
1009 def notebook_info(self):
1010 "Return the current working directory and the server url information"
1010 "Return the current working directory and the server url information"
1011 info = self.contents_manager.info_string() + "\n"
1011 info = self.contents_manager.info_string() + "\n"
1012 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
1012 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
1013 return info + "The IPython Notebook is running at: %s" % self.display_url
1013 return info + "The IPython Notebook is running at: %s" % self.display_url
1014
1014
1015 def server_info(self):
1015 def server_info(self):
1016 """Return a JSONable dict of information about this server."""
1016 """Return a JSONable dict of information about this server."""
1017 return {'url': self.connection_url,
1017 return {'url': self.connection_url,
1018 'hostname': self.ip if self.ip else 'localhost',
1018 'hostname': self.ip if self.ip else 'localhost',
1019 'port': self.port,
1019 'port': self.port,
1020 'secure': bool(self.certfile),
1020 'secure': bool(self.certfile),
1021 'base_url': self.base_url,
1021 'base_url': self.base_url,
1022 'notebook_dir': os.path.abspath(self.notebook_dir),
1022 'notebook_dir': os.path.abspath(self.notebook_dir),
1023 'pid': os.getpid()
1023 'pid': os.getpid()
1024 }
1024 }
1025
1025
1026 def write_server_info_file(self):
1026 def write_server_info_file(self):
1027 """Write the result of server_info() to the JSON file info_file."""
1027 """Write the result of server_info() to the JSON file info_file."""
1028 with open(self.info_file, 'w') as f:
1028 with open(self.info_file, 'w') as f:
1029 json.dump(self.server_info(), f, indent=2)
1029 json.dump(self.server_info(), f, indent=2)
1030
1030
1031 def remove_server_info_file(self):
1031 def remove_server_info_file(self):
1032 """Remove the nbserver-<pid>.json file created for this server.
1032 """Remove the nbserver-<pid>.json file created for this server.
1033
1033
1034 Ignores the error raised when the file has already been removed.
1034 Ignores the error raised when the file has already been removed.
1035 """
1035 """
1036 try:
1036 try:
1037 os.unlink(self.info_file)
1037 os.unlink(self.info_file)
1038 except OSError as e:
1038 except OSError as e:
1039 if e.errno != errno.ENOENT:
1039 if e.errno != errno.ENOENT:
1040 raise
1040 raise
1041
1041
1042 def start(self):
1042 def start(self):
1043 """ Start the IPython Notebook server app, after initialization
1043 """ Start the IPython Notebook server app, after initialization
1044
1044
1045 This method takes no arguments so all configuration and initialization
1045 This method takes no arguments so all configuration and initialization
1046 must be done prior to calling this method."""
1046 must be done prior to calling this method."""
1047 if self.subapp is not None:
1047 if self.subapp is not None:
1048 return self.subapp.start()
1048 return self.subapp.start()
1049
1049
1050 info = self.log.info
1050 info = self.log.info
1051 for line in self.notebook_info().split("\n"):
1051 for line in self.notebook_info().split("\n"):
1052 info(line)
1052 info(line)
1053 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
1053 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
1054
1054
1055 self.write_server_info_file()
1055 self.write_server_info_file()
1056
1056
1057 if self.open_browser or self.file_to_run:
1057 if self.open_browser or self.file_to_run:
1058 try:
1058 try:
1059 browser = webbrowser.get(self.browser or None)
1059 browser = webbrowser.get(self.browser or None)
1060 except webbrowser.Error as e:
1060 except webbrowser.Error as e:
1061 self.log.warn('No web browser found: %s.' % e)
1061 self.log.warn('No web browser found: %s.' % e)
1062 browser = None
1062 browser = None
1063
1063
1064 if self.file_to_run:
1064 if self.file_to_run:
1065 if not os.path.exists(self.file_to_run):
1065 if not os.path.exists(self.file_to_run):
1066 self.log.critical("%s does not exist" % self.file_to_run)
1066 self.log.critical("%s does not exist" % self.file_to_run)
1067 self.exit(1)
1067 self.exit(1)
1068
1068
1069 relpath = os.path.relpath(self.file_to_run, self.notebook_dir)
1069 relpath = os.path.relpath(self.file_to_run, self.notebook_dir)
1070 uri = url_path_join('notebooks', *relpath.split(os.sep))
1070 uri = url_path_join('notebooks', *relpath.split(os.sep))
1071 else:
1071 else:
1072 uri = 'tree'
1072 uri = 'tree'
1073 if browser:
1073 if browser:
1074 b = lambda : browser.open(url_path_join(self.connection_url, uri),
1074 b = lambda : browser.open(url_path_join(self.connection_url, uri),
1075 new=2)
1075 new=2)
1076 threading.Thread(target=b).start()
1076 threading.Thread(target=b).start()
1077
1077
1078 self.io_loop = ioloop.IOLoop.current()
1078 self.io_loop = ioloop.IOLoop.current()
1079 if sys.platform.startswith('win'):
1079 if sys.platform.startswith('win'):
1080 # add no-op to wake every 5s
1080 # add no-op to wake every 5s
1081 # to handle signals that may be ignored by the inner loop
1081 # to handle signals that may be ignored by the inner loop
1082 pc = ioloop.PeriodicCallback(lambda : None, 5000)
1082 pc = ioloop.PeriodicCallback(lambda : None, 5000)
1083 pc.start()
1083 pc.start()
1084 try:
1084 try:
1085 self.io_loop.start()
1085 self.io_loop.start()
1086 except KeyboardInterrupt:
1086 except KeyboardInterrupt:
1087 info("Interrupted...")
1087 info("Interrupted...")
1088 finally:
1088 finally:
1089 self.cleanup_kernels()
1089 self.cleanup_kernels()
1090 self.remove_server_info_file()
1090 self.remove_server_info_file()
1091
1091
1092 def stop(self):
1092 def stop(self):
1093 def _stop():
1093 def _stop():
1094 self.http_server.stop()
1094 self.http_server.stop()
1095 self.io_loop.stop()
1095 self.io_loop.stop()
1096 self.io_loop.add_callback(_stop)
1096 self.io_loop.add_callback(_stop)
1097
1097
1098
1098
1099 def list_running_servers(profile='default'):
1099 def list_running_servers(profile='default'):
1100 """Iterate over the server info files of running notebook servers.
1100 """Iterate over the server info files of running notebook servers.
1101
1101
1102 Given a profile name, find nbserver-* files in the security directory of
1102 Given a profile name, find nbserver-* files in the security directory of
1103 that profile, and yield dicts of their information, each one pertaining to
1103 that profile, and yield dicts of their information, each one pertaining to
1104 a currently running notebook server instance.
1104 a currently running notebook server instance.
1105 """
1105 """
1106 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
1106 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
1107 for file in os.listdir(pd.security_dir):
1107 for file in os.listdir(pd.security_dir):
1108 if file.startswith('nbserver-'):
1108 if file.startswith('nbserver-'):
1109 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
1109 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
1110 info = json.load(f)
1110 info = json.load(f)
1111
1111
1112 # Simple check whether that process is really still running
1112 # Simple check whether that process is really still running
1113 # Also remove leftover files from IPython 2.x without a pid field
1113 # Also remove leftover files from IPython 2.x without a pid field
1114 if ('pid' in info) and check_pid(info['pid']):
1114 if ('pid' in info) and check_pid(info['pid']):
1115 yield info
1115 yield info
1116 else:
1116 else:
1117 # If the process has died, try to delete its info file
1117 # If the process has died, try to delete its info file
1118 try:
1118 try:
1119 os.unlink(file)
1119 os.unlink(file)
1120 except OSError:
1120 except OSError:
1121 pass # TODO: This should warn or log or something
1121 pass # TODO: This should warn or log or something
1122 #-----------------------------------------------------------------------------
1122 #-----------------------------------------------------------------------------
1123 # Main entry point
1123 # Main entry point
1124 #-----------------------------------------------------------------------------
1124 #-----------------------------------------------------------------------------
1125
1125
1126 launch_new_instance = NotebookApp.launch_instance
1126 launch_new_instance = NotebookApp.launch_instance
1127
1127
@@ -1,162 +1,162 b''
1 """Manage IPython.parallel clusters in the notebook."""
1 """Manage IPython.parallel clusters in the notebook."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from tornado import web
6 from tornado import web
7
7
8 from IPython.config.configurable import LoggingConfigurable
8 from IPython.config.configurable import LoggingConfigurable
9 from IPython.utils.traitlets import Dict, Instance, Float
9 from IPython.utils.traitlets import Dict, Instance, Float
10 from IPython.core.profileapp import list_profiles_in
10 from IPython.core.profileapp import list_profiles_in
11 from IPython.core.profiledir import ProfileDir
11 from IPython.core.profiledir import ProfileDir
12 from IPython.utils import py3compat
12 from IPython.utils import py3compat
13 from IPython.utils.path import get_ipython_dir
13 from IPython.utils.path import get_ipython_dir
14
14
15
15
16 class ClusterManager(LoggingConfigurable):
16 class ClusterManager(LoggingConfigurable):
17
17
18 profiles = Dict()
18 profiles = Dict()
19
19
20 delay = Float(1., config=True,
20 delay = Float(1., config=True,
21 help="delay (in s) between starting the controller and the engines")
21 help="delay (in s) between starting the controller and the engines")
22
22
23 loop = Instance('zmq.eventloop.ioloop.IOLoop')
23 loop = Instance('zmq.eventloop.ioloop.IOLoop', allow_none=True)
24 def _loop_default(self):
24 def _loop_default(self):
25 from zmq.eventloop.ioloop import IOLoop
25 from zmq.eventloop.ioloop import IOLoop
26 return IOLoop.instance()
26 return IOLoop.instance()
27
27
28 def build_launchers(self, profile_dir):
28 def build_launchers(self, profile_dir):
29 from IPython.parallel.apps.ipclusterapp import IPClusterStart
29 from IPython.parallel.apps.ipclusterapp import IPClusterStart
30
30
31 class DummyIPClusterStart(IPClusterStart):
31 class DummyIPClusterStart(IPClusterStart):
32 """Dummy subclass to skip init steps that conflict with global app.
32 """Dummy subclass to skip init steps that conflict with global app.
33
33
34 Instantiating and initializing this class should result in fully configured
34 Instantiating and initializing this class should result in fully configured
35 launchers, but no other side effects or state.
35 launchers, but no other side effects or state.
36 """
36 """
37
37
38 def init_signal(self):
38 def init_signal(self):
39 pass
39 pass
40 def reinit_logging(self):
40 def reinit_logging(self):
41 pass
41 pass
42
42
43 starter = DummyIPClusterStart(log=self.log)
43 starter = DummyIPClusterStart(log=self.log)
44 starter.initialize(['--profile-dir', profile_dir])
44 starter.initialize(['--profile-dir', profile_dir])
45 cl = starter.controller_launcher
45 cl = starter.controller_launcher
46 esl = starter.engine_launcher
46 esl = starter.engine_launcher
47 n = starter.n
47 n = starter.n
48 return cl, esl, n
48 return cl, esl, n
49
49
50 def get_profile_dir(self, name, path):
50 def get_profile_dir(self, name, path):
51 p = ProfileDir.find_profile_dir_by_name(path,name=name)
51 p = ProfileDir.find_profile_dir_by_name(path,name=name)
52 return p.location
52 return p.location
53
53
54 def update_profiles(self):
54 def update_profiles(self):
55 """List all profiles in the ipython_dir and cwd.
55 """List all profiles in the ipython_dir and cwd.
56 """
56 """
57
57
58 stale = set(self.profiles)
58 stale = set(self.profiles)
59 for path in [get_ipython_dir(), py3compat.getcwd()]:
59 for path in [get_ipython_dir(), py3compat.getcwd()]:
60 for profile in list_profiles_in(path):
60 for profile in list_profiles_in(path):
61 if profile in stale:
61 if profile in stale:
62 stale.remove(profile)
62 stale.remove(profile)
63 pd = self.get_profile_dir(profile, path)
63 pd = self.get_profile_dir(profile, path)
64 if profile not in self.profiles:
64 if profile not in self.profiles:
65 self.log.debug("Adding cluster profile '%s'", profile)
65 self.log.debug("Adding cluster profile '%s'", profile)
66 self.profiles[profile] = {
66 self.profiles[profile] = {
67 'profile': profile,
67 'profile': profile,
68 'profile_dir': pd,
68 'profile_dir': pd,
69 'status': 'stopped'
69 'status': 'stopped'
70 }
70 }
71 for profile in stale:
71 for profile in stale:
72 # remove profiles that no longer exist
72 # remove profiles that no longer exist
73 self.log.debug("Profile '%s' no longer exists", profile)
73 self.log.debug("Profile '%s' no longer exists", profile)
74 self.profiles.pop(stale)
74 self.profiles.pop(stale)
75
75
76 def list_profiles(self):
76 def list_profiles(self):
77 self.update_profiles()
77 self.update_profiles()
78 # sorted list, but ensure that 'default' always comes first
78 # sorted list, but ensure that 'default' always comes first
79 default_first = lambda name: name if name != 'default' else ''
79 default_first = lambda name: name if name != 'default' else ''
80 result = [self.profile_info(p) for p in sorted(self.profiles, key=default_first)]
80 result = [self.profile_info(p) for p in sorted(self.profiles, key=default_first)]
81 return result
81 return result
82
82
83 def check_profile(self, profile):
83 def check_profile(self, profile):
84 if profile not in self.profiles:
84 if profile not in self.profiles:
85 raise web.HTTPError(404, u'profile not found')
85 raise web.HTTPError(404, u'profile not found')
86
86
87 def profile_info(self, profile):
87 def profile_info(self, profile):
88 self.check_profile(profile)
88 self.check_profile(profile)
89 result = {}
89 result = {}
90 data = self.profiles.get(profile)
90 data = self.profiles.get(profile)
91 result['profile'] = profile
91 result['profile'] = profile
92 result['profile_dir'] = data['profile_dir']
92 result['profile_dir'] = data['profile_dir']
93 result['status'] = data['status']
93 result['status'] = data['status']
94 if 'n' in data:
94 if 'n' in data:
95 result['n'] = data['n']
95 result['n'] = data['n']
96 return result
96 return result
97
97
98 def start_cluster(self, profile, n=None):
98 def start_cluster(self, profile, n=None):
99 """Start a cluster for a given profile."""
99 """Start a cluster for a given profile."""
100 self.check_profile(profile)
100 self.check_profile(profile)
101 data = self.profiles[profile]
101 data = self.profiles[profile]
102 if data['status'] == 'running':
102 if data['status'] == 'running':
103 raise web.HTTPError(409, u'cluster already running')
103 raise web.HTTPError(409, u'cluster already running')
104 cl, esl, default_n = self.build_launchers(data['profile_dir'])
104 cl, esl, default_n = self.build_launchers(data['profile_dir'])
105 n = n if n is not None else default_n
105 n = n if n is not None else default_n
106 def clean_data():
106 def clean_data():
107 data.pop('controller_launcher',None)
107 data.pop('controller_launcher',None)
108 data.pop('engine_set_launcher',None)
108 data.pop('engine_set_launcher',None)
109 data.pop('n',None)
109 data.pop('n',None)
110 data['status'] = 'stopped'
110 data['status'] = 'stopped'
111 def engines_stopped(r):
111 def engines_stopped(r):
112 self.log.debug('Engines stopped')
112 self.log.debug('Engines stopped')
113 if cl.running:
113 if cl.running:
114 cl.stop()
114 cl.stop()
115 clean_data()
115 clean_data()
116 esl.on_stop(engines_stopped)
116 esl.on_stop(engines_stopped)
117 def controller_stopped(r):
117 def controller_stopped(r):
118 self.log.debug('Controller stopped')
118 self.log.debug('Controller stopped')
119 if esl.running:
119 if esl.running:
120 esl.stop()
120 esl.stop()
121 clean_data()
121 clean_data()
122 cl.on_stop(controller_stopped)
122 cl.on_stop(controller_stopped)
123 loop = self.loop
123 loop = self.loop
124
124
125 def start():
125 def start():
126 """start the controller, then the engines after a delay"""
126 """start the controller, then the engines after a delay"""
127 cl.start()
127 cl.start()
128 loop.add_timeout(self.loop.time() + self.delay, lambda : esl.start(n))
128 loop.add_timeout(self.loop.time() + self.delay, lambda : esl.start(n))
129 self.loop.add_callback(start)
129 self.loop.add_callback(start)
130
130
131 self.log.debug('Cluster started')
131 self.log.debug('Cluster started')
132 data['controller_launcher'] = cl
132 data['controller_launcher'] = cl
133 data['engine_set_launcher'] = esl
133 data['engine_set_launcher'] = esl
134 data['n'] = n
134 data['n'] = n
135 data['status'] = 'running'
135 data['status'] = 'running'
136 return self.profile_info(profile)
136 return self.profile_info(profile)
137
137
138 def stop_cluster(self, profile):
138 def stop_cluster(self, profile):
139 """Stop a cluster for a given profile."""
139 """Stop a cluster for a given profile."""
140 self.check_profile(profile)
140 self.check_profile(profile)
141 data = self.profiles[profile]
141 data = self.profiles[profile]
142 if data['status'] == 'stopped':
142 if data['status'] == 'stopped':
143 raise web.HTTPError(409, u'cluster not running')
143 raise web.HTTPError(409, u'cluster not running')
144 data = self.profiles[profile]
144 data = self.profiles[profile]
145 cl = data['controller_launcher']
145 cl = data['controller_launcher']
146 esl = data['engine_set_launcher']
146 esl = data['engine_set_launcher']
147 if cl.running:
147 if cl.running:
148 cl.stop()
148 cl.stop()
149 if esl.running:
149 if esl.running:
150 esl.stop()
150 esl.stop()
151 # Return a temp info dict, the real one is updated in the on_stop
151 # Return a temp info dict, the real one is updated in the on_stop
152 # logic above.
152 # logic above.
153 result = {
153 result = {
154 'profile': data['profile'],
154 'profile': data['profile'],
155 'profile_dir': data['profile_dir'],
155 'profile_dir': data['profile_dir'],
156 'status': 'stopped'
156 'status': 'stopped'
157 }
157 }
158 return result
158 return result
159
159
160 def stop_all_clusters(self):
160 def stop_all_clusters(self):
161 for p in self.profiles.keys():
161 for p in self.profiles.keys():
162 self.stop_cluster(p)
162 self.stop_cluster(p)
@@ -1,497 +1,497 b''
1 """Base Widget class. Allows user to create widgets in the back-end that render
1 """Base Widget class. Allows user to create widgets in the back-end that render
2 in the IPython notebook front-end.
2 in the IPython notebook front-end.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # 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.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from contextlib import contextmanager
15 from contextlib import contextmanager
16 import collections
16 import collections
17
17
18 from IPython.core.getipython import get_ipython
18 from IPython.core.getipython import get_ipython
19 from IPython.kernel.comm import Comm
19 from IPython.kernel.comm import Comm
20 from IPython.config import LoggingConfigurable
20 from IPython.config import LoggingConfigurable
21 from IPython.utils.importstring import import_item
21 from IPython.utils.importstring import import_item
22 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, \
22 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, \
23 CaselessStrEnum, Tuple, CUnicode, Int, Set
23 CaselessStrEnum, Tuple, CUnicode, Int, Set
24 from IPython.utils.py3compat import string_types
24 from IPython.utils.py3compat import string_types
25 from .trait_types import Color
25 from .trait_types import Color
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Classes
28 # Classes
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 class CallbackDispatcher(LoggingConfigurable):
30 class CallbackDispatcher(LoggingConfigurable):
31 """A structure for registering and running callbacks"""
31 """A structure for registering and running callbacks"""
32 callbacks = List()
32 callbacks = List()
33
33
34 def __call__(self, *args, **kwargs):
34 def __call__(self, *args, **kwargs):
35 """Call all of the registered callbacks."""
35 """Call all of the registered callbacks."""
36 value = None
36 value = None
37 for callback in self.callbacks:
37 for callback in self.callbacks:
38 try:
38 try:
39 local_value = callback(*args, **kwargs)
39 local_value = callback(*args, **kwargs)
40 except Exception as e:
40 except Exception as e:
41 ip = get_ipython()
41 ip = get_ipython()
42 if ip is None:
42 if ip is None:
43 self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
43 self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
44 else:
44 else:
45 ip.showtraceback()
45 ip.showtraceback()
46 else:
46 else:
47 value = local_value if local_value is not None else value
47 value = local_value if local_value is not None else value
48 return value
48 return value
49
49
50 def register_callback(self, callback, remove=False):
50 def register_callback(self, callback, remove=False):
51 """(Un)Register a callback
51 """(Un)Register a callback
52
52
53 Parameters
53 Parameters
54 ----------
54 ----------
55 callback: method handle
55 callback: method handle
56 Method to be registered or unregistered.
56 Method to be registered or unregistered.
57 remove=False: bool
57 remove=False: bool
58 Whether to unregister the callback."""
58 Whether to unregister the callback."""
59
59
60 # (Un)Register the callback.
60 # (Un)Register the callback.
61 if remove and callback in self.callbacks:
61 if remove and callback in self.callbacks:
62 self.callbacks.remove(callback)
62 self.callbacks.remove(callback)
63 elif not remove and callback not in self.callbacks:
63 elif not remove and callback not in self.callbacks:
64 self.callbacks.append(callback)
64 self.callbacks.append(callback)
65
65
66 def _show_traceback(method):
66 def _show_traceback(method):
67 """decorator for showing tracebacks in IPython"""
67 """decorator for showing tracebacks in IPython"""
68 def m(self, *args, **kwargs):
68 def m(self, *args, **kwargs):
69 try:
69 try:
70 return(method(self, *args, **kwargs))
70 return(method(self, *args, **kwargs))
71 except Exception as e:
71 except Exception as e:
72 ip = get_ipython()
72 ip = get_ipython()
73 if ip is None:
73 if ip is None:
74 self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
74 self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
75 else:
75 else:
76 ip.showtraceback()
76 ip.showtraceback()
77 return m
77 return m
78
78
79
79
80 def register(key=None):
80 def register(key=None):
81 """Returns a decorator registering a widget class in the widget registry.
81 """Returns a decorator registering a widget class in the widget registry.
82 If no key is provided, the class name is used as a key. A key is
82 If no key is provided, the class name is used as a key. A key is
83 provided for each core IPython widget so that the frontend can use
83 provided for each core IPython widget so that the frontend can use
84 this key regardless of the language of the kernel"""
84 this key regardless of the language of the kernel"""
85 def wrap(widget):
85 def wrap(widget):
86 l = key if key is not None else widget.__module__ + widget.__name__
86 l = key if key is not None else widget.__module__ + widget.__name__
87 Widget.widget_types[l] = widget
87 Widget.widget_types[l] = widget
88 return widget
88 return widget
89 return wrap
89 return wrap
90
90
91
91
92 class Widget(LoggingConfigurable):
92 class Widget(LoggingConfigurable):
93 #-------------------------------------------------------------------------
93 #-------------------------------------------------------------------------
94 # Class attributes
94 # Class attributes
95 #-------------------------------------------------------------------------
95 #-------------------------------------------------------------------------
96 _widget_construction_callback = None
96 _widget_construction_callback = None
97 widgets = {}
97 widgets = {}
98 widget_types = {}
98 widget_types = {}
99
99
100 @staticmethod
100 @staticmethod
101 def on_widget_constructed(callback):
101 def on_widget_constructed(callback):
102 """Registers a callback to be called when a widget is constructed.
102 """Registers a callback to be called when a widget is constructed.
103
103
104 The callback must have the following signature:
104 The callback must have the following signature:
105 callback(widget)"""
105 callback(widget)"""
106 Widget._widget_construction_callback = callback
106 Widget._widget_construction_callback = callback
107
107
108 @staticmethod
108 @staticmethod
109 def _call_widget_constructed(widget):
109 def _call_widget_constructed(widget):
110 """Static method, called when a widget is constructed."""
110 """Static method, called when a widget is constructed."""
111 if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
111 if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
112 Widget._widget_construction_callback(widget)
112 Widget._widget_construction_callback(widget)
113
113
114 @staticmethod
114 @staticmethod
115 def handle_comm_opened(comm, msg):
115 def handle_comm_opened(comm, msg):
116 """Static method, called when a widget is constructed."""
116 """Static method, called when a widget is constructed."""
117 widget_class = import_item(msg['content']['data']['widget_class'])
117 widget_class = import_item(msg['content']['data']['widget_class'])
118 widget = widget_class(comm=comm)
118 widget = widget_class(comm=comm)
119
119
120
120
121 #-------------------------------------------------------------------------
121 #-------------------------------------------------------------------------
122 # Traits
122 # Traits
123 #-------------------------------------------------------------------------
123 #-------------------------------------------------------------------------
124 _model_module = Unicode(None, allow_none=True, help="""A requirejs module name
124 _model_module = Unicode(None, allow_none=True, help="""A requirejs module name
125 in which to find _model_name. If empty, look in the global registry.""")
125 in which to find _model_name. If empty, look in the global registry.""")
126 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
126 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
127 registered in the front-end to create and sync this widget with.""")
127 registered in the front-end to create and sync this widget with.""")
128 _view_module = Unicode(help="""A requirejs module in which to find _view_name.
128 _view_module = Unicode(help="""A requirejs module in which to find _view_name.
129 If empty, look in the global registry.""", sync=True)
129 If empty, look in the global registry.""", sync=True)
130 _view_name = Unicode(None, allow_none=True, help="""Default view registered in the front-end
130 _view_name = Unicode(None, allow_none=True, help="""Default view registered in the front-end
131 to use to represent the widget.""", sync=True)
131 to use to represent the widget.""", sync=True)
132 comm = Instance('IPython.kernel.comm.Comm')
132 comm = Instance('IPython.kernel.comm.Comm', allow_none=True)
133
133
134 msg_throttle = Int(3, sync=True, help="""Maximum number of msgs the
134 msg_throttle = Int(3, sync=True, help="""Maximum number of msgs the
135 front-end can send before receiving an idle msg from the back-end.""")
135 front-end can send before receiving an idle msg from the back-end.""")
136
136
137 version = Int(0, sync=True, help="""Widget's version""")
137 version = Int(0, sync=True, help="""Widget's version""")
138 keys = List()
138 keys = List()
139 def _keys_default(self):
139 def _keys_default(self):
140 return [name for name in self.traits(sync=True)]
140 return [name for name in self.traits(sync=True)]
141
141
142 _property_lock = Tuple((None, None))
142 _property_lock = Tuple((None, None))
143 _send_state_lock = Int(0)
143 _send_state_lock = Int(0)
144 _states_to_send = Set()
144 _states_to_send = Set()
145 _display_callbacks = Instance(CallbackDispatcher, ())
145 _display_callbacks = Instance(CallbackDispatcher, ())
146 _msg_callbacks = Instance(CallbackDispatcher, ())
146 _msg_callbacks = Instance(CallbackDispatcher, ())
147
147
148 #-------------------------------------------------------------------------
148 #-------------------------------------------------------------------------
149 # (Con/de)structor
149 # (Con/de)structor
150 #-------------------------------------------------------------------------
150 #-------------------------------------------------------------------------
151 def __init__(self, **kwargs):
151 def __init__(self, **kwargs):
152 """Public constructor"""
152 """Public constructor"""
153 self._model_id = kwargs.pop('model_id', None)
153 self._model_id = kwargs.pop('model_id', None)
154 super(Widget, self).__init__(**kwargs)
154 super(Widget, self).__init__(**kwargs)
155
155
156 Widget._call_widget_constructed(self)
156 Widget._call_widget_constructed(self)
157 self.open()
157 self.open()
158
158
159 def __del__(self):
159 def __del__(self):
160 """Object disposal"""
160 """Object disposal"""
161 self.close()
161 self.close()
162
162
163 #-------------------------------------------------------------------------
163 #-------------------------------------------------------------------------
164 # Properties
164 # Properties
165 #-------------------------------------------------------------------------
165 #-------------------------------------------------------------------------
166
166
167 def open(self):
167 def open(self):
168 """Open a comm to the frontend if one isn't already open."""
168 """Open a comm to the frontend if one isn't already open."""
169 if self.comm is None:
169 if self.comm is None:
170 args = dict(target_name='ipython.widget',
170 args = dict(target_name='ipython.widget',
171 data={'model_name': self._model_name,
171 data={'model_name': self._model_name,
172 'model_module': self._model_module})
172 'model_module': self._model_module})
173 if self._model_id is not None:
173 if self._model_id is not None:
174 args['comm_id'] = self._model_id
174 args['comm_id'] = self._model_id
175 self.comm = Comm(**args)
175 self.comm = Comm(**args)
176
176
177 def _comm_changed(self, name, new):
177 def _comm_changed(self, name, new):
178 """Called when the comm is changed."""
178 """Called when the comm is changed."""
179 if new is None:
179 if new is None:
180 return
180 return
181 self._model_id = self.model_id
181 self._model_id = self.model_id
182
182
183 self.comm.on_msg(self._handle_msg)
183 self.comm.on_msg(self._handle_msg)
184 Widget.widgets[self.model_id] = self
184 Widget.widgets[self.model_id] = self
185
185
186 # first update
186 # first update
187 self.send_state()
187 self.send_state()
188
188
189 @property
189 @property
190 def model_id(self):
190 def model_id(self):
191 """Gets the model id of this widget.
191 """Gets the model id of this widget.
192
192
193 If a Comm doesn't exist yet, a Comm will be created automagically."""
193 If a Comm doesn't exist yet, a Comm will be created automagically."""
194 return self.comm.comm_id
194 return self.comm.comm_id
195
195
196 #-------------------------------------------------------------------------
196 #-------------------------------------------------------------------------
197 # Methods
197 # Methods
198 #-------------------------------------------------------------------------
198 #-------------------------------------------------------------------------
199
199
200 def close(self):
200 def close(self):
201 """Close method.
201 """Close method.
202
202
203 Closes the underlying comm.
203 Closes the underlying comm.
204 When the comm is closed, all of the widget views are automatically
204 When the comm is closed, all of the widget views are automatically
205 removed from the front-end."""
205 removed from the front-end."""
206 if self.comm is not None:
206 if self.comm is not None:
207 Widget.widgets.pop(self.model_id, None)
207 Widget.widgets.pop(self.model_id, None)
208 self.comm.close()
208 self.comm.close()
209 self.comm = None
209 self.comm = None
210
210
211 def send_state(self, key=None):
211 def send_state(self, key=None):
212 """Sends the widget state, or a piece of it, to the front-end.
212 """Sends the widget state, or a piece of it, to the front-end.
213
213
214 Parameters
214 Parameters
215 ----------
215 ----------
216 key : unicode, or iterable (optional)
216 key : unicode, or iterable (optional)
217 A single property's name or iterable of property names to sync with the front-end.
217 A single property's name or iterable of property names to sync with the front-end.
218 """
218 """
219 self._send({
219 self._send({
220 "method" : "update",
220 "method" : "update",
221 "state" : self.get_state(key=key)
221 "state" : self.get_state(key=key)
222 })
222 })
223
223
224 def get_state(self, key=None):
224 def get_state(self, key=None):
225 """Gets the widget state, or a piece of it.
225 """Gets the widget state, or a piece of it.
226
226
227 Parameters
227 Parameters
228 ----------
228 ----------
229 key : unicode or iterable (optional)
229 key : unicode or iterable (optional)
230 A single property's name or iterable of property names to get.
230 A single property's name or iterable of property names to get.
231 """
231 """
232 if key is None:
232 if key is None:
233 keys = self.keys
233 keys = self.keys
234 elif isinstance(key, string_types):
234 elif isinstance(key, string_types):
235 keys = [key]
235 keys = [key]
236 elif isinstance(key, collections.Iterable):
236 elif isinstance(key, collections.Iterable):
237 keys = key
237 keys = key
238 else:
238 else:
239 raise ValueError("key must be a string, an iterable of keys, or None")
239 raise ValueError("key must be a string, an iterable of keys, or None")
240 state = {}
240 state = {}
241 for k in keys:
241 for k in keys:
242 f = self.trait_metadata(k, 'to_json', self._trait_to_json)
242 f = self.trait_metadata(k, 'to_json', self._trait_to_json)
243 value = getattr(self, k)
243 value = getattr(self, k)
244 state[k] = f(value)
244 state[k] = f(value)
245 return state
245 return state
246
246
247 def set_state(self, sync_data):
247 def set_state(self, sync_data):
248 """Called when a state is received from the front-end."""
248 """Called when a state is received from the front-end."""
249 for name in self.keys:
249 for name in self.keys:
250 if name in sync_data:
250 if name in sync_data:
251 json_value = sync_data[name]
251 json_value = sync_data[name]
252 from_json = self.trait_metadata(name, 'from_json', self._trait_from_json)
252 from_json = self.trait_metadata(name, 'from_json', self._trait_from_json)
253 with self._lock_property(name, json_value):
253 with self._lock_property(name, json_value):
254 setattr(self, name, from_json(json_value))
254 setattr(self, name, from_json(json_value))
255
255
256 def send(self, content):
256 def send(self, content):
257 """Sends a custom msg to the widget model in the front-end.
257 """Sends a custom msg to the widget model in the front-end.
258
258
259 Parameters
259 Parameters
260 ----------
260 ----------
261 content : dict
261 content : dict
262 Content of the message to send.
262 Content of the message to send.
263 """
263 """
264 self._send({"method": "custom", "content": content})
264 self._send({"method": "custom", "content": content})
265
265
266 def on_msg(self, callback, remove=False):
266 def on_msg(self, callback, remove=False):
267 """(Un)Register a custom msg receive callback.
267 """(Un)Register a custom msg receive callback.
268
268
269 Parameters
269 Parameters
270 ----------
270 ----------
271 callback: callable
271 callback: callable
272 callback will be passed two arguments when a message arrives::
272 callback will be passed two arguments when a message arrives::
273
273
274 callback(widget, content)
274 callback(widget, content)
275
275
276 remove: bool
276 remove: bool
277 True if the callback should be unregistered."""
277 True if the callback should be unregistered."""
278 self._msg_callbacks.register_callback(callback, remove=remove)
278 self._msg_callbacks.register_callback(callback, remove=remove)
279
279
280 def on_displayed(self, callback, remove=False):
280 def on_displayed(self, callback, remove=False):
281 """(Un)Register a widget displayed callback.
281 """(Un)Register a widget displayed callback.
282
282
283 Parameters
283 Parameters
284 ----------
284 ----------
285 callback: method handler
285 callback: method handler
286 Must have a signature of::
286 Must have a signature of::
287
287
288 callback(widget, **kwargs)
288 callback(widget, **kwargs)
289
289
290 kwargs from display are passed through without modification.
290 kwargs from display are passed through without modification.
291 remove: bool
291 remove: bool
292 True if the callback should be unregistered."""
292 True if the callback should be unregistered."""
293 self._display_callbacks.register_callback(callback, remove=remove)
293 self._display_callbacks.register_callback(callback, remove=remove)
294
294
295 def add_trait(self, traitname, trait):
295 def add_trait(self, traitname, trait):
296 """Dynamically add a trait attribute to the Widget."""
296 """Dynamically add a trait attribute to the Widget."""
297 super(Widget, self).add_trait(traitname, trait)
297 super(Widget, self).add_trait(traitname, trait)
298 if trait.get_metadata('sync'):
298 if trait.get_metadata('sync'):
299 self.keys.append(traitname)
299 self.keys.append(traitname)
300 self.send_state(traitname)
300 self.send_state(traitname)
301
301
302 #-------------------------------------------------------------------------
302 #-------------------------------------------------------------------------
303 # Support methods
303 # Support methods
304 #-------------------------------------------------------------------------
304 #-------------------------------------------------------------------------
305 @contextmanager
305 @contextmanager
306 def _lock_property(self, key, value):
306 def _lock_property(self, key, value):
307 """Lock a property-value pair.
307 """Lock a property-value pair.
308
308
309 The value should be the JSON state of the property.
309 The value should be the JSON state of the property.
310
310
311 NOTE: This, in addition to the single lock for all state changes, is
311 NOTE: This, in addition to the single lock for all state changes, is
312 flawed. In the future we may want to look into buffering state changes
312 flawed. In the future we may want to look into buffering state changes
313 back to the front-end."""
313 back to the front-end."""
314 self._property_lock = (key, value)
314 self._property_lock = (key, value)
315 try:
315 try:
316 yield
316 yield
317 finally:
317 finally:
318 self._property_lock = (None, None)
318 self._property_lock = (None, None)
319
319
320 @contextmanager
320 @contextmanager
321 def hold_sync(self):
321 def hold_sync(self):
322 """Hold syncing any state until the context manager is released"""
322 """Hold syncing any state until the context manager is released"""
323 # We increment a value so that this can be nested. Syncing will happen when
323 # We increment a value so that this can be nested. Syncing will happen when
324 # all levels have been released.
324 # all levels have been released.
325 self._send_state_lock += 1
325 self._send_state_lock += 1
326 try:
326 try:
327 yield
327 yield
328 finally:
328 finally:
329 self._send_state_lock -=1
329 self._send_state_lock -=1
330 if self._send_state_lock == 0:
330 if self._send_state_lock == 0:
331 self.send_state(self._states_to_send)
331 self.send_state(self._states_to_send)
332 self._states_to_send.clear()
332 self._states_to_send.clear()
333
333
334 def _should_send_property(self, key, value):
334 def _should_send_property(self, key, value):
335 """Check the property lock (property_lock)"""
335 """Check the property lock (property_lock)"""
336 to_json = self.trait_metadata(key, 'to_json', self._trait_to_json)
336 to_json = self.trait_metadata(key, 'to_json', self._trait_to_json)
337 if (key == self._property_lock[0]
337 if (key == self._property_lock[0]
338 and to_json(value) == self._property_lock[1]):
338 and to_json(value) == self._property_lock[1]):
339 return False
339 return False
340 elif self._send_state_lock > 0:
340 elif self._send_state_lock > 0:
341 self._states_to_send.add(key)
341 self._states_to_send.add(key)
342 return False
342 return False
343 else:
343 else:
344 return True
344 return True
345
345
346 # Event handlers
346 # Event handlers
347 @_show_traceback
347 @_show_traceback
348 def _handle_msg(self, msg):
348 def _handle_msg(self, msg):
349 """Called when a msg is received from the front-end"""
349 """Called when a msg is received from the front-end"""
350 data = msg['content']['data']
350 data = msg['content']['data']
351 method = data['method']
351 method = data['method']
352
352
353 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
353 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
354 if method == 'backbone':
354 if method == 'backbone':
355 if 'sync_data' in data:
355 if 'sync_data' in data:
356 sync_data = data['sync_data']
356 sync_data = data['sync_data']
357 self.set_state(sync_data) # handles all methods
357 self.set_state(sync_data) # handles all methods
358
358
359 # Handle a state request.
359 # Handle a state request.
360 elif method == 'request_state':
360 elif method == 'request_state':
361 self.send_state()
361 self.send_state()
362
362
363 # Handle a custom msg from the front-end.
363 # Handle a custom msg from the front-end.
364 elif method == 'custom':
364 elif method == 'custom':
365 if 'content' in data:
365 if 'content' in data:
366 self._handle_custom_msg(data['content'])
366 self._handle_custom_msg(data['content'])
367
367
368 # Catch remainder.
368 # Catch remainder.
369 else:
369 else:
370 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
370 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
371
371
372 def _handle_custom_msg(self, content):
372 def _handle_custom_msg(self, content):
373 """Called when a custom msg is received."""
373 """Called when a custom msg is received."""
374 self._msg_callbacks(self, content)
374 self._msg_callbacks(self, content)
375
375
376 def _notify_trait(self, name, old_value, new_value):
376 def _notify_trait(self, name, old_value, new_value):
377 """Called when a property has been changed."""
377 """Called when a property has been changed."""
378 # Trigger default traitlet callback machinery. This allows any user
378 # Trigger default traitlet callback machinery. This allows any user
379 # registered validation to be processed prior to allowing the widget
379 # registered validation to be processed prior to allowing the widget
380 # machinery to handle the state.
380 # machinery to handle the state.
381 LoggingConfigurable._notify_trait(self, name, old_value, new_value)
381 LoggingConfigurable._notify_trait(self, name, old_value, new_value)
382
382
383 # Send the state after the user registered callbacks for trait changes
383 # Send the state after the user registered callbacks for trait changes
384 # have all fired (allows for user to validate values).
384 # have all fired (allows for user to validate values).
385 if self.comm is not None and name in self.keys:
385 if self.comm is not None and name in self.keys:
386 # Make sure this isn't information that the front-end just sent us.
386 # Make sure this isn't information that the front-end just sent us.
387 if self._should_send_property(name, new_value):
387 if self._should_send_property(name, new_value):
388 # Send new state to front-end
388 # Send new state to front-end
389 self.send_state(key=name)
389 self.send_state(key=name)
390
390
391 def _handle_displayed(self, **kwargs):
391 def _handle_displayed(self, **kwargs):
392 """Called when a view has been displayed for this widget instance"""
392 """Called when a view has been displayed for this widget instance"""
393 self._display_callbacks(self, **kwargs)
393 self._display_callbacks(self, **kwargs)
394
394
395 def _trait_to_json(self, x):
395 def _trait_to_json(self, x):
396 """Convert a trait value to json
396 """Convert a trait value to json
397
397
398 Traverse lists/tuples and dicts and serialize their values as well.
398 Traverse lists/tuples and dicts and serialize their values as well.
399 Replace any widgets with their model_id
399 Replace any widgets with their model_id
400 """
400 """
401 if isinstance(x, dict):
401 if isinstance(x, dict):
402 return {k: self._trait_to_json(v) for k, v in x.items()}
402 return {k: self._trait_to_json(v) for k, v in x.items()}
403 elif isinstance(x, (list, tuple)):
403 elif isinstance(x, (list, tuple)):
404 return [self._trait_to_json(v) for v in x]
404 return [self._trait_to_json(v) for v in x]
405 elif isinstance(x, Widget):
405 elif isinstance(x, Widget):
406 return "IPY_MODEL_" + x.model_id
406 return "IPY_MODEL_" + x.model_id
407 else:
407 else:
408 return x # Value must be JSON-able
408 return x # Value must be JSON-able
409
409
410 def _trait_from_json(self, x):
410 def _trait_from_json(self, x):
411 """Convert json values to objects
411 """Convert json values to objects
412
412
413 Replace any strings representing valid model id values to Widget references.
413 Replace any strings representing valid model id values to Widget references.
414 """
414 """
415 if isinstance(x, dict):
415 if isinstance(x, dict):
416 return {k: self._trait_from_json(v) for k, v in x.items()}
416 return {k: self._trait_from_json(v) for k, v in x.items()}
417 elif isinstance(x, (list, tuple)):
417 elif isinstance(x, (list, tuple)):
418 return [self._trait_from_json(v) for v in x]
418 return [self._trait_from_json(v) for v in x]
419 elif isinstance(x, string_types) and x.startswith('IPY_MODEL_') and x[10:] in Widget.widgets:
419 elif isinstance(x, string_types) and x.startswith('IPY_MODEL_') and x[10:] in Widget.widgets:
420 # we want to support having child widgets at any level in a hierarchy
420 # we want to support having child widgets at any level in a hierarchy
421 # trusting that a widget UUID will not appear out in the wild
421 # trusting that a widget UUID will not appear out in the wild
422 return Widget.widgets[x[10:]]
422 return Widget.widgets[x[10:]]
423 else:
423 else:
424 return x
424 return x
425
425
426 def _ipython_display_(self, **kwargs):
426 def _ipython_display_(self, **kwargs):
427 """Called when `IPython.display.display` is called on the widget."""
427 """Called when `IPython.display.display` is called on the widget."""
428 # Show view.
428 # Show view.
429 if self._view_name is not None:
429 if self._view_name is not None:
430 self._send({"method": "display"})
430 self._send({"method": "display"})
431 self._handle_displayed(**kwargs)
431 self._handle_displayed(**kwargs)
432
432
433 def _send(self, msg):
433 def _send(self, msg):
434 """Sends a message to the model in the front-end."""
434 """Sends a message to the model in the front-end."""
435 self.comm.send(msg)
435 self.comm.send(msg)
436
436
437
437
438 class DOMWidget(Widget):
438 class DOMWidget(Widget):
439 visible = Bool(True, allow_none=True, help="Whether the widget is visible. False collapses the empty space, while None preserves the empty space.", sync=True)
439 visible = Bool(True, allow_none=True, help="Whether the widget is visible. False collapses the empty space, while None preserves the empty space.", sync=True)
440 _css = Tuple(sync=True, help="CSS property list: (selector, key, value)")
440 _css = Tuple(sync=True, help="CSS property list: (selector, key, value)")
441 _dom_classes = Tuple(sync=True, help="DOM classes applied to widget.$el.")
441 _dom_classes = Tuple(sync=True, help="DOM classes applied to widget.$el.")
442
442
443 width = CUnicode(sync=True)
443 width = CUnicode(sync=True)
444 height = CUnicode(sync=True)
444 height = CUnicode(sync=True)
445 # A default padding of 2.5 px makes the widgets look nice when displayed inline.
445 # A default padding of 2.5 px makes the widgets look nice when displayed inline.
446 padding = CUnicode(sync=True)
446 padding = CUnicode(sync=True)
447 margin = CUnicode(sync=True)
447 margin = CUnicode(sync=True)
448
448
449 color = Color(None, allow_none=True, sync=True)
449 color = Color(None, allow_none=True, sync=True)
450 background_color = Color(None, allow_none=True, sync=True)
450 background_color = Color(None, allow_none=True, sync=True)
451 border_color = Color(None, allow_none=True, sync=True)
451 border_color = Color(None, allow_none=True, sync=True)
452
452
453 border_width = CUnicode(sync=True)
453 border_width = CUnicode(sync=True)
454 border_radius = CUnicode(sync=True)
454 border_radius = CUnicode(sync=True)
455 border_style = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_border-style.asp
455 border_style = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_border-style.asp
456 'none',
456 'none',
457 'hidden',
457 'hidden',
458 'dotted',
458 'dotted',
459 'dashed',
459 'dashed',
460 'solid',
460 'solid',
461 'double',
461 'double',
462 'groove',
462 'groove',
463 'ridge',
463 'ridge',
464 'inset',
464 'inset',
465 'outset',
465 'outset',
466 'initial',
466 'initial',
467 'inherit', ''],
467 'inherit', ''],
468 default_value='', sync=True)
468 default_value='', sync=True)
469
469
470 font_style = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_font_font-style.asp
470 font_style = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_font_font-style.asp
471 'normal',
471 'normal',
472 'italic',
472 'italic',
473 'oblique',
473 'oblique',
474 'initial',
474 'initial',
475 'inherit', ''],
475 'inherit', ''],
476 default_value='', sync=True)
476 default_value='', sync=True)
477 font_weight = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_font_weight.asp
477 font_weight = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_font_weight.asp
478 'normal',
478 'normal',
479 'bold',
479 'bold',
480 'bolder',
480 'bolder',
481 'lighter',
481 'lighter',
482 'initial',
482 'initial',
483 'inherit', ''] + list(map(str, range(100,1000,100))),
483 'inherit', ''] + list(map(str, range(100,1000,100))),
484 default_value='', sync=True)
484 default_value='', sync=True)
485 font_size = CUnicode(sync=True)
485 font_size = CUnicode(sync=True)
486 font_family = Unicode(sync=True)
486 font_family = Unicode(sync=True)
487
487
488 def __init__(self, *pargs, **kwargs):
488 def __init__(self, *pargs, **kwargs):
489 super(DOMWidget, self).__init__(*pargs, **kwargs)
489 super(DOMWidget, self).__init__(*pargs, **kwargs)
490
490
491 def _validate_border(name, old, new):
491 def _validate_border(name, old, new):
492 if new is not None and new != '':
492 if new is not None and new != '':
493 if name != 'border_width' and not self.border_width:
493 if name != 'border_width' and not self.border_width:
494 self.border_width = 1
494 self.border_width = 1
495 if name != 'border_style' and self.border_style == '':
495 if name != 'border_style' and self.border_style == '':
496 self.border_style = 'solid'
496 self.border_style = 'solid'
497 self.on_trait_change(_validate_border, ['border_width', 'border_style', 'border_color'])
497 self.on_trait_change(_validate_border, ['border_width', 'border_style', 'border_color'])
@@ -1,156 +1,157 b''
1 """A client for in-process kernels."""
1 """A client for in-process kernels."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2012 The IPython Development Team
4 # Copyright (C) 2012 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 # IPython imports
14 # IPython imports
15 from IPython.kernel.inprocess.socket import DummySocket
15 from IPython.kernel.inprocess.socket import DummySocket
16 from IPython.utils.traitlets import Type, Instance
16 from IPython.utils.traitlets import Type, Instance
17 from IPython.kernel.clientabc import KernelClientABC
17 from IPython.kernel.clientabc import KernelClientABC
18 from IPython.kernel.client import KernelClient
18 from IPython.kernel.client import KernelClient
19
19
20 # Local imports
20 # Local imports
21 from .channels import (
21 from .channels import (
22 InProcessChannel,
22 InProcessChannel,
23 InProcessHBChannel,
23 InProcessHBChannel,
24
24
25 )
25 )
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Main kernel Client class
28 # Main kernel Client class
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class InProcessKernelClient(KernelClient):
31 class InProcessKernelClient(KernelClient):
32 """A client for an in-process kernel.
32 """A client for an in-process kernel.
33
33
34 This class implements the interface of
34 This class implements the interface of
35 `IPython.kernel.clientabc.KernelClientABC` and allows
35 `IPython.kernel.clientabc.KernelClientABC` and allows
36 (asynchronous) frontends to be used seamlessly with an in-process kernel.
36 (asynchronous) frontends to be used seamlessly with an in-process kernel.
37
37
38 See `IPython.kernel.client.KernelClient` for docstrings.
38 See `IPython.kernel.client.KernelClient` for docstrings.
39 """
39 """
40
40
41 # The classes to use for the various channels.
41 # The classes to use for the various channels.
42 shell_channel_class = Type(InProcessChannel)
42 shell_channel_class = Type(InProcessChannel)
43 iopub_channel_class = Type(InProcessChannel)
43 iopub_channel_class = Type(InProcessChannel)
44 stdin_channel_class = Type(InProcessChannel)
44 stdin_channel_class = Type(InProcessChannel)
45 hb_channel_class = Type(InProcessHBChannel)
45 hb_channel_class = Type(InProcessHBChannel)
46
46
47 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel')
47 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel',
48 allow_none=True)
48
49
49 #--------------------------------------------------------------------------
50 #--------------------------------------------------------------------------
50 # Channel management methods
51 # Channel management methods
51 #--------------------------------------------------------------------------
52 #--------------------------------------------------------------------------
52
53
53 def start_channels(self, *args, **kwargs):
54 def start_channels(self, *args, **kwargs):
54 super(InProcessKernelClient, self).start_channels(self)
55 super(InProcessKernelClient, self).start_channels(self)
55 self.kernel.frontends.append(self)
56 self.kernel.frontends.append(self)
56
57
57 @property
58 @property
58 def shell_channel(self):
59 def shell_channel(self):
59 if self._shell_channel is None:
60 if self._shell_channel is None:
60 self._shell_channel = self.shell_channel_class(self)
61 self._shell_channel = self.shell_channel_class(self)
61 return self._shell_channel
62 return self._shell_channel
62
63
63 @property
64 @property
64 def iopub_channel(self):
65 def iopub_channel(self):
65 if self._iopub_channel is None:
66 if self._iopub_channel is None:
66 self._iopub_channel = self.iopub_channel_class(self)
67 self._iopub_channel = self.iopub_channel_class(self)
67 return self._iopub_channel
68 return self._iopub_channel
68
69
69 @property
70 @property
70 def stdin_channel(self):
71 def stdin_channel(self):
71 if self._stdin_channel is None:
72 if self._stdin_channel is None:
72 self._stdin_channel = self.stdin_channel_class(self)
73 self._stdin_channel = self.stdin_channel_class(self)
73 return self._stdin_channel
74 return self._stdin_channel
74
75
75 @property
76 @property
76 def hb_channel(self):
77 def hb_channel(self):
77 if self._hb_channel is None:
78 if self._hb_channel is None:
78 self._hb_channel = self.hb_channel_class(self)
79 self._hb_channel = self.hb_channel_class(self)
79 return self._hb_channel
80 return self._hb_channel
80
81
81 # Methods for sending specific messages
82 # Methods for sending specific messages
82 # -------------------------------------
83 # -------------------------------------
83
84
84 def execute(self, code, silent=False, store_history=True,
85 def execute(self, code, silent=False, store_history=True,
85 user_expressions={}, allow_stdin=None):
86 user_expressions={}, allow_stdin=None):
86 if allow_stdin is None:
87 if allow_stdin is None:
87 allow_stdin = self.allow_stdin
88 allow_stdin = self.allow_stdin
88 content = dict(code=code, silent=silent, store_history=store_history,
89 content = dict(code=code, silent=silent, store_history=store_history,
89 user_expressions=user_expressions,
90 user_expressions=user_expressions,
90 allow_stdin=allow_stdin)
91 allow_stdin=allow_stdin)
91 msg = self.session.msg('execute_request', content)
92 msg = self.session.msg('execute_request', content)
92 self._dispatch_to_kernel(msg)
93 self._dispatch_to_kernel(msg)
93 return msg['header']['msg_id']
94 return msg['header']['msg_id']
94
95
95 def complete(self, code, cursor_pos=None):
96 def complete(self, code, cursor_pos=None):
96 if cursor_pos is None:
97 if cursor_pos is None:
97 cursor_pos = len(code)
98 cursor_pos = len(code)
98 content = dict(code=code, cursor_pos=cursor_pos)
99 content = dict(code=code, cursor_pos=cursor_pos)
99 msg = self.session.msg('complete_request', content)
100 msg = self.session.msg('complete_request', content)
100 self._dispatch_to_kernel(msg)
101 self._dispatch_to_kernel(msg)
101 return msg['header']['msg_id']
102 return msg['header']['msg_id']
102
103
103 def inspect(self, code, cursor_pos=None, detail_level=0):
104 def inspect(self, code, cursor_pos=None, detail_level=0):
104 if cursor_pos is None:
105 if cursor_pos is None:
105 cursor_pos = len(code)
106 cursor_pos = len(code)
106 content = dict(code=code, cursor_pos=cursor_pos,
107 content = dict(code=code, cursor_pos=cursor_pos,
107 detail_level=detail_level,
108 detail_level=detail_level,
108 )
109 )
109 msg = self.session.msg('inspect_request', content)
110 msg = self.session.msg('inspect_request', content)
110 self._dispatch_to_kernel(msg)
111 self._dispatch_to_kernel(msg)
111 return msg['header']['msg_id']
112 return msg['header']['msg_id']
112
113
113 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
114 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
114 content = dict(raw=raw, output=output,
115 content = dict(raw=raw, output=output,
115 hist_access_type=hist_access_type, **kwds)
116 hist_access_type=hist_access_type, **kwds)
116 msg = self.session.msg('history_request', content)
117 msg = self.session.msg('history_request', content)
117 self._dispatch_to_kernel(msg)
118 self._dispatch_to_kernel(msg)
118 return msg['header']['msg_id']
119 return msg['header']['msg_id']
119
120
120 def shutdown(self, restart=False):
121 def shutdown(self, restart=False):
121 # FIXME: What to do here?
122 # FIXME: What to do here?
122 raise NotImplementedError('Cannot shutdown in-process kernel')
123 raise NotImplementedError('Cannot shutdown in-process kernel')
123
124
124 def kernel_info(self):
125 def kernel_info(self):
125 """Request kernel info."""
126 """Request kernel info."""
126 msg = self.session.msg('kernel_info_request')
127 msg = self.session.msg('kernel_info_request')
127 self._dispatch_to_kernel(msg)
128 self._dispatch_to_kernel(msg)
128 return msg['header']['msg_id']
129 return msg['header']['msg_id']
129
130
130 def input(self, string):
131 def input(self, string):
131 if self.kernel is None:
132 if self.kernel is None:
132 raise RuntimeError('Cannot send input reply. No kernel exists.')
133 raise RuntimeError('Cannot send input reply. No kernel exists.')
133 self.kernel.raw_input_str = string
134 self.kernel.raw_input_str = string
134
135
135
136
136 def _dispatch_to_kernel(self, msg):
137 def _dispatch_to_kernel(self, msg):
137 """ Send a message to the kernel and handle a reply.
138 """ Send a message to the kernel and handle a reply.
138 """
139 """
139 kernel = self.kernel
140 kernel = self.kernel
140 if kernel is None:
141 if kernel is None:
141 raise RuntimeError('Cannot send request. No kernel exists.')
142 raise RuntimeError('Cannot send request. No kernel exists.')
142
143
143 stream = DummySocket()
144 stream = DummySocket()
144 self.session.send(stream, msg)
145 self.session.send(stream, msg)
145 msg_parts = stream.recv_multipart()
146 msg_parts = stream.recv_multipart()
146 kernel.dispatch_shell(stream, msg_parts)
147 kernel.dispatch_shell(stream, msg_parts)
147
148
148 idents, reply_msg = self.session.recv(stream, copy=False)
149 idents, reply_msg = self.session.recv(stream, copy=False)
149 self.shell_channel.call_handlers_later(reply_msg)
150 self.shell_channel.call_handlers_later(reply_msg)
150
151
151
152
152 #-----------------------------------------------------------------------------
153 #-----------------------------------------------------------------------------
153 # ABC Registration
154 # ABC Registration
154 #-----------------------------------------------------------------------------
155 #-----------------------------------------------------------------------------
155
156
156 KernelClientABC.register(InProcessKernelClient)
157 KernelClientABC.register(InProcessKernelClient)
@@ -1,169 +1,171 b''
1 """An in-process kernel"""
1 """An in-process kernel"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from contextlib import contextmanager
6 from contextlib import contextmanager
7 import logging
7 import logging
8 import sys
8 import sys
9
9
10 from IPython.core.interactiveshell import InteractiveShellABC
10 from IPython.core.interactiveshell import InteractiveShellABC
11 from IPython.utils.jsonutil import json_clean
11 from IPython.utils.jsonutil import json_clean
12 from IPython.utils.traitlets import Any, Enum, Instance, List, Type
12 from IPython.utils.traitlets import Any, Enum, Instance, List, Type
13 from IPython.kernel.zmq.ipkernel import IPythonKernel
13 from IPython.kernel.zmq.ipkernel import IPythonKernel
14 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
14 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
15
15
16 from .socket import DummySocket
16 from .socket import DummySocket
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Main kernel class
19 # Main kernel class
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class InProcessKernel(IPythonKernel):
22 class InProcessKernel(IPythonKernel):
23
23
24 #-------------------------------------------------------------------------
24 #-------------------------------------------------------------------------
25 # InProcessKernel interface
25 # InProcessKernel interface
26 #-------------------------------------------------------------------------
26 #-------------------------------------------------------------------------
27
27
28 # The frontends connected to this kernel.
28 # The frontends connected to this kernel.
29 frontends = List(
29 frontends = List(
30 Instance('IPython.kernel.inprocess.client.InProcessKernelClient')
30 Instance('IPython.kernel.inprocess.client.InProcessKernelClient'
31 allow_none=True)
31 )
32 )
32
33
33 # The GUI environment that the kernel is running under. This need not be
34 # The GUI environment that the kernel is running under. This need not be
34 # specified for the normal operation for the kernel, but is required for
35 # specified for the normal operation for the kernel, but is required for
35 # IPython's GUI support (including pylab). The default is 'inline' because
36 # IPython's GUI support (including pylab). The default is 'inline' because
36 # it is safe under all GUI toolkits.
37 # it is safe under all GUI toolkits.
37 gui = Enum(('tk', 'gtk', 'wx', 'qt', 'qt4', 'inline'),
38 gui = Enum(('tk', 'gtk', 'wx', 'qt', 'qt4', 'inline'),
38 default_value='inline')
39 default_value='inline')
39
40
40 raw_input_str = Any()
41 raw_input_str = Any()
41 stdout = Any()
42 stdout = Any()
42 stderr = Any()
43 stderr = Any()
43
44
44 #-------------------------------------------------------------------------
45 #-------------------------------------------------------------------------
45 # Kernel interface
46 # Kernel interface
46 #-------------------------------------------------------------------------
47 #-------------------------------------------------------------------------
47
48
48 shell_class = Type()
49 shell_class = Type()
49 shell_streams = List()
50 shell_streams = List()
50 control_stream = Any()
51 control_stream = Any()
51 iopub_socket = Instance(DummySocket, ())
52 iopub_socket = Instance(DummySocket, ())
52 stdin_socket = Instance(DummySocket, ())
53 stdin_socket = Instance(DummySocket, ())
53
54
54 def __init__(self, **traits):
55 def __init__(self, **traits):
55 super(InProcessKernel, self).__init__(**traits)
56 super(InProcessKernel, self).__init__(**traits)
56
57
57 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
58 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
58 self.shell.kernel = self
59 self.shell.kernel = self
59
60
60 def execute_request(self, stream, ident, parent):
61 def execute_request(self, stream, ident, parent):
61 """ Override for temporary IO redirection. """
62 """ Override for temporary IO redirection. """
62 with self._redirected_io():
63 with self._redirected_io():
63 super(InProcessKernel, self).execute_request(stream, ident, parent)
64 super(InProcessKernel, self).execute_request(stream, ident, parent)
64
65
65 def start(self):
66 def start(self):
66 """ Override registration of dispatchers for streams. """
67 """ Override registration of dispatchers for streams. """
67 self.shell.exit_now = False
68 self.shell.exit_now = False
68
69
69 def _abort_queue(self, stream):
70 def _abort_queue(self, stream):
70 """ The in-process kernel doesn't abort requests. """
71 """ The in-process kernel doesn't abort requests. """
71 pass
72 pass
72
73
73 def _input_request(self, prompt, ident, parent, password=False):
74 def _input_request(self, prompt, ident, parent, password=False):
74 # Flush output before making the request.
75 # Flush output before making the request.
75 self.raw_input_str = None
76 self.raw_input_str = None
76 sys.stderr.flush()
77 sys.stderr.flush()
77 sys.stdout.flush()
78 sys.stdout.flush()
78
79
79 # Send the input request.
80 # Send the input request.
80 content = json_clean(dict(prompt=prompt, password=password))
81 content = json_clean(dict(prompt=prompt, password=password))
81 msg = self.session.msg(u'input_request', content, parent)
82 msg = self.session.msg(u'input_request', content, parent)
82 for frontend in self.frontends:
83 for frontend in self.frontends:
83 if frontend.session.session == parent['header']['session']:
84 if frontend.session.session == parent['header']['session']:
84 frontend.stdin_channel.call_handlers(msg)
85 frontend.stdin_channel.call_handlers(msg)
85 break
86 break
86 else:
87 else:
87 logging.error('No frontend found for raw_input request')
88 logging.error('No frontend found for raw_input request')
88 return str()
89 return str()
89
90
90 # Await a response.
91 # Await a response.
91 while self.raw_input_str is None:
92 while self.raw_input_str is None:
92 frontend.stdin_channel.process_events()
93 frontend.stdin_channel.process_events()
93 return self.raw_input_str
94 return self.raw_input_str
94
95
95 #-------------------------------------------------------------------------
96 #-------------------------------------------------------------------------
96 # Protected interface
97 # Protected interface
97 #-------------------------------------------------------------------------
98 #-------------------------------------------------------------------------
98
99
99 @contextmanager
100 @contextmanager
100 def _redirected_io(self):
101 def _redirected_io(self):
101 """ Temporarily redirect IO to the kernel.
102 """ Temporarily redirect IO to the kernel.
102 """
103 """
103 sys_stdout, sys_stderr = sys.stdout, sys.stderr
104 sys_stdout, sys_stderr = sys.stdout, sys.stderr
104 sys.stdout, sys.stderr = self.stdout, self.stderr
105 sys.stdout, sys.stderr = self.stdout, self.stderr
105 yield
106 yield
106 sys.stdout, sys.stderr = sys_stdout, sys_stderr
107 sys.stdout, sys.stderr = sys_stdout, sys_stderr
107
108
108 #------ Trait change handlers --------------------------------------------
109 #------ Trait change handlers --------------------------------------------
109
110
110 def _io_dispatch(self):
111 def _io_dispatch(self):
111 """ Called when a message is sent to the IO socket.
112 """ Called when a message is sent to the IO socket.
112 """
113 """
113 ident, msg = self.session.recv(self.iopub_socket, copy=False)
114 ident, msg = self.session.recv(self.iopub_socket, copy=False)
114 for frontend in self.frontends:
115 for frontend in self.frontends:
115 frontend.iopub_channel.call_handlers(msg)
116 frontend.iopub_channel.call_handlers(msg)
116
117
117 #------ Trait initializers -----------------------------------------------
118 #------ Trait initializers -----------------------------------------------
118
119
119 def _log_default(self):
120 def _log_default(self):
120 return logging.getLogger(__name__)
121 return logging.getLogger(__name__)
121
122
122 def _session_default(self):
123 def _session_default(self):
123 from IPython.kernel.zmq.session import Session
124 from IPython.kernel.zmq.session import Session
124 return Session(parent=self, key=b'')
125 return Session(parent=self, key=b'')
125
126
126 def _shell_class_default(self):
127 def _shell_class_default(self):
127 return InProcessInteractiveShell
128 return InProcessInteractiveShell
128
129
129 def _stdout_default(self):
130 def _stdout_default(self):
130 from IPython.kernel.zmq.iostream import OutStream
131 from IPython.kernel.zmq.iostream import OutStream
131 return OutStream(self.session, self.iopub_socket, u'stdout', pipe=False)
132 return OutStream(self.session, self.iopub_socket, u'stdout', pipe=False)
132
133
133 def _stderr_default(self):
134 def _stderr_default(self):
134 from IPython.kernel.zmq.iostream import OutStream
135 from IPython.kernel.zmq.iostream import OutStream
135 return OutStream(self.session, self.iopub_socket, u'stderr', pipe=False)
136 return OutStream(self.session, self.iopub_socket, u'stderr', pipe=False)
136
137
137 #-----------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
138 # Interactive shell subclass
139 # Interactive shell subclass
139 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
140
141
141 class InProcessInteractiveShell(ZMQInteractiveShell):
142 class InProcessInteractiveShell(ZMQInteractiveShell):
142
143
143 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel')
144 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel',
145 allow_none=True)
144
146
145 #-------------------------------------------------------------------------
147 #-------------------------------------------------------------------------
146 # InteractiveShell interface
148 # InteractiveShell interface
147 #-------------------------------------------------------------------------
149 #-------------------------------------------------------------------------
148
150
149 def enable_gui(self, gui=None):
151 def enable_gui(self, gui=None):
150 """Enable GUI integration for the kernel."""
152 """Enable GUI integration for the kernel."""
151 from IPython.kernel.zmq.eventloops import enable_gui
153 from IPython.kernel.zmq.eventloops import enable_gui
152 if not gui:
154 if not gui:
153 gui = self.kernel.gui
155 gui = self.kernel.gui
154 return enable_gui(gui, kernel=self.kernel)
156 return enable_gui(gui, kernel=self.kernel)
155
157
156 def enable_matplotlib(self, gui=None):
158 def enable_matplotlib(self, gui=None):
157 """Enable matplotlib integration for the kernel."""
159 """Enable matplotlib integration for the kernel."""
158 if not gui:
160 if not gui:
159 gui = self.kernel.gui
161 gui = self.kernel.gui
160 return super(InProcessInteractiveShell, self).enable_matplotlib(gui)
162 return super(InProcessInteractiveShell, self).enable_matplotlib(gui)
161
163
162 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
164 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
163 """Activate pylab support at runtime."""
165 """Activate pylab support at runtime."""
164 if not gui:
166 if not gui:
165 gui = self.kernel.gui
167 gui = self.kernel.gui
166 return super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
168 return super(InProcessInteractiveShell, self).enable_pylab(gui, import_all,
167 welcome_message)
169 welcome_message)
168
170
169 InteractiveShellABC.register(InProcessInteractiveShell)
171 InteractiveShellABC.register(InProcessInteractiveShell)
@@ -1,71 +1,72 b''
1 """A kernel manager for in-process kernels."""
1 """A kernel manager for in-process kernels."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from IPython.utils.traitlets import Instance, DottedObjectName
6 from IPython.utils.traitlets import Instance, DottedObjectName
7 from IPython.kernel.managerabc import KernelManagerABC
7 from IPython.kernel.managerabc import KernelManagerABC
8 from IPython.kernel.manager import KernelManager
8 from IPython.kernel.manager import KernelManager
9 from IPython.kernel.zmq.session import Session
9 from IPython.kernel.zmq.session import Session
10
10
11
11
12 class InProcessKernelManager(KernelManager):
12 class InProcessKernelManager(KernelManager):
13 """A manager for an in-process kernel.
13 """A manager for an in-process kernel.
14
14
15 This class implements the interface of
15 This class implements the interface of
16 `IPython.kernel.kernelmanagerabc.KernelManagerABC` and allows
16 `IPython.kernel.kernelmanagerabc.KernelManagerABC` and allows
17 (asynchronous) frontends to be used seamlessly with an in-process kernel.
17 (asynchronous) frontends to be used seamlessly with an in-process kernel.
18
18
19 See `IPython.kernel.kernelmanager.KernelManager` for docstrings.
19 See `IPython.kernel.kernelmanager.KernelManager` for docstrings.
20 """
20 """
21
21
22 # The kernel process with which the KernelManager is communicating.
22 # The kernel process with which the KernelManager is communicating.
23 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel')
23 kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel',
24 allow_none=True)
24 # the client class for KM.client() shortcut
25 # the client class for KM.client() shortcut
25 client_class = DottedObjectName('IPython.kernel.inprocess.BlockingInProcessKernelClient')
26 client_class = DottedObjectName('IPython.kernel.inprocess.BlockingInProcessKernelClient')
26
27
27 def _session_default(self):
28 def _session_default(self):
28 # don't sign in-process messages
29 # don't sign in-process messages
29 return Session(key=b'', parent=self)
30 return Session(key=b'', parent=self)
30
31
31 #--------------------------------------------------------------------------
32 #--------------------------------------------------------------------------
32 # Kernel management methods
33 # Kernel management methods
33 #--------------------------------------------------------------------------
34 #--------------------------------------------------------------------------
34
35
35 def start_kernel(self, **kwds):
36 def start_kernel(self, **kwds):
36 from IPython.kernel.inprocess.ipkernel import InProcessKernel
37 from IPython.kernel.inprocess.ipkernel import InProcessKernel
37 self.kernel = InProcessKernel(parent=self, session=self.session)
38 self.kernel = InProcessKernel(parent=self, session=self.session)
38
39
39 def shutdown_kernel(self):
40 def shutdown_kernel(self):
40 self._kill_kernel()
41 self._kill_kernel()
41
42
42 def restart_kernel(self, now=False, **kwds):
43 def restart_kernel(self, now=False, **kwds):
43 self.shutdown_kernel()
44 self.shutdown_kernel()
44 self.start_kernel(**kwds)
45 self.start_kernel(**kwds)
45
46
46 @property
47 @property
47 def has_kernel(self):
48 def has_kernel(self):
48 return self.kernel is not None
49 return self.kernel is not None
49
50
50 def _kill_kernel(self):
51 def _kill_kernel(self):
51 self.kernel = None
52 self.kernel = None
52
53
53 def interrupt_kernel(self):
54 def interrupt_kernel(self):
54 raise NotImplementedError("Cannot interrupt in-process kernel.")
55 raise NotImplementedError("Cannot interrupt in-process kernel.")
55
56
56 def signal_kernel(self, signum):
57 def signal_kernel(self, signum):
57 raise NotImplementedError("Cannot signal in-process kernel.")
58 raise NotImplementedError("Cannot signal in-process kernel.")
58
59
59 def is_alive(self):
60 def is_alive(self):
60 return self.kernel is not None
61 return self.kernel is not None
61
62
62 def client(self, **kwargs):
63 def client(self, **kwargs):
63 kwargs['kernel'] = self.kernel
64 kwargs['kernel'] = self.kernel
64 return super(InProcessKernelManager, self).client(**kwargs)
65 return super(InProcessKernelManager, self).client(**kwargs)
65
66
66
67
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68 # ABC Registration
69 # ABC Registration
69 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
70
71
71 KernelManagerABC.register(InProcessKernelManager)
72 KernelManagerABC.register(InProcessKernelManager)
@@ -1,62 +1,62 b''
1 """A kernel manager with a tornado IOLoop"""
1 """A kernel manager with a tornado IOLoop"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
4 # Copyright (C) 2013 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from __future__ import absolute_import
14 from __future__ import absolute_import
15
15
16 from zmq.eventloop import ioloop
16 from zmq.eventloop import ioloop
17 from zmq.eventloop.zmqstream import ZMQStream
17 from zmq.eventloop.zmqstream import ZMQStream
18
18
19 from IPython.utils.traitlets import (
19 from IPython.utils.traitlets import (
20 Instance
20 Instance
21 )
21 )
22
22
23 from IPython.kernel.manager import KernelManager
23 from IPython.kernel.manager import KernelManager
24 from .restarter import IOLoopKernelRestarter
24 from .restarter import IOLoopKernelRestarter
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Code
27 # Code
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30
30
31 def as_zmqstream(f):
31 def as_zmqstream(f):
32 def wrapped(self, *args, **kwargs):
32 def wrapped(self, *args, **kwargs):
33 socket = f(self, *args, **kwargs)
33 socket = f(self, *args, **kwargs)
34 return ZMQStream(socket, self.loop)
34 return ZMQStream(socket, self.loop)
35 return wrapped
35 return wrapped
36
36
37 class IOLoopKernelManager(KernelManager):
37 class IOLoopKernelManager(KernelManager):
38
38
39 loop = Instance('zmq.eventloop.ioloop.IOLoop', allow_none=False)
39 loop = Instance('zmq.eventloop.ioloop.IOLoop')
40 def _loop_default(self):
40 def _loop_default(self):
41 return ioloop.IOLoop.instance()
41 return ioloop.IOLoop.instance()
42
42
43 _restarter = Instance('IPython.kernel.ioloop.IOLoopKernelRestarter')
43 _restarter = Instance('IPython.kernel.ioloop.IOLoopKernelRestarter', allow_none=True)
44
44
45 def start_restarter(self):
45 def start_restarter(self):
46 if self.autorestart and self.has_kernel:
46 if self.autorestart and self.has_kernel:
47 if self._restarter is None:
47 if self._restarter is None:
48 self._restarter = IOLoopKernelRestarter(
48 self._restarter = IOLoopKernelRestarter(
49 kernel_manager=self, loop=self.loop,
49 kernel_manager=self, loop=self.loop,
50 parent=self, log=self.log
50 parent=self, log=self.log
51 )
51 )
52 self._restarter.start()
52 self._restarter.start()
53
53
54 def stop_restarter(self):
54 def stop_restarter(self):
55 if self.autorestart:
55 if self.autorestart:
56 if self._restarter is not None:
56 if self._restarter is not None:
57 self._restarter.stop()
57 self._restarter.stop()
58
58
59 connect_shell = as_zmqstream(KernelManager.connect_shell)
59 connect_shell = as_zmqstream(KernelManager.connect_shell)
60 connect_iopub = as_zmqstream(KernelManager.connect_iopub)
60 connect_iopub = as_zmqstream(KernelManager.connect_iopub)
61 connect_stdin = as_zmqstream(KernelManager.connect_stdin)
61 connect_stdin = as_zmqstream(KernelManager.connect_stdin)
62 connect_hb = as_zmqstream(KernelManager.connect_hb)
62 connect_hb = as_zmqstream(KernelManager.connect_hb)
@@ -1,54 +1,54 b''
1 """A basic in process kernel monitor with autorestarting.
1 """A basic in process kernel monitor with autorestarting.
2
2
3 This watches a kernel's state using KernelManager.is_alive and auto
3 This watches a kernel's state using KernelManager.is_alive and auto
4 restarts the kernel if it dies.
4 restarts the kernel if it dies.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2013 The IPython Development Team
8 # Copyright (C) 2013 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 from zmq.eventloop import ioloop
20 from zmq.eventloop import ioloop
21
21
22
22
23 from IPython.kernel.restarter import KernelRestarter
23 from IPython.kernel.restarter import KernelRestarter
24 from IPython.utils.traitlets import (
24 from IPython.utils.traitlets import (
25 Instance,
25 Instance,
26 )
26 )
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Code
29 # Code
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class IOLoopKernelRestarter(KernelRestarter):
32 class IOLoopKernelRestarter(KernelRestarter):
33 """Monitor and autorestart a kernel."""
33 """Monitor and autorestart a kernel."""
34
34
35 loop = Instance('zmq.eventloop.ioloop.IOLoop', allow_none=False)
35 loop = Instance('zmq.eventloop.ioloop.IOLoop')
36 def _loop_default(self):
36 def _loop_default(self):
37 return ioloop.IOLoop.instance()
37 return ioloop.IOLoop.instance()
38
38
39 _pcallback = None
39 _pcallback = None
40
40
41 def start(self):
41 def start(self):
42 """Start the polling of the kernel."""
42 """Start the polling of the kernel."""
43 if self._pcallback is None:
43 if self._pcallback is None:
44 self._pcallback = ioloop.PeriodicCallback(
44 self._pcallback = ioloop.PeriodicCallback(
45 self.poll, 1000*self.time_to_dead, self.loop
45 self.poll, 1000*self.time_to_dead, self.loop
46 )
46 )
47 self._pcallback.start()
47 self._pcallback.start()
48
48
49 def stop(self):
49 def stop(self):
50 """Stop the kernel polling."""
50 """Stop the kernel polling."""
51 if self._pcallback is not None:
51 if self._pcallback is not None:
52 self._pcallback.stop()
52 self._pcallback.stop()
53 self._pcallback = None
53 self._pcallback = None
54
54
@@ -1,70 +1,70 b''
1 """Publishing native (typically pickled) objects.
1 """Publishing native (typically pickled) objects.
2 """
2 """
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2012 The IPython Development Team
5 # Copyright (C) 2012 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from IPython.config import Configurable
15 from IPython.config import Configurable
16 from IPython.kernel.inprocess.socket import SocketABC
16 from IPython.kernel.inprocess.socket import SocketABC
17 from IPython.utils.jsonutil import json_clean
17 from IPython.utils.jsonutil import json_clean
18 from IPython.utils.traitlets import Instance, Dict, CBytes
18 from IPython.utils.traitlets import Instance, Dict, CBytes
19 from IPython.kernel.zmq.serialize import serialize_object
19 from IPython.kernel.zmq.serialize import serialize_object
20 from IPython.kernel.zmq.session import Session, extract_header
20 from IPython.kernel.zmq.session import Session, extract_header
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Code
23 # Code
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 class ZMQDataPublisher(Configurable):
27 class ZMQDataPublisher(Configurable):
28
28
29 topic = topic = CBytes(b'datapub')
29 topic = topic = CBytes(b'datapub')
30 session = Instance(Session)
30 session = Instance(Session, allow_none=True)
31 pub_socket = Instance(SocketABC)
31 pub_socket = Instance(SocketABC, allow_none=True)
32 parent_header = Dict({})
32 parent_header = Dict({})
33
33
34 def set_parent(self, parent):
34 def set_parent(self, parent):
35 """Set the parent for outbound messages."""
35 """Set the parent for outbound messages."""
36 self.parent_header = extract_header(parent)
36 self.parent_header = extract_header(parent)
37
37
38 def publish_data(self, data):
38 def publish_data(self, data):
39 """publish a data_message on the IOPub channel
39 """publish a data_message on the IOPub channel
40
40
41 Parameters
41 Parameters
42 ----------
42 ----------
43
43
44 data : dict
44 data : dict
45 The data to be published. Think of it as a namespace.
45 The data to be published. Think of it as a namespace.
46 """
46 """
47 session = self.session
47 session = self.session
48 buffers = serialize_object(data,
48 buffers = serialize_object(data,
49 buffer_threshold=session.buffer_threshold,
49 buffer_threshold=session.buffer_threshold,
50 item_threshold=session.item_threshold,
50 item_threshold=session.item_threshold,
51 )
51 )
52 content = json_clean(dict(keys=data.keys()))
52 content = json_clean(dict(keys=data.keys()))
53 session.send(self.pub_socket, 'data_message', content=content,
53 session.send(self.pub_socket, 'data_message', content=content,
54 parent=self.parent_header,
54 parent=self.parent_header,
55 buffers=buffers,
55 buffers=buffers,
56 ident=self.topic,
56 ident=self.topic,
57 )
57 )
58
58
59
59
60 def publish_data(data):
60 def publish_data(data):
61 """publish a data_message on the IOPub channel
61 """publish a data_message on the IOPub channel
62
62
63 Parameters
63 Parameters
64 ----------
64 ----------
65
65
66 data : dict
66 data : dict
67 The data to be published. Think of it as a namespace.
67 The data to be published. Think of it as a namespace.
68 """
68 """
69 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
69 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
70 ZMQInteractiveShell.instance().data_pub.publish_data(data)
70 ZMQInteractiveShell.instance().data_pub.publish_data(data)
@@ -1,74 +1,74 b''
1 """Replacements for sys.displayhook that publish over ZMQ."""
1 """Replacements for sys.displayhook that publish over ZMQ."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import sys
6 import sys
7
7
8 from IPython.core.displayhook import DisplayHook
8 from IPython.core.displayhook import DisplayHook
9 from IPython.kernel.inprocess.socket import SocketABC
9 from IPython.kernel.inprocess.socket import SocketABC
10 from IPython.utils.jsonutil import encode_images
10 from IPython.utils.jsonutil import encode_images
11 from IPython.utils.py3compat import builtin_mod
11 from IPython.utils.py3compat import builtin_mod
12 from IPython.utils.traitlets import Instance, Dict
12 from IPython.utils.traitlets import Instance, Dict
13 from .session import extract_header, Session
13 from .session import extract_header, Session
14
14
15 class ZMQDisplayHook(object):
15 class ZMQDisplayHook(object):
16 """A simple displayhook that publishes the object's repr over a ZeroMQ
16 """A simple displayhook that publishes the object's repr over a ZeroMQ
17 socket."""
17 socket."""
18 topic=b'execute_result'
18 topic=b'execute_result'
19
19
20 def __init__(self, session, pub_socket):
20 def __init__(self, session, pub_socket):
21 self.session = session
21 self.session = session
22 self.pub_socket = pub_socket
22 self.pub_socket = pub_socket
23 self.parent_header = {}
23 self.parent_header = {}
24
24
25 def __call__(self, obj):
25 def __call__(self, obj):
26 if obj is None:
26 if obj is None:
27 return
27 return
28
28
29 builtin_mod._ = obj
29 builtin_mod._ = obj
30 sys.stdout.flush()
30 sys.stdout.flush()
31 sys.stderr.flush()
31 sys.stderr.flush()
32 msg = self.session.send(self.pub_socket, u'execute_result', {u'data':repr(obj)},
32 msg = self.session.send(self.pub_socket, u'execute_result', {u'data':repr(obj)},
33 parent=self.parent_header, ident=self.topic)
33 parent=self.parent_header, ident=self.topic)
34
34
35 def set_parent(self, parent):
35 def set_parent(self, parent):
36 self.parent_header = extract_header(parent)
36 self.parent_header = extract_header(parent)
37
37
38
38
39 class ZMQShellDisplayHook(DisplayHook):
39 class ZMQShellDisplayHook(DisplayHook):
40 """A displayhook subclass that publishes data using ZeroMQ. This is intended
40 """A displayhook subclass that publishes data using ZeroMQ. This is intended
41 to work with an InteractiveShell instance. It sends a dict of different
41 to work with an InteractiveShell instance. It sends a dict of different
42 representations of the object."""
42 representations of the object."""
43 topic=None
43 topic=None
44
44
45 session = Instance(Session)
45 session = Instance(Session, allow_none=True)
46 pub_socket = Instance(SocketABC)
46 pub_socket = Instance(SocketABC, allow_none=True)
47 parent_header = Dict({})
47 parent_header = Dict({})
48
48
49 def set_parent(self, parent):
49 def set_parent(self, parent):
50 """Set the parent for outbound messages."""
50 """Set the parent for outbound messages."""
51 self.parent_header = extract_header(parent)
51 self.parent_header = extract_header(parent)
52
52
53 def start_displayhook(self):
53 def start_displayhook(self):
54 self.msg = self.session.msg(u'execute_result', {
54 self.msg = self.session.msg(u'execute_result', {
55 'data': {},
55 'data': {},
56 'metadata': {},
56 'metadata': {},
57 }, parent=self.parent_header)
57 }, parent=self.parent_header)
58
58
59 def write_output_prompt(self):
59 def write_output_prompt(self):
60 """Write the output prompt."""
60 """Write the output prompt."""
61 self.msg['content']['execution_count'] = self.prompt_count
61 self.msg['content']['execution_count'] = self.prompt_count
62
62
63 def write_format_data(self, format_dict, md_dict=None):
63 def write_format_data(self, format_dict, md_dict=None):
64 self.msg['content']['data'] = encode_images(format_dict)
64 self.msg['content']['data'] = encode_images(format_dict)
65 self.msg['content']['metadata'] = md_dict
65 self.msg['content']['metadata'] = md_dict
66
66
67 def finish_displayhook(self):
67 def finish_displayhook(self):
68 """Finish up all displayhook activities."""
68 """Finish up all displayhook activities."""
69 sys.stdout.flush()
69 sys.stdout.flush()
70 sys.stderr.flush()
70 sys.stderr.flush()
71 if self.msg['content']['data']:
71 if self.msg['content']['data']:
72 self.session.send(self.pub_socket, self.msg, ident=self.topic)
72 self.session.send(self.pub_socket, self.msg, ident=self.topic)
73 self.msg = None
73 self.msg = None
74
74
@@ -1,367 +1,368 b''
1 """The IPython kernel implementation"""
1 """The IPython kernel implementation"""
2
2
3 import getpass
3 import getpass
4 import sys
4 import sys
5 import traceback
5 import traceback
6
6
7 from IPython.core import release
7 from IPython.core import release
8 from IPython.utils.py3compat import builtin_mod, PY3
8 from IPython.utils.py3compat import builtin_mod, PY3
9 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
9 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
10 from IPython.utils.traitlets import Instance, Type, Any, List
10 from IPython.utils.traitlets import Instance, Type, Any, List
11 from IPython.utils.decorators import undoc
11 from IPython.utils.decorators import undoc
12
12
13 from ..comm import CommManager
13 from ..comm import CommManager
14 from .kernelbase import Kernel as KernelBase
14 from .kernelbase import Kernel as KernelBase
15 from .serialize import serialize_object, unpack_apply_message
15 from .serialize import serialize_object, unpack_apply_message
16 from .zmqshell import ZMQInteractiveShell
16 from .zmqshell import ZMQInteractiveShell
17
17
18
18
19 def lazy_import_handle_comm_opened(*args, **kwargs):
19 def lazy_import_handle_comm_opened(*args, **kwargs):
20 from IPython.html.widgets import Widget
20 from IPython.html.widgets import Widget
21 Widget.handle_comm_opened(*args, **kwargs)
21 Widget.handle_comm_opened(*args, **kwargs)
22
22
23
23
24 class IPythonKernel(KernelBase):
24 class IPythonKernel(KernelBase):
25 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
25 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
26 allow_none=True)
26 shell_class = Type(ZMQInteractiveShell)
27 shell_class = Type(ZMQInteractiveShell)
27
28
28 user_module = Any()
29 user_module = Any()
29 def _user_module_changed(self, name, old, new):
30 def _user_module_changed(self, name, old, new):
30 if self.shell is not None:
31 if self.shell is not None:
31 self.shell.user_module = new
32 self.shell.user_module = new
32
33
33 user_ns = Instance(dict, args=None, allow_none=True)
34 user_ns = Instance(dict, args=None, allow_none=True)
34 def _user_ns_changed(self, name, old, new):
35 def _user_ns_changed(self, name, old, new):
35 if self.shell is not None:
36 if self.shell is not None:
36 self.shell.user_ns = new
37 self.shell.user_ns = new
37 self.shell.init_user_ns()
38 self.shell.init_user_ns()
38
39
39 # A reference to the Python builtin 'raw_input' function.
40 # A reference to the Python builtin 'raw_input' function.
40 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
41 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
41 _sys_raw_input = Any()
42 _sys_raw_input = Any()
42 _sys_eval_input = Any()
43 _sys_eval_input = Any()
43
44
44 def __init__(self, **kwargs):
45 def __init__(self, **kwargs):
45 super(IPythonKernel, self).__init__(**kwargs)
46 super(IPythonKernel, self).__init__(**kwargs)
46
47
47 # Initialize the InteractiveShell subclass
48 # Initialize the InteractiveShell subclass
48 self.shell = self.shell_class.instance(parent=self,
49 self.shell = self.shell_class.instance(parent=self,
49 profile_dir = self.profile_dir,
50 profile_dir = self.profile_dir,
50 user_module = self.user_module,
51 user_module = self.user_module,
51 user_ns = self.user_ns,
52 user_ns = self.user_ns,
52 kernel = self,
53 kernel = self,
53 )
54 )
54 self.shell.displayhook.session = self.session
55 self.shell.displayhook.session = self.session
55 self.shell.displayhook.pub_socket = self.iopub_socket
56 self.shell.displayhook.pub_socket = self.iopub_socket
56 self.shell.displayhook.topic = self._topic('execute_result')
57 self.shell.displayhook.topic = self._topic('execute_result')
57 self.shell.display_pub.session = self.session
58 self.shell.display_pub.session = self.session
58 self.shell.display_pub.pub_socket = self.iopub_socket
59 self.shell.display_pub.pub_socket = self.iopub_socket
59 self.shell.data_pub.session = self.session
60 self.shell.data_pub.session = self.session
60 self.shell.data_pub.pub_socket = self.iopub_socket
61 self.shell.data_pub.pub_socket = self.iopub_socket
61
62
62 # TMP - hack while developing
63 # TMP - hack while developing
63 self.shell._reply_content = None
64 self.shell._reply_content = None
64
65
65 self.comm_manager = CommManager(shell=self.shell, parent=self,
66 self.comm_manager = CommManager(shell=self.shell, parent=self,
66 kernel=self)
67 kernel=self)
67 self.comm_manager.register_target('ipython.widget', lazy_import_handle_comm_opened)
68 self.comm_manager.register_target('ipython.widget', lazy_import_handle_comm_opened)
68
69
69 self.shell.configurables.append(self.comm_manager)
70 self.shell.configurables.append(self.comm_manager)
70 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
71 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
71 for msg_type in comm_msg_types:
72 for msg_type in comm_msg_types:
72 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
73 self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type)
73
74
74 help_links = List([
75 help_links = List([
75 {
76 {
76 'text': "Python",
77 'text': "Python",
77 'url': "http://docs.python.org/%i.%i" % sys.version_info[:2],
78 'url': "http://docs.python.org/%i.%i" % sys.version_info[:2],
78 },
79 },
79 {
80 {
80 'text': "IPython",
81 'text': "IPython",
81 'url': "http://ipython.org/documentation.html",
82 'url': "http://ipython.org/documentation.html",
82 },
83 },
83 {
84 {
84 'text': "NumPy",
85 'text': "NumPy",
85 'url': "http://docs.scipy.org/doc/numpy/reference/",
86 'url': "http://docs.scipy.org/doc/numpy/reference/",
86 },
87 },
87 {
88 {
88 'text': "SciPy",
89 'text': "SciPy",
89 'url': "http://docs.scipy.org/doc/scipy/reference/",
90 'url': "http://docs.scipy.org/doc/scipy/reference/",
90 },
91 },
91 {
92 {
92 'text': "Matplotlib",
93 'text': "Matplotlib",
93 'url': "http://matplotlib.org/contents.html",
94 'url': "http://matplotlib.org/contents.html",
94 },
95 },
95 {
96 {
96 'text': "SymPy",
97 'text': "SymPy",
97 'url': "http://docs.sympy.org/latest/index.html",
98 'url': "http://docs.sympy.org/latest/index.html",
98 },
99 },
99 {
100 {
100 'text': "pandas",
101 'text': "pandas",
101 'url': "http://pandas.pydata.org/pandas-docs/stable/",
102 'url': "http://pandas.pydata.org/pandas-docs/stable/",
102 },
103 },
103 ])
104 ])
104
105
105 # Kernel info fields
106 # Kernel info fields
106 implementation = 'ipython'
107 implementation = 'ipython'
107 implementation_version = release.version
108 implementation_version = release.version
108 language_info = {
109 language_info = {
109 'name': 'python',
110 'name': 'python',
110 'version': sys.version.split()[0],
111 'version': sys.version.split()[0],
111 'mimetype': 'text/x-python',
112 'mimetype': 'text/x-python',
112 'codemirror_mode': {'name': 'ipython',
113 'codemirror_mode': {'name': 'ipython',
113 'version': sys.version_info[0]},
114 'version': sys.version_info[0]},
114 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
115 'pygments_lexer': 'ipython%d' % (3 if PY3 else 2),
115 'nbconvert_exporter': 'python',
116 'nbconvert_exporter': 'python',
116 'file_extension': '.py'
117 'file_extension': '.py'
117 }
118 }
118 @property
119 @property
119 def banner(self):
120 def banner(self):
120 return self.shell.banner
121 return self.shell.banner
121
122
122 def start(self):
123 def start(self):
123 self.shell.exit_now = False
124 self.shell.exit_now = False
124 super(IPythonKernel, self).start()
125 super(IPythonKernel, self).start()
125
126
126 def set_parent(self, ident, parent):
127 def set_parent(self, ident, parent):
127 """Overridden from parent to tell the display hook and output streams
128 """Overridden from parent to tell the display hook and output streams
128 about the parent message.
129 about the parent message.
129 """
130 """
130 super(IPythonKernel, self).set_parent(ident, parent)
131 super(IPythonKernel, self).set_parent(ident, parent)
131 self.shell.set_parent(parent)
132 self.shell.set_parent(parent)
132
133
133 def _forward_input(self, allow_stdin=False):
134 def _forward_input(self, allow_stdin=False):
134 """Forward raw_input and getpass to the current frontend.
135 """Forward raw_input and getpass to the current frontend.
135
136
136 via input_request
137 via input_request
137 """
138 """
138 self._allow_stdin = allow_stdin
139 self._allow_stdin = allow_stdin
139
140
140 if PY3:
141 if PY3:
141 self._sys_raw_input = builtin_mod.input
142 self._sys_raw_input = builtin_mod.input
142 builtin_mod.input = self.raw_input
143 builtin_mod.input = self.raw_input
143 else:
144 else:
144 self._sys_raw_input = builtin_mod.raw_input
145 self._sys_raw_input = builtin_mod.raw_input
145 self._sys_eval_input = builtin_mod.input
146 self._sys_eval_input = builtin_mod.input
146 builtin_mod.raw_input = self.raw_input
147 builtin_mod.raw_input = self.raw_input
147 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
148 builtin_mod.input = lambda prompt='': eval(self.raw_input(prompt))
148 self._save_getpass = getpass.getpass
149 self._save_getpass = getpass.getpass
149 getpass.getpass = self.getpass
150 getpass.getpass = self.getpass
150
151
151 def _restore_input(self):
152 def _restore_input(self):
152 """Restore raw_input, getpass"""
153 """Restore raw_input, getpass"""
153 if PY3:
154 if PY3:
154 builtin_mod.input = self._sys_raw_input
155 builtin_mod.input = self._sys_raw_input
155 else:
156 else:
156 builtin_mod.raw_input = self._sys_raw_input
157 builtin_mod.raw_input = self._sys_raw_input
157 builtin_mod.input = self._sys_eval_input
158 builtin_mod.input = self._sys_eval_input
158
159
159 getpass.getpass = self._save_getpass
160 getpass.getpass = self._save_getpass
160
161
161 @property
162 @property
162 def execution_count(self):
163 def execution_count(self):
163 return self.shell.execution_count
164 return self.shell.execution_count
164
165
165 @execution_count.setter
166 @execution_count.setter
166 def execution_count(self, value):
167 def execution_count(self, value):
167 # Ignore the incrememnting done by KernelBase, in favour of our shell's
168 # Ignore the incrememnting done by KernelBase, in favour of our shell's
168 # execution counter.
169 # execution counter.
169 pass
170 pass
170
171
171 def do_execute(self, code, silent, store_history=True,
172 def do_execute(self, code, silent, store_history=True,
172 user_expressions=None, allow_stdin=False):
173 user_expressions=None, allow_stdin=False):
173 shell = self.shell # we'll need this a lot here
174 shell = self.shell # we'll need this a lot here
174
175
175 self._forward_input(allow_stdin)
176 self._forward_input(allow_stdin)
176
177
177 reply_content = {}
178 reply_content = {}
178 # FIXME: the shell calls the exception handler itself.
179 # FIXME: the shell calls the exception handler itself.
179 shell._reply_content = None
180 shell._reply_content = None
180 try:
181 try:
181 shell.run_cell(code, store_history=store_history, silent=silent)
182 shell.run_cell(code, store_history=store_history, silent=silent)
182 except:
183 except:
183 status = u'error'
184 status = u'error'
184 # FIXME: this code right now isn't being used yet by default,
185 # FIXME: this code right now isn't being used yet by default,
185 # because the run_cell() call above directly fires off exception
186 # because the run_cell() call above directly fires off exception
186 # reporting. This code, therefore, is only active in the scenario
187 # reporting. This code, therefore, is only active in the scenario
187 # where runlines itself has an unhandled exception. We need to
188 # where runlines itself has an unhandled exception. We need to
188 # uniformize this, for all exception construction to come from a
189 # uniformize this, for all exception construction to come from a
189 # single location in the codbase.
190 # single location in the codbase.
190 etype, evalue, tb = sys.exc_info()
191 etype, evalue, tb = sys.exc_info()
191 tb_list = traceback.format_exception(etype, evalue, tb)
192 tb_list = traceback.format_exception(etype, evalue, tb)
192 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
193 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
193 else:
194 else:
194 status = u'ok'
195 status = u'ok'
195 finally:
196 finally:
196 self._restore_input()
197 self._restore_input()
197
198
198 reply_content[u'status'] = status
199 reply_content[u'status'] = status
199
200
200 # Return the execution counter so clients can display prompts
201 # Return the execution counter so clients can display prompts
201 reply_content['execution_count'] = shell.execution_count - 1
202 reply_content['execution_count'] = shell.execution_count - 1
202
203
203 # FIXME - fish exception info out of shell, possibly left there by
204 # FIXME - fish exception info out of shell, possibly left there by
204 # runlines. We'll need to clean up this logic later.
205 # runlines. We'll need to clean up this logic later.
205 if shell._reply_content is not None:
206 if shell._reply_content is not None:
206 reply_content.update(shell._reply_content)
207 reply_content.update(shell._reply_content)
207 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
208 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
208 reply_content['engine_info'] = e_info
209 reply_content['engine_info'] = e_info
209 # reset after use
210 # reset after use
210 shell._reply_content = None
211 shell._reply_content = None
211
212
212 if 'traceback' in reply_content:
213 if 'traceback' in reply_content:
213 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
214 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
214
215
215
216
216 # At this point, we can tell whether the main code execution succeeded
217 # At this point, we can tell whether the main code execution succeeded
217 # or not. If it did, we proceed to evaluate user_expressions
218 # or not. If it did, we proceed to evaluate user_expressions
218 if reply_content['status'] == 'ok':
219 if reply_content['status'] == 'ok':
219 reply_content[u'user_expressions'] = \
220 reply_content[u'user_expressions'] = \
220 shell.user_expressions(user_expressions or {})
221 shell.user_expressions(user_expressions or {})
221 else:
222 else:
222 # If there was an error, don't even try to compute expressions
223 # If there was an error, don't even try to compute expressions
223 reply_content[u'user_expressions'] = {}
224 reply_content[u'user_expressions'] = {}
224
225
225 # Payloads should be retrieved regardless of outcome, so we can both
226 # Payloads should be retrieved regardless of outcome, so we can both
226 # recover partial output (that could have been generated early in a
227 # recover partial output (that could have been generated early in a
227 # block, before an error) and clear the payload system always.
228 # block, before an error) and clear the payload system always.
228 reply_content[u'payload'] = shell.payload_manager.read_payload()
229 reply_content[u'payload'] = shell.payload_manager.read_payload()
229 # Be agressive about clearing the payload because we don't want
230 # Be agressive about clearing the payload because we don't want
230 # it to sit in memory until the next execute_request comes in.
231 # it to sit in memory until the next execute_request comes in.
231 shell.payload_manager.clear_payload()
232 shell.payload_manager.clear_payload()
232
233
233 return reply_content
234 return reply_content
234
235
235 def do_complete(self, code, cursor_pos):
236 def do_complete(self, code, cursor_pos):
236 # FIXME: IPython completers currently assume single line,
237 # FIXME: IPython completers currently assume single line,
237 # but completion messages give multi-line context
238 # but completion messages give multi-line context
238 # For now, extract line from cell, based on cursor_pos:
239 # For now, extract line from cell, based on cursor_pos:
239 if cursor_pos is None:
240 if cursor_pos is None:
240 cursor_pos = len(code)
241 cursor_pos = len(code)
241 line, offset = line_at_cursor(code, cursor_pos)
242 line, offset = line_at_cursor(code, cursor_pos)
242 line_cursor = cursor_pos - offset
243 line_cursor = cursor_pos - offset
243
244
244 txt, matches = self.shell.complete('', line, line_cursor)
245 txt, matches = self.shell.complete('', line, line_cursor)
245 return {'matches' : matches,
246 return {'matches' : matches,
246 'cursor_end' : cursor_pos,
247 'cursor_end' : cursor_pos,
247 'cursor_start' : cursor_pos - len(txt),
248 'cursor_start' : cursor_pos - len(txt),
248 'metadata' : {},
249 'metadata' : {},
249 'status' : 'ok'}
250 'status' : 'ok'}
250
251
251 def do_inspect(self, code, cursor_pos, detail_level=0):
252 def do_inspect(self, code, cursor_pos, detail_level=0):
252 name = token_at_cursor(code, cursor_pos)
253 name = token_at_cursor(code, cursor_pos)
253 info = self.shell.object_inspect(name)
254 info = self.shell.object_inspect(name)
254
255
255 reply_content = {'status' : 'ok'}
256 reply_content = {'status' : 'ok'}
256 reply_content['data'] = data = {}
257 reply_content['data'] = data = {}
257 reply_content['metadata'] = {}
258 reply_content['metadata'] = {}
258 reply_content['found'] = info['found']
259 reply_content['found'] = info['found']
259 if info['found']:
260 if info['found']:
260 info_text = self.shell.object_inspect_text(
261 info_text = self.shell.object_inspect_text(
261 name,
262 name,
262 detail_level=detail_level,
263 detail_level=detail_level,
263 )
264 )
264 data['text/plain'] = info_text
265 data['text/plain'] = info_text
265
266
266 return reply_content
267 return reply_content
267
268
268 def do_history(self, hist_access_type, output, raw, session=None, start=None,
269 def do_history(self, hist_access_type, output, raw, session=None, start=None,
269 stop=None, n=None, pattern=None, unique=False):
270 stop=None, n=None, pattern=None, unique=False):
270 if hist_access_type == 'tail':
271 if hist_access_type == 'tail':
271 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
272 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
272 include_latest=True)
273 include_latest=True)
273
274
274 elif hist_access_type == 'range':
275 elif hist_access_type == 'range':
275 hist = self.shell.history_manager.get_range(session, start, stop,
276 hist = self.shell.history_manager.get_range(session, start, stop,
276 raw=raw, output=output)
277 raw=raw, output=output)
277
278
278 elif hist_access_type == 'search':
279 elif hist_access_type == 'search':
279 hist = self.shell.history_manager.search(
280 hist = self.shell.history_manager.search(
280 pattern, raw=raw, output=output, n=n, unique=unique)
281 pattern, raw=raw, output=output, n=n, unique=unique)
281 else:
282 else:
282 hist = []
283 hist = []
283
284
284 return {'history' : list(hist)}
285 return {'history' : list(hist)}
285
286
286 def do_shutdown(self, restart):
287 def do_shutdown(self, restart):
287 self.shell.exit_now = True
288 self.shell.exit_now = True
288 return dict(status='ok', restart=restart)
289 return dict(status='ok', restart=restart)
289
290
290 def do_is_complete(self, code):
291 def do_is_complete(self, code):
291 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
292 status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
292 r = {'status': status}
293 r = {'status': status}
293 if status == 'incomplete':
294 if status == 'incomplete':
294 r['indent'] = ' ' * indent_spaces
295 r['indent'] = ' ' * indent_spaces
295 return r
296 return r
296
297
297 def do_apply(self, content, bufs, msg_id, reply_metadata):
298 def do_apply(self, content, bufs, msg_id, reply_metadata):
298 shell = self.shell
299 shell = self.shell
299 try:
300 try:
300 working = shell.user_ns
301 working = shell.user_ns
301
302
302 prefix = "_"+str(msg_id).replace("-","")+"_"
303 prefix = "_"+str(msg_id).replace("-","")+"_"
303
304
304 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
305 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
305
306
306 fname = getattr(f, '__name__', 'f')
307 fname = getattr(f, '__name__', 'f')
307
308
308 fname = prefix+"f"
309 fname = prefix+"f"
309 argname = prefix+"args"
310 argname = prefix+"args"
310 kwargname = prefix+"kwargs"
311 kwargname = prefix+"kwargs"
311 resultname = prefix+"result"
312 resultname = prefix+"result"
312
313
313 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
314 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
314 # print ns
315 # print ns
315 working.update(ns)
316 working.update(ns)
316 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
317 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
317 try:
318 try:
318 exec(code, shell.user_global_ns, shell.user_ns)
319 exec(code, shell.user_global_ns, shell.user_ns)
319 result = working.get(resultname)
320 result = working.get(resultname)
320 finally:
321 finally:
321 for key in ns:
322 for key in ns:
322 working.pop(key)
323 working.pop(key)
323
324
324 result_buf = serialize_object(result,
325 result_buf = serialize_object(result,
325 buffer_threshold=self.session.buffer_threshold,
326 buffer_threshold=self.session.buffer_threshold,
326 item_threshold=self.session.item_threshold,
327 item_threshold=self.session.item_threshold,
327 )
328 )
328
329
329 except:
330 except:
330 # invoke IPython traceback formatting
331 # invoke IPython traceback formatting
331 shell.showtraceback()
332 shell.showtraceback()
332 # FIXME - fish exception info out of shell, possibly left there by
333 # FIXME - fish exception info out of shell, possibly left there by
333 # run_code. We'll need to clean up this logic later.
334 # run_code. We'll need to clean up this logic later.
334 reply_content = {}
335 reply_content = {}
335 if shell._reply_content is not None:
336 if shell._reply_content is not None:
336 reply_content.update(shell._reply_content)
337 reply_content.update(shell._reply_content)
337 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
338 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
338 reply_content['engine_info'] = e_info
339 reply_content['engine_info'] = e_info
339 # reset after use
340 # reset after use
340 shell._reply_content = None
341 shell._reply_content = None
341
342
342 self.send_response(self.iopub_socket, u'error', reply_content,
343 self.send_response(self.iopub_socket, u'error', reply_content,
343 ident=self._topic('error'))
344 ident=self._topic('error'))
344 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
345 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
345 result_buf = []
346 result_buf = []
346
347
347 if reply_content['ename'] == 'UnmetDependency':
348 if reply_content['ename'] == 'UnmetDependency':
348 reply_metadata['dependencies_met'] = False
349 reply_metadata['dependencies_met'] = False
349 else:
350 else:
350 reply_content = {'status' : 'ok'}
351 reply_content = {'status' : 'ok'}
351
352
352 return reply_content, result_buf
353 return reply_content, result_buf
353
354
354 def do_clear(self):
355 def do_clear(self):
355 self.shell.reset(False)
356 self.shell.reset(False)
356 return dict(status='ok')
357 return dict(status='ok')
357
358
358
359
359 # This exists only for backwards compatibility - use IPythonKernel instead
360 # This exists only for backwards compatibility - use IPythonKernel instead
360
361
361 @undoc
362 @undoc
362 class Kernel(IPythonKernel):
363 class Kernel(IPythonKernel):
363 def __init__(self, *args, **kwargs):
364 def __init__(self, *args, **kwargs):
364 import warnings
365 import warnings
365 warnings.warn('Kernel is a deprecated alias of IPython.kernel.zmq.ipkernel.IPythonKernel',
366 warnings.warn('Kernel is a deprecated alias of IPython.kernel.zmq.ipkernel.IPythonKernel',
366 DeprecationWarning)
367 DeprecationWarning)
367 super(Kernel, self).__init__(*args, **kwargs)
368 super(Kernel, self).__init__(*args, **kwargs)
@@ -1,387 +1,387 b''
1 """An Application for launching a kernel"""
1 """An Application for launching a kernel"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 import atexit
8 import atexit
9 import os
9 import os
10 import sys
10 import sys
11 import signal
11 import signal
12
12
13 import zmq
13 import zmq
14 from zmq.eventloop import ioloop
14 from zmq.eventloop import ioloop
15 from zmq.eventloop.zmqstream import ZMQStream
15 from zmq.eventloop.zmqstream import ZMQStream
16
16
17 from IPython.core.ultratb import FormattedTB
17 from IPython.core.ultratb import FormattedTB
18 from IPython.core.application import (
18 from IPython.core.application import (
19 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
19 BaseIPythonApplication, base_flags, base_aliases, catch_config_error
20 )
20 )
21 from IPython.core.profiledir import ProfileDir
21 from IPython.core.profiledir import ProfileDir
22 from IPython.core.shellapp import (
22 from IPython.core.shellapp import (
23 InteractiveShellApp, shell_flags, shell_aliases
23 InteractiveShellApp, shell_flags, shell_aliases
24 )
24 )
25 from IPython.utils import io
25 from IPython.utils import io
26 from IPython.utils.path import filefind
26 from IPython.utils.path import filefind
27 from IPython.utils.traitlets import (
27 from IPython.utils.traitlets import (
28 Any, Instance, Dict, Unicode, Integer, Bool, DottedObjectName, Type,
28 Any, Instance, Dict, Unicode, Integer, Bool, DottedObjectName, Type,
29 )
29 )
30 from IPython.utils.importstring import import_item
30 from IPython.utils.importstring import import_item
31 from IPython.kernel import write_connection_file
31 from IPython.kernel import write_connection_file
32 from IPython.kernel.connect import ConnectionFileMixin
32 from IPython.kernel.connect import ConnectionFileMixin
33
33
34 # local imports
34 # local imports
35 from .heartbeat import Heartbeat
35 from .heartbeat import Heartbeat
36 from .ipkernel import IPythonKernel
36 from .ipkernel import IPythonKernel
37 from .parentpoller import ParentPollerUnix, ParentPollerWindows
37 from .parentpoller import ParentPollerUnix, ParentPollerWindows
38 from .session import (
38 from .session import (
39 Session, session_flags, session_aliases,
39 Session, session_flags, session_aliases,
40 )
40 )
41 from .zmqshell import ZMQInteractiveShell
41 from .zmqshell import ZMQInteractiveShell
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Flags and Aliases
44 # Flags and Aliases
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 kernel_aliases = dict(base_aliases)
47 kernel_aliases = dict(base_aliases)
48 kernel_aliases.update({
48 kernel_aliases.update({
49 'ip' : 'IPKernelApp.ip',
49 'ip' : 'IPKernelApp.ip',
50 'hb' : 'IPKernelApp.hb_port',
50 'hb' : 'IPKernelApp.hb_port',
51 'shell' : 'IPKernelApp.shell_port',
51 'shell' : 'IPKernelApp.shell_port',
52 'iopub' : 'IPKernelApp.iopub_port',
52 'iopub' : 'IPKernelApp.iopub_port',
53 'stdin' : 'IPKernelApp.stdin_port',
53 'stdin' : 'IPKernelApp.stdin_port',
54 'control' : 'IPKernelApp.control_port',
54 'control' : 'IPKernelApp.control_port',
55 'f' : 'IPKernelApp.connection_file',
55 'f' : 'IPKernelApp.connection_file',
56 'transport': 'IPKernelApp.transport',
56 'transport': 'IPKernelApp.transport',
57 })
57 })
58
58
59 kernel_flags = dict(base_flags)
59 kernel_flags = dict(base_flags)
60 kernel_flags.update({
60 kernel_flags.update({
61 'no-stdout' : (
61 'no-stdout' : (
62 {'IPKernelApp' : {'no_stdout' : True}},
62 {'IPKernelApp' : {'no_stdout' : True}},
63 "redirect stdout to the null device"),
63 "redirect stdout to the null device"),
64 'no-stderr' : (
64 'no-stderr' : (
65 {'IPKernelApp' : {'no_stderr' : True}},
65 {'IPKernelApp' : {'no_stderr' : True}},
66 "redirect stderr to the null device"),
66 "redirect stderr to the null device"),
67 'pylab' : (
67 'pylab' : (
68 {'IPKernelApp' : {'pylab' : 'auto'}},
68 {'IPKernelApp' : {'pylab' : 'auto'}},
69 """Pre-load matplotlib and numpy for interactive use with
69 """Pre-load matplotlib and numpy for interactive use with
70 the default matplotlib backend."""),
70 the default matplotlib backend."""),
71 })
71 })
72
72
73 # inherit flags&aliases for any IPython shell apps
73 # inherit flags&aliases for any IPython shell apps
74 kernel_aliases.update(shell_aliases)
74 kernel_aliases.update(shell_aliases)
75 kernel_flags.update(shell_flags)
75 kernel_flags.update(shell_flags)
76
76
77 # inherit flags&aliases for Sessions
77 # inherit flags&aliases for Sessions
78 kernel_aliases.update(session_aliases)
78 kernel_aliases.update(session_aliases)
79 kernel_flags.update(session_flags)
79 kernel_flags.update(session_flags)
80
80
81 _ctrl_c_message = """\
81 _ctrl_c_message = """\
82 NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.
82 NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.
83
83
84 To exit, you will have to explicitly quit this process, by either sending
84 To exit, you will have to explicitly quit this process, by either sending
85 "quit" from a client, or using Ctrl-\\ in UNIX-like environments.
85 "quit" from a client, or using Ctrl-\\ in UNIX-like environments.
86
86
87 To read more about this, see https://github.com/ipython/ipython/issues/2049
87 To read more about this, see https://github.com/ipython/ipython/issues/2049
88
88
89 """
89 """
90
90
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92 # Application class for starting an IPython Kernel
92 # Application class for starting an IPython Kernel
93 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
94
94
95 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,
95 class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,
96 ConnectionFileMixin):
96 ConnectionFileMixin):
97 name='ipython-kernel'
97 name='ipython-kernel'
98 aliases = Dict(kernel_aliases)
98 aliases = Dict(kernel_aliases)
99 flags = Dict(kernel_flags)
99 flags = Dict(kernel_flags)
100 classes = [IPythonKernel, ZMQInteractiveShell, ProfileDir, Session]
100 classes = [IPythonKernel, ZMQInteractiveShell, ProfileDir, Session]
101 # the kernel class, as an importstring
101 # the kernel class, as an importstring
102 kernel_class = Type('IPython.kernel.zmq.ipkernel.IPythonKernel', config=True,
102 kernel_class = Type('IPython.kernel.zmq.ipkernel.IPythonKernel', config=True,
103 klass='IPython.kernel.zmq.kernelbase.Kernel',
103 klass='IPython.kernel.zmq.kernelbase.Kernel',
104 help="""The Kernel subclass to be used.
104 help="""The Kernel subclass to be used.
105
105
106 This should allow easy re-use of the IPKernelApp entry point
106 This should allow easy re-use of the IPKernelApp entry point
107 to configure and launch kernels other than IPython's own.
107 to configure and launch kernels other than IPython's own.
108 """)
108 """)
109 kernel = Any()
109 kernel = Any()
110 poller = Any() # don't restrict this even though current pollers are all Threads
110 poller = Any() # don't restrict this even though current pollers are all Threads
111 heartbeat = Instance(Heartbeat)
111 heartbeat = Instance(Heartbeat, allow_none=True)
112 ports = Dict()
112 ports = Dict()
113
113
114 # connection info:
114 # connection info:
115
115
116 @property
116 @property
117 def abs_connection_file(self):
117 def abs_connection_file(self):
118 if os.path.basename(self.connection_file) == self.connection_file:
118 if os.path.basename(self.connection_file) == self.connection_file:
119 return os.path.join(self.profile_dir.security_dir, self.connection_file)
119 return os.path.join(self.profile_dir.security_dir, self.connection_file)
120 else:
120 else:
121 return self.connection_file
121 return self.connection_file
122
122
123
123
124 # streams, etc.
124 # streams, etc.
125 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
125 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
126 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
126 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
127 outstream_class = DottedObjectName('IPython.kernel.zmq.iostream.OutStream',
127 outstream_class = DottedObjectName('IPython.kernel.zmq.iostream.OutStream',
128 config=True, help="The importstring for the OutStream factory")
128 config=True, help="The importstring for the OutStream factory")
129 displayhook_class = DottedObjectName('IPython.kernel.zmq.displayhook.ZMQDisplayHook',
129 displayhook_class = DottedObjectName('IPython.kernel.zmq.displayhook.ZMQDisplayHook',
130 config=True, help="The importstring for the DisplayHook factory")
130 config=True, help="The importstring for the DisplayHook factory")
131
131
132 # polling
132 # polling
133 parent_handle = Integer(int(os.environ.get('JPY_PARENT_PID') or 0), config=True,
133 parent_handle = Integer(int(os.environ.get('JPY_PARENT_PID') or 0), config=True,
134 help="""kill this process if its parent dies. On Windows, the argument
134 help="""kill this process if its parent dies. On Windows, the argument
135 specifies the HANDLE of the parent process, otherwise it is simply boolean.
135 specifies the HANDLE of the parent process, otherwise it is simply boolean.
136 """)
136 """)
137 interrupt = Integer(int(os.environ.get('JPY_INTERRUPT_EVENT') or 0), config=True,
137 interrupt = Integer(int(os.environ.get('JPY_INTERRUPT_EVENT') or 0), config=True,
138 help="""ONLY USED ON WINDOWS
138 help="""ONLY USED ON WINDOWS
139 Interrupt this process when the parent is signaled.
139 Interrupt this process when the parent is signaled.
140 """)
140 """)
141
141
142 def init_crash_handler(self):
142 def init_crash_handler(self):
143 # Install minimal exception handling
143 # Install minimal exception handling
144 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
144 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
145 ostream=sys.__stdout__)
145 ostream=sys.__stdout__)
146
146
147 def init_poller(self):
147 def init_poller(self):
148 if sys.platform == 'win32':
148 if sys.platform == 'win32':
149 if self.interrupt or self.parent_handle:
149 if self.interrupt or self.parent_handle:
150 self.poller = ParentPollerWindows(self.interrupt, self.parent_handle)
150 self.poller = ParentPollerWindows(self.interrupt, self.parent_handle)
151 elif self.parent_handle:
151 elif self.parent_handle:
152 self.poller = ParentPollerUnix()
152 self.poller = ParentPollerUnix()
153
153
154 def _bind_socket(self, s, port):
154 def _bind_socket(self, s, port):
155 iface = '%s://%s' % (self.transport, self.ip)
155 iface = '%s://%s' % (self.transport, self.ip)
156 if self.transport == 'tcp':
156 if self.transport == 'tcp':
157 if port <= 0:
157 if port <= 0:
158 port = s.bind_to_random_port(iface)
158 port = s.bind_to_random_port(iface)
159 else:
159 else:
160 s.bind("tcp://%s:%i" % (self.ip, port))
160 s.bind("tcp://%s:%i" % (self.ip, port))
161 elif self.transport == 'ipc':
161 elif self.transport == 'ipc':
162 if port <= 0:
162 if port <= 0:
163 port = 1
163 port = 1
164 path = "%s-%i" % (self.ip, port)
164 path = "%s-%i" % (self.ip, port)
165 while os.path.exists(path):
165 while os.path.exists(path):
166 port = port + 1
166 port = port + 1
167 path = "%s-%i" % (self.ip, port)
167 path = "%s-%i" % (self.ip, port)
168 else:
168 else:
169 path = "%s-%i" % (self.ip, port)
169 path = "%s-%i" % (self.ip, port)
170 s.bind("ipc://%s" % path)
170 s.bind("ipc://%s" % path)
171 return port
171 return port
172
172
173 def write_connection_file(self):
173 def write_connection_file(self):
174 """write connection info to JSON file"""
174 """write connection info to JSON file"""
175 cf = self.abs_connection_file
175 cf = self.abs_connection_file
176 self.log.debug("Writing connection file: %s", cf)
176 self.log.debug("Writing connection file: %s", cf)
177 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
177 write_connection_file(cf, ip=self.ip, key=self.session.key, transport=self.transport,
178 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
178 shell_port=self.shell_port, stdin_port=self.stdin_port, hb_port=self.hb_port,
179 iopub_port=self.iopub_port, control_port=self.control_port)
179 iopub_port=self.iopub_port, control_port=self.control_port)
180
180
181 def cleanup_connection_file(self):
181 def cleanup_connection_file(self):
182 cf = self.abs_connection_file
182 cf = self.abs_connection_file
183 self.log.debug("Cleaning up connection file: %s", cf)
183 self.log.debug("Cleaning up connection file: %s", cf)
184 try:
184 try:
185 os.remove(cf)
185 os.remove(cf)
186 except (IOError, OSError):
186 except (IOError, OSError):
187 pass
187 pass
188
188
189 self.cleanup_ipc_files()
189 self.cleanup_ipc_files()
190
190
191 def init_connection_file(self):
191 def init_connection_file(self):
192 if not self.connection_file:
192 if not self.connection_file:
193 self.connection_file = "kernel-%s.json"%os.getpid()
193 self.connection_file = "kernel-%s.json"%os.getpid()
194 try:
194 try:
195 self.connection_file = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
195 self.connection_file = filefind(self.connection_file, ['.', self.profile_dir.security_dir])
196 except IOError:
196 except IOError:
197 self.log.debug("Connection file not found: %s", self.connection_file)
197 self.log.debug("Connection file not found: %s", self.connection_file)
198 # This means I own it, so I will clean it up:
198 # This means I own it, so I will clean it up:
199 atexit.register(self.cleanup_connection_file)
199 atexit.register(self.cleanup_connection_file)
200 return
200 return
201 try:
201 try:
202 self.load_connection_file()
202 self.load_connection_file()
203 except Exception:
203 except Exception:
204 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
204 self.log.error("Failed to load connection file: %r", self.connection_file, exc_info=True)
205 self.exit(1)
205 self.exit(1)
206
206
207 def init_sockets(self):
207 def init_sockets(self):
208 # Create a context, a session, and the kernel sockets.
208 # Create a context, a session, and the kernel sockets.
209 self.log.info("Starting the kernel at pid: %i", os.getpid())
209 self.log.info("Starting the kernel at pid: %i", os.getpid())
210 context = zmq.Context.instance()
210 context = zmq.Context.instance()
211 # Uncomment this to try closing the context.
211 # Uncomment this to try closing the context.
212 # atexit.register(context.term)
212 # atexit.register(context.term)
213
213
214 self.shell_socket = context.socket(zmq.ROUTER)
214 self.shell_socket = context.socket(zmq.ROUTER)
215 self.shell_socket.linger = 1000
215 self.shell_socket.linger = 1000
216 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
216 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
217 self.log.debug("shell ROUTER Channel on port: %i" % self.shell_port)
217 self.log.debug("shell ROUTER Channel on port: %i" % self.shell_port)
218
218
219 self.iopub_socket = context.socket(zmq.PUB)
219 self.iopub_socket = context.socket(zmq.PUB)
220 self.iopub_socket.linger = 1000
220 self.iopub_socket.linger = 1000
221 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
221 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
222 self.log.debug("iopub PUB Channel on port: %i" % self.iopub_port)
222 self.log.debug("iopub PUB Channel on port: %i" % self.iopub_port)
223
223
224 self.stdin_socket = context.socket(zmq.ROUTER)
224 self.stdin_socket = context.socket(zmq.ROUTER)
225 self.stdin_socket.linger = 1000
225 self.stdin_socket.linger = 1000
226 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
226 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
227 self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
227 self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
228
228
229 self.control_socket = context.socket(zmq.ROUTER)
229 self.control_socket = context.socket(zmq.ROUTER)
230 self.control_socket.linger = 1000
230 self.control_socket.linger = 1000
231 self.control_port = self._bind_socket(self.control_socket, self.control_port)
231 self.control_port = self._bind_socket(self.control_socket, self.control_port)
232 self.log.debug("control ROUTER Channel on port: %i" % self.control_port)
232 self.log.debug("control ROUTER Channel on port: %i" % self.control_port)
233
233
234 def init_heartbeat(self):
234 def init_heartbeat(self):
235 """start the heart beating"""
235 """start the heart beating"""
236 # heartbeat doesn't share context, because it mustn't be blocked
236 # heartbeat doesn't share context, because it mustn't be blocked
237 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
237 # by the GIL, which is accessed by libzmq when freeing zero-copy messages
238 hb_ctx = zmq.Context()
238 hb_ctx = zmq.Context()
239 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
239 self.heartbeat = Heartbeat(hb_ctx, (self.transport, self.ip, self.hb_port))
240 self.hb_port = self.heartbeat.port
240 self.hb_port = self.heartbeat.port
241 self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port)
241 self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port)
242 self.heartbeat.start()
242 self.heartbeat.start()
243
243
244 def log_connection_info(self):
244 def log_connection_info(self):
245 """display connection info, and store ports"""
245 """display connection info, and store ports"""
246 basename = os.path.basename(self.connection_file)
246 basename = os.path.basename(self.connection_file)
247 if basename == self.connection_file or \
247 if basename == self.connection_file or \
248 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
248 os.path.dirname(self.connection_file) == self.profile_dir.security_dir:
249 # use shortname
249 # use shortname
250 tail = basename
250 tail = basename
251 if self.profile != 'default':
251 if self.profile != 'default':
252 tail += " --profile %s" % self.profile
252 tail += " --profile %s" % self.profile
253 else:
253 else:
254 tail = self.connection_file
254 tail = self.connection_file
255 lines = [
255 lines = [
256 "To connect another client to this kernel, use:",
256 "To connect another client to this kernel, use:",
257 " --existing %s" % tail,
257 " --existing %s" % tail,
258 ]
258 ]
259 # log connection info
259 # log connection info
260 # info-level, so often not shown.
260 # info-level, so often not shown.
261 # frontends should use the %connect_info magic
261 # frontends should use the %connect_info magic
262 # to see the connection info
262 # to see the connection info
263 for line in lines:
263 for line in lines:
264 self.log.info(line)
264 self.log.info(line)
265 # also raw print to the terminal if no parent_handle (`ipython kernel`)
265 # also raw print to the terminal if no parent_handle (`ipython kernel`)
266 if not self.parent_handle:
266 if not self.parent_handle:
267 io.rprint(_ctrl_c_message)
267 io.rprint(_ctrl_c_message)
268 for line in lines:
268 for line in lines:
269 io.rprint(line)
269 io.rprint(line)
270
270
271 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
271 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
272 stdin=self.stdin_port, hb=self.hb_port,
272 stdin=self.stdin_port, hb=self.hb_port,
273 control=self.control_port)
273 control=self.control_port)
274
274
275 def init_blackhole(self):
275 def init_blackhole(self):
276 """redirects stdout/stderr to devnull if necessary"""
276 """redirects stdout/stderr to devnull if necessary"""
277 if self.no_stdout or self.no_stderr:
277 if self.no_stdout or self.no_stderr:
278 blackhole = open(os.devnull, 'w')
278 blackhole = open(os.devnull, 'w')
279 if self.no_stdout:
279 if self.no_stdout:
280 sys.stdout = sys.__stdout__ = blackhole
280 sys.stdout = sys.__stdout__ = blackhole
281 if self.no_stderr:
281 if self.no_stderr:
282 sys.stderr = sys.__stderr__ = blackhole
282 sys.stderr = sys.__stderr__ = blackhole
283
283
284 def init_io(self):
284 def init_io(self):
285 """Redirect input streams and set a display hook."""
285 """Redirect input streams and set a display hook."""
286 if self.outstream_class:
286 if self.outstream_class:
287 outstream_factory = import_item(str(self.outstream_class))
287 outstream_factory = import_item(str(self.outstream_class))
288 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
288 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
289 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
289 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
290 if self.displayhook_class:
290 if self.displayhook_class:
291 displayhook_factory = import_item(str(self.displayhook_class))
291 displayhook_factory = import_item(str(self.displayhook_class))
292 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
292 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
293
293
294 def init_signal(self):
294 def init_signal(self):
295 signal.signal(signal.SIGINT, signal.SIG_IGN)
295 signal.signal(signal.SIGINT, signal.SIG_IGN)
296
296
297 def init_kernel(self):
297 def init_kernel(self):
298 """Create the Kernel object itself"""
298 """Create the Kernel object itself"""
299 shell_stream = ZMQStream(self.shell_socket)
299 shell_stream = ZMQStream(self.shell_socket)
300 control_stream = ZMQStream(self.control_socket)
300 control_stream = ZMQStream(self.control_socket)
301
301
302 kernel_factory = self.kernel_class.instance
302 kernel_factory = self.kernel_class.instance
303
303
304 kernel = kernel_factory(parent=self, session=self.session,
304 kernel = kernel_factory(parent=self, session=self.session,
305 shell_streams=[shell_stream, control_stream],
305 shell_streams=[shell_stream, control_stream],
306 iopub_socket=self.iopub_socket,
306 iopub_socket=self.iopub_socket,
307 stdin_socket=self.stdin_socket,
307 stdin_socket=self.stdin_socket,
308 log=self.log,
308 log=self.log,
309 profile_dir=self.profile_dir,
309 profile_dir=self.profile_dir,
310 user_ns=self.user_ns,
310 user_ns=self.user_ns,
311 )
311 )
312 kernel.record_ports(self.ports)
312 kernel.record_ports(self.ports)
313 self.kernel = kernel
313 self.kernel = kernel
314
314
315 def init_gui_pylab(self):
315 def init_gui_pylab(self):
316 """Enable GUI event loop integration, taking pylab into account."""
316 """Enable GUI event loop integration, taking pylab into account."""
317
317
318 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
318 # Provide a wrapper for :meth:`InteractiveShellApp.init_gui_pylab`
319 # to ensure that any exception is printed straight to stderr.
319 # to ensure that any exception is printed straight to stderr.
320 # Normally _showtraceback associates the reply with an execution,
320 # Normally _showtraceback associates the reply with an execution,
321 # which means frontends will never draw it, as this exception
321 # which means frontends will never draw it, as this exception
322 # is not associated with any execute request.
322 # is not associated with any execute request.
323
323
324 shell = self.shell
324 shell = self.shell
325 _showtraceback = shell._showtraceback
325 _showtraceback = shell._showtraceback
326 try:
326 try:
327 # replace error-sending traceback with stderr
327 # replace error-sending traceback with stderr
328 def print_tb(etype, evalue, stb):
328 def print_tb(etype, evalue, stb):
329 print ("GUI event loop or pylab initialization failed",
329 print ("GUI event loop or pylab initialization failed",
330 file=io.stderr)
330 file=io.stderr)
331 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
331 print (shell.InteractiveTB.stb2text(stb), file=io.stderr)
332 shell._showtraceback = print_tb
332 shell._showtraceback = print_tb
333 InteractiveShellApp.init_gui_pylab(self)
333 InteractiveShellApp.init_gui_pylab(self)
334 finally:
334 finally:
335 shell._showtraceback = _showtraceback
335 shell._showtraceback = _showtraceback
336
336
337 def init_shell(self):
337 def init_shell(self):
338 self.shell = getattr(self.kernel, 'shell', None)
338 self.shell = getattr(self.kernel, 'shell', None)
339 if self.shell:
339 if self.shell:
340 self.shell.configurables.append(self)
340 self.shell.configurables.append(self)
341
341
342 @catch_config_error
342 @catch_config_error
343 def initialize(self, argv=None):
343 def initialize(self, argv=None):
344 super(IPKernelApp, self).initialize(argv)
344 super(IPKernelApp, self).initialize(argv)
345 self.init_blackhole()
345 self.init_blackhole()
346 self.init_connection_file()
346 self.init_connection_file()
347 self.init_poller()
347 self.init_poller()
348 self.init_sockets()
348 self.init_sockets()
349 self.init_heartbeat()
349 self.init_heartbeat()
350 # writing/displaying connection info must be *after* init_sockets/heartbeat
350 # writing/displaying connection info must be *after* init_sockets/heartbeat
351 self.log_connection_info()
351 self.log_connection_info()
352 self.write_connection_file()
352 self.write_connection_file()
353 self.init_io()
353 self.init_io()
354 self.init_signal()
354 self.init_signal()
355 self.init_kernel()
355 self.init_kernel()
356 # shell init steps
356 # shell init steps
357 self.init_path()
357 self.init_path()
358 self.init_shell()
358 self.init_shell()
359 if self.shell:
359 if self.shell:
360 self.init_gui_pylab()
360 self.init_gui_pylab()
361 self.init_extensions()
361 self.init_extensions()
362 self.init_code()
362 self.init_code()
363 # flush stdout/stderr, so that anything written to these streams during
363 # flush stdout/stderr, so that anything written to these streams during
364 # initialization do not get associated with the first execution request
364 # initialization do not get associated with the first execution request
365 sys.stdout.flush()
365 sys.stdout.flush()
366 sys.stderr.flush()
366 sys.stderr.flush()
367
367
368 def start(self):
368 def start(self):
369 if self.poller is not None:
369 if self.poller is not None:
370 self.poller.start()
370 self.poller.start()
371 self.kernel.start()
371 self.kernel.start()
372 try:
372 try:
373 ioloop.IOLoop.instance().start()
373 ioloop.IOLoop.instance().start()
374 except KeyboardInterrupt:
374 except KeyboardInterrupt:
375 pass
375 pass
376
376
377 launch_new_instance = IPKernelApp.launch_instance
377 launch_new_instance = IPKernelApp.launch_instance
378
378
379 def main():
379 def main():
380 """Run an IPKernel as an application"""
380 """Run an IPKernel as an application"""
381 app = IPKernelApp.instance()
381 app = IPKernelApp.instance()
382 app.initialize()
382 app.initialize()
383 app.start()
383 app.start()
384
384
385
385
386 if __name__ == '__main__':
386 if __name__ == '__main__':
387 main()
387 main()
@@ -1,701 +1,701 b''
1 """Base class for a kernel that talks to frontends over 0MQ."""
1 """Base class for a kernel that talks to frontends over 0MQ."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 import sys
8 import sys
9 import time
9 import time
10 import logging
10 import logging
11 import uuid
11 import uuid
12
12
13 from datetime import datetime
13 from datetime import datetime
14 from signal import (
14 from signal import (
15 signal, default_int_handler, SIGINT
15 signal, default_int_handler, SIGINT
16 )
16 )
17
17
18 import zmq
18 import zmq
19 from zmq.eventloop import ioloop
19 from zmq.eventloop import ioloop
20 from zmq.eventloop.zmqstream import ZMQStream
20 from zmq.eventloop.zmqstream import ZMQStream
21
21
22 from IPython.config.configurable import SingletonConfigurable
22 from IPython.config.configurable import SingletonConfigurable
23 from IPython.core.error import StdinNotImplementedError
23 from IPython.core.error import StdinNotImplementedError
24 from IPython.core import release
24 from IPython.core import release
25 from IPython.utils import py3compat
25 from IPython.utils import py3compat
26 from IPython.utils.py3compat import unicode_type, string_types
26 from IPython.utils.py3compat import unicode_type, string_types
27 from IPython.utils.jsonutil import json_clean
27 from IPython.utils.jsonutil import json_clean
28 from IPython.utils.traitlets import (
28 from IPython.utils.traitlets import (
29 Any, Instance, Float, Dict, List, Set, Integer, Unicode, Bool,
29 Any, Instance, Float, Dict, List, Set, Integer, Unicode, Bool,
30 )
30 )
31
31
32 from .session import Session
32 from .session import Session
33
33
34
34
35 class Kernel(SingletonConfigurable):
35 class Kernel(SingletonConfigurable):
36
36
37 #---------------------------------------------------------------------------
37 #---------------------------------------------------------------------------
38 # Kernel interface
38 # Kernel interface
39 #---------------------------------------------------------------------------
39 #---------------------------------------------------------------------------
40
40
41 # attribute to override with a GUI
41 # attribute to override with a GUI
42 eventloop = Any(None)
42 eventloop = Any(None)
43 def _eventloop_changed(self, name, old, new):
43 def _eventloop_changed(self, name, old, new):
44 """schedule call to eventloop from IOLoop"""
44 """schedule call to eventloop from IOLoop"""
45 loop = ioloop.IOLoop.instance()
45 loop = ioloop.IOLoop.instance()
46 loop.add_callback(self.enter_eventloop)
46 loop.add_callback(self.enter_eventloop)
47
47
48 session = Instance(Session)
48 session = Instance(Session, allow_none=True)
49 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
49 profile_dir = Instance('IPython.core.profiledir.ProfileDir', allow_none=True)
50 shell_streams = List()
50 shell_streams = List()
51 control_stream = Instance(ZMQStream)
51 control_stream = Instance(ZMQStream, allow_none=True)
52 iopub_socket = Instance(zmq.Socket)
52 iopub_socket = Instance(zmq.Socket, allow_none=True)
53 stdin_socket = Instance(zmq.Socket)
53 stdin_socket = Instance(zmq.Socket, allow_none=True)
54 log = Instance(logging.Logger)
54 log = Instance(logging.Logger, allow_none=True)
55
55
56 # identities:
56 # identities:
57 int_id = Integer(-1)
57 int_id = Integer(-1)
58 ident = Unicode()
58 ident = Unicode()
59
59
60 def _ident_default(self):
60 def _ident_default(self):
61 return unicode_type(uuid.uuid4())
61 return unicode_type(uuid.uuid4())
62
62
63 # This should be overridden by wrapper kernels that implement any real
63 # This should be overridden by wrapper kernels that implement any real
64 # language.
64 # language.
65 language_info = {}
65 language_info = {}
66
66
67 # any links that should go in the help menu
67 # any links that should go in the help menu
68 help_links = List()
68 help_links = List()
69
69
70 # Private interface
70 # Private interface
71
71
72 _darwin_app_nap = Bool(True, config=True,
72 _darwin_app_nap = Bool(True, config=True,
73 help="""Whether to use appnope for compatiblity with OS X App Nap.
73 help="""Whether to use appnope for compatiblity with OS X App Nap.
74
74
75 Only affects OS X >= 10.9.
75 Only affects OS X >= 10.9.
76 """
76 """
77 )
77 )
78
78
79 # track associations with current request
79 # track associations with current request
80 _allow_stdin = Bool(False)
80 _allow_stdin = Bool(False)
81 _parent_header = Dict()
81 _parent_header = Dict()
82 _parent_ident = Any(b'')
82 _parent_ident = Any(b'')
83 # Time to sleep after flushing the stdout/err buffers in each execute
83 # Time to sleep after flushing the stdout/err buffers in each execute
84 # cycle. While this introduces a hard limit on the minimal latency of the
84 # cycle. While this introduces a hard limit on the minimal latency of the
85 # execute cycle, it helps prevent output synchronization problems for
85 # execute cycle, it helps prevent output synchronization problems for
86 # clients.
86 # clients.
87 # Units are in seconds. The minimum zmq latency on local host is probably
87 # Units are in seconds. The minimum zmq latency on local host is probably
88 # ~150 microseconds, set this to 500us for now. We may need to increase it
88 # ~150 microseconds, set this to 500us for now. We may need to increase it
89 # a little if it's not enough after more interactive testing.
89 # a little if it's not enough after more interactive testing.
90 _execute_sleep = Float(0.0005, config=True)
90 _execute_sleep = Float(0.0005, config=True)
91
91
92 # Frequency of the kernel's event loop.
92 # Frequency of the kernel's event loop.
93 # Units are in seconds, kernel subclasses for GUI toolkits may need to
93 # Units are in seconds, kernel subclasses for GUI toolkits may need to
94 # adapt to milliseconds.
94 # adapt to milliseconds.
95 _poll_interval = Float(0.05, config=True)
95 _poll_interval = Float(0.05, config=True)
96
96
97 # If the shutdown was requested over the network, we leave here the
97 # If the shutdown was requested over the network, we leave here the
98 # necessary reply message so it can be sent by our registered atexit
98 # necessary reply message so it can be sent by our registered atexit
99 # handler. This ensures that the reply is only sent to clients truly at
99 # handler. This ensures that the reply is only sent to clients truly at
100 # the end of our shutdown process (which happens after the underlying
100 # the end of our shutdown process (which happens after the underlying
101 # IPython shell's own shutdown).
101 # IPython shell's own shutdown).
102 _shutdown_message = None
102 _shutdown_message = None
103
103
104 # This is a dict of port number that the kernel is listening on. It is set
104 # This is a dict of port number that the kernel is listening on. It is set
105 # by record_ports and used by connect_request.
105 # by record_ports and used by connect_request.
106 _recorded_ports = Dict()
106 _recorded_ports = Dict()
107
107
108 # set of aborted msg_ids
108 # set of aborted msg_ids
109 aborted = Set()
109 aborted = Set()
110
110
111 # Track execution count here. For IPython, we override this to use the
111 # Track execution count here. For IPython, we override this to use the
112 # execution count we store in the shell.
112 # execution count we store in the shell.
113 execution_count = 0
113 execution_count = 0
114
114
115
115
116 def __init__(self, **kwargs):
116 def __init__(self, **kwargs):
117 super(Kernel, self).__init__(**kwargs)
117 super(Kernel, self).__init__(**kwargs)
118
118
119 # Build dict of handlers for message types
119 # Build dict of handlers for message types
120 msg_types = [ 'execute_request', 'complete_request',
120 msg_types = [ 'execute_request', 'complete_request',
121 'inspect_request', 'history_request',
121 'inspect_request', 'history_request',
122 'kernel_info_request',
122 'kernel_info_request',
123 'connect_request', 'shutdown_request',
123 'connect_request', 'shutdown_request',
124 'apply_request', 'is_complete_request',
124 'apply_request', 'is_complete_request',
125 ]
125 ]
126 self.shell_handlers = {}
126 self.shell_handlers = {}
127 for msg_type in msg_types:
127 for msg_type in msg_types:
128 self.shell_handlers[msg_type] = getattr(self, msg_type)
128 self.shell_handlers[msg_type] = getattr(self, msg_type)
129
129
130 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
130 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
131 self.control_handlers = {}
131 self.control_handlers = {}
132 for msg_type in control_msg_types:
132 for msg_type in control_msg_types:
133 self.control_handlers[msg_type] = getattr(self, msg_type)
133 self.control_handlers[msg_type] = getattr(self, msg_type)
134
134
135
135
136 def dispatch_control(self, msg):
136 def dispatch_control(self, msg):
137 """dispatch control requests"""
137 """dispatch control requests"""
138 idents,msg = self.session.feed_identities(msg, copy=False)
138 idents,msg = self.session.feed_identities(msg, copy=False)
139 try:
139 try:
140 msg = self.session.deserialize(msg, content=True, copy=False)
140 msg = self.session.deserialize(msg, content=True, copy=False)
141 except:
141 except:
142 self.log.error("Invalid Control Message", exc_info=True)
142 self.log.error("Invalid Control Message", exc_info=True)
143 return
143 return
144
144
145 self.log.debug("Control received: %s", msg)
145 self.log.debug("Control received: %s", msg)
146
146
147 # Set the parent message for side effects.
147 # Set the parent message for side effects.
148 self.set_parent(idents, msg)
148 self.set_parent(idents, msg)
149 self._publish_status(u'busy')
149 self._publish_status(u'busy')
150
150
151 header = msg['header']
151 header = msg['header']
152 msg_type = header['msg_type']
152 msg_type = header['msg_type']
153
153
154 handler = self.control_handlers.get(msg_type, None)
154 handler = self.control_handlers.get(msg_type, None)
155 if handler is None:
155 if handler is None:
156 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
156 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
157 else:
157 else:
158 try:
158 try:
159 handler(self.control_stream, idents, msg)
159 handler(self.control_stream, idents, msg)
160 except Exception:
160 except Exception:
161 self.log.error("Exception in control handler:", exc_info=True)
161 self.log.error("Exception in control handler:", exc_info=True)
162
162
163 sys.stdout.flush()
163 sys.stdout.flush()
164 sys.stderr.flush()
164 sys.stderr.flush()
165 self._publish_status(u'idle')
165 self._publish_status(u'idle')
166
166
167 def dispatch_shell(self, stream, msg):
167 def dispatch_shell(self, stream, msg):
168 """dispatch shell requests"""
168 """dispatch shell requests"""
169 # flush control requests first
169 # flush control requests first
170 if self.control_stream:
170 if self.control_stream:
171 self.control_stream.flush()
171 self.control_stream.flush()
172
172
173 idents,msg = self.session.feed_identities(msg, copy=False)
173 idents,msg = self.session.feed_identities(msg, copy=False)
174 try:
174 try:
175 msg = self.session.deserialize(msg, content=True, copy=False)
175 msg = self.session.deserialize(msg, content=True, copy=False)
176 except:
176 except:
177 self.log.error("Invalid Message", exc_info=True)
177 self.log.error("Invalid Message", exc_info=True)
178 return
178 return
179
179
180 # Set the parent message for side effects.
180 # Set the parent message for side effects.
181 self.set_parent(idents, msg)
181 self.set_parent(idents, msg)
182 self._publish_status(u'busy')
182 self._publish_status(u'busy')
183
183
184 header = msg['header']
184 header = msg['header']
185 msg_id = header['msg_id']
185 msg_id = header['msg_id']
186 msg_type = msg['header']['msg_type']
186 msg_type = msg['header']['msg_type']
187
187
188 # Print some info about this message and leave a '--->' marker, so it's
188 # Print some info about this message and leave a '--->' marker, so it's
189 # easier to trace visually the message chain when debugging. Each
189 # easier to trace visually the message chain when debugging. Each
190 # handler prints its message at the end.
190 # handler prints its message at the end.
191 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
191 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
192 self.log.debug(' Content: %s\n --->\n ', msg['content'])
192 self.log.debug(' Content: %s\n --->\n ', msg['content'])
193
193
194 if msg_id in self.aborted:
194 if msg_id in self.aborted:
195 self.aborted.remove(msg_id)
195 self.aborted.remove(msg_id)
196 # is it safe to assume a msg_id will not be resubmitted?
196 # is it safe to assume a msg_id will not be resubmitted?
197 reply_type = msg_type.split('_')[0] + '_reply'
197 reply_type = msg_type.split('_')[0] + '_reply'
198 status = {'status' : 'aborted'}
198 status = {'status' : 'aborted'}
199 md = {'engine' : self.ident}
199 md = {'engine' : self.ident}
200 md.update(status)
200 md.update(status)
201 self.session.send(stream, reply_type, metadata=md,
201 self.session.send(stream, reply_type, metadata=md,
202 content=status, parent=msg, ident=idents)
202 content=status, parent=msg, ident=idents)
203 return
203 return
204
204
205 handler = self.shell_handlers.get(msg_type, None)
205 handler = self.shell_handlers.get(msg_type, None)
206 if handler is None:
206 if handler is None:
207 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
207 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
208 else:
208 else:
209 # ensure default_int_handler during handler call
209 # ensure default_int_handler during handler call
210 sig = signal(SIGINT, default_int_handler)
210 sig = signal(SIGINT, default_int_handler)
211 self.log.debug("%s: %s", msg_type, msg)
211 self.log.debug("%s: %s", msg_type, msg)
212 try:
212 try:
213 handler(stream, idents, msg)
213 handler(stream, idents, msg)
214 except Exception:
214 except Exception:
215 self.log.error("Exception in message handler:", exc_info=True)
215 self.log.error("Exception in message handler:", exc_info=True)
216 finally:
216 finally:
217 signal(SIGINT, sig)
217 signal(SIGINT, sig)
218
218
219 sys.stdout.flush()
219 sys.stdout.flush()
220 sys.stderr.flush()
220 sys.stderr.flush()
221 self._publish_status(u'idle')
221 self._publish_status(u'idle')
222
222
223 def enter_eventloop(self):
223 def enter_eventloop(self):
224 """enter eventloop"""
224 """enter eventloop"""
225 self.log.info("entering eventloop %s", self.eventloop)
225 self.log.info("entering eventloop %s", self.eventloop)
226 for stream in self.shell_streams:
226 for stream in self.shell_streams:
227 # flush any pending replies,
227 # flush any pending replies,
228 # which may be skipped by entering the eventloop
228 # which may be skipped by entering the eventloop
229 stream.flush(zmq.POLLOUT)
229 stream.flush(zmq.POLLOUT)
230 # restore default_int_handler
230 # restore default_int_handler
231 signal(SIGINT, default_int_handler)
231 signal(SIGINT, default_int_handler)
232 while self.eventloop is not None:
232 while self.eventloop is not None:
233 try:
233 try:
234 self.eventloop(self)
234 self.eventloop(self)
235 except KeyboardInterrupt:
235 except KeyboardInterrupt:
236 # Ctrl-C shouldn't crash the kernel
236 # Ctrl-C shouldn't crash the kernel
237 self.log.error("KeyboardInterrupt caught in kernel")
237 self.log.error("KeyboardInterrupt caught in kernel")
238 continue
238 continue
239 else:
239 else:
240 # eventloop exited cleanly, this means we should stop (right?)
240 # eventloop exited cleanly, this means we should stop (right?)
241 self.eventloop = None
241 self.eventloop = None
242 break
242 break
243 self.log.info("exiting eventloop")
243 self.log.info("exiting eventloop")
244
244
245 def start(self):
245 def start(self):
246 """register dispatchers for streams"""
246 """register dispatchers for streams"""
247 if self.control_stream:
247 if self.control_stream:
248 self.control_stream.on_recv(self.dispatch_control, copy=False)
248 self.control_stream.on_recv(self.dispatch_control, copy=False)
249
249
250 def make_dispatcher(stream):
250 def make_dispatcher(stream):
251 def dispatcher(msg):
251 def dispatcher(msg):
252 return self.dispatch_shell(stream, msg)
252 return self.dispatch_shell(stream, msg)
253 return dispatcher
253 return dispatcher
254
254
255 for s in self.shell_streams:
255 for s in self.shell_streams:
256 s.on_recv(make_dispatcher(s), copy=False)
256 s.on_recv(make_dispatcher(s), copy=False)
257
257
258 # publish idle status
258 # publish idle status
259 self._publish_status('starting')
259 self._publish_status('starting')
260
260
261 def do_one_iteration(self):
261 def do_one_iteration(self):
262 """step eventloop just once"""
262 """step eventloop just once"""
263 if self.control_stream:
263 if self.control_stream:
264 self.control_stream.flush()
264 self.control_stream.flush()
265 for stream in self.shell_streams:
265 for stream in self.shell_streams:
266 # handle at most one request per iteration
266 # handle at most one request per iteration
267 stream.flush(zmq.POLLIN, 1)
267 stream.flush(zmq.POLLIN, 1)
268 stream.flush(zmq.POLLOUT)
268 stream.flush(zmq.POLLOUT)
269
269
270
270
271 def record_ports(self, ports):
271 def record_ports(self, ports):
272 """Record the ports that this kernel is using.
272 """Record the ports that this kernel is using.
273
273
274 The creator of the Kernel instance must call this methods if they
274 The creator of the Kernel instance must call this methods if they
275 want the :meth:`connect_request` method to return the port numbers.
275 want the :meth:`connect_request` method to return the port numbers.
276 """
276 """
277 self._recorded_ports = ports
277 self._recorded_ports = ports
278
278
279 #---------------------------------------------------------------------------
279 #---------------------------------------------------------------------------
280 # Kernel request handlers
280 # Kernel request handlers
281 #---------------------------------------------------------------------------
281 #---------------------------------------------------------------------------
282
282
283 def _make_metadata(self, other=None):
283 def _make_metadata(self, other=None):
284 """init metadata dict, for execute/apply_reply"""
284 """init metadata dict, for execute/apply_reply"""
285 new_md = {
285 new_md = {
286 'dependencies_met' : True,
286 'dependencies_met' : True,
287 'engine' : self.ident,
287 'engine' : self.ident,
288 'started': datetime.now(),
288 'started': datetime.now(),
289 }
289 }
290 if other:
290 if other:
291 new_md.update(other)
291 new_md.update(other)
292 return new_md
292 return new_md
293
293
294 def _publish_execute_input(self, code, parent, execution_count):
294 def _publish_execute_input(self, code, parent, execution_count):
295 """Publish the code request on the iopub stream."""
295 """Publish the code request on the iopub stream."""
296
296
297 self.session.send(self.iopub_socket, u'execute_input',
297 self.session.send(self.iopub_socket, u'execute_input',
298 {u'code':code, u'execution_count': execution_count},
298 {u'code':code, u'execution_count': execution_count},
299 parent=parent, ident=self._topic('execute_input')
299 parent=parent, ident=self._topic('execute_input')
300 )
300 )
301
301
302 def _publish_status(self, status, parent=None):
302 def _publish_status(self, status, parent=None):
303 """send status (busy/idle) on IOPub"""
303 """send status (busy/idle) on IOPub"""
304 self.session.send(self.iopub_socket,
304 self.session.send(self.iopub_socket,
305 u'status',
305 u'status',
306 {u'execution_state': status},
306 {u'execution_state': status},
307 parent=parent or self._parent_header,
307 parent=parent or self._parent_header,
308 ident=self._topic('status'),
308 ident=self._topic('status'),
309 )
309 )
310
310
311 def set_parent(self, ident, parent):
311 def set_parent(self, ident, parent):
312 """Set the current parent_header
312 """Set the current parent_header
313
313
314 Side effects (IOPub messages) and replies are associated with
314 Side effects (IOPub messages) and replies are associated with
315 the request that caused them via the parent_header.
315 the request that caused them via the parent_header.
316
316
317 The parent identity is used to route input_request messages
317 The parent identity is used to route input_request messages
318 on the stdin channel.
318 on the stdin channel.
319 """
319 """
320 self._parent_ident = ident
320 self._parent_ident = ident
321 self._parent_header = parent
321 self._parent_header = parent
322
322
323 def send_response(self, stream, msg_or_type, content=None, ident=None,
323 def send_response(self, stream, msg_or_type, content=None, ident=None,
324 buffers=None, track=False, header=None, metadata=None):
324 buffers=None, track=False, header=None, metadata=None):
325 """Send a response to the message we're currently processing.
325 """Send a response to the message we're currently processing.
326
326
327 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
327 This accepts all the parameters of :meth:`IPython.kernel.zmq.session.Session.send`
328 except ``parent``.
328 except ``parent``.
329
329
330 This relies on :meth:`set_parent` having been called for the current
330 This relies on :meth:`set_parent` having been called for the current
331 message.
331 message.
332 """
332 """
333 return self.session.send(stream, msg_or_type, content, self._parent_header,
333 return self.session.send(stream, msg_or_type, content, self._parent_header,
334 ident, buffers, track, header, metadata)
334 ident, buffers, track, header, metadata)
335
335
336 def execute_request(self, stream, ident, parent):
336 def execute_request(self, stream, ident, parent):
337 """handle an execute_request"""
337 """handle an execute_request"""
338
338
339 try:
339 try:
340 content = parent[u'content']
340 content = parent[u'content']
341 code = py3compat.cast_unicode_py2(content[u'code'])
341 code = py3compat.cast_unicode_py2(content[u'code'])
342 silent = content[u'silent']
342 silent = content[u'silent']
343 store_history = content.get(u'store_history', not silent)
343 store_history = content.get(u'store_history', not silent)
344 user_expressions = content.get('user_expressions', {})
344 user_expressions = content.get('user_expressions', {})
345 allow_stdin = content.get('allow_stdin', False)
345 allow_stdin = content.get('allow_stdin', False)
346 except:
346 except:
347 self.log.error("Got bad msg: ")
347 self.log.error("Got bad msg: ")
348 self.log.error("%s", parent)
348 self.log.error("%s", parent)
349 return
349 return
350
350
351 stop_on_error = content.get('stop_on_error', True)
351 stop_on_error = content.get('stop_on_error', True)
352
352
353 md = self._make_metadata(parent['metadata'])
353 md = self._make_metadata(parent['metadata'])
354
354
355 # Re-broadcast our input for the benefit of listening clients, and
355 # Re-broadcast our input for the benefit of listening clients, and
356 # start computing output
356 # start computing output
357 if not silent:
357 if not silent:
358 self.execution_count += 1
358 self.execution_count += 1
359 self._publish_execute_input(code, parent, self.execution_count)
359 self._publish_execute_input(code, parent, self.execution_count)
360
360
361 reply_content = self.do_execute(code, silent, store_history,
361 reply_content = self.do_execute(code, silent, store_history,
362 user_expressions, allow_stdin)
362 user_expressions, allow_stdin)
363
363
364 # Flush output before sending the reply.
364 # Flush output before sending the reply.
365 sys.stdout.flush()
365 sys.stdout.flush()
366 sys.stderr.flush()
366 sys.stderr.flush()
367 # FIXME: on rare occasions, the flush doesn't seem to make it to the
367 # FIXME: on rare occasions, the flush doesn't seem to make it to the
368 # clients... This seems to mitigate the problem, but we definitely need
368 # clients... This seems to mitigate the problem, but we definitely need
369 # to better understand what's going on.
369 # to better understand what's going on.
370 if self._execute_sleep:
370 if self._execute_sleep:
371 time.sleep(self._execute_sleep)
371 time.sleep(self._execute_sleep)
372
372
373 # Send the reply.
373 # Send the reply.
374 reply_content = json_clean(reply_content)
374 reply_content = json_clean(reply_content)
375
375
376 md['status'] = reply_content['status']
376 md['status'] = reply_content['status']
377 if reply_content['status'] == 'error' and \
377 if reply_content['status'] == 'error' and \
378 reply_content['ename'] == 'UnmetDependency':
378 reply_content['ename'] == 'UnmetDependency':
379 md['dependencies_met'] = False
379 md['dependencies_met'] = False
380
380
381 reply_msg = self.session.send(stream, u'execute_reply',
381 reply_msg = self.session.send(stream, u'execute_reply',
382 reply_content, parent, metadata=md,
382 reply_content, parent, metadata=md,
383 ident=ident)
383 ident=ident)
384
384
385 self.log.debug("%s", reply_msg)
385 self.log.debug("%s", reply_msg)
386
386
387 if not silent and reply_msg['content']['status'] == u'error' and stop_on_error:
387 if not silent and reply_msg['content']['status'] == u'error' and stop_on_error:
388 self._abort_queues()
388 self._abort_queues()
389
389
390 def do_execute(self, code, silent, store_history=True,
390 def do_execute(self, code, silent, store_history=True,
391 user_expressions=None, allow_stdin=False):
391 user_expressions=None, allow_stdin=False):
392 """Execute user code. Must be overridden by subclasses.
392 """Execute user code. Must be overridden by subclasses.
393 """
393 """
394 raise NotImplementedError
394 raise NotImplementedError
395
395
396 def complete_request(self, stream, ident, parent):
396 def complete_request(self, stream, ident, parent):
397 content = parent['content']
397 content = parent['content']
398 code = content['code']
398 code = content['code']
399 cursor_pos = content['cursor_pos']
399 cursor_pos = content['cursor_pos']
400
400
401 matches = self.do_complete(code, cursor_pos)
401 matches = self.do_complete(code, cursor_pos)
402 matches = json_clean(matches)
402 matches = json_clean(matches)
403 completion_msg = self.session.send(stream, 'complete_reply',
403 completion_msg = self.session.send(stream, 'complete_reply',
404 matches, parent, ident)
404 matches, parent, ident)
405 self.log.debug("%s", completion_msg)
405 self.log.debug("%s", completion_msg)
406
406
407 def do_complete(self, code, cursor_pos):
407 def do_complete(self, code, cursor_pos):
408 """Override in subclasses to find completions.
408 """Override in subclasses to find completions.
409 """
409 """
410 return {'matches' : [],
410 return {'matches' : [],
411 'cursor_end' : cursor_pos,
411 'cursor_end' : cursor_pos,
412 'cursor_start' : cursor_pos,
412 'cursor_start' : cursor_pos,
413 'metadata' : {},
413 'metadata' : {},
414 'status' : 'ok'}
414 'status' : 'ok'}
415
415
416 def inspect_request(self, stream, ident, parent):
416 def inspect_request(self, stream, ident, parent):
417 content = parent['content']
417 content = parent['content']
418
418
419 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
419 reply_content = self.do_inspect(content['code'], content['cursor_pos'],
420 content.get('detail_level', 0))
420 content.get('detail_level', 0))
421 # Before we send this object over, we scrub it for JSON usage
421 # Before we send this object over, we scrub it for JSON usage
422 reply_content = json_clean(reply_content)
422 reply_content = json_clean(reply_content)
423 msg = self.session.send(stream, 'inspect_reply',
423 msg = self.session.send(stream, 'inspect_reply',
424 reply_content, parent, ident)
424 reply_content, parent, ident)
425 self.log.debug("%s", msg)
425 self.log.debug("%s", msg)
426
426
427 def do_inspect(self, code, cursor_pos, detail_level=0):
427 def do_inspect(self, code, cursor_pos, detail_level=0):
428 """Override in subclasses to allow introspection.
428 """Override in subclasses to allow introspection.
429 """
429 """
430 return {'status': 'ok', 'data':{}, 'metadata':{}, 'found':False}
430 return {'status': 'ok', 'data':{}, 'metadata':{}, 'found':False}
431
431
432 def history_request(self, stream, ident, parent):
432 def history_request(self, stream, ident, parent):
433 content = parent['content']
433 content = parent['content']
434
434
435 reply_content = self.do_history(**content)
435 reply_content = self.do_history(**content)
436
436
437 reply_content = json_clean(reply_content)
437 reply_content = json_clean(reply_content)
438 msg = self.session.send(stream, 'history_reply',
438 msg = self.session.send(stream, 'history_reply',
439 reply_content, parent, ident)
439 reply_content, parent, ident)
440 self.log.debug("%s", msg)
440 self.log.debug("%s", msg)
441
441
442 def do_history(self, hist_access_type, output, raw, session=None, start=None,
442 def do_history(self, hist_access_type, output, raw, session=None, start=None,
443 stop=None, n=None, pattern=None, unique=False):
443 stop=None, n=None, pattern=None, unique=False):
444 """Override in subclasses to access history.
444 """Override in subclasses to access history.
445 """
445 """
446 return {'history': []}
446 return {'history': []}
447
447
448 def connect_request(self, stream, ident, parent):
448 def connect_request(self, stream, ident, parent):
449 if self._recorded_ports is not None:
449 if self._recorded_ports is not None:
450 content = self._recorded_ports.copy()
450 content = self._recorded_ports.copy()
451 else:
451 else:
452 content = {}
452 content = {}
453 msg = self.session.send(stream, 'connect_reply',
453 msg = self.session.send(stream, 'connect_reply',
454 content, parent, ident)
454 content, parent, ident)
455 self.log.debug("%s", msg)
455 self.log.debug("%s", msg)
456
456
457 @property
457 @property
458 def kernel_info(self):
458 def kernel_info(self):
459 return {
459 return {
460 'protocol_version': release.kernel_protocol_version,
460 'protocol_version': release.kernel_protocol_version,
461 'implementation': self.implementation,
461 'implementation': self.implementation,
462 'implementation_version': self.implementation_version,
462 'implementation_version': self.implementation_version,
463 'language_info': self.language_info,
463 'language_info': self.language_info,
464 'banner': self.banner,
464 'banner': self.banner,
465 'help_links': self.help_links,
465 'help_links': self.help_links,
466 }
466 }
467
467
468 def kernel_info_request(self, stream, ident, parent):
468 def kernel_info_request(self, stream, ident, parent):
469 msg = self.session.send(stream, 'kernel_info_reply',
469 msg = self.session.send(stream, 'kernel_info_reply',
470 self.kernel_info, parent, ident)
470 self.kernel_info, parent, ident)
471 self.log.debug("%s", msg)
471 self.log.debug("%s", msg)
472
472
473 def shutdown_request(self, stream, ident, parent):
473 def shutdown_request(self, stream, ident, parent):
474 content = self.do_shutdown(parent['content']['restart'])
474 content = self.do_shutdown(parent['content']['restart'])
475 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
475 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
476 # same content, but different msg_id for broadcasting on IOPub
476 # same content, but different msg_id for broadcasting on IOPub
477 self._shutdown_message = self.session.msg(u'shutdown_reply',
477 self._shutdown_message = self.session.msg(u'shutdown_reply',
478 content, parent
478 content, parent
479 )
479 )
480
480
481 self._at_shutdown()
481 self._at_shutdown()
482 # call sys.exit after a short delay
482 # call sys.exit after a short delay
483 loop = ioloop.IOLoop.instance()
483 loop = ioloop.IOLoop.instance()
484 loop.add_timeout(time.time()+0.1, loop.stop)
484 loop.add_timeout(time.time()+0.1, loop.stop)
485
485
486 def do_shutdown(self, restart):
486 def do_shutdown(self, restart):
487 """Override in subclasses to do things when the frontend shuts down the
487 """Override in subclasses to do things when the frontend shuts down the
488 kernel.
488 kernel.
489 """
489 """
490 return {'status': 'ok', 'restart': restart}
490 return {'status': 'ok', 'restart': restart}
491
491
492 def is_complete_request(self, stream, ident, parent):
492 def is_complete_request(self, stream, ident, parent):
493 content = parent['content']
493 content = parent['content']
494 code = content['code']
494 code = content['code']
495
495
496 reply_content = self.do_is_complete(code)
496 reply_content = self.do_is_complete(code)
497 reply_content = json_clean(reply_content)
497 reply_content = json_clean(reply_content)
498 reply_msg = self.session.send(stream, 'is_complete_reply',
498 reply_msg = self.session.send(stream, 'is_complete_reply',
499 reply_content, parent, ident)
499 reply_content, parent, ident)
500 self.log.debug("%s", reply_msg)
500 self.log.debug("%s", reply_msg)
501
501
502 def do_is_complete(self, code):
502 def do_is_complete(self, code):
503 """Override in subclasses to find completions.
503 """Override in subclasses to find completions.
504 """
504 """
505 return {'status' : 'unknown',
505 return {'status' : 'unknown',
506 }
506 }
507
507
508 #---------------------------------------------------------------------------
508 #---------------------------------------------------------------------------
509 # Engine methods
509 # Engine methods
510 #---------------------------------------------------------------------------
510 #---------------------------------------------------------------------------
511
511
512 def apply_request(self, stream, ident, parent):
512 def apply_request(self, stream, ident, parent):
513 try:
513 try:
514 content = parent[u'content']
514 content = parent[u'content']
515 bufs = parent[u'buffers']
515 bufs = parent[u'buffers']
516 msg_id = parent['header']['msg_id']
516 msg_id = parent['header']['msg_id']
517 except:
517 except:
518 self.log.error("Got bad msg: %s", parent, exc_info=True)
518 self.log.error("Got bad msg: %s", parent, exc_info=True)
519 return
519 return
520
520
521 md = self._make_metadata(parent['metadata'])
521 md = self._make_metadata(parent['metadata'])
522
522
523 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
523 reply_content, result_buf = self.do_apply(content, bufs, msg_id, md)
524
524
525 # put 'ok'/'error' status in header, for scheduler introspection:
525 # put 'ok'/'error' status in header, for scheduler introspection:
526 md['status'] = reply_content['status']
526 md['status'] = reply_content['status']
527
527
528 # flush i/o
528 # flush i/o
529 sys.stdout.flush()
529 sys.stdout.flush()
530 sys.stderr.flush()
530 sys.stderr.flush()
531
531
532 self.session.send(stream, u'apply_reply', reply_content,
532 self.session.send(stream, u'apply_reply', reply_content,
533 parent=parent, ident=ident,buffers=result_buf, metadata=md)
533 parent=parent, ident=ident,buffers=result_buf, metadata=md)
534
534
535 def do_apply(self, content, bufs, msg_id, reply_metadata):
535 def do_apply(self, content, bufs, msg_id, reply_metadata):
536 """Override in subclasses to support the IPython parallel framework.
536 """Override in subclasses to support the IPython parallel framework.
537 """
537 """
538 raise NotImplementedError
538 raise NotImplementedError
539
539
540 #---------------------------------------------------------------------------
540 #---------------------------------------------------------------------------
541 # Control messages
541 # Control messages
542 #---------------------------------------------------------------------------
542 #---------------------------------------------------------------------------
543
543
544 def abort_request(self, stream, ident, parent):
544 def abort_request(self, stream, ident, parent):
545 """abort a specific msg by id"""
545 """abort a specific msg by id"""
546 msg_ids = parent['content'].get('msg_ids', None)
546 msg_ids = parent['content'].get('msg_ids', None)
547 if isinstance(msg_ids, string_types):
547 if isinstance(msg_ids, string_types):
548 msg_ids = [msg_ids]
548 msg_ids = [msg_ids]
549 if not msg_ids:
549 if not msg_ids:
550 self._abort_queues()
550 self._abort_queues()
551 for mid in msg_ids:
551 for mid in msg_ids:
552 self.aborted.add(str(mid))
552 self.aborted.add(str(mid))
553
553
554 content = dict(status='ok')
554 content = dict(status='ok')
555 reply_msg = self.session.send(stream, 'abort_reply', content=content,
555 reply_msg = self.session.send(stream, 'abort_reply', content=content,
556 parent=parent, ident=ident)
556 parent=parent, ident=ident)
557 self.log.debug("%s", reply_msg)
557 self.log.debug("%s", reply_msg)
558
558
559 def clear_request(self, stream, idents, parent):
559 def clear_request(self, stream, idents, parent):
560 """Clear our namespace."""
560 """Clear our namespace."""
561 content = self.do_clear()
561 content = self.do_clear()
562 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
562 self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
563 content = content)
563 content = content)
564
564
565 def do_clear(self):
565 def do_clear(self):
566 """Override in subclasses to clear the namespace
566 """Override in subclasses to clear the namespace
567
567
568 This is only required for IPython.parallel.
568 This is only required for IPython.parallel.
569 """
569 """
570 raise NotImplementedError
570 raise NotImplementedError
571
571
572 #---------------------------------------------------------------------------
572 #---------------------------------------------------------------------------
573 # Protected interface
573 # Protected interface
574 #---------------------------------------------------------------------------
574 #---------------------------------------------------------------------------
575
575
576 def _topic(self, topic):
576 def _topic(self, topic):
577 """prefixed topic for IOPub messages"""
577 """prefixed topic for IOPub messages"""
578 if self.int_id >= 0:
578 if self.int_id >= 0:
579 base = "engine.%i" % self.int_id
579 base = "engine.%i" % self.int_id
580 else:
580 else:
581 base = "kernel.%s" % self.ident
581 base = "kernel.%s" % self.ident
582
582
583 return py3compat.cast_bytes("%s.%s" % (base, topic))
583 return py3compat.cast_bytes("%s.%s" % (base, topic))
584
584
585 def _abort_queues(self):
585 def _abort_queues(self):
586 for stream in self.shell_streams:
586 for stream in self.shell_streams:
587 if stream:
587 if stream:
588 self._abort_queue(stream)
588 self._abort_queue(stream)
589
589
590 def _abort_queue(self, stream):
590 def _abort_queue(self, stream):
591 poller = zmq.Poller()
591 poller = zmq.Poller()
592 poller.register(stream.socket, zmq.POLLIN)
592 poller.register(stream.socket, zmq.POLLIN)
593 while True:
593 while True:
594 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
594 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
595 if msg is None:
595 if msg is None:
596 return
596 return
597
597
598 self.log.info("Aborting:")
598 self.log.info("Aborting:")
599 self.log.info("%s", msg)
599 self.log.info("%s", msg)
600 msg_type = msg['header']['msg_type']
600 msg_type = msg['header']['msg_type']
601 reply_type = msg_type.split('_')[0] + '_reply'
601 reply_type = msg_type.split('_')[0] + '_reply'
602
602
603 status = {'status' : 'aborted'}
603 status = {'status' : 'aborted'}
604 md = {'engine' : self.ident}
604 md = {'engine' : self.ident}
605 md.update(status)
605 md.update(status)
606 reply_msg = self.session.send(stream, reply_type, metadata=md,
606 reply_msg = self.session.send(stream, reply_type, metadata=md,
607 content=status, parent=msg, ident=idents)
607 content=status, parent=msg, ident=idents)
608 self.log.debug("%s", reply_msg)
608 self.log.debug("%s", reply_msg)
609 # We need to wait a bit for requests to come in. This can probably
609 # We need to wait a bit for requests to come in. This can probably
610 # be set shorter for true asynchronous clients.
610 # be set shorter for true asynchronous clients.
611 poller.poll(50)
611 poller.poll(50)
612
612
613
613
614 def _no_raw_input(self):
614 def _no_raw_input(self):
615 """Raise StdinNotImplentedError if active frontend doesn't support
615 """Raise StdinNotImplentedError if active frontend doesn't support
616 stdin."""
616 stdin."""
617 raise StdinNotImplementedError("raw_input was called, but this "
617 raise StdinNotImplementedError("raw_input was called, but this "
618 "frontend does not support stdin.")
618 "frontend does not support stdin.")
619
619
620 def getpass(self, prompt=''):
620 def getpass(self, prompt=''):
621 """Forward getpass to frontends
621 """Forward getpass to frontends
622
622
623 Raises
623 Raises
624 ------
624 ------
625 StdinNotImplentedError if active frontend doesn't support stdin.
625 StdinNotImplentedError if active frontend doesn't support stdin.
626 """
626 """
627 if not self._allow_stdin:
627 if not self._allow_stdin:
628 raise StdinNotImplementedError(
628 raise StdinNotImplementedError(
629 "getpass was called, but this frontend does not support input requests."
629 "getpass was called, but this frontend does not support input requests."
630 )
630 )
631 return self._input_request(prompt,
631 return self._input_request(prompt,
632 self._parent_ident,
632 self._parent_ident,
633 self._parent_header,
633 self._parent_header,
634 password=True,
634 password=True,
635 )
635 )
636
636
637 def raw_input(self, prompt=''):
637 def raw_input(self, prompt=''):
638 """Forward raw_input to frontends
638 """Forward raw_input to frontends
639
639
640 Raises
640 Raises
641 ------
641 ------
642 StdinNotImplentedError if active frontend doesn't support stdin.
642 StdinNotImplentedError if active frontend doesn't support stdin.
643 """
643 """
644 if not self._allow_stdin:
644 if not self._allow_stdin:
645 raise StdinNotImplementedError(
645 raise StdinNotImplementedError(
646 "raw_input was called, but this frontend does not support input requests."
646 "raw_input was called, but this frontend does not support input requests."
647 )
647 )
648 return self._input_request(prompt,
648 return self._input_request(prompt,
649 self._parent_ident,
649 self._parent_ident,
650 self._parent_header,
650 self._parent_header,
651 password=False,
651 password=False,
652 )
652 )
653
653
654 def _input_request(self, prompt, ident, parent, password=False):
654 def _input_request(self, prompt, ident, parent, password=False):
655 # Flush output before making the request.
655 # Flush output before making the request.
656 sys.stderr.flush()
656 sys.stderr.flush()
657 sys.stdout.flush()
657 sys.stdout.flush()
658 # flush the stdin socket, to purge stale replies
658 # flush the stdin socket, to purge stale replies
659 while True:
659 while True:
660 try:
660 try:
661 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
661 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
662 except zmq.ZMQError as e:
662 except zmq.ZMQError as e:
663 if e.errno == zmq.EAGAIN:
663 if e.errno == zmq.EAGAIN:
664 break
664 break
665 else:
665 else:
666 raise
666 raise
667
667
668 # Send the input request.
668 # Send the input request.
669 content = json_clean(dict(prompt=prompt, password=password))
669 content = json_clean(dict(prompt=prompt, password=password))
670 self.session.send(self.stdin_socket, u'input_request', content, parent,
670 self.session.send(self.stdin_socket, u'input_request', content, parent,
671 ident=ident)
671 ident=ident)
672
672
673 # Await a response.
673 # Await a response.
674 while True:
674 while True:
675 try:
675 try:
676 ident, reply = self.session.recv(self.stdin_socket, 0)
676 ident, reply = self.session.recv(self.stdin_socket, 0)
677 except Exception:
677 except Exception:
678 self.log.warn("Invalid Message:", exc_info=True)
678 self.log.warn("Invalid Message:", exc_info=True)
679 except KeyboardInterrupt:
679 except KeyboardInterrupt:
680 # re-raise KeyboardInterrupt, to truncate traceback
680 # re-raise KeyboardInterrupt, to truncate traceback
681 raise KeyboardInterrupt
681 raise KeyboardInterrupt
682 else:
682 else:
683 break
683 break
684 try:
684 try:
685 value = py3compat.unicode_to_str(reply['content']['value'])
685 value = py3compat.unicode_to_str(reply['content']['value'])
686 except:
686 except:
687 self.log.error("Bad input_reply: %s", parent)
687 self.log.error("Bad input_reply: %s", parent)
688 value = ''
688 value = ''
689 if value == '\x04':
689 if value == '\x04':
690 # EOF
690 # EOF
691 raise EOFError
691 raise EOFError
692 return value
692 return value
693
693
694 def _at_shutdown(self):
694 def _at_shutdown(self):
695 """Actions taken at shutdown by the kernel, called by python's atexit.
695 """Actions taken at shutdown by the kernel, called by python's atexit.
696 """
696 """
697 # io.rprint("Kernel at_shutdown") # dbg
697 # io.rprint("Kernel at_shutdown") # dbg
698 if self._shutdown_message is not None:
698 if self._shutdown_message is not None:
699 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
699 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
700 self.log.debug("%s", self._shutdown_message)
700 self.log.debug("%s", self._shutdown_message)
701 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
701 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
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