##// END OF EJS Templates
add utils.path.ensure_dir_exists...
MinRK -
Show More
@@ -1,392 +1,390 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 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15 * Min RK
15 * Min RK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008 The IPython Development Team
20 # Copyright (C) 2008 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 import atexit
30 import atexit
31 import errno
31 import errno
32 import glob
32 import glob
33 import logging
33 import logging
34 import os
34 import os
35 import shutil
35 import shutil
36 import sys
36 import sys
37
37
38 from IPython.config.application import Application, catch_config_error
38 from IPython.config.application import Application, catch_config_error
39 from IPython.config.loader import ConfigFileNotFound
39 from IPython.config.loader import ConfigFileNotFound
40 from IPython.core import release, crashhandler
40 from IPython.core import release, crashhandler
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
43 from IPython.utils import py3compat
43 from IPython.utils import py3compat
44 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
44 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Classes and functions
47 # Classes and functions
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Base Application Class
52 # Base Application Class
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55 # aliases and flags
55 # aliases and flags
56
56
57 base_aliases = {
57 base_aliases = {
58 'profile-dir' : 'ProfileDir.location',
58 'profile-dir' : 'ProfileDir.location',
59 'profile' : 'BaseIPythonApplication.profile',
59 'profile' : 'BaseIPythonApplication.profile',
60 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
61 'log-level' : 'Application.log_level',
61 'log-level' : 'Application.log_level',
62 'config' : 'BaseIPythonApplication.extra_config_file',
62 'config' : 'BaseIPythonApplication.extra_config_file',
63 }
63 }
64
64
65 base_flags = dict(
65 base_flags = dict(
66 debug = ({'Application' : {'log_level' : logging.DEBUG}},
66 debug = ({'Application' : {'log_level' : logging.DEBUG}},
67 "set log level to logging.DEBUG (maximize logging output)"),
67 "set log level to logging.DEBUG (maximize logging output)"),
68 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
68 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
69 "set log level to logging.CRITICAL (minimize logging output)"),
69 "set log level to logging.CRITICAL (minimize logging output)"),
70 init = ({'BaseIPythonApplication' : {
70 init = ({'BaseIPythonApplication' : {
71 'copy_config_files' : True,
71 'copy_config_files' : True,
72 'auto_create' : True}
72 'auto_create' : True}
73 }, """Initialize profile with default config files. This is equivalent
73 }, """Initialize profile with default config files. This is equivalent
74 to running `ipython profile create <profile>` prior to startup.
74 to running `ipython profile create <profile>` prior to startup.
75 """)
75 """)
76 )
76 )
77
77
78
78
79 class BaseIPythonApplication(Application):
79 class BaseIPythonApplication(Application):
80
80
81 name = Unicode(u'ipython')
81 name = Unicode(u'ipython')
82 description = Unicode(u'IPython: an enhanced interactive Python shell.')
82 description = Unicode(u'IPython: an enhanced interactive Python shell.')
83 version = Unicode(release.version)
83 version = Unicode(release.version)
84
84
85 aliases = Dict(base_aliases)
85 aliases = Dict(base_aliases)
86 flags = Dict(base_flags)
86 flags = Dict(base_flags)
87 classes = List([ProfileDir])
87 classes = List([ProfileDir])
88
88
89 # Track whether the config_file has changed,
89 # Track whether the config_file has changed,
90 # because some logic happens only if we aren't using the default.
90 # because some logic happens only if we aren't using the default.
91 config_file_specified = Set()
91 config_file_specified = Set()
92
92
93 config_file_name = Unicode()
93 config_file_name = Unicode()
94 def _config_file_name_default(self):
94 def _config_file_name_default(self):
95 return self.name.replace('-','_') + u'_config.py'
95 return self.name.replace('-','_') + u'_config.py'
96 def _config_file_name_changed(self, name, old, new):
96 def _config_file_name_changed(self, name, old, new):
97 if new != old:
97 if new != old:
98 self.config_file_specified.add(new)
98 self.config_file_specified.add(new)
99
99
100 # The directory that contains IPython's builtin profiles.
100 # The directory that contains IPython's builtin profiles.
101 builtin_profile_dir = Unicode(
101 builtin_profile_dir = Unicode(
102 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
102 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
103 )
103 )
104
104
105 config_file_paths = List(Unicode)
105 config_file_paths = List(Unicode)
106 def _config_file_paths_default(self):
106 def _config_file_paths_default(self):
107 return [py3compat.getcwd()]
107 return [py3compat.getcwd()]
108
108
109 extra_config_file = Unicode(config=True,
109 extra_config_file = Unicode(config=True,
110 help="""Path to an extra config file to load.
110 help="""Path to an extra config file to load.
111
111
112 If specified, load this config file in addition to any other IPython config.
112 If specified, load this config file in addition to any other IPython config.
113 """)
113 """)
114 def _extra_config_file_changed(self, name, old, new):
114 def _extra_config_file_changed(self, name, old, new):
115 try:
115 try:
116 self.config_files.remove(old)
116 self.config_files.remove(old)
117 except ValueError:
117 except ValueError:
118 pass
118 pass
119 self.config_file_specified.add(new)
119 self.config_file_specified.add(new)
120 self.config_files.append(new)
120 self.config_files.append(new)
121
121
122 profile = Unicode(u'default', config=True,
122 profile = Unicode(u'default', config=True,
123 help="""The IPython profile to use."""
123 help="""The IPython profile to use."""
124 )
124 )
125
125
126 def _profile_changed(self, name, old, new):
126 def _profile_changed(self, name, old, new):
127 self.builtin_profile_dir = os.path.join(
127 self.builtin_profile_dir = os.path.join(
128 get_ipython_package_dir(), u'config', u'profile', new
128 get_ipython_package_dir(), u'config', u'profile', new
129 )
129 )
130
130
131 ipython_dir = Unicode(config=True,
131 ipython_dir = Unicode(config=True,
132 help="""
132 help="""
133 The name of the IPython directory. This directory is used for logging
133 The name of the IPython directory. This directory is used for logging
134 configuration (through profiles), history storage, etc. The default
134 configuration (through profiles), history storage, etc. The default
135 is usually $HOME/.ipython. This options can also be specified through
135 is usually $HOME/.ipython. This options can also be specified through
136 the environment variable IPYTHONDIR.
136 the environment variable IPYTHONDIR.
137 """
137 """
138 )
138 )
139 def _ipython_dir_default(self):
139 def _ipython_dir_default(self):
140 d = get_ipython_dir()
140 d = get_ipython_dir()
141 self._ipython_dir_changed('ipython_dir', d, d)
141 self._ipython_dir_changed('ipython_dir', d, d)
142 return d
142 return d
143
143
144 _in_init_profile_dir = False
144 _in_init_profile_dir = False
145 profile_dir = Instance(ProfileDir)
145 profile_dir = Instance(ProfileDir)
146 def _profile_dir_default(self):
146 def _profile_dir_default(self):
147 # avoid recursion
147 # avoid recursion
148 if self._in_init_profile_dir:
148 if self._in_init_profile_dir:
149 return
149 return
150 # profile_dir requested early, force initialization
150 # profile_dir requested early, force initialization
151 self.init_profile_dir()
151 self.init_profile_dir()
152 return self.profile_dir
152 return self.profile_dir
153
153
154 overwrite = Bool(False, config=True,
154 overwrite = Bool(False, config=True,
155 help="""Whether to overwrite existing config files when copying""")
155 help="""Whether to overwrite existing config files when copying""")
156 auto_create = Bool(False, config=True,
156 auto_create = Bool(False, config=True,
157 help="""Whether to create profile dir if it doesn't exist""")
157 help="""Whether to create profile dir if it doesn't exist""")
158
158
159 config_files = List(Unicode)
159 config_files = List(Unicode)
160 def _config_files_default(self):
160 def _config_files_default(self):
161 return [self.config_file_name]
161 return [self.config_file_name]
162
162
163 copy_config_files = Bool(False, config=True,
163 copy_config_files = Bool(False, config=True,
164 help="""Whether to install the default config files into the profile dir.
164 help="""Whether to install the default config files into the profile dir.
165 If a new profile is being created, and IPython contains config files for that
165 If a new profile is being created, and IPython contains config files for that
166 profile, then they will be staged into the new directory. Otherwise,
166 profile, then they will be staged into the new directory. Otherwise,
167 default config files will be automatically generated.
167 default config files will be automatically generated.
168 """)
168 """)
169
169
170 verbose_crash = Bool(False, config=True,
170 verbose_crash = Bool(False, config=True,
171 help="""Create a massive crash report when IPython encounters what may be an
171 help="""Create a massive crash report when IPython encounters what may be an
172 internal error. The default is to append a short message to the
172 internal error. The default is to append a short message to the
173 usual traceback""")
173 usual traceback""")
174
174
175 # The class to use as the crash handler.
175 # The class to use as the crash handler.
176 crash_handler_class = Type(crashhandler.CrashHandler)
176 crash_handler_class = Type(crashhandler.CrashHandler)
177
177
178 @catch_config_error
178 @catch_config_error
179 def __init__(self, **kwargs):
179 def __init__(self, **kwargs):
180 super(BaseIPythonApplication, self).__init__(**kwargs)
180 super(BaseIPythonApplication, self).__init__(**kwargs)
181 # ensure current working directory exists
181 # ensure current working directory exists
182 try:
182 try:
183 directory = py3compat.getcwd()
183 directory = py3compat.getcwd()
184 except:
184 except:
185 # raise exception
185 # raise exception
186 self.log.error("Current working directory doesn't exist.")
186 self.log.error("Current working directory doesn't exist.")
187 raise
187 raise
188
188
189 #-------------------------------------------------------------------------
189 #-------------------------------------------------------------------------
190 # Various stages of Application creation
190 # Various stages of Application creation
191 #-------------------------------------------------------------------------
191 #-------------------------------------------------------------------------
192
192
193 def init_crash_handler(self):
193 def init_crash_handler(self):
194 """Create a crash handler, typically setting sys.excepthook to it."""
194 """Create a crash handler, typically setting sys.excepthook to it."""
195 self.crash_handler = self.crash_handler_class(self)
195 self.crash_handler = self.crash_handler_class(self)
196 sys.excepthook = self.excepthook
196 sys.excepthook = self.excepthook
197 def unset_crashhandler():
197 def unset_crashhandler():
198 sys.excepthook = sys.__excepthook__
198 sys.excepthook = sys.__excepthook__
199 atexit.register(unset_crashhandler)
199 atexit.register(unset_crashhandler)
200
200
201 def excepthook(self, etype, evalue, tb):
201 def excepthook(self, etype, evalue, tb):
202 """this is sys.excepthook after init_crashhandler
202 """this is sys.excepthook after init_crashhandler
203
203
204 set self.verbose_crash=True to use our full crashhandler, instead of
204 set self.verbose_crash=True to use our full crashhandler, instead of
205 a regular traceback with a short message (crash_handler_lite)
205 a regular traceback with a short message (crash_handler_lite)
206 """
206 """
207
207
208 if self.verbose_crash:
208 if self.verbose_crash:
209 return self.crash_handler(etype, evalue, tb)
209 return self.crash_handler(etype, evalue, tb)
210 else:
210 else:
211 return crashhandler.crash_handler_lite(etype, evalue, tb)
211 return crashhandler.crash_handler_lite(etype, evalue, tb)
212
212
213 def _ipython_dir_changed(self, name, old, new):
213 def _ipython_dir_changed(self, name, old, new):
214 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
214 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
215 sys.getfilesystemencoding()
215 sys.getfilesystemencoding()
216 )
216 )
217 if str_old in sys.path:
217 if str_old in sys.path:
218 sys.path.remove(str_old)
218 sys.path.remove(str_old)
219 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
219 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
220 sys.getfilesystemencoding()
220 sys.getfilesystemencoding()
221 )
221 )
222 sys.path.append(str_path)
222 sys.path.append(str_path)
223 if not os.path.isdir(new):
223 ensure_dir_exists(new)
224 os.makedirs(new, mode=0o777)
225 readme = os.path.join(new, 'README')
224 readme = os.path.join(new, 'README')
226 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
225 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
227 if not os.path.exists(readme) and os.path.exists(readme_src):
226 if not os.path.exists(readme) and os.path.exists(readme_src):
228 shutil.copy(readme_src, readme)
227 shutil.copy(readme_src, readme)
229 for d in ('extensions', 'nbextensions'):
228 for d in ('extensions', 'nbextensions'):
230 path = os.path.join(new, d)
229 path = os.path.join(new, d)
231 if not os.path.exists(path):
232 try:
230 try:
233 os.mkdir(path)
231 ensure_dir_exists(path)
234 except OSError as e:
232 except OSError:
235 if e.errno != errno.EEXIST:
233 # this will not be EEXIST
236 self.log.error("couldn't create path %s: %s", path, e)
234 self.log.error("couldn't create path %s: %s", path, e)
237 self.log.debug("IPYTHONDIR set to: %s" % new)
235 self.log.debug("IPYTHONDIR set to: %s" % new)
238
236
239 def load_config_file(self, suppress_errors=True):
237 def load_config_file(self, suppress_errors=True):
240 """Load the config file.
238 """Load the config file.
241
239
242 By default, errors in loading config are handled, and a warning
240 By default, errors in loading config are handled, and a warning
243 printed on screen. For testing, the suppress_errors option is set
241 printed on screen. For testing, the suppress_errors option is set
244 to False, so errors will make tests fail.
242 to False, so errors will make tests fail.
245 """
243 """
246 self.log.debug("Searching path %s for config files", self.config_file_paths)
244 self.log.debug("Searching path %s for config files", self.config_file_paths)
247 base_config = 'ipython_config.py'
245 base_config = 'ipython_config.py'
248 self.log.debug("Attempting to load config file: %s" %
246 self.log.debug("Attempting to load config file: %s" %
249 base_config)
247 base_config)
250 try:
248 try:
251 Application.load_config_file(
249 Application.load_config_file(
252 self,
250 self,
253 base_config,
251 base_config,
254 path=self.config_file_paths
252 path=self.config_file_paths
255 )
253 )
256 except ConfigFileNotFound:
254 except ConfigFileNotFound:
257 # ignore errors loading parent
255 # ignore errors loading parent
258 self.log.debug("Config file %s not found", base_config)
256 self.log.debug("Config file %s not found", base_config)
259 pass
257 pass
260
258
261 for config_file_name in self.config_files:
259 for config_file_name in self.config_files:
262 if not config_file_name or config_file_name == base_config:
260 if not config_file_name or config_file_name == base_config:
263 continue
261 continue
264 self.log.debug("Attempting to load config file: %s" %
262 self.log.debug("Attempting to load config file: %s" %
265 self.config_file_name)
263 self.config_file_name)
266 try:
264 try:
267 Application.load_config_file(
265 Application.load_config_file(
268 self,
266 self,
269 config_file_name,
267 config_file_name,
270 path=self.config_file_paths
268 path=self.config_file_paths
271 )
269 )
272 except ConfigFileNotFound:
270 except ConfigFileNotFound:
273 # Only warn if the default config file was NOT being used.
271 # Only warn if the default config file was NOT being used.
274 if config_file_name in self.config_file_specified:
272 if config_file_name in self.config_file_specified:
275 msg = self.log.warn
273 msg = self.log.warn
276 else:
274 else:
277 msg = self.log.debug
275 msg = self.log.debug
278 msg("Config file not found, skipping: %s", config_file_name)
276 msg("Config file not found, skipping: %s", config_file_name)
279 except:
277 except:
280 # For testing purposes.
278 # For testing purposes.
281 if not suppress_errors:
279 if not suppress_errors:
282 raise
280 raise
283 self.log.warn("Error loading config file: %s" %
281 self.log.warn("Error loading config file: %s" %
284 self.config_file_name, exc_info=True)
282 self.config_file_name, exc_info=True)
285
283
286 def init_profile_dir(self):
284 def init_profile_dir(self):
287 """initialize the profile dir"""
285 """initialize the profile dir"""
288 self._in_init_profile_dir = True
286 self._in_init_profile_dir = True
289 if self.profile_dir is not None:
287 if self.profile_dir is not None:
290 # already ran
288 # already ran
291 return
289 return
292 if 'ProfileDir.location' not in self.config:
290 if 'ProfileDir.location' not in self.config:
293 # location not specified, find by profile name
291 # location not specified, find by profile name
294 try:
292 try:
295 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
293 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
296 except ProfileDirError:
294 except ProfileDirError:
297 # not found, maybe create it (always create default profile)
295 # not found, maybe create it (always create default profile)
298 if self.auto_create or self.profile == 'default':
296 if self.auto_create or self.profile == 'default':
299 try:
297 try:
300 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
298 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
301 except ProfileDirError:
299 except ProfileDirError:
302 self.log.fatal("Could not create profile: %r"%self.profile)
300 self.log.fatal("Could not create profile: %r"%self.profile)
303 self.exit(1)
301 self.exit(1)
304 else:
302 else:
305 self.log.info("Created profile dir: %r"%p.location)
303 self.log.info("Created profile dir: %r"%p.location)
306 else:
304 else:
307 self.log.fatal("Profile %r not found."%self.profile)
305 self.log.fatal("Profile %r not found."%self.profile)
308 self.exit(1)
306 self.exit(1)
309 else:
307 else:
310 self.log.info("Using existing profile dir: %r"%p.location)
308 self.log.info("Using existing profile dir: %r"%p.location)
311 else:
309 else:
312 location = self.config.ProfileDir.location
310 location = self.config.ProfileDir.location
313 # location is fully specified
311 # location is fully specified
314 try:
312 try:
315 p = ProfileDir.find_profile_dir(location, self.config)
313 p = ProfileDir.find_profile_dir(location, self.config)
316 except ProfileDirError:
314 except ProfileDirError:
317 # not found, maybe create it
315 # not found, maybe create it
318 if self.auto_create:
316 if self.auto_create:
319 try:
317 try:
320 p = ProfileDir.create_profile_dir(location, self.config)
318 p = ProfileDir.create_profile_dir(location, self.config)
321 except ProfileDirError:
319 except ProfileDirError:
322 self.log.fatal("Could not create profile directory: %r"%location)
320 self.log.fatal("Could not create profile directory: %r"%location)
323 self.exit(1)
321 self.exit(1)
324 else:
322 else:
325 self.log.info("Creating new profile dir: %r"%location)
323 self.log.info("Creating new profile dir: %r"%location)
326 else:
324 else:
327 self.log.fatal("Profile directory %r not found."%location)
325 self.log.fatal("Profile directory %r not found."%location)
328 self.exit(1)
326 self.exit(1)
329 else:
327 else:
330 self.log.info("Using existing profile dir: %r"%location)
328 self.log.info("Using existing profile dir: %r"%location)
331 # if profile_dir is specified explicitly, set profile name
329 # if profile_dir is specified explicitly, set profile name
332 dir_name = os.path.basename(p.location)
330 dir_name = os.path.basename(p.location)
333 if dir_name.startswith('profile_'):
331 if dir_name.startswith('profile_'):
334 self.profile = dir_name[8:]
332 self.profile = dir_name[8:]
335
333
336 self.profile_dir = p
334 self.profile_dir = p
337 self.config_file_paths.append(p.location)
335 self.config_file_paths.append(p.location)
338 self._in_init_profile_dir = False
336 self._in_init_profile_dir = False
339
337
340 def init_config_files(self):
338 def init_config_files(self):
341 """[optionally] copy default config files into profile dir."""
339 """[optionally] copy default config files into profile dir."""
342 # copy config files
340 # copy config files
343 path = self.builtin_profile_dir
341 path = self.builtin_profile_dir
344 if self.copy_config_files:
342 if self.copy_config_files:
345 src = self.profile
343 src = self.profile
346
344
347 cfg = self.config_file_name
345 cfg = self.config_file_name
348 if path and os.path.exists(os.path.join(path, cfg)):
346 if path and os.path.exists(os.path.join(path, cfg)):
349 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
347 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
350 cfg, src, self.profile_dir.location, self.overwrite)
348 cfg, src, self.profile_dir.location, self.overwrite)
351 )
349 )
352 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
350 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
353 else:
351 else:
354 self.stage_default_config_file()
352 self.stage_default_config_file()
355 else:
353 else:
356 # Still stage *bundled* config files, but not generated ones
354 # Still stage *bundled* config files, but not generated ones
357 # This is necessary for `ipython profile=sympy` to load the profile
355 # This is necessary for `ipython profile=sympy` to load the profile
358 # on the first go
356 # on the first go
359 files = glob.glob(os.path.join(path, '*.py'))
357 files = glob.glob(os.path.join(path, '*.py'))
360 for fullpath in files:
358 for fullpath in files:
361 cfg = os.path.basename(fullpath)
359 cfg = os.path.basename(fullpath)
362 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
360 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
363 # file was copied
361 # file was copied
364 self.log.warn("Staging bundled %s from %s into %r"%(
362 self.log.warn("Staging bundled %s from %s into %r"%(
365 cfg, self.profile, self.profile_dir.location)
363 cfg, self.profile, self.profile_dir.location)
366 )
364 )
367
365
368
366
369 def stage_default_config_file(self):
367 def stage_default_config_file(self):
370 """auto generate default config file, and stage it into the profile."""
368 """auto generate default config file, and stage it into the profile."""
371 s = self.generate_config_file()
369 s = self.generate_config_file()
372 fname = os.path.join(self.profile_dir.location, self.config_file_name)
370 fname = os.path.join(self.profile_dir.location, self.config_file_name)
373 if self.overwrite or not os.path.exists(fname):
371 if self.overwrite or not os.path.exists(fname):
374 self.log.warn("Generating default config file: %r"%(fname))
372 self.log.warn("Generating default config file: %r"%(fname))
375 with open(fname, 'w') as f:
373 with open(fname, 'w') as f:
376 f.write(s)
374 f.write(s)
377
375
378 @catch_config_error
376 @catch_config_error
379 def initialize(self, argv=None):
377 def initialize(self, argv=None):
380 # don't hook up crash handler before parsing command-line
378 # don't hook up crash handler before parsing command-line
381 self.parse_command_line(argv)
379 self.parse_command_line(argv)
382 self.init_crash_handler()
380 self.init_crash_handler()
383 if self.subapp is not None:
381 if self.subapp is not None:
384 # stop here if subapp is taking over
382 # stop here if subapp is taking over
385 return
383 return
386 cl_config = self.config
384 cl_config = self.config
387 self.init_profile_dir()
385 self.init_profile_dir()
388 self.init_config_files()
386 self.init_config_files()
389 self.load_config_file()
387 self.load_config_file()
390 # enforce cl-opts override configfile opts:
388 # enforce cl-opts override configfile opts:
391 self.update_config(cl_config)
389 self.update_config(cl_config)
392
390
@@ -1,189 +1,175 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 Authors:
4 # Copyright (c) IPython Development Team.
5
5 # Distributed under the terms of the Modified BSD License.
6 * Brian Granger
7 """
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
6
20 import os
7 import os
21 from shutil import copyfile
8 from shutil import copyfile
22 import sys
9 import sys
23
10
24 from IPython.config.configurable import Configurable
11 from IPython.config.configurable import Configurable
12 from IPython.utils.path import ensure_dir_exists
25 from IPython.utils.traitlets import Instance
13 from IPython.utils.traitlets import Instance
26 from IPython.utils.py3compat import PY3
14 from IPython.utils.py3compat import PY3
27 if PY3:
15 if PY3:
28 from imp import reload
16 from imp import reload
29
17
30 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
31 # Main class
19 # Main class
32 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
33
21
34 class ExtensionManager(Configurable):
22 class ExtensionManager(Configurable):
35 """A class to manage IPython extensions.
23 """A class to manage IPython extensions.
36
24
37 An IPython extension is an importable Python module that has
25 An IPython extension is an importable Python module that has
38 a function with the signature::
26 a function with the signature::
39
27
40 def load_ipython_extension(ipython):
28 def load_ipython_extension(ipython):
41 # Do things with ipython
29 # Do things with ipython
42
30
43 This function is called after your extension is imported and the
31 This function is called after your extension is imported and the
44 currently active :class:`InteractiveShell` instance is passed as
32 currently active :class:`InteractiveShell` instance is passed as
45 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
46 that point, including defining new magic and aliases, adding new
34 that point, including defining new magic and aliases, adding new
47 components, etc.
35 components, etc.
48
36
49 You can also optionally define an :func:`unload_ipython_extension(ipython)`
37 You can also optionally define an :func:`unload_ipython_extension(ipython)`
50 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.
51 The extension manager will only call :func:`load_ipython_extension` again
39 The extension manager will only call :func:`load_ipython_extension` again
52 if the extension is reloaded.
40 if the extension is reloaded.
53
41
54 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
55 they can be imported by Python's standard import mechanism. However,
43 they can be imported by Python's standard import mechanism. However,
56 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
57 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
45 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
58 is added to ``sys.path`` automatically.
46 is added to ``sys.path`` automatically.
59 """
47 """
60
48
61 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
49 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
62
50
63 def __init__(self, shell=None, **kwargs):
51 def __init__(self, shell=None, **kwargs):
64 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
52 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
65 self.shell.on_trait_change(
53 self.shell.on_trait_change(
66 self._on_ipython_dir_changed, 'ipython_dir'
54 self._on_ipython_dir_changed, 'ipython_dir'
67 )
55 )
68 self.loaded = set()
56 self.loaded = set()
69
57
70 def __del__(self):
58 def __del__(self):
71 self.shell.on_trait_change(
59 self.shell.on_trait_change(
72 self._on_ipython_dir_changed, 'ipython_dir', remove=True
60 self._on_ipython_dir_changed, 'ipython_dir', remove=True
73 )
61 )
74
62
75 @property
63 @property
76 def ipython_extension_dir(self):
64 def ipython_extension_dir(self):
77 return os.path.join(self.shell.ipython_dir, u'extensions')
65 return os.path.join(self.shell.ipython_dir, u'extensions')
78
66
79 def _on_ipython_dir_changed(self):
67 def _on_ipython_dir_changed(self):
80 if not os.path.isdir(self.ipython_extension_dir):
68 ensure_dir_exists(self.ipython_extension_dir)
81 os.makedirs(self.ipython_extension_dir, mode = 0o777)
82
69
83 def load_extension(self, module_str):
70 def load_extension(self, module_str):
84 """Load an IPython extension by its module name.
71 """Load an IPython extension by its module name.
85
72
86 Returns the string "already loaded" if the extension is already loaded,
73 Returns the string "already loaded" if the extension is already loaded,
87 "no load function" if the module doesn't have a load_ipython_extension
74 "no load function" if the module doesn't have a load_ipython_extension
88 function, or None if it succeeded.
75 function, or None if it succeeded.
89 """
76 """
90 if module_str in self.loaded:
77 if module_str in self.loaded:
91 return "already loaded"
78 return "already loaded"
92
79
93 from IPython.utils.syspathcontext import prepended_to_syspath
80 from IPython.utils.syspathcontext import prepended_to_syspath
94
81
95 with self.shell.builtin_trap:
82 with self.shell.builtin_trap:
96 if module_str not in sys.modules:
83 if module_str not in sys.modules:
97 with prepended_to_syspath(self.ipython_extension_dir):
84 with prepended_to_syspath(self.ipython_extension_dir):
98 __import__(module_str)
85 __import__(module_str)
99 mod = sys.modules[module_str]
86 mod = sys.modules[module_str]
100 if self._call_load_ipython_extension(mod):
87 if self._call_load_ipython_extension(mod):
101 self.loaded.add(module_str)
88 self.loaded.add(module_str)
102 else:
89 else:
103 return "no load function"
90 return "no load function"
104
91
105 def unload_extension(self, module_str):
92 def unload_extension(self, module_str):
106 """Unload an IPython extension by its module name.
93 """Unload an IPython extension by its module name.
107
94
108 This function looks up the extension's name in ``sys.modules`` and
95 This function looks up the extension's name in ``sys.modules`` and
109 simply calls ``mod.unload_ipython_extension(self)``.
96 simply calls ``mod.unload_ipython_extension(self)``.
110
97
111 Returns the string "no unload function" if the extension doesn't define
98 Returns the string "no unload function" if the extension doesn't define
112 a function to unload itself, "not loaded" if the extension isn't loaded,
99 a function to unload itself, "not loaded" if the extension isn't loaded,
113 otherwise None.
100 otherwise None.
114 """
101 """
115 if module_str not in self.loaded:
102 if module_str not in self.loaded:
116 return "not loaded"
103 return "not loaded"
117
104
118 if module_str in sys.modules:
105 if module_str in sys.modules:
119 mod = sys.modules[module_str]
106 mod = sys.modules[module_str]
120 if self._call_unload_ipython_extension(mod):
107 if self._call_unload_ipython_extension(mod):
121 self.loaded.discard(module_str)
108 self.loaded.discard(module_str)
122 else:
109 else:
123 return "no unload function"
110 return "no unload function"
124
111
125 def reload_extension(self, module_str):
112 def reload_extension(self, module_str):
126 """Reload an IPython extension by calling reload.
113 """Reload an IPython extension by calling reload.
127
114
128 If the module has not been loaded before,
115 If the module has not been loaded before,
129 :meth:`InteractiveShell.load_extension` is called. Otherwise
116 :meth:`InteractiveShell.load_extension` is called. Otherwise
130 :func:`reload` is called and then the :func:`load_ipython_extension`
117 :func:`reload` is called and then the :func:`load_ipython_extension`
131 function of the module, if it exists is called.
118 function of the module, if it exists is called.
132 """
119 """
133 from IPython.utils.syspathcontext import prepended_to_syspath
120 from IPython.utils.syspathcontext import prepended_to_syspath
134
121
135 if (module_str in self.loaded) and (module_str in sys.modules):
122 if (module_str in self.loaded) and (module_str in sys.modules):
136 self.unload_extension(module_str)
123 self.unload_extension(module_str)
137 mod = sys.modules[module_str]
124 mod = sys.modules[module_str]
138 with prepended_to_syspath(self.ipython_extension_dir):
125 with prepended_to_syspath(self.ipython_extension_dir):
139 reload(mod)
126 reload(mod)
140 if self._call_load_ipython_extension(mod):
127 if self._call_load_ipython_extension(mod):
141 self.loaded.add(module_str)
128 self.loaded.add(module_str)
142 else:
129 else:
143 self.load_extension(module_str)
130 self.load_extension(module_str)
144
131
145 def _call_load_ipython_extension(self, mod):
132 def _call_load_ipython_extension(self, mod):
146 if hasattr(mod, 'load_ipython_extension'):
133 if hasattr(mod, 'load_ipython_extension'):
147 mod.load_ipython_extension(self.shell)
134 mod.load_ipython_extension(self.shell)
148 return True
135 return True
149
136
150 def _call_unload_ipython_extension(self, mod):
137 def _call_unload_ipython_extension(self, mod):
151 if hasattr(mod, 'unload_ipython_extension'):
138 if hasattr(mod, 'unload_ipython_extension'):
152 mod.unload_ipython_extension(self.shell)
139 mod.unload_ipython_extension(self.shell)
153 return True
140 return True
154
141
155 def install_extension(self, url, filename=None):
142 def install_extension(self, url, filename=None):
156 """Download and install an IPython extension.
143 """Download and install an IPython extension.
157
144
158 If filename is given, the file will be so named (inside the extension
145 If filename is given, the file will be so named (inside the extension
159 directory). Otherwise, the name from the URL will be used. The file must
146 directory). Otherwise, the name from the URL will be used. The file must
160 have a .py or .zip extension; otherwise, a ValueError will be raised.
147 have a .py or .zip extension; otherwise, a ValueError will be raised.
161
148
162 Returns the full path to the installed file.
149 Returns the full path to the installed file.
163 """
150 """
164 # Ensure the extension directory exists
151 # Ensure the extension directory exists
165 if not os.path.isdir(self.ipython_extension_dir):
152 ensure_dir_exists(self.ipython_extension_dir)
166 os.makedirs(self.ipython_extension_dir, mode = 0o777)
167
153
168 if os.path.isfile(url):
154 if os.path.isfile(url):
169 src_filename = os.path.basename(url)
155 src_filename = os.path.basename(url)
170 copy = copyfile
156 copy = copyfile
171 else:
157 else:
172 # Deferred imports
158 # Deferred imports
173 try:
159 try:
174 from urllib.parse import urlparse # Py3
160 from urllib.parse import urlparse # Py3
175 from urllib.request import urlretrieve
161 from urllib.request import urlretrieve
176 except ImportError:
162 except ImportError:
177 from urlparse import urlparse
163 from urlparse import urlparse
178 from urllib import urlretrieve
164 from urllib import urlretrieve
179 src_filename = urlparse(url).path.split('/')[-1]
165 src_filename = urlparse(url).path.split('/')[-1]
180 copy = urlretrieve
166 copy = urlretrieve
181
167
182 if filename is None:
168 if filename is None:
183 filename = src_filename
169 filename = src_filename
184 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
170 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
185 raise ValueError("The file must have a .py or .zip extension", filename)
171 raise ValueError("The file must have a .py or .zip extension", filename)
186
172
187 filename = os.path.join(self.ipython_extension_dir, filename)
173 filename = os.path.join(self.ipython_extension_dir, filename)
188 copy(url, filename)
174 copy(url, filename)
189 return filename
175 return filename
@@ -1,3224 +1,3223 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 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import absolute_import
17 from __future__ import absolute_import
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import __future__
20 import __future__
21 import abc
21 import abc
22 import ast
22 import ast
23 import atexit
23 import atexit
24 import functools
24 import functools
25 import os
25 import os
26 import re
26 import re
27 import runpy
27 import runpy
28 import sys
28 import sys
29 import tempfile
29 import tempfile
30 import types
30 import types
31 import subprocess
31 import subprocess
32 from io import open as io_open
32 from io import open as io_open
33
33
34 from IPython.config.configurable import SingletonConfigurable
34 from IPython.config.configurable import SingletonConfigurable
35 from IPython.core import debugger, oinspect
35 from IPython.core import debugger, oinspect
36 from IPython.core import magic
36 from IPython.core import magic
37 from IPython.core import page
37 from IPython.core import page
38 from IPython.core import prefilter
38 from IPython.core import prefilter
39 from IPython.core import shadowns
39 from IPython.core import shadowns
40 from IPython.core import ultratb
40 from IPython.core import ultratb
41 from IPython.core.alias import AliasManager, AliasError
41 from IPython.core.alias import AliasManager, AliasError
42 from IPython.core.autocall import ExitAutocall
42 from IPython.core.autocall import ExitAutocall
43 from IPython.core.builtin_trap import BuiltinTrap
43 from IPython.core.builtin_trap import BuiltinTrap
44 from IPython.core.events import EventManager, available_events
44 from IPython.core.events import EventManager, available_events
45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
46 from IPython.core.display_trap import DisplayTrap
46 from IPython.core.display_trap import DisplayTrap
47 from IPython.core.displayhook import DisplayHook
47 from IPython.core.displayhook import DisplayHook
48 from IPython.core.displaypub import DisplayPublisher
48 from IPython.core.displaypub import DisplayPublisher
49 from IPython.core.error import UsageError
49 from IPython.core.error import UsageError
50 from IPython.core.extensions import ExtensionManager
50 from IPython.core.extensions import ExtensionManager
51 from IPython.core.formatters import DisplayFormatter
51 from IPython.core.formatters import DisplayFormatter
52 from IPython.core.history import HistoryManager
52 from IPython.core.history import HistoryManager
53 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
53 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
54 from IPython.core.logger import Logger
54 from IPython.core.logger import Logger
55 from IPython.core.macro import Macro
55 from IPython.core.macro import Macro
56 from IPython.core.payload import PayloadManager
56 from IPython.core.payload import PayloadManager
57 from IPython.core.prefilter import PrefilterManager
57 from IPython.core.prefilter import PrefilterManager
58 from IPython.core.profiledir import ProfileDir
58 from IPython.core.profiledir import ProfileDir
59 from IPython.core.prompts import PromptManager
59 from IPython.core.prompts import PromptManager
60 from IPython.lib.latextools import LaTeXTool
60 from IPython.lib.latextools import LaTeXTool
61 from IPython.testing.skipdoctest import skip_doctest
61 from IPython.testing.skipdoctest import skip_doctest
62 from IPython.utils import PyColorize
62 from IPython.utils import PyColorize
63 from IPython.utils import io
63 from IPython.utils import io
64 from IPython.utils import py3compat
64 from IPython.utils import py3compat
65 from IPython.utils import openpy
65 from IPython.utils import openpy
66 from IPython.utils.decorators import undoc
66 from IPython.utils.decorators import undoc
67 from IPython.utils.io import ask_yes_no
67 from IPython.utils.io import ask_yes_no
68 from IPython.utils.ipstruct import Struct
68 from IPython.utils.ipstruct import Struct
69 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename
69 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename, ensure_dir_exists
70 from IPython.utils.pickleshare import PickleShareDB
70 from IPython.utils.pickleshare import PickleShareDB
71 from IPython.utils.process import system, getoutput
71 from IPython.utils.process import system, getoutput
72 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
72 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
73 with_metaclass, iteritems)
73 with_metaclass, iteritems)
74 from IPython.utils.strdispatch import StrDispatch
74 from IPython.utils.strdispatch import StrDispatch
75 from IPython.utils.syspathcontext import prepended_to_syspath
75 from IPython.utils.syspathcontext import prepended_to_syspath
76 from IPython.utils.text import (format_screen, LSString, SList,
76 from IPython.utils.text import (format_screen, LSString, SList,
77 DollarFormatter)
77 DollarFormatter)
78 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
78 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
79 List, Unicode, Instance, Type)
79 List, Unicode, Instance, Type)
80 from IPython.utils.warn import warn, error
80 from IPython.utils.warn import warn, error
81 import IPython.core.hooks
81 import IPython.core.hooks
82
82
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84 # Globals
84 # Globals
85 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
86
86
87 # compiled regexps for autoindent management
87 # compiled regexps for autoindent management
88 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
89
89
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91 # Utilities
91 # Utilities
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93
93
94 @undoc
94 @undoc
95 def softspace(file, newvalue):
95 def softspace(file, newvalue):
96 """Copied from code.py, to remove the dependency"""
96 """Copied from code.py, to remove the dependency"""
97
97
98 oldvalue = 0
98 oldvalue = 0
99 try:
99 try:
100 oldvalue = file.softspace
100 oldvalue = file.softspace
101 except AttributeError:
101 except AttributeError:
102 pass
102 pass
103 try:
103 try:
104 file.softspace = newvalue
104 file.softspace = newvalue
105 except (AttributeError, TypeError):
105 except (AttributeError, TypeError):
106 # "attribute-less object" or "read-only attributes"
106 # "attribute-less object" or "read-only attributes"
107 pass
107 pass
108 return oldvalue
108 return oldvalue
109
109
110 @undoc
110 @undoc
111 def no_op(*a, **kw): pass
111 def no_op(*a, **kw): pass
112
112
113 @undoc
113 @undoc
114 class NoOpContext(object):
114 class NoOpContext(object):
115 def __enter__(self): pass
115 def __enter__(self): pass
116 def __exit__(self, type, value, traceback): pass
116 def __exit__(self, type, value, traceback): pass
117 no_op_context = NoOpContext()
117 no_op_context = NoOpContext()
118
118
119 class SpaceInInput(Exception): pass
119 class SpaceInInput(Exception): pass
120
120
121 @undoc
121 @undoc
122 class Bunch: pass
122 class Bunch: pass
123
123
124
124
125 def get_default_colors():
125 def get_default_colors():
126 if sys.platform=='darwin':
126 if sys.platform=='darwin':
127 return "LightBG"
127 return "LightBG"
128 elif os.name=='nt':
128 elif os.name=='nt':
129 return 'Linux'
129 return 'Linux'
130 else:
130 else:
131 return 'Linux'
131 return 'Linux'
132
132
133
133
134 class SeparateUnicode(Unicode):
134 class SeparateUnicode(Unicode):
135 r"""A Unicode subclass to validate separate_in, separate_out, etc.
135 r"""A Unicode subclass to validate separate_in, separate_out, etc.
136
136
137 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
137 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
138 """
138 """
139
139
140 def validate(self, obj, value):
140 def validate(self, obj, value):
141 if value == '0': value = ''
141 if value == '0': value = ''
142 value = value.replace('\\n','\n')
142 value = value.replace('\\n','\n')
143 return super(SeparateUnicode, self).validate(obj, value)
143 return super(SeparateUnicode, self).validate(obj, value)
144
144
145
145
146 class ReadlineNoRecord(object):
146 class ReadlineNoRecord(object):
147 """Context manager to execute some code, then reload readline history
147 """Context manager to execute some code, then reload readline history
148 so that interactive input to the code doesn't appear when pressing up."""
148 so that interactive input to the code doesn't appear when pressing up."""
149 def __init__(self, shell):
149 def __init__(self, shell):
150 self.shell = shell
150 self.shell = shell
151 self._nested_level = 0
151 self._nested_level = 0
152
152
153 def __enter__(self):
153 def __enter__(self):
154 if self._nested_level == 0:
154 if self._nested_level == 0:
155 try:
155 try:
156 self.orig_length = self.current_length()
156 self.orig_length = self.current_length()
157 self.readline_tail = self.get_readline_tail()
157 self.readline_tail = self.get_readline_tail()
158 except (AttributeError, IndexError): # Can fail with pyreadline
158 except (AttributeError, IndexError): # Can fail with pyreadline
159 self.orig_length, self.readline_tail = 999999, []
159 self.orig_length, self.readline_tail = 999999, []
160 self._nested_level += 1
160 self._nested_level += 1
161
161
162 def __exit__(self, type, value, traceback):
162 def __exit__(self, type, value, traceback):
163 self._nested_level -= 1
163 self._nested_level -= 1
164 if self._nested_level == 0:
164 if self._nested_level == 0:
165 # Try clipping the end if it's got longer
165 # Try clipping the end if it's got longer
166 try:
166 try:
167 e = self.current_length() - self.orig_length
167 e = self.current_length() - self.orig_length
168 if e > 0:
168 if e > 0:
169 for _ in range(e):
169 for _ in range(e):
170 self.shell.readline.remove_history_item(self.orig_length)
170 self.shell.readline.remove_history_item(self.orig_length)
171
171
172 # If it still doesn't match, just reload readline history.
172 # If it still doesn't match, just reload readline history.
173 if self.current_length() != self.orig_length \
173 if self.current_length() != self.orig_length \
174 or self.get_readline_tail() != self.readline_tail:
174 or self.get_readline_tail() != self.readline_tail:
175 self.shell.refill_readline_hist()
175 self.shell.refill_readline_hist()
176 except (AttributeError, IndexError):
176 except (AttributeError, IndexError):
177 pass
177 pass
178 # Returning False will cause exceptions to propagate
178 # Returning False will cause exceptions to propagate
179 return False
179 return False
180
180
181 def current_length(self):
181 def current_length(self):
182 return self.shell.readline.get_current_history_length()
182 return self.shell.readline.get_current_history_length()
183
183
184 def get_readline_tail(self, n=10):
184 def get_readline_tail(self, n=10):
185 """Get the last n items in readline history."""
185 """Get the last n items in readline history."""
186 end = self.shell.readline.get_current_history_length() + 1
186 end = self.shell.readline.get_current_history_length() + 1
187 start = max(end-n, 1)
187 start = max(end-n, 1)
188 ghi = self.shell.readline.get_history_item
188 ghi = self.shell.readline.get_history_item
189 return [ghi(x) for x in range(start, end)]
189 return [ghi(x) for x in range(start, end)]
190
190
191
191
192 @undoc
192 @undoc
193 class DummyMod(object):
193 class DummyMod(object):
194 """A dummy module used for IPython's interactive module when
194 """A dummy module used for IPython's interactive module when
195 a namespace must be assigned to the module's __dict__."""
195 a namespace must be assigned to the module's __dict__."""
196 pass
196 pass
197
197
198 #-----------------------------------------------------------------------------
198 #-----------------------------------------------------------------------------
199 # Main IPython class
199 # Main IPython class
200 #-----------------------------------------------------------------------------
200 #-----------------------------------------------------------------------------
201
201
202 class InteractiveShell(SingletonConfigurable):
202 class InteractiveShell(SingletonConfigurable):
203 """An enhanced, interactive shell for Python."""
203 """An enhanced, interactive shell for Python."""
204
204
205 _instance = None
205 _instance = None
206
206
207 ast_transformers = List([], config=True, help=
207 ast_transformers = List([], config=True, help=
208 """
208 """
209 A list of ast.NodeTransformer subclass instances, which will be applied
209 A list of ast.NodeTransformer subclass instances, which will be applied
210 to user input before code is run.
210 to user input before code is run.
211 """
211 """
212 )
212 )
213
213
214 autocall = Enum((0,1,2), default_value=0, config=True, help=
214 autocall = Enum((0,1,2), default_value=0, config=True, help=
215 """
215 """
216 Make IPython automatically call any callable object even if you didn't
216 Make IPython automatically call any callable object even if you didn't
217 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
217 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
218 automatically. The value can be '0' to disable the feature, '1' for
218 automatically. The value can be '0' to disable the feature, '1' for
219 'smart' autocall, where it is not applied if there are no more
219 'smart' autocall, where it is not applied if there are no more
220 arguments on the line, and '2' for 'full' autocall, where all callable
220 arguments on the line, and '2' for 'full' autocall, where all callable
221 objects are automatically called (even if no arguments are present).
221 objects are automatically called (even if no arguments are present).
222 """
222 """
223 )
223 )
224 # TODO: remove all autoindent logic and put into frontends.
224 # TODO: remove all autoindent logic and put into frontends.
225 # We can't do this yet because even runlines uses the autoindent.
225 # We can't do this yet because even runlines uses the autoindent.
226 autoindent = CBool(True, config=True, help=
226 autoindent = CBool(True, config=True, help=
227 """
227 """
228 Autoindent IPython code entered interactively.
228 Autoindent IPython code entered interactively.
229 """
229 """
230 )
230 )
231 automagic = CBool(True, config=True, help=
231 automagic = CBool(True, config=True, help=
232 """
232 """
233 Enable magic commands to be called without the leading %.
233 Enable magic commands to be called without the leading %.
234 """
234 """
235 )
235 )
236 cache_size = Integer(1000, config=True, help=
236 cache_size = Integer(1000, config=True, help=
237 """
237 """
238 Set the size of the output cache. The default is 1000, you can
238 Set the size of the output cache. The default is 1000, you can
239 change it permanently in your config file. Setting it to 0 completely
239 change it permanently in your config file. Setting it to 0 completely
240 disables the caching system, and the minimum value accepted is 20 (if
240 disables the caching system, and the minimum value accepted is 20 (if
241 you provide a value less than 20, it is reset to 0 and a warning is
241 you provide a value less than 20, it is reset to 0 and a warning is
242 issued). This limit is defined because otherwise you'll spend more
242 issued). This limit is defined because otherwise you'll spend more
243 time re-flushing a too small cache than working
243 time re-flushing a too small cache than working
244 """
244 """
245 )
245 )
246 color_info = CBool(True, config=True, help=
246 color_info = CBool(True, config=True, help=
247 """
247 """
248 Use colors for displaying information about objects. Because this
248 Use colors for displaying information about objects. Because this
249 information is passed through a pager (like 'less'), and some pagers
249 information is passed through a pager (like 'less'), and some pagers
250 get confused with color codes, this capability can be turned off.
250 get confused with color codes, this capability can be turned off.
251 """
251 """
252 )
252 )
253 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
253 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
254 default_value=get_default_colors(), config=True,
254 default_value=get_default_colors(), config=True,
255 help="Set the color scheme (NoColor, Linux, or LightBG)."
255 help="Set the color scheme (NoColor, Linux, or LightBG)."
256 )
256 )
257 colors_force = CBool(False, help=
257 colors_force = CBool(False, help=
258 """
258 """
259 Force use of ANSI color codes, regardless of OS and readline
259 Force use of ANSI color codes, regardless of OS and readline
260 availability.
260 availability.
261 """
261 """
262 # FIXME: This is essentially a hack to allow ZMQShell to show colors
262 # FIXME: This is essentially a hack to allow ZMQShell to show colors
263 # without readline on Win32. When the ZMQ formatting system is
263 # without readline on Win32. When the ZMQ formatting system is
264 # refactored, this should be removed.
264 # refactored, this should be removed.
265 )
265 )
266 debug = CBool(False, config=True)
266 debug = CBool(False, config=True)
267 deep_reload = CBool(False, config=True, help=
267 deep_reload = CBool(False, config=True, help=
268 """
268 """
269 Enable deep (recursive) reloading by default. IPython can use the
269 Enable deep (recursive) reloading by default. IPython can use the
270 deep_reload module which reloads changes in modules recursively (it
270 deep_reload module which reloads changes in modules recursively (it
271 replaces the reload() function, so you don't need to change anything to
271 replaces the reload() function, so you don't need to change anything to
272 use it). deep_reload() forces a full reload of modules whose code may
272 use it). deep_reload() forces a full reload of modules whose code may
273 have changed, which the default reload() function does not. When
273 have changed, which the default reload() function does not. When
274 deep_reload is off, IPython will use the normal reload(), but
274 deep_reload is off, IPython will use the normal reload(), but
275 deep_reload will still be available as dreload().
275 deep_reload will still be available as dreload().
276 """
276 """
277 )
277 )
278 disable_failing_post_execute = CBool(False, config=True,
278 disable_failing_post_execute = CBool(False, config=True,
279 help="Don't call post-execute functions that have failed in the past."
279 help="Don't call post-execute functions that have failed in the past."
280 )
280 )
281 display_formatter = Instance(DisplayFormatter)
281 display_formatter = Instance(DisplayFormatter)
282 displayhook_class = Type(DisplayHook)
282 displayhook_class = Type(DisplayHook)
283 display_pub_class = Type(DisplayPublisher)
283 display_pub_class = Type(DisplayPublisher)
284 data_pub_class = None
284 data_pub_class = None
285
285
286 exit_now = CBool(False)
286 exit_now = CBool(False)
287 exiter = Instance(ExitAutocall)
287 exiter = Instance(ExitAutocall)
288 def _exiter_default(self):
288 def _exiter_default(self):
289 return ExitAutocall(self)
289 return ExitAutocall(self)
290 # Monotonically increasing execution counter
290 # Monotonically increasing execution counter
291 execution_count = Integer(1)
291 execution_count = Integer(1)
292 filename = Unicode("<ipython console>")
292 filename = Unicode("<ipython console>")
293 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
293 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
294
294
295 # Input splitter, to transform input line by line and detect when a block
295 # Input splitter, to transform input line by line and detect when a block
296 # is ready to be executed.
296 # is ready to be executed.
297 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
297 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
298 (), {'line_input_checker': True})
298 (), {'line_input_checker': True})
299
299
300 # This InputSplitter instance is used to transform completed cells before
300 # This InputSplitter instance is used to transform completed cells before
301 # running them. It allows cell magics to contain blank lines.
301 # running them. It allows cell magics to contain blank lines.
302 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
302 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
303 (), {'line_input_checker': False})
303 (), {'line_input_checker': False})
304
304
305 logstart = CBool(False, config=True, help=
305 logstart = CBool(False, config=True, help=
306 """
306 """
307 Start logging to the default log file.
307 Start logging to the default log file.
308 """
308 """
309 )
309 )
310 logfile = Unicode('', config=True, help=
310 logfile = Unicode('', config=True, help=
311 """
311 """
312 The name of the logfile to use.
312 The name of the logfile to use.
313 """
313 """
314 )
314 )
315 logappend = Unicode('', config=True, help=
315 logappend = Unicode('', config=True, help=
316 """
316 """
317 Start logging to the given file in append mode.
317 Start logging to the given file in append mode.
318 """
318 """
319 )
319 )
320 object_info_string_level = Enum((0,1,2), default_value=0,
320 object_info_string_level = Enum((0,1,2), default_value=0,
321 config=True)
321 config=True)
322 pdb = CBool(False, config=True, help=
322 pdb = CBool(False, config=True, help=
323 """
323 """
324 Automatically call the pdb debugger after every exception.
324 Automatically call the pdb debugger after every exception.
325 """
325 """
326 )
326 )
327 multiline_history = CBool(sys.platform != 'win32', config=True,
327 multiline_history = CBool(sys.platform != 'win32', config=True,
328 help="Save multi-line entries as one entry in readline history"
328 help="Save multi-line entries as one entry in readline history"
329 )
329 )
330
330
331 # deprecated prompt traits:
331 # deprecated prompt traits:
332
332
333 prompt_in1 = Unicode('In [\\#]: ', config=True,
333 prompt_in1 = Unicode('In [\\#]: ', config=True,
334 help="Deprecated, use PromptManager.in_template")
334 help="Deprecated, use PromptManager.in_template")
335 prompt_in2 = Unicode(' .\\D.: ', config=True,
335 prompt_in2 = Unicode(' .\\D.: ', config=True,
336 help="Deprecated, use PromptManager.in2_template")
336 help="Deprecated, use PromptManager.in2_template")
337 prompt_out = Unicode('Out[\\#]: ', config=True,
337 prompt_out = Unicode('Out[\\#]: ', config=True,
338 help="Deprecated, use PromptManager.out_template")
338 help="Deprecated, use PromptManager.out_template")
339 prompts_pad_left = CBool(True, config=True,
339 prompts_pad_left = CBool(True, config=True,
340 help="Deprecated, use PromptManager.justify")
340 help="Deprecated, use PromptManager.justify")
341
341
342 def _prompt_trait_changed(self, name, old, new):
342 def _prompt_trait_changed(self, name, old, new):
343 table = {
343 table = {
344 'prompt_in1' : 'in_template',
344 'prompt_in1' : 'in_template',
345 'prompt_in2' : 'in2_template',
345 'prompt_in2' : 'in2_template',
346 'prompt_out' : 'out_template',
346 'prompt_out' : 'out_template',
347 'prompts_pad_left' : 'justify',
347 'prompts_pad_left' : 'justify',
348 }
348 }
349 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
349 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
350 name=name, newname=table[name])
350 name=name, newname=table[name])
351 )
351 )
352 # protect against weird cases where self.config may not exist:
352 # protect against weird cases where self.config may not exist:
353 if self.config is not None:
353 if self.config is not None:
354 # propagate to corresponding PromptManager trait
354 # propagate to corresponding PromptManager trait
355 setattr(self.config.PromptManager, table[name], new)
355 setattr(self.config.PromptManager, table[name], new)
356
356
357 _prompt_in1_changed = _prompt_trait_changed
357 _prompt_in1_changed = _prompt_trait_changed
358 _prompt_in2_changed = _prompt_trait_changed
358 _prompt_in2_changed = _prompt_trait_changed
359 _prompt_out_changed = _prompt_trait_changed
359 _prompt_out_changed = _prompt_trait_changed
360 _prompt_pad_left_changed = _prompt_trait_changed
360 _prompt_pad_left_changed = _prompt_trait_changed
361
361
362 show_rewritten_input = CBool(True, config=True,
362 show_rewritten_input = CBool(True, config=True,
363 help="Show rewritten input, e.g. for autocall."
363 help="Show rewritten input, e.g. for autocall."
364 )
364 )
365
365
366 quiet = CBool(False, config=True)
366 quiet = CBool(False, config=True)
367
367
368 history_length = Integer(10000, config=True)
368 history_length = Integer(10000, config=True)
369
369
370 # The readline stuff will eventually be moved to the terminal subclass
370 # The readline stuff will eventually be moved to the terminal subclass
371 # but for now, we can't do that as readline is welded in everywhere.
371 # but for now, we can't do that as readline is welded in everywhere.
372 readline_use = CBool(True, config=True)
372 readline_use = CBool(True, config=True)
373 readline_remove_delims = Unicode('-/~', config=True)
373 readline_remove_delims = Unicode('-/~', config=True)
374 readline_delims = Unicode() # set by init_readline()
374 readline_delims = Unicode() # set by init_readline()
375 # don't use \M- bindings by default, because they
375 # don't use \M- bindings by default, because they
376 # conflict with 8-bit encodings. See gh-58,gh-88
376 # conflict with 8-bit encodings. See gh-58,gh-88
377 readline_parse_and_bind = List([
377 readline_parse_and_bind = List([
378 'tab: complete',
378 'tab: complete',
379 '"\C-l": clear-screen',
379 '"\C-l": clear-screen',
380 'set show-all-if-ambiguous on',
380 'set show-all-if-ambiguous on',
381 '"\C-o": tab-insert',
381 '"\C-o": tab-insert',
382 '"\C-r": reverse-search-history',
382 '"\C-r": reverse-search-history',
383 '"\C-s": forward-search-history',
383 '"\C-s": forward-search-history',
384 '"\C-p": history-search-backward',
384 '"\C-p": history-search-backward',
385 '"\C-n": history-search-forward',
385 '"\C-n": history-search-forward',
386 '"\e[A": history-search-backward',
386 '"\e[A": history-search-backward',
387 '"\e[B": history-search-forward',
387 '"\e[B": history-search-forward',
388 '"\C-k": kill-line',
388 '"\C-k": kill-line',
389 '"\C-u": unix-line-discard',
389 '"\C-u": unix-line-discard',
390 ], allow_none=False, config=True)
390 ], allow_none=False, config=True)
391
391
392 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
392 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
393 default_value='last_expr', config=True,
393 default_value='last_expr', config=True,
394 help="""
394 help="""
395 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
395 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
396 run interactively (displaying output from expressions).""")
396 run interactively (displaying output from expressions).""")
397
397
398 # TODO: this part of prompt management should be moved to the frontends.
398 # TODO: this part of prompt management should be moved to the frontends.
399 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
399 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
400 separate_in = SeparateUnicode('\n', config=True)
400 separate_in = SeparateUnicode('\n', config=True)
401 separate_out = SeparateUnicode('', config=True)
401 separate_out = SeparateUnicode('', config=True)
402 separate_out2 = SeparateUnicode('', config=True)
402 separate_out2 = SeparateUnicode('', config=True)
403 wildcards_case_sensitive = CBool(True, config=True)
403 wildcards_case_sensitive = CBool(True, config=True)
404 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
404 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
405 default_value='Context', config=True)
405 default_value='Context', config=True)
406
406
407 # Subcomponents of InteractiveShell
407 # Subcomponents of InteractiveShell
408 alias_manager = Instance('IPython.core.alias.AliasManager')
408 alias_manager = Instance('IPython.core.alias.AliasManager')
409 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
409 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
410 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
410 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
411 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
411 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
412 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
412 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
413 payload_manager = Instance('IPython.core.payload.PayloadManager')
413 payload_manager = Instance('IPython.core.payload.PayloadManager')
414 history_manager = Instance('IPython.core.history.HistoryManager')
414 history_manager = Instance('IPython.core.history.HistoryManager')
415 magics_manager = Instance('IPython.core.magic.MagicsManager')
415 magics_manager = Instance('IPython.core.magic.MagicsManager')
416
416
417 profile_dir = Instance('IPython.core.application.ProfileDir')
417 profile_dir = Instance('IPython.core.application.ProfileDir')
418 @property
418 @property
419 def profile(self):
419 def profile(self):
420 if self.profile_dir is not None:
420 if self.profile_dir is not None:
421 name = os.path.basename(self.profile_dir.location)
421 name = os.path.basename(self.profile_dir.location)
422 return name.replace('profile_','')
422 return name.replace('profile_','')
423
423
424
424
425 # Private interface
425 # Private interface
426 _post_execute = Instance(dict)
426 _post_execute = Instance(dict)
427
427
428 # Tracks any GUI loop loaded for pylab
428 # Tracks any GUI loop loaded for pylab
429 pylab_gui_select = None
429 pylab_gui_select = None
430
430
431 def __init__(self, ipython_dir=None, profile_dir=None,
431 def __init__(self, ipython_dir=None, profile_dir=None,
432 user_module=None, user_ns=None,
432 user_module=None, user_ns=None,
433 custom_exceptions=((), None), **kwargs):
433 custom_exceptions=((), None), **kwargs):
434
434
435 # This is where traits with a config_key argument are updated
435 # This is where traits with a config_key argument are updated
436 # from the values on config.
436 # from the values on config.
437 super(InteractiveShell, self).__init__(**kwargs)
437 super(InteractiveShell, self).__init__(**kwargs)
438 self.configurables = [self]
438 self.configurables = [self]
439
439
440 # These are relatively independent and stateless
440 # These are relatively independent and stateless
441 self.init_ipython_dir(ipython_dir)
441 self.init_ipython_dir(ipython_dir)
442 self.init_profile_dir(profile_dir)
442 self.init_profile_dir(profile_dir)
443 self.init_instance_attrs()
443 self.init_instance_attrs()
444 self.init_environment()
444 self.init_environment()
445
445
446 # Check if we're in a virtualenv, and set up sys.path.
446 # Check if we're in a virtualenv, and set up sys.path.
447 self.init_virtualenv()
447 self.init_virtualenv()
448
448
449 # Create namespaces (user_ns, user_global_ns, etc.)
449 # Create namespaces (user_ns, user_global_ns, etc.)
450 self.init_create_namespaces(user_module, user_ns)
450 self.init_create_namespaces(user_module, user_ns)
451 # This has to be done after init_create_namespaces because it uses
451 # This has to be done after init_create_namespaces because it uses
452 # something in self.user_ns, but before init_sys_modules, which
452 # something in self.user_ns, but before init_sys_modules, which
453 # is the first thing to modify sys.
453 # is the first thing to modify sys.
454 # TODO: When we override sys.stdout and sys.stderr before this class
454 # TODO: When we override sys.stdout and sys.stderr before this class
455 # is created, we are saving the overridden ones here. Not sure if this
455 # is created, we are saving the overridden ones here. Not sure if this
456 # is what we want to do.
456 # is what we want to do.
457 self.save_sys_module_state()
457 self.save_sys_module_state()
458 self.init_sys_modules()
458 self.init_sys_modules()
459
459
460 # While we're trying to have each part of the code directly access what
460 # While we're trying to have each part of the code directly access what
461 # it needs without keeping redundant references to objects, we have too
461 # it needs without keeping redundant references to objects, we have too
462 # much legacy code that expects ip.db to exist.
462 # much legacy code that expects ip.db to exist.
463 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
463 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
464
464
465 self.init_history()
465 self.init_history()
466 self.init_encoding()
466 self.init_encoding()
467 self.init_prefilter()
467 self.init_prefilter()
468
468
469 self.init_syntax_highlighting()
469 self.init_syntax_highlighting()
470 self.init_hooks()
470 self.init_hooks()
471 self.init_events()
471 self.init_events()
472 self.init_pushd_popd_magic()
472 self.init_pushd_popd_magic()
473 # self.init_traceback_handlers use to be here, but we moved it below
473 # self.init_traceback_handlers use to be here, but we moved it below
474 # because it and init_io have to come after init_readline.
474 # because it and init_io have to come after init_readline.
475 self.init_user_ns()
475 self.init_user_ns()
476 self.init_logger()
476 self.init_logger()
477 self.init_builtins()
477 self.init_builtins()
478
478
479 # The following was in post_config_initialization
479 # The following was in post_config_initialization
480 self.init_inspector()
480 self.init_inspector()
481 # init_readline() must come before init_io(), because init_io uses
481 # init_readline() must come before init_io(), because init_io uses
482 # readline related things.
482 # readline related things.
483 self.init_readline()
483 self.init_readline()
484 # We save this here in case user code replaces raw_input, but it needs
484 # We save this here in case user code replaces raw_input, but it needs
485 # to be after init_readline(), because PyPy's readline works by replacing
485 # to be after init_readline(), because PyPy's readline works by replacing
486 # raw_input.
486 # raw_input.
487 if py3compat.PY3:
487 if py3compat.PY3:
488 self.raw_input_original = input
488 self.raw_input_original = input
489 else:
489 else:
490 self.raw_input_original = raw_input
490 self.raw_input_original = raw_input
491 # init_completer must come after init_readline, because it needs to
491 # init_completer must come after init_readline, because it needs to
492 # know whether readline is present or not system-wide to configure the
492 # know whether readline is present or not system-wide to configure the
493 # completers, since the completion machinery can now operate
493 # completers, since the completion machinery can now operate
494 # independently of readline (e.g. over the network)
494 # independently of readline (e.g. over the network)
495 self.init_completer()
495 self.init_completer()
496 # TODO: init_io() needs to happen before init_traceback handlers
496 # TODO: init_io() needs to happen before init_traceback handlers
497 # because the traceback handlers hardcode the stdout/stderr streams.
497 # because the traceback handlers hardcode the stdout/stderr streams.
498 # This logic in in debugger.Pdb and should eventually be changed.
498 # This logic in in debugger.Pdb and should eventually be changed.
499 self.init_io()
499 self.init_io()
500 self.init_traceback_handlers(custom_exceptions)
500 self.init_traceback_handlers(custom_exceptions)
501 self.init_prompts()
501 self.init_prompts()
502 self.init_display_formatter()
502 self.init_display_formatter()
503 self.init_display_pub()
503 self.init_display_pub()
504 self.init_data_pub()
504 self.init_data_pub()
505 self.init_displayhook()
505 self.init_displayhook()
506 self.init_latextool()
506 self.init_latextool()
507 self.init_magics()
507 self.init_magics()
508 self.init_alias()
508 self.init_alias()
509 self.init_logstart()
509 self.init_logstart()
510 self.init_pdb()
510 self.init_pdb()
511 self.init_extension_manager()
511 self.init_extension_manager()
512 self.init_payload()
512 self.init_payload()
513 self.init_comms()
513 self.init_comms()
514 self.hooks.late_startup_hook()
514 self.hooks.late_startup_hook()
515 self.events.trigger('shell_initialized', self)
515 self.events.trigger('shell_initialized', self)
516 atexit.register(self.atexit_operations)
516 atexit.register(self.atexit_operations)
517
517
518 def get_ipython(self):
518 def get_ipython(self):
519 """Return the currently running IPython instance."""
519 """Return the currently running IPython instance."""
520 return self
520 return self
521
521
522 #-------------------------------------------------------------------------
522 #-------------------------------------------------------------------------
523 # Trait changed handlers
523 # Trait changed handlers
524 #-------------------------------------------------------------------------
524 #-------------------------------------------------------------------------
525
525
526 def _ipython_dir_changed(self, name, new):
526 def _ipython_dir_changed(self, name, new):
527 if not os.path.isdir(new):
527 ensure_dir_exists(new)
528 os.makedirs(new, mode = 0o777)
529
528
530 def set_autoindent(self,value=None):
529 def set_autoindent(self,value=None):
531 """Set the autoindent flag, checking for readline support.
530 """Set the autoindent flag, checking for readline support.
532
531
533 If called with no arguments, it acts as a toggle."""
532 If called with no arguments, it acts as a toggle."""
534
533
535 if value != 0 and not self.has_readline:
534 if value != 0 and not self.has_readline:
536 if os.name == 'posix':
535 if os.name == 'posix':
537 warn("The auto-indent feature requires the readline library")
536 warn("The auto-indent feature requires the readline library")
538 self.autoindent = 0
537 self.autoindent = 0
539 return
538 return
540 if value is None:
539 if value is None:
541 self.autoindent = not self.autoindent
540 self.autoindent = not self.autoindent
542 else:
541 else:
543 self.autoindent = value
542 self.autoindent = value
544
543
545 #-------------------------------------------------------------------------
544 #-------------------------------------------------------------------------
546 # init_* methods called by __init__
545 # init_* methods called by __init__
547 #-------------------------------------------------------------------------
546 #-------------------------------------------------------------------------
548
547
549 def init_ipython_dir(self, ipython_dir):
548 def init_ipython_dir(self, ipython_dir):
550 if ipython_dir is not None:
549 if ipython_dir is not None:
551 self.ipython_dir = ipython_dir
550 self.ipython_dir = ipython_dir
552 return
551 return
553
552
554 self.ipython_dir = get_ipython_dir()
553 self.ipython_dir = get_ipython_dir()
555
554
556 def init_profile_dir(self, profile_dir):
555 def init_profile_dir(self, profile_dir):
557 if profile_dir is not None:
556 if profile_dir is not None:
558 self.profile_dir = profile_dir
557 self.profile_dir = profile_dir
559 return
558 return
560 self.profile_dir =\
559 self.profile_dir =\
561 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
560 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
562
561
563 def init_instance_attrs(self):
562 def init_instance_attrs(self):
564 self.more = False
563 self.more = False
565
564
566 # command compiler
565 # command compiler
567 self.compile = CachingCompiler()
566 self.compile = CachingCompiler()
568
567
569 # Make an empty namespace, which extension writers can rely on both
568 # Make an empty namespace, which extension writers can rely on both
570 # existing and NEVER being used by ipython itself. This gives them a
569 # existing and NEVER being used by ipython itself. This gives them a
571 # convenient location for storing additional information and state
570 # convenient location for storing additional information and state
572 # their extensions may require, without fear of collisions with other
571 # their extensions may require, without fear of collisions with other
573 # ipython names that may develop later.
572 # ipython names that may develop later.
574 self.meta = Struct()
573 self.meta = Struct()
575
574
576 # Temporary files used for various purposes. Deleted at exit.
575 # Temporary files used for various purposes. Deleted at exit.
577 self.tempfiles = []
576 self.tempfiles = []
578 self.tempdirs = []
577 self.tempdirs = []
579
578
580 # Keep track of readline usage (later set by init_readline)
579 # Keep track of readline usage (later set by init_readline)
581 self.has_readline = False
580 self.has_readline = False
582
581
583 # keep track of where we started running (mainly for crash post-mortem)
582 # keep track of where we started running (mainly for crash post-mortem)
584 # This is not being used anywhere currently.
583 # This is not being used anywhere currently.
585 self.starting_dir = py3compat.getcwd()
584 self.starting_dir = py3compat.getcwd()
586
585
587 # Indentation management
586 # Indentation management
588 self.indent_current_nsp = 0
587 self.indent_current_nsp = 0
589
588
590 # Dict to track post-execution functions that have been registered
589 # Dict to track post-execution functions that have been registered
591 self._post_execute = {}
590 self._post_execute = {}
592
591
593 def init_environment(self):
592 def init_environment(self):
594 """Any changes we need to make to the user's environment."""
593 """Any changes we need to make to the user's environment."""
595 pass
594 pass
596
595
597 def init_encoding(self):
596 def init_encoding(self):
598 # Get system encoding at startup time. Certain terminals (like Emacs
597 # Get system encoding at startup time. Certain terminals (like Emacs
599 # under Win32 have it set to None, and we need to have a known valid
598 # under Win32 have it set to None, and we need to have a known valid
600 # encoding to use in the raw_input() method
599 # encoding to use in the raw_input() method
601 try:
600 try:
602 self.stdin_encoding = sys.stdin.encoding or 'ascii'
601 self.stdin_encoding = sys.stdin.encoding or 'ascii'
603 except AttributeError:
602 except AttributeError:
604 self.stdin_encoding = 'ascii'
603 self.stdin_encoding = 'ascii'
605
604
606 def init_syntax_highlighting(self):
605 def init_syntax_highlighting(self):
607 # Python source parser/formatter for syntax highlighting
606 # Python source parser/formatter for syntax highlighting
608 pyformat = PyColorize.Parser().format
607 pyformat = PyColorize.Parser().format
609 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
608 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
610
609
611 def init_pushd_popd_magic(self):
610 def init_pushd_popd_magic(self):
612 # for pushd/popd management
611 # for pushd/popd management
613 self.home_dir = get_home_dir()
612 self.home_dir = get_home_dir()
614
613
615 self.dir_stack = []
614 self.dir_stack = []
616
615
617 def init_logger(self):
616 def init_logger(self):
618 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
617 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
619 logmode='rotate')
618 logmode='rotate')
620
619
621 def init_logstart(self):
620 def init_logstart(self):
622 """Initialize logging in case it was requested at the command line.
621 """Initialize logging in case it was requested at the command line.
623 """
622 """
624 if self.logappend:
623 if self.logappend:
625 self.magic('logstart %s append' % self.logappend)
624 self.magic('logstart %s append' % self.logappend)
626 elif self.logfile:
625 elif self.logfile:
627 self.magic('logstart %s' % self.logfile)
626 self.magic('logstart %s' % self.logfile)
628 elif self.logstart:
627 elif self.logstart:
629 self.magic('logstart')
628 self.magic('logstart')
630
629
631 def init_builtins(self):
630 def init_builtins(self):
632 # A single, static flag that we set to True. Its presence indicates
631 # A single, static flag that we set to True. Its presence indicates
633 # that an IPython shell has been created, and we make no attempts at
632 # that an IPython shell has been created, and we make no attempts at
634 # removing on exit or representing the existence of more than one
633 # removing on exit or representing the existence of more than one
635 # IPython at a time.
634 # IPython at a time.
636 builtin_mod.__dict__['__IPYTHON__'] = True
635 builtin_mod.__dict__['__IPYTHON__'] = True
637
636
638 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
637 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
639 # manage on enter/exit, but with all our shells it's virtually
638 # manage on enter/exit, but with all our shells it's virtually
640 # impossible to get all the cases right. We're leaving the name in for
639 # impossible to get all the cases right. We're leaving the name in for
641 # those who adapted their codes to check for this flag, but will
640 # those who adapted their codes to check for this flag, but will
642 # eventually remove it after a few more releases.
641 # eventually remove it after a few more releases.
643 builtin_mod.__dict__['__IPYTHON__active'] = \
642 builtin_mod.__dict__['__IPYTHON__active'] = \
644 'Deprecated, check for __IPYTHON__'
643 'Deprecated, check for __IPYTHON__'
645
644
646 self.builtin_trap = BuiltinTrap(shell=self)
645 self.builtin_trap = BuiltinTrap(shell=self)
647
646
648 def init_inspector(self):
647 def init_inspector(self):
649 # Object inspector
648 # Object inspector
650 self.inspector = oinspect.Inspector(oinspect.InspectColors,
649 self.inspector = oinspect.Inspector(oinspect.InspectColors,
651 PyColorize.ANSICodeColors,
650 PyColorize.ANSICodeColors,
652 'NoColor',
651 'NoColor',
653 self.object_info_string_level)
652 self.object_info_string_level)
654
653
655 def init_io(self):
654 def init_io(self):
656 # This will just use sys.stdout and sys.stderr. If you want to
655 # This will just use sys.stdout and sys.stderr. If you want to
657 # override sys.stdout and sys.stderr themselves, you need to do that
656 # override sys.stdout and sys.stderr themselves, you need to do that
658 # *before* instantiating this class, because io holds onto
657 # *before* instantiating this class, because io holds onto
659 # references to the underlying streams.
658 # references to the underlying streams.
660 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
659 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
661 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
660 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
662 else:
661 else:
663 io.stdout = io.IOStream(sys.stdout)
662 io.stdout = io.IOStream(sys.stdout)
664 io.stderr = io.IOStream(sys.stderr)
663 io.stderr = io.IOStream(sys.stderr)
665
664
666 def init_prompts(self):
665 def init_prompts(self):
667 self.prompt_manager = PromptManager(shell=self, parent=self)
666 self.prompt_manager = PromptManager(shell=self, parent=self)
668 self.configurables.append(self.prompt_manager)
667 self.configurables.append(self.prompt_manager)
669 # Set system prompts, so that scripts can decide if they are running
668 # Set system prompts, so that scripts can decide if they are running
670 # interactively.
669 # interactively.
671 sys.ps1 = 'In : '
670 sys.ps1 = 'In : '
672 sys.ps2 = '...: '
671 sys.ps2 = '...: '
673 sys.ps3 = 'Out: '
672 sys.ps3 = 'Out: '
674
673
675 def init_display_formatter(self):
674 def init_display_formatter(self):
676 self.display_formatter = DisplayFormatter(parent=self)
675 self.display_formatter = DisplayFormatter(parent=self)
677 self.configurables.append(self.display_formatter)
676 self.configurables.append(self.display_formatter)
678
677
679 def init_display_pub(self):
678 def init_display_pub(self):
680 self.display_pub = self.display_pub_class(parent=self)
679 self.display_pub = self.display_pub_class(parent=self)
681 self.configurables.append(self.display_pub)
680 self.configurables.append(self.display_pub)
682
681
683 def init_data_pub(self):
682 def init_data_pub(self):
684 if not self.data_pub_class:
683 if not self.data_pub_class:
685 self.data_pub = None
684 self.data_pub = None
686 return
685 return
687 self.data_pub = self.data_pub_class(parent=self)
686 self.data_pub = self.data_pub_class(parent=self)
688 self.configurables.append(self.data_pub)
687 self.configurables.append(self.data_pub)
689
688
690 def init_displayhook(self):
689 def init_displayhook(self):
691 # Initialize displayhook, set in/out prompts and printing system
690 # Initialize displayhook, set in/out prompts and printing system
692 self.displayhook = self.displayhook_class(
691 self.displayhook = self.displayhook_class(
693 parent=self,
692 parent=self,
694 shell=self,
693 shell=self,
695 cache_size=self.cache_size,
694 cache_size=self.cache_size,
696 )
695 )
697 self.configurables.append(self.displayhook)
696 self.configurables.append(self.displayhook)
698 # This is a context manager that installs/revmoes the displayhook at
697 # This is a context manager that installs/revmoes the displayhook at
699 # the appropriate time.
698 # the appropriate time.
700 self.display_trap = DisplayTrap(hook=self.displayhook)
699 self.display_trap = DisplayTrap(hook=self.displayhook)
701
700
702 def init_latextool(self):
701 def init_latextool(self):
703 """Configure LaTeXTool."""
702 """Configure LaTeXTool."""
704 cfg = LaTeXTool.instance(parent=self)
703 cfg = LaTeXTool.instance(parent=self)
705 if cfg not in self.configurables:
704 if cfg not in self.configurables:
706 self.configurables.append(cfg)
705 self.configurables.append(cfg)
707
706
708 def init_virtualenv(self):
707 def init_virtualenv(self):
709 """Add a virtualenv to sys.path so the user can import modules from it.
708 """Add a virtualenv to sys.path so the user can import modules from it.
710 This isn't perfect: it doesn't use the Python interpreter with which the
709 This isn't perfect: it doesn't use the Python interpreter with which the
711 virtualenv was built, and it ignores the --no-site-packages option. A
710 virtualenv was built, and it ignores the --no-site-packages option. A
712 warning will appear suggesting the user installs IPython in the
711 warning will appear suggesting the user installs IPython in the
713 virtualenv, but for many cases, it probably works well enough.
712 virtualenv, but for many cases, it probably works well enough.
714
713
715 Adapted from code snippets online.
714 Adapted from code snippets online.
716
715
717 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
716 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
718 """
717 """
719 if 'VIRTUAL_ENV' not in os.environ:
718 if 'VIRTUAL_ENV' not in os.environ:
720 # Not in a virtualenv
719 # Not in a virtualenv
721 return
720 return
722
721
723 # venv detection:
722 # venv detection:
724 # stdlib venv may symlink sys.executable, so we can't use realpath.
723 # stdlib venv may symlink sys.executable, so we can't use realpath.
725 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
724 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
726 # So we just check every item in the symlink tree (generally <= 3)
725 # So we just check every item in the symlink tree (generally <= 3)
727 p = sys.executable
726 p = sys.executable
728 paths = [p]
727 paths = [p]
729 while os.path.islink(p):
728 while os.path.islink(p):
730 p = os.path.join(os.path.dirname(p), os.readlink(p))
729 p = os.path.join(os.path.dirname(p), os.readlink(p))
731 paths.append(p)
730 paths.append(p)
732 if any(p.startswith(os.environ['VIRTUAL_ENV']) for p in paths):
731 if any(p.startswith(os.environ['VIRTUAL_ENV']) for p in paths):
733 # Running properly in the virtualenv, don't need to do anything
732 # Running properly in the virtualenv, don't need to do anything
734 return
733 return
735
734
736 warn("Attempting to work in a virtualenv. If you encounter problems, please "
735 warn("Attempting to work in a virtualenv. If you encounter problems, please "
737 "install IPython inside the virtualenv.")
736 "install IPython inside the virtualenv.")
738 if sys.platform == "win32":
737 if sys.platform == "win32":
739 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
738 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
740 else:
739 else:
741 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
740 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
742 'python%d.%d' % sys.version_info[:2], 'site-packages')
741 'python%d.%d' % sys.version_info[:2], 'site-packages')
743
742
744 import site
743 import site
745 sys.path.insert(0, virtual_env)
744 sys.path.insert(0, virtual_env)
746 site.addsitedir(virtual_env)
745 site.addsitedir(virtual_env)
747
746
748 #-------------------------------------------------------------------------
747 #-------------------------------------------------------------------------
749 # Things related to injections into the sys module
748 # Things related to injections into the sys module
750 #-------------------------------------------------------------------------
749 #-------------------------------------------------------------------------
751
750
752 def save_sys_module_state(self):
751 def save_sys_module_state(self):
753 """Save the state of hooks in the sys module.
752 """Save the state of hooks in the sys module.
754
753
755 This has to be called after self.user_module is created.
754 This has to be called after self.user_module is created.
756 """
755 """
757 self._orig_sys_module_state = {}
756 self._orig_sys_module_state = {}
758 self._orig_sys_module_state['stdin'] = sys.stdin
757 self._orig_sys_module_state['stdin'] = sys.stdin
759 self._orig_sys_module_state['stdout'] = sys.stdout
758 self._orig_sys_module_state['stdout'] = sys.stdout
760 self._orig_sys_module_state['stderr'] = sys.stderr
759 self._orig_sys_module_state['stderr'] = sys.stderr
761 self._orig_sys_module_state['excepthook'] = sys.excepthook
760 self._orig_sys_module_state['excepthook'] = sys.excepthook
762 self._orig_sys_modules_main_name = self.user_module.__name__
761 self._orig_sys_modules_main_name = self.user_module.__name__
763 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
762 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
764
763
765 def restore_sys_module_state(self):
764 def restore_sys_module_state(self):
766 """Restore the state of the sys module."""
765 """Restore the state of the sys module."""
767 try:
766 try:
768 for k, v in iteritems(self._orig_sys_module_state):
767 for k, v in iteritems(self._orig_sys_module_state):
769 setattr(sys, k, v)
768 setattr(sys, k, v)
770 except AttributeError:
769 except AttributeError:
771 pass
770 pass
772 # Reset what what done in self.init_sys_modules
771 # Reset what what done in self.init_sys_modules
773 if self._orig_sys_modules_main_mod is not None:
772 if self._orig_sys_modules_main_mod is not None:
774 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
773 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
775
774
776 #-------------------------------------------------------------------------
775 #-------------------------------------------------------------------------
777 # Things related to hooks
776 # Things related to hooks
778 #-------------------------------------------------------------------------
777 #-------------------------------------------------------------------------
779
778
780 def init_hooks(self):
779 def init_hooks(self):
781 # hooks holds pointers used for user-side customizations
780 # hooks holds pointers used for user-side customizations
782 self.hooks = Struct()
781 self.hooks = Struct()
783
782
784 self.strdispatchers = {}
783 self.strdispatchers = {}
785
784
786 # Set all default hooks, defined in the IPython.hooks module.
785 # Set all default hooks, defined in the IPython.hooks module.
787 hooks = IPython.core.hooks
786 hooks = IPython.core.hooks
788 for hook_name in hooks.__all__:
787 for hook_name in hooks.__all__:
789 # default hooks have priority 100, i.e. low; user hooks should have
788 # default hooks have priority 100, i.e. low; user hooks should have
790 # 0-100 priority
789 # 0-100 priority
791 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
790 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
792
791
793 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
792 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
794 _warn_deprecated=True):
793 _warn_deprecated=True):
795 """set_hook(name,hook) -> sets an internal IPython hook.
794 """set_hook(name,hook) -> sets an internal IPython hook.
796
795
797 IPython exposes some of its internal API as user-modifiable hooks. By
796 IPython exposes some of its internal API as user-modifiable hooks. By
798 adding your function to one of these hooks, you can modify IPython's
797 adding your function to one of these hooks, you can modify IPython's
799 behavior to call at runtime your own routines."""
798 behavior to call at runtime your own routines."""
800
799
801 # At some point in the future, this should validate the hook before it
800 # At some point in the future, this should validate the hook before it
802 # accepts it. Probably at least check that the hook takes the number
801 # accepts it. Probably at least check that the hook takes the number
803 # of args it's supposed to.
802 # of args it's supposed to.
804
803
805 f = types.MethodType(hook,self)
804 f = types.MethodType(hook,self)
806
805
807 # check if the hook is for strdispatcher first
806 # check if the hook is for strdispatcher first
808 if str_key is not None:
807 if str_key is not None:
809 sdp = self.strdispatchers.get(name, StrDispatch())
808 sdp = self.strdispatchers.get(name, StrDispatch())
810 sdp.add_s(str_key, f, priority )
809 sdp.add_s(str_key, f, priority )
811 self.strdispatchers[name] = sdp
810 self.strdispatchers[name] = sdp
812 return
811 return
813 if re_key is not None:
812 if re_key is not None:
814 sdp = self.strdispatchers.get(name, StrDispatch())
813 sdp = self.strdispatchers.get(name, StrDispatch())
815 sdp.add_re(re.compile(re_key), f, priority )
814 sdp.add_re(re.compile(re_key), f, priority )
816 self.strdispatchers[name] = sdp
815 self.strdispatchers[name] = sdp
817 return
816 return
818
817
819 dp = getattr(self.hooks, name, None)
818 dp = getattr(self.hooks, name, None)
820 if name not in IPython.core.hooks.__all__:
819 if name not in IPython.core.hooks.__all__:
821 print("Warning! Hook '%s' is not one of %s" % \
820 print("Warning! Hook '%s' is not one of %s" % \
822 (name, IPython.core.hooks.__all__ ))
821 (name, IPython.core.hooks.__all__ ))
823
822
824 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
823 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
825 alternative = IPython.core.hooks.deprecated[name]
824 alternative = IPython.core.hooks.deprecated[name]
826 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
825 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
827
826
828 if not dp:
827 if not dp:
829 dp = IPython.core.hooks.CommandChainDispatcher()
828 dp = IPython.core.hooks.CommandChainDispatcher()
830
829
831 try:
830 try:
832 dp.add(f,priority)
831 dp.add(f,priority)
833 except AttributeError:
832 except AttributeError:
834 # it was not commandchain, plain old func - replace
833 # it was not commandchain, plain old func - replace
835 dp = f
834 dp = f
836
835
837 setattr(self.hooks,name, dp)
836 setattr(self.hooks,name, dp)
838
837
839 #-------------------------------------------------------------------------
838 #-------------------------------------------------------------------------
840 # Things related to events
839 # Things related to events
841 #-------------------------------------------------------------------------
840 #-------------------------------------------------------------------------
842
841
843 def init_events(self):
842 def init_events(self):
844 self.events = EventManager(self, available_events)
843 self.events = EventManager(self, available_events)
845
844
846 def register_post_execute(self, func):
845 def register_post_execute(self, func):
847 """DEPRECATED: Use ip.events.register('post_run_cell', func)
846 """DEPRECATED: Use ip.events.register('post_run_cell', func)
848
847
849 Register a function for calling after code execution.
848 Register a function for calling after code execution.
850 """
849 """
851 warn("ip.register_post_execute is deprecated, use "
850 warn("ip.register_post_execute is deprecated, use "
852 "ip.events.register('post_run_cell', func) instead.")
851 "ip.events.register('post_run_cell', func) instead.")
853 self.events.register('post_run_cell', func)
852 self.events.register('post_run_cell', func)
854
853
855 #-------------------------------------------------------------------------
854 #-------------------------------------------------------------------------
856 # Things related to the "main" module
855 # Things related to the "main" module
857 #-------------------------------------------------------------------------
856 #-------------------------------------------------------------------------
858
857
859 def new_main_mod(self, filename, modname):
858 def new_main_mod(self, filename, modname):
860 """Return a new 'main' module object for user code execution.
859 """Return a new 'main' module object for user code execution.
861
860
862 ``filename`` should be the path of the script which will be run in the
861 ``filename`` should be the path of the script which will be run in the
863 module. Requests with the same filename will get the same module, with
862 module. Requests with the same filename will get the same module, with
864 its namespace cleared.
863 its namespace cleared.
865
864
866 ``modname`` should be the module name - normally either '__main__' or
865 ``modname`` should be the module name - normally either '__main__' or
867 the basename of the file without the extension.
866 the basename of the file without the extension.
868
867
869 When scripts are executed via %run, we must keep a reference to their
868 When scripts are executed via %run, we must keep a reference to their
870 __main__ module around so that Python doesn't
869 __main__ module around so that Python doesn't
871 clear it, rendering references to module globals useless.
870 clear it, rendering references to module globals useless.
872
871
873 This method keeps said reference in a private dict, keyed by the
872 This method keeps said reference in a private dict, keyed by the
874 absolute path of the script. This way, for multiple executions of the
873 absolute path of the script. This way, for multiple executions of the
875 same script we only keep one copy of the namespace (the last one),
874 same script we only keep one copy of the namespace (the last one),
876 thus preventing memory leaks from old references while allowing the
875 thus preventing memory leaks from old references while allowing the
877 objects from the last execution to be accessible.
876 objects from the last execution to be accessible.
878 """
877 """
879 filename = os.path.abspath(filename)
878 filename = os.path.abspath(filename)
880 try:
879 try:
881 main_mod = self._main_mod_cache[filename]
880 main_mod = self._main_mod_cache[filename]
882 except KeyError:
881 except KeyError:
883 main_mod = self._main_mod_cache[filename] = types.ModuleType(modname,
882 main_mod = self._main_mod_cache[filename] = types.ModuleType(modname,
884 doc="Module created for script run in IPython")
883 doc="Module created for script run in IPython")
885 else:
884 else:
886 main_mod.__dict__.clear()
885 main_mod.__dict__.clear()
887 main_mod.__name__ = modname
886 main_mod.__name__ = modname
888
887
889 main_mod.__file__ = filename
888 main_mod.__file__ = filename
890 # It seems pydoc (and perhaps others) needs any module instance to
889 # It seems pydoc (and perhaps others) needs any module instance to
891 # implement a __nonzero__ method
890 # implement a __nonzero__ method
892 main_mod.__nonzero__ = lambda : True
891 main_mod.__nonzero__ = lambda : True
893
892
894 return main_mod
893 return main_mod
895
894
896 def clear_main_mod_cache(self):
895 def clear_main_mod_cache(self):
897 """Clear the cache of main modules.
896 """Clear the cache of main modules.
898
897
899 Mainly for use by utilities like %reset.
898 Mainly for use by utilities like %reset.
900
899
901 Examples
900 Examples
902 --------
901 --------
903
902
904 In [15]: import IPython
903 In [15]: import IPython
905
904
906 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
905 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
907
906
908 In [17]: len(_ip._main_mod_cache) > 0
907 In [17]: len(_ip._main_mod_cache) > 0
909 Out[17]: True
908 Out[17]: True
910
909
911 In [18]: _ip.clear_main_mod_cache()
910 In [18]: _ip.clear_main_mod_cache()
912
911
913 In [19]: len(_ip._main_mod_cache) == 0
912 In [19]: len(_ip._main_mod_cache) == 0
914 Out[19]: True
913 Out[19]: True
915 """
914 """
916 self._main_mod_cache.clear()
915 self._main_mod_cache.clear()
917
916
918 #-------------------------------------------------------------------------
917 #-------------------------------------------------------------------------
919 # Things related to debugging
918 # Things related to debugging
920 #-------------------------------------------------------------------------
919 #-------------------------------------------------------------------------
921
920
922 def init_pdb(self):
921 def init_pdb(self):
923 # Set calling of pdb on exceptions
922 # Set calling of pdb on exceptions
924 # self.call_pdb is a property
923 # self.call_pdb is a property
925 self.call_pdb = self.pdb
924 self.call_pdb = self.pdb
926
925
927 def _get_call_pdb(self):
926 def _get_call_pdb(self):
928 return self._call_pdb
927 return self._call_pdb
929
928
930 def _set_call_pdb(self,val):
929 def _set_call_pdb(self,val):
931
930
932 if val not in (0,1,False,True):
931 if val not in (0,1,False,True):
933 raise ValueError('new call_pdb value must be boolean')
932 raise ValueError('new call_pdb value must be boolean')
934
933
935 # store value in instance
934 # store value in instance
936 self._call_pdb = val
935 self._call_pdb = val
937
936
938 # notify the actual exception handlers
937 # notify the actual exception handlers
939 self.InteractiveTB.call_pdb = val
938 self.InteractiveTB.call_pdb = val
940
939
941 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
940 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
942 'Control auto-activation of pdb at exceptions')
941 'Control auto-activation of pdb at exceptions')
943
942
944 def debugger(self,force=False):
943 def debugger(self,force=False):
945 """Call the pydb/pdb debugger.
944 """Call the pydb/pdb debugger.
946
945
947 Keywords:
946 Keywords:
948
947
949 - force(False): by default, this routine checks the instance call_pdb
948 - force(False): by default, this routine checks the instance call_pdb
950 flag and does not actually invoke the debugger if the flag is false.
949 flag and does not actually invoke the debugger if the flag is false.
951 The 'force' option forces the debugger to activate even if the flag
950 The 'force' option forces the debugger to activate even if the flag
952 is false.
951 is false.
953 """
952 """
954
953
955 if not (force or self.call_pdb):
954 if not (force or self.call_pdb):
956 return
955 return
957
956
958 if not hasattr(sys,'last_traceback'):
957 if not hasattr(sys,'last_traceback'):
959 error('No traceback has been produced, nothing to debug.')
958 error('No traceback has been produced, nothing to debug.')
960 return
959 return
961
960
962 # use pydb if available
961 # use pydb if available
963 if debugger.has_pydb:
962 if debugger.has_pydb:
964 from pydb import pm
963 from pydb import pm
965 else:
964 else:
966 # fallback to our internal debugger
965 # fallback to our internal debugger
967 pm = lambda : self.InteractiveTB.debugger(force=True)
966 pm = lambda : self.InteractiveTB.debugger(force=True)
968
967
969 with self.readline_no_record:
968 with self.readline_no_record:
970 pm()
969 pm()
971
970
972 #-------------------------------------------------------------------------
971 #-------------------------------------------------------------------------
973 # Things related to IPython's various namespaces
972 # Things related to IPython's various namespaces
974 #-------------------------------------------------------------------------
973 #-------------------------------------------------------------------------
975 default_user_namespaces = True
974 default_user_namespaces = True
976
975
977 def init_create_namespaces(self, user_module=None, user_ns=None):
976 def init_create_namespaces(self, user_module=None, user_ns=None):
978 # Create the namespace where the user will operate. user_ns is
977 # Create the namespace where the user will operate. user_ns is
979 # normally the only one used, and it is passed to the exec calls as
978 # normally the only one used, and it is passed to the exec calls as
980 # the locals argument. But we do carry a user_global_ns namespace
979 # the locals argument. But we do carry a user_global_ns namespace
981 # given as the exec 'globals' argument, This is useful in embedding
980 # given as the exec 'globals' argument, This is useful in embedding
982 # situations where the ipython shell opens in a context where the
981 # situations where the ipython shell opens in a context where the
983 # distinction between locals and globals is meaningful. For
982 # distinction between locals and globals is meaningful. For
984 # non-embedded contexts, it is just the same object as the user_ns dict.
983 # non-embedded contexts, it is just the same object as the user_ns dict.
985
984
986 # FIXME. For some strange reason, __builtins__ is showing up at user
985 # FIXME. For some strange reason, __builtins__ is showing up at user
987 # level as a dict instead of a module. This is a manual fix, but I
986 # level as a dict instead of a module. This is a manual fix, but I
988 # should really track down where the problem is coming from. Alex
987 # should really track down where the problem is coming from. Alex
989 # Schmolck reported this problem first.
988 # Schmolck reported this problem first.
990
989
991 # A useful post by Alex Martelli on this topic:
990 # A useful post by Alex Martelli on this topic:
992 # Re: inconsistent value from __builtins__
991 # Re: inconsistent value from __builtins__
993 # Von: Alex Martelli <aleaxit@yahoo.com>
992 # Von: Alex Martelli <aleaxit@yahoo.com>
994 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
993 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
995 # Gruppen: comp.lang.python
994 # Gruppen: comp.lang.python
996
995
997 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
996 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
998 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
997 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
999 # > <type 'dict'>
998 # > <type 'dict'>
1000 # > >>> print type(__builtins__)
999 # > >>> print type(__builtins__)
1001 # > <type 'module'>
1000 # > <type 'module'>
1002 # > Is this difference in return value intentional?
1001 # > Is this difference in return value intentional?
1003
1002
1004 # Well, it's documented that '__builtins__' can be either a dictionary
1003 # Well, it's documented that '__builtins__' can be either a dictionary
1005 # or a module, and it's been that way for a long time. Whether it's
1004 # or a module, and it's been that way for a long time. Whether it's
1006 # intentional (or sensible), I don't know. In any case, the idea is
1005 # intentional (or sensible), I don't know. In any case, the idea is
1007 # that if you need to access the built-in namespace directly, you
1006 # that if you need to access the built-in namespace directly, you
1008 # should start with "import __builtin__" (note, no 's') which will
1007 # should start with "import __builtin__" (note, no 's') which will
1009 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1008 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1010
1009
1011 # These routines return a properly built module and dict as needed by
1010 # These routines return a properly built module and dict as needed by
1012 # the rest of the code, and can also be used by extension writers to
1011 # the rest of the code, and can also be used by extension writers to
1013 # generate properly initialized namespaces.
1012 # generate properly initialized namespaces.
1014 if (user_ns is not None) or (user_module is not None):
1013 if (user_ns is not None) or (user_module is not None):
1015 self.default_user_namespaces = False
1014 self.default_user_namespaces = False
1016 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1015 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1017
1016
1018 # A record of hidden variables we have added to the user namespace, so
1017 # A record of hidden variables we have added to the user namespace, so
1019 # we can list later only variables defined in actual interactive use.
1018 # we can list later only variables defined in actual interactive use.
1020 self.user_ns_hidden = {}
1019 self.user_ns_hidden = {}
1021
1020
1022 # Now that FakeModule produces a real module, we've run into a nasty
1021 # Now that FakeModule produces a real module, we've run into a nasty
1023 # problem: after script execution (via %run), the module where the user
1022 # problem: after script execution (via %run), the module where the user
1024 # code ran is deleted. Now that this object is a true module (needed
1023 # code ran is deleted. Now that this object is a true module (needed
1025 # so docetst and other tools work correctly), the Python module
1024 # so docetst and other tools work correctly), the Python module
1026 # teardown mechanism runs over it, and sets to None every variable
1025 # teardown mechanism runs over it, and sets to None every variable
1027 # present in that module. Top-level references to objects from the
1026 # present in that module. Top-level references to objects from the
1028 # script survive, because the user_ns is updated with them. However,
1027 # script survive, because the user_ns is updated with them. However,
1029 # calling functions defined in the script that use other things from
1028 # calling functions defined in the script that use other things from
1030 # the script will fail, because the function's closure had references
1029 # the script will fail, because the function's closure had references
1031 # to the original objects, which are now all None. So we must protect
1030 # to the original objects, which are now all None. So we must protect
1032 # these modules from deletion by keeping a cache.
1031 # these modules from deletion by keeping a cache.
1033 #
1032 #
1034 # To avoid keeping stale modules around (we only need the one from the
1033 # To avoid keeping stale modules around (we only need the one from the
1035 # last run), we use a dict keyed with the full path to the script, so
1034 # last run), we use a dict keyed with the full path to the script, so
1036 # only the last version of the module is held in the cache. Note,
1035 # only the last version of the module is held in the cache. Note,
1037 # however, that we must cache the module *namespace contents* (their
1036 # however, that we must cache the module *namespace contents* (their
1038 # __dict__). Because if we try to cache the actual modules, old ones
1037 # __dict__). Because if we try to cache the actual modules, old ones
1039 # (uncached) could be destroyed while still holding references (such as
1038 # (uncached) could be destroyed while still holding references (such as
1040 # those held by GUI objects that tend to be long-lived)>
1039 # those held by GUI objects that tend to be long-lived)>
1041 #
1040 #
1042 # The %reset command will flush this cache. See the cache_main_mod()
1041 # The %reset command will flush this cache. See the cache_main_mod()
1043 # and clear_main_mod_cache() methods for details on use.
1042 # and clear_main_mod_cache() methods for details on use.
1044
1043
1045 # This is the cache used for 'main' namespaces
1044 # This is the cache used for 'main' namespaces
1046 self._main_mod_cache = {}
1045 self._main_mod_cache = {}
1047
1046
1048 # A table holding all the namespaces IPython deals with, so that
1047 # A table holding all the namespaces IPython deals with, so that
1049 # introspection facilities can search easily.
1048 # introspection facilities can search easily.
1050 self.ns_table = {'user_global':self.user_module.__dict__,
1049 self.ns_table = {'user_global':self.user_module.__dict__,
1051 'user_local':self.user_ns,
1050 'user_local':self.user_ns,
1052 'builtin':builtin_mod.__dict__
1051 'builtin':builtin_mod.__dict__
1053 }
1052 }
1054
1053
1055 @property
1054 @property
1056 def user_global_ns(self):
1055 def user_global_ns(self):
1057 return self.user_module.__dict__
1056 return self.user_module.__dict__
1058
1057
1059 def prepare_user_module(self, user_module=None, user_ns=None):
1058 def prepare_user_module(self, user_module=None, user_ns=None):
1060 """Prepare the module and namespace in which user code will be run.
1059 """Prepare the module and namespace in which user code will be run.
1061
1060
1062 When IPython is started normally, both parameters are None: a new module
1061 When IPython is started normally, both parameters are None: a new module
1063 is created automatically, and its __dict__ used as the namespace.
1062 is created automatically, and its __dict__ used as the namespace.
1064
1063
1065 If only user_module is provided, its __dict__ is used as the namespace.
1064 If only user_module is provided, its __dict__ is used as the namespace.
1066 If only user_ns is provided, a dummy module is created, and user_ns
1065 If only user_ns is provided, a dummy module is created, and user_ns
1067 becomes the global namespace. If both are provided (as they may be
1066 becomes the global namespace. If both are provided (as they may be
1068 when embedding), user_ns is the local namespace, and user_module
1067 when embedding), user_ns is the local namespace, and user_module
1069 provides the global namespace.
1068 provides the global namespace.
1070
1069
1071 Parameters
1070 Parameters
1072 ----------
1071 ----------
1073 user_module : module, optional
1072 user_module : module, optional
1074 The current user module in which IPython is being run. If None,
1073 The current user module in which IPython is being run. If None,
1075 a clean module will be created.
1074 a clean module will be created.
1076 user_ns : dict, optional
1075 user_ns : dict, optional
1077 A namespace in which to run interactive commands.
1076 A namespace in which to run interactive commands.
1078
1077
1079 Returns
1078 Returns
1080 -------
1079 -------
1081 A tuple of user_module and user_ns, each properly initialised.
1080 A tuple of user_module and user_ns, each properly initialised.
1082 """
1081 """
1083 if user_module is None and user_ns is not None:
1082 if user_module is None and user_ns is not None:
1084 user_ns.setdefault("__name__", "__main__")
1083 user_ns.setdefault("__name__", "__main__")
1085 user_module = DummyMod()
1084 user_module = DummyMod()
1086 user_module.__dict__ = user_ns
1085 user_module.__dict__ = user_ns
1087
1086
1088 if user_module is None:
1087 if user_module is None:
1089 user_module = types.ModuleType("__main__",
1088 user_module = types.ModuleType("__main__",
1090 doc="Automatically created module for IPython interactive environment")
1089 doc="Automatically created module for IPython interactive environment")
1091
1090
1092 # We must ensure that __builtin__ (without the final 's') is always
1091 # We must ensure that __builtin__ (without the final 's') is always
1093 # available and pointing to the __builtin__ *module*. For more details:
1092 # available and pointing to the __builtin__ *module*. For more details:
1094 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1093 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1095 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1094 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1096 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1095 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1097
1096
1098 if user_ns is None:
1097 if user_ns is None:
1099 user_ns = user_module.__dict__
1098 user_ns = user_module.__dict__
1100
1099
1101 return user_module, user_ns
1100 return user_module, user_ns
1102
1101
1103 def init_sys_modules(self):
1102 def init_sys_modules(self):
1104 # We need to insert into sys.modules something that looks like a
1103 # We need to insert into sys.modules something that looks like a
1105 # module but which accesses the IPython namespace, for shelve and
1104 # module but which accesses the IPython namespace, for shelve and
1106 # pickle to work interactively. Normally they rely on getting
1105 # pickle to work interactively. Normally they rely on getting
1107 # everything out of __main__, but for embedding purposes each IPython
1106 # everything out of __main__, but for embedding purposes each IPython
1108 # instance has its own private namespace, so we can't go shoving
1107 # instance has its own private namespace, so we can't go shoving
1109 # everything into __main__.
1108 # everything into __main__.
1110
1109
1111 # note, however, that we should only do this for non-embedded
1110 # note, however, that we should only do this for non-embedded
1112 # ipythons, which really mimic the __main__.__dict__ with their own
1111 # ipythons, which really mimic the __main__.__dict__ with their own
1113 # namespace. Embedded instances, on the other hand, should not do
1112 # namespace. Embedded instances, on the other hand, should not do
1114 # this because they need to manage the user local/global namespaces
1113 # this because they need to manage the user local/global namespaces
1115 # only, but they live within a 'normal' __main__ (meaning, they
1114 # only, but they live within a 'normal' __main__ (meaning, they
1116 # shouldn't overtake the execution environment of the script they're
1115 # shouldn't overtake the execution environment of the script they're
1117 # embedded in).
1116 # embedded in).
1118
1117
1119 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1118 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1120 main_name = self.user_module.__name__
1119 main_name = self.user_module.__name__
1121 sys.modules[main_name] = self.user_module
1120 sys.modules[main_name] = self.user_module
1122
1121
1123 def init_user_ns(self):
1122 def init_user_ns(self):
1124 """Initialize all user-visible namespaces to their minimum defaults.
1123 """Initialize all user-visible namespaces to their minimum defaults.
1125
1124
1126 Certain history lists are also initialized here, as they effectively
1125 Certain history lists are also initialized here, as they effectively
1127 act as user namespaces.
1126 act as user namespaces.
1128
1127
1129 Notes
1128 Notes
1130 -----
1129 -----
1131 All data structures here are only filled in, they are NOT reset by this
1130 All data structures here are only filled in, they are NOT reset by this
1132 method. If they were not empty before, data will simply be added to
1131 method. If they were not empty before, data will simply be added to
1133 therm.
1132 therm.
1134 """
1133 """
1135 # This function works in two parts: first we put a few things in
1134 # This function works in two parts: first we put a few things in
1136 # user_ns, and we sync that contents into user_ns_hidden so that these
1135 # user_ns, and we sync that contents into user_ns_hidden so that these
1137 # initial variables aren't shown by %who. After the sync, we add the
1136 # initial variables aren't shown by %who. After the sync, we add the
1138 # rest of what we *do* want the user to see with %who even on a new
1137 # rest of what we *do* want the user to see with %who even on a new
1139 # session (probably nothing, so theye really only see their own stuff)
1138 # session (probably nothing, so theye really only see their own stuff)
1140
1139
1141 # The user dict must *always* have a __builtin__ reference to the
1140 # The user dict must *always* have a __builtin__ reference to the
1142 # Python standard __builtin__ namespace, which must be imported.
1141 # Python standard __builtin__ namespace, which must be imported.
1143 # This is so that certain operations in prompt evaluation can be
1142 # This is so that certain operations in prompt evaluation can be
1144 # reliably executed with builtins. Note that we can NOT use
1143 # reliably executed with builtins. Note that we can NOT use
1145 # __builtins__ (note the 's'), because that can either be a dict or a
1144 # __builtins__ (note the 's'), because that can either be a dict or a
1146 # module, and can even mutate at runtime, depending on the context
1145 # module, and can even mutate at runtime, depending on the context
1147 # (Python makes no guarantees on it). In contrast, __builtin__ is
1146 # (Python makes no guarantees on it). In contrast, __builtin__ is
1148 # always a module object, though it must be explicitly imported.
1147 # always a module object, though it must be explicitly imported.
1149
1148
1150 # For more details:
1149 # For more details:
1151 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1150 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1152 ns = dict()
1151 ns = dict()
1153
1152
1154 # make global variables for user access to the histories
1153 # make global variables for user access to the histories
1155 ns['_ih'] = self.history_manager.input_hist_parsed
1154 ns['_ih'] = self.history_manager.input_hist_parsed
1156 ns['_oh'] = self.history_manager.output_hist
1155 ns['_oh'] = self.history_manager.output_hist
1157 ns['_dh'] = self.history_manager.dir_hist
1156 ns['_dh'] = self.history_manager.dir_hist
1158
1157
1159 ns['_sh'] = shadowns
1158 ns['_sh'] = shadowns
1160
1159
1161 # user aliases to input and output histories. These shouldn't show up
1160 # user aliases to input and output histories. These shouldn't show up
1162 # in %who, as they can have very large reprs.
1161 # in %who, as they can have very large reprs.
1163 ns['In'] = self.history_manager.input_hist_parsed
1162 ns['In'] = self.history_manager.input_hist_parsed
1164 ns['Out'] = self.history_manager.output_hist
1163 ns['Out'] = self.history_manager.output_hist
1165
1164
1166 # Store myself as the public api!!!
1165 # Store myself as the public api!!!
1167 ns['get_ipython'] = self.get_ipython
1166 ns['get_ipython'] = self.get_ipython
1168
1167
1169 ns['exit'] = self.exiter
1168 ns['exit'] = self.exiter
1170 ns['quit'] = self.exiter
1169 ns['quit'] = self.exiter
1171
1170
1172 # Sync what we've added so far to user_ns_hidden so these aren't seen
1171 # Sync what we've added so far to user_ns_hidden so these aren't seen
1173 # by %who
1172 # by %who
1174 self.user_ns_hidden.update(ns)
1173 self.user_ns_hidden.update(ns)
1175
1174
1176 # Anything put into ns now would show up in %who. Think twice before
1175 # Anything put into ns now would show up in %who. Think twice before
1177 # putting anything here, as we really want %who to show the user their
1176 # putting anything here, as we really want %who to show the user their
1178 # stuff, not our variables.
1177 # stuff, not our variables.
1179
1178
1180 # Finally, update the real user's namespace
1179 # Finally, update the real user's namespace
1181 self.user_ns.update(ns)
1180 self.user_ns.update(ns)
1182
1181
1183 @property
1182 @property
1184 def all_ns_refs(self):
1183 def all_ns_refs(self):
1185 """Get a list of references to all the namespace dictionaries in which
1184 """Get a list of references to all the namespace dictionaries in which
1186 IPython might store a user-created object.
1185 IPython might store a user-created object.
1187
1186
1188 Note that this does not include the displayhook, which also caches
1187 Note that this does not include the displayhook, which also caches
1189 objects from the output."""
1188 objects from the output."""
1190 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1189 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1191 [m.__dict__ for m in self._main_mod_cache.values()]
1190 [m.__dict__ for m in self._main_mod_cache.values()]
1192
1191
1193 def reset(self, new_session=True):
1192 def reset(self, new_session=True):
1194 """Clear all internal namespaces, and attempt to release references to
1193 """Clear all internal namespaces, and attempt to release references to
1195 user objects.
1194 user objects.
1196
1195
1197 If new_session is True, a new history session will be opened.
1196 If new_session is True, a new history session will be opened.
1198 """
1197 """
1199 # Clear histories
1198 # Clear histories
1200 self.history_manager.reset(new_session)
1199 self.history_manager.reset(new_session)
1201 # Reset counter used to index all histories
1200 # Reset counter used to index all histories
1202 if new_session:
1201 if new_session:
1203 self.execution_count = 1
1202 self.execution_count = 1
1204
1203
1205 # Flush cached output items
1204 # Flush cached output items
1206 if self.displayhook.do_full_cache:
1205 if self.displayhook.do_full_cache:
1207 self.displayhook.flush()
1206 self.displayhook.flush()
1208
1207
1209 # The main execution namespaces must be cleared very carefully,
1208 # The main execution namespaces must be cleared very carefully,
1210 # skipping the deletion of the builtin-related keys, because doing so
1209 # skipping the deletion of the builtin-related keys, because doing so
1211 # would cause errors in many object's __del__ methods.
1210 # would cause errors in many object's __del__ methods.
1212 if self.user_ns is not self.user_global_ns:
1211 if self.user_ns is not self.user_global_ns:
1213 self.user_ns.clear()
1212 self.user_ns.clear()
1214 ns = self.user_global_ns
1213 ns = self.user_global_ns
1215 drop_keys = set(ns.keys())
1214 drop_keys = set(ns.keys())
1216 drop_keys.discard('__builtin__')
1215 drop_keys.discard('__builtin__')
1217 drop_keys.discard('__builtins__')
1216 drop_keys.discard('__builtins__')
1218 drop_keys.discard('__name__')
1217 drop_keys.discard('__name__')
1219 for k in drop_keys:
1218 for k in drop_keys:
1220 del ns[k]
1219 del ns[k]
1221
1220
1222 self.user_ns_hidden.clear()
1221 self.user_ns_hidden.clear()
1223
1222
1224 # Restore the user namespaces to minimal usability
1223 # Restore the user namespaces to minimal usability
1225 self.init_user_ns()
1224 self.init_user_ns()
1226
1225
1227 # Restore the default and user aliases
1226 # Restore the default and user aliases
1228 self.alias_manager.clear_aliases()
1227 self.alias_manager.clear_aliases()
1229 self.alias_manager.init_aliases()
1228 self.alias_manager.init_aliases()
1230
1229
1231 # Flush the private list of module references kept for script
1230 # Flush the private list of module references kept for script
1232 # execution protection
1231 # execution protection
1233 self.clear_main_mod_cache()
1232 self.clear_main_mod_cache()
1234
1233
1235 def del_var(self, varname, by_name=False):
1234 def del_var(self, varname, by_name=False):
1236 """Delete a variable from the various namespaces, so that, as
1235 """Delete a variable from the various namespaces, so that, as
1237 far as possible, we're not keeping any hidden references to it.
1236 far as possible, we're not keeping any hidden references to it.
1238
1237
1239 Parameters
1238 Parameters
1240 ----------
1239 ----------
1241 varname : str
1240 varname : str
1242 The name of the variable to delete.
1241 The name of the variable to delete.
1243 by_name : bool
1242 by_name : bool
1244 If True, delete variables with the given name in each
1243 If True, delete variables with the given name in each
1245 namespace. If False (default), find the variable in the user
1244 namespace. If False (default), find the variable in the user
1246 namespace, and delete references to it.
1245 namespace, and delete references to it.
1247 """
1246 """
1248 if varname in ('__builtin__', '__builtins__'):
1247 if varname in ('__builtin__', '__builtins__'):
1249 raise ValueError("Refusing to delete %s" % varname)
1248 raise ValueError("Refusing to delete %s" % varname)
1250
1249
1251 ns_refs = self.all_ns_refs
1250 ns_refs = self.all_ns_refs
1252
1251
1253 if by_name: # Delete by name
1252 if by_name: # Delete by name
1254 for ns in ns_refs:
1253 for ns in ns_refs:
1255 try:
1254 try:
1256 del ns[varname]
1255 del ns[varname]
1257 except KeyError:
1256 except KeyError:
1258 pass
1257 pass
1259 else: # Delete by object
1258 else: # Delete by object
1260 try:
1259 try:
1261 obj = self.user_ns[varname]
1260 obj = self.user_ns[varname]
1262 except KeyError:
1261 except KeyError:
1263 raise NameError("name '%s' is not defined" % varname)
1262 raise NameError("name '%s' is not defined" % varname)
1264 # Also check in output history
1263 # Also check in output history
1265 ns_refs.append(self.history_manager.output_hist)
1264 ns_refs.append(self.history_manager.output_hist)
1266 for ns in ns_refs:
1265 for ns in ns_refs:
1267 to_delete = [n for n, o in iteritems(ns) if o is obj]
1266 to_delete = [n for n, o in iteritems(ns) if o is obj]
1268 for name in to_delete:
1267 for name in to_delete:
1269 del ns[name]
1268 del ns[name]
1270
1269
1271 # displayhook keeps extra references, but not in a dictionary
1270 # displayhook keeps extra references, but not in a dictionary
1272 for name in ('_', '__', '___'):
1271 for name in ('_', '__', '___'):
1273 if getattr(self.displayhook, name) is obj:
1272 if getattr(self.displayhook, name) is obj:
1274 setattr(self.displayhook, name, None)
1273 setattr(self.displayhook, name, None)
1275
1274
1276 def reset_selective(self, regex=None):
1275 def reset_selective(self, regex=None):
1277 """Clear selective variables from internal namespaces based on a
1276 """Clear selective variables from internal namespaces based on a
1278 specified regular expression.
1277 specified regular expression.
1279
1278
1280 Parameters
1279 Parameters
1281 ----------
1280 ----------
1282 regex : string or compiled pattern, optional
1281 regex : string or compiled pattern, optional
1283 A regular expression pattern that will be used in searching
1282 A regular expression pattern that will be used in searching
1284 variable names in the users namespaces.
1283 variable names in the users namespaces.
1285 """
1284 """
1286 if regex is not None:
1285 if regex is not None:
1287 try:
1286 try:
1288 m = re.compile(regex)
1287 m = re.compile(regex)
1289 except TypeError:
1288 except TypeError:
1290 raise TypeError('regex must be a string or compiled pattern')
1289 raise TypeError('regex must be a string or compiled pattern')
1291 # Search for keys in each namespace that match the given regex
1290 # Search for keys in each namespace that match the given regex
1292 # If a match is found, delete the key/value pair.
1291 # If a match is found, delete the key/value pair.
1293 for ns in self.all_ns_refs:
1292 for ns in self.all_ns_refs:
1294 for var in ns:
1293 for var in ns:
1295 if m.search(var):
1294 if m.search(var):
1296 del ns[var]
1295 del ns[var]
1297
1296
1298 def push(self, variables, interactive=True):
1297 def push(self, variables, interactive=True):
1299 """Inject a group of variables into the IPython user namespace.
1298 """Inject a group of variables into the IPython user namespace.
1300
1299
1301 Parameters
1300 Parameters
1302 ----------
1301 ----------
1303 variables : dict, str or list/tuple of str
1302 variables : dict, str or list/tuple of str
1304 The variables to inject into the user's namespace. If a dict, a
1303 The variables to inject into the user's namespace. If a dict, a
1305 simple update is done. If a str, the string is assumed to have
1304 simple update is done. If a str, the string is assumed to have
1306 variable names separated by spaces. A list/tuple of str can also
1305 variable names separated by spaces. A list/tuple of str can also
1307 be used to give the variable names. If just the variable names are
1306 be used to give the variable names. If just the variable names are
1308 give (list/tuple/str) then the variable values looked up in the
1307 give (list/tuple/str) then the variable values looked up in the
1309 callers frame.
1308 callers frame.
1310 interactive : bool
1309 interactive : bool
1311 If True (default), the variables will be listed with the ``who``
1310 If True (default), the variables will be listed with the ``who``
1312 magic.
1311 magic.
1313 """
1312 """
1314 vdict = None
1313 vdict = None
1315
1314
1316 # We need a dict of name/value pairs to do namespace updates.
1315 # We need a dict of name/value pairs to do namespace updates.
1317 if isinstance(variables, dict):
1316 if isinstance(variables, dict):
1318 vdict = variables
1317 vdict = variables
1319 elif isinstance(variables, string_types+(list, tuple)):
1318 elif isinstance(variables, string_types+(list, tuple)):
1320 if isinstance(variables, string_types):
1319 if isinstance(variables, string_types):
1321 vlist = variables.split()
1320 vlist = variables.split()
1322 else:
1321 else:
1323 vlist = variables
1322 vlist = variables
1324 vdict = {}
1323 vdict = {}
1325 cf = sys._getframe(1)
1324 cf = sys._getframe(1)
1326 for name in vlist:
1325 for name in vlist:
1327 try:
1326 try:
1328 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1327 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1329 except:
1328 except:
1330 print('Could not get variable %s from %s' %
1329 print('Could not get variable %s from %s' %
1331 (name,cf.f_code.co_name))
1330 (name,cf.f_code.co_name))
1332 else:
1331 else:
1333 raise ValueError('variables must be a dict/str/list/tuple')
1332 raise ValueError('variables must be a dict/str/list/tuple')
1334
1333
1335 # Propagate variables to user namespace
1334 # Propagate variables to user namespace
1336 self.user_ns.update(vdict)
1335 self.user_ns.update(vdict)
1337
1336
1338 # And configure interactive visibility
1337 # And configure interactive visibility
1339 user_ns_hidden = self.user_ns_hidden
1338 user_ns_hidden = self.user_ns_hidden
1340 if interactive:
1339 if interactive:
1341 for name in vdict:
1340 for name in vdict:
1342 user_ns_hidden.pop(name, None)
1341 user_ns_hidden.pop(name, None)
1343 else:
1342 else:
1344 user_ns_hidden.update(vdict)
1343 user_ns_hidden.update(vdict)
1345
1344
1346 def drop_by_id(self, variables):
1345 def drop_by_id(self, variables):
1347 """Remove a dict of variables from the user namespace, if they are the
1346 """Remove a dict of variables from the user namespace, if they are the
1348 same as the values in the dictionary.
1347 same as the values in the dictionary.
1349
1348
1350 This is intended for use by extensions: variables that they've added can
1349 This is intended for use by extensions: variables that they've added can
1351 be taken back out if they are unloaded, without removing any that the
1350 be taken back out if they are unloaded, without removing any that the
1352 user has overwritten.
1351 user has overwritten.
1353
1352
1354 Parameters
1353 Parameters
1355 ----------
1354 ----------
1356 variables : dict
1355 variables : dict
1357 A dictionary mapping object names (as strings) to the objects.
1356 A dictionary mapping object names (as strings) to the objects.
1358 """
1357 """
1359 for name, obj in iteritems(variables):
1358 for name, obj in iteritems(variables):
1360 if name in self.user_ns and self.user_ns[name] is obj:
1359 if name in self.user_ns and self.user_ns[name] is obj:
1361 del self.user_ns[name]
1360 del self.user_ns[name]
1362 self.user_ns_hidden.pop(name, None)
1361 self.user_ns_hidden.pop(name, None)
1363
1362
1364 #-------------------------------------------------------------------------
1363 #-------------------------------------------------------------------------
1365 # Things related to object introspection
1364 # Things related to object introspection
1366 #-------------------------------------------------------------------------
1365 #-------------------------------------------------------------------------
1367
1366
1368 def _ofind(self, oname, namespaces=None):
1367 def _ofind(self, oname, namespaces=None):
1369 """Find an object in the available namespaces.
1368 """Find an object in the available namespaces.
1370
1369
1371 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1370 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1372
1371
1373 Has special code to detect magic functions.
1372 Has special code to detect magic functions.
1374 """
1373 """
1375 oname = oname.strip()
1374 oname = oname.strip()
1376 #print '1- oname: <%r>' % oname # dbg
1375 #print '1- oname: <%r>' % oname # dbg
1377 if not oname.startswith(ESC_MAGIC) and \
1376 if not oname.startswith(ESC_MAGIC) and \
1378 not oname.startswith(ESC_MAGIC2) and \
1377 not oname.startswith(ESC_MAGIC2) and \
1379 not py3compat.isidentifier(oname, dotted=True):
1378 not py3compat.isidentifier(oname, dotted=True):
1380 return dict(found=False)
1379 return dict(found=False)
1381
1380
1382 alias_ns = None
1381 alias_ns = None
1383 if namespaces is None:
1382 if namespaces is None:
1384 # Namespaces to search in:
1383 # Namespaces to search in:
1385 # Put them in a list. The order is important so that we
1384 # Put them in a list. The order is important so that we
1386 # find things in the same order that Python finds them.
1385 # find things in the same order that Python finds them.
1387 namespaces = [ ('Interactive', self.user_ns),
1386 namespaces = [ ('Interactive', self.user_ns),
1388 ('Interactive (global)', self.user_global_ns),
1387 ('Interactive (global)', self.user_global_ns),
1389 ('Python builtin', builtin_mod.__dict__),
1388 ('Python builtin', builtin_mod.__dict__),
1390 ]
1389 ]
1391
1390
1392 # initialize results to 'null'
1391 # initialize results to 'null'
1393 found = False; obj = None; ospace = None; ds = None;
1392 found = False; obj = None; ospace = None; ds = None;
1394 ismagic = False; isalias = False; parent = None
1393 ismagic = False; isalias = False; parent = None
1395
1394
1396 # We need to special-case 'print', which as of python2.6 registers as a
1395 # We need to special-case 'print', which as of python2.6 registers as a
1397 # function but should only be treated as one if print_function was
1396 # function but should only be treated as one if print_function was
1398 # loaded with a future import. In this case, just bail.
1397 # loaded with a future import. In this case, just bail.
1399 if (oname == 'print' and not py3compat.PY3 and not \
1398 if (oname == 'print' and not py3compat.PY3 and not \
1400 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1399 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1401 return {'found':found, 'obj':obj, 'namespace':ospace,
1400 return {'found':found, 'obj':obj, 'namespace':ospace,
1402 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1401 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1403
1402
1404 # Look for the given name by splitting it in parts. If the head is
1403 # Look for the given name by splitting it in parts. If the head is
1405 # found, then we look for all the remaining parts as members, and only
1404 # found, then we look for all the remaining parts as members, and only
1406 # declare success if we can find them all.
1405 # declare success if we can find them all.
1407 oname_parts = oname.split('.')
1406 oname_parts = oname.split('.')
1408 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1407 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1409 for nsname,ns in namespaces:
1408 for nsname,ns in namespaces:
1410 try:
1409 try:
1411 obj = ns[oname_head]
1410 obj = ns[oname_head]
1412 except KeyError:
1411 except KeyError:
1413 continue
1412 continue
1414 else:
1413 else:
1415 #print 'oname_rest:', oname_rest # dbg
1414 #print 'oname_rest:', oname_rest # dbg
1416 for part in oname_rest:
1415 for part in oname_rest:
1417 try:
1416 try:
1418 parent = obj
1417 parent = obj
1419 obj = getattr(obj,part)
1418 obj = getattr(obj,part)
1420 except:
1419 except:
1421 # Blanket except b/c some badly implemented objects
1420 # Blanket except b/c some badly implemented objects
1422 # allow __getattr__ to raise exceptions other than
1421 # allow __getattr__ to raise exceptions other than
1423 # AttributeError, which then crashes IPython.
1422 # AttributeError, which then crashes IPython.
1424 break
1423 break
1425 else:
1424 else:
1426 # If we finish the for loop (no break), we got all members
1425 # If we finish the for loop (no break), we got all members
1427 found = True
1426 found = True
1428 ospace = nsname
1427 ospace = nsname
1429 break # namespace loop
1428 break # namespace loop
1430
1429
1431 # Try to see if it's magic
1430 # Try to see if it's magic
1432 if not found:
1431 if not found:
1433 obj = None
1432 obj = None
1434 if oname.startswith(ESC_MAGIC2):
1433 if oname.startswith(ESC_MAGIC2):
1435 oname = oname.lstrip(ESC_MAGIC2)
1434 oname = oname.lstrip(ESC_MAGIC2)
1436 obj = self.find_cell_magic(oname)
1435 obj = self.find_cell_magic(oname)
1437 elif oname.startswith(ESC_MAGIC):
1436 elif oname.startswith(ESC_MAGIC):
1438 oname = oname.lstrip(ESC_MAGIC)
1437 oname = oname.lstrip(ESC_MAGIC)
1439 obj = self.find_line_magic(oname)
1438 obj = self.find_line_magic(oname)
1440 else:
1439 else:
1441 # search without prefix, so run? will find %run?
1440 # search without prefix, so run? will find %run?
1442 obj = self.find_line_magic(oname)
1441 obj = self.find_line_magic(oname)
1443 if obj is None:
1442 if obj is None:
1444 obj = self.find_cell_magic(oname)
1443 obj = self.find_cell_magic(oname)
1445 if obj is not None:
1444 if obj is not None:
1446 found = True
1445 found = True
1447 ospace = 'IPython internal'
1446 ospace = 'IPython internal'
1448 ismagic = True
1447 ismagic = True
1449
1448
1450 # Last try: special-case some literals like '', [], {}, etc:
1449 # Last try: special-case some literals like '', [], {}, etc:
1451 if not found and oname_head in ["''",'""','[]','{}','()']:
1450 if not found and oname_head in ["''",'""','[]','{}','()']:
1452 obj = eval(oname_head)
1451 obj = eval(oname_head)
1453 found = True
1452 found = True
1454 ospace = 'Interactive'
1453 ospace = 'Interactive'
1455
1454
1456 return {'found':found, 'obj':obj, 'namespace':ospace,
1455 return {'found':found, 'obj':obj, 'namespace':ospace,
1457 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1456 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1458
1457
1459 def _ofind_property(self, oname, info):
1458 def _ofind_property(self, oname, info):
1460 """Second part of object finding, to look for property details."""
1459 """Second part of object finding, to look for property details."""
1461 if info.found:
1460 if info.found:
1462 # Get the docstring of the class property if it exists.
1461 # Get the docstring of the class property if it exists.
1463 path = oname.split('.')
1462 path = oname.split('.')
1464 root = '.'.join(path[:-1])
1463 root = '.'.join(path[:-1])
1465 if info.parent is not None:
1464 if info.parent is not None:
1466 try:
1465 try:
1467 target = getattr(info.parent, '__class__')
1466 target = getattr(info.parent, '__class__')
1468 # The object belongs to a class instance.
1467 # The object belongs to a class instance.
1469 try:
1468 try:
1470 target = getattr(target, path[-1])
1469 target = getattr(target, path[-1])
1471 # The class defines the object.
1470 # The class defines the object.
1472 if isinstance(target, property):
1471 if isinstance(target, property):
1473 oname = root + '.__class__.' + path[-1]
1472 oname = root + '.__class__.' + path[-1]
1474 info = Struct(self._ofind(oname))
1473 info = Struct(self._ofind(oname))
1475 except AttributeError: pass
1474 except AttributeError: pass
1476 except AttributeError: pass
1475 except AttributeError: pass
1477
1476
1478 # We return either the new info or the unmodified input if the object
1477 # We return either the new info or the unmodified input if the object
1479 # hadn't been found
1478 # hadn't been found
1480 return info
1479 return info
1481
1480
1482 def _object_find(self, oname, namespaces=None):
1481 def _object_find(self, oname, namespaces=None):
1483 """Find an object and return a struct with info about it."""
1482 """Find an object and return a struct with info about it."""
1484 inf = Struct(self._ofind(oname, namespaces))
1483 inf = Struct(self._ofind(oname, namespaces))
1485 return Struct(self._ofind_property(oname, inf))
1484 return Struct(self._ofind_property(oname, inf))
1486
1485
1487 def _inspect(self, meth, oname, namespaces=None, **kw):
1486 def _inspect(self, meth, oname, namespaces=None, **kw):
1488 """Generic interface to the inspector system.
1487 """Generic interface to the inspector system.
1489
1488
1490 This function is meant to be called by pdef, pdoc & friends."""
1489 This function is meant to be called by pdef, pdoc & friends."""
1491 info = self._object_find(oname, namespaces)
1490 info = self._object_find(oname, namespaces)
1492 if info.found:
1491 if info.found:
1493 pmethod = getattr(self.inspector, meth)
1492 pmethod = getattr(self.inspector, meth)
1494 formatter = format_screen if info.ismagic else None
1493 formatter = format_screen if info.ismagic else None
1495 if meth == 'pdoc':
1494 if meth == 'pdoc':
1496 pmethod(info.obj, oname, formatter)
1495 pmethod(info.obj, oname, formatter)
1497 elif meth == 'pinfo':
1496 elif meth == 'pinfo':
1498 pmethod(info.obj, oname, formatter, info, **kw)
1497 pmethod(info.obj, oname, formatter, info, **kw)
1499 else:
1498 else:
1500 pmethod(info.obj, oname)
1499 pmethod(info.obj, oname)
1501 else:
1500 else:
1502 print('Object `%s` not found.' % oname)
1501 print('Object `%s` not found.' % oname)
1503 return 'not found' # so callers can take other action
1502 return 'not found' # so callers can take other action
1504
1503
1505 def object_inspect(self, oname, detail_level=0):
1504 def object_inspect(self, oname, detail_level=0):
1506 with self.builtin_trap:
1505 with self.builtin_trap:
1507 info = self._object_find(oname)
1506 info = self._object_find(oname)
1508 if info.found:
1507 if info.found:
1509 return self.inspector.info(info.obj, oname, info=info,
1508 return self.inspector.info(info.obj, oname, info=info,
1510 detail_level=detail_level
1509 detail_level=detail_level
1511 )
1510 )
1512 else:
1511 else:
1513 return oinspect.object_info(name=oname, found=False)
1512 return oinspect.object_info(name=oname, found=False)
1514
1513
1515 #-------------------------------------------------------------------------
1514 #-------------------------------------------------------------------------
1516 # Things related to history management
1515 # Things related to history management
1517 #-------------------------------------------------------------------------
1516 #-------------------------------------------------------------------------
1518
1517
1519 def init_history(self):
1518 def init_history(self):
1520 """Sets up the command history, and starts regular autosaves."""
1519 """Sets up the command history, and starts regular autosaves."""
1521 self.history_manager = HistoryManager(shell=self, parent=self)
1520 self.history_manager = HistoryManager(shell=self, parent=self)
1522 self.configurables.append(self.history_manager)
1521 self.configurables.append(self.history_manager)
1523
1522
1524 #-------------------------------------------------------------------------
1523 #-------------------------------------------------------------------------
1525 # Things related to exception handling and tracebacks (not debugging)
1524 # Things related to exception handling and tracebacks (not debugging)
1526 #-------------------------------------------------------------------------
1525 #-------------------------------------------------------------------------
1527
1526
1528 def init_traceback_handlers(self, custom_exceptions):
1527 def init_traceback_handlers(self, custom_exceptions):
1529 # Syntax error handler.
1528 # Syntax error handler.
1530 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1529 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1531
1530
1532 # The interactive one is initialized with an offset, meaning we always
1531 # The interactive one is initialized with an offset, meaning we always
1533 # want to remove the topmost item in the traceback, which is our own
1532 # want to remove the topmost item in the traceback, which is our own
1534 # internal code. Valid modes: ['Plain','Context','Verbose']
1533 # internal code. Valid modes: ['Plain','Context','Verbose']
1535 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1534 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1536 color_scheme='NoColor',
1535 color_scheme='NoColor',
1537 tb_offset = 1,
1536 tb_offset = 1,
1538 check_cache=check_linecache_ipython)
1537 check_cache=check_linecache_ipython)
1539
1538
1540 # The instance will store a pointer to the system-wide exception hook,
1539 # The instance will store a pointer to the system-wide exception hook,
1541 # so that runtime code (such as magics) can access it. This is because
1540 # so that runtime code (such as magics) can access it. This is because
1542 # during the read-eval loop, it may get temporarily overwritten.
1541 # during the read-eval loop, it may get temporarily overwritten.
1543 self.sys_excepthook = sys.excepthook
1542 self.sys_excepthook = sys.excepthook
1544
1543
1545 # and add any custom exception handlers the user may have specified
1544 # and add any custom exception handlers the user may have specified
1546 self.set_custom_exc(*custom_exceptions)
1545 self.set_custom_exc(*custom_exceptions)
1547
1546
1548 # Set the exception mode
1547 # Set the exception mode
1549 self.InteractiveTB.set_mode(mode=self.xmode)
1548 self.InteractiveTB.set_mode(mode=self.xmode)
1550
1549
1551 def set_custom_exc(self, exc_tuple, handler):
1550 def set_custom_exc(self, exc_tuple, handler):
1552 """set_custom_exc(exc_tuple,handler)
1551 """set_custom_exc(exc_tuple,handler)
1553
1552
1554 Set a custom exception handler, which will be called if any of the
1553 Set a custom exception handler, which will be called if any of the
1555 exceptions in exc_tuple occur in the mainloop (specifically, in the
1554 exceptions in exc_tuple occur in the mainloop (specifically, in the
1556 run_code() method).
1555 run_code() method).
1557
1556
1558 Parameters
1557 Parameters
1559 ----------
1558 ----------
1560
1559
1561 exc_tuple : tuple of exception classes
1560 exc_tuple : tuple of exception classes
1562 A *tuple* of exception classes, for which to call the defined
1561 A *tuple* of exception classes, for which to call the defined
1563 handler. It is very important that you use a tuple, and NOT A
1562 handler. It is very important that you use a tuple, and NOT A
1564 LIST here, because of the way Python's except statement works. If
1563 LIST here, because of the way Python's except statement works. If
1565 you only want to trap a single exception, use a singleton tuple::
1564 you only want to trap a single exception, use a singleton tuple::
1566
1565
1567 exc_tuple == (MyCustomException,)
1566 exc_tuple == (MyCustomException,)
1568
1567
1569 handler : callable
1568 handler : callable
1570 handler must have the following signature::
1569 handler must have the following signature::
1571
1570
1572 def my_handler(self, etype, value, tb, tb_offset=None):
1571 def my_handler(self, etype, value, tb, tb_offset=None):
1573 ...
1572 ...
1574 return structured_traceback
1573 return structured_traceback
1575
1574
1576 Your handler must return a structured traceback (a list of strings),
1575 Your handler must return a structured traceback (a list of strings),
1577 or None.
1576 or None.
1578
1577
1579 This will be made into an instance method (via types.MethodType)
1578 This will be made into an instance method (via types.MethodType)
1580 of IPython itself, and it will be called if any of the exceptions
1579 of IPython itself, and it will be called if any of the exceptions
1581 listed in the exc_tuple are caught. If the handler is None, an
1580 listed in the exc_tuple are caught. If the handler is None, an
1582 internal basic one is used, which just prints basic info.
1581 internal basic one is used, which just prints basic info.
1583
1582
1584 To protect IPython from crashes, if your handler ever raises an
1583 To protect IPython from crashes, if your handler ever raises an
1585 exception or returns an invalid result, it will be immediately
1584 exception or returns an invalid result, it will be immediately
1586 disabled.
1585 disabled.
1587
1586
1588 WARNING: by putting in your own exception handler into IPython's main
1587 WARNING: by putting in your own exception handler into IPython's main
1589 execution loop, you run a very good chance of nasty crashes. This
1588 execution loop, you run a very good chance of nasty crashes. This
1590 facility should only be used if you really know what you are doing."""
1589 facility should only be used if you really know what you are doing."""
1591
1590
1592 assert type(exc_tuple)==type(()) , \
1591 assert type(exc_tuple)==type(()) , \
1593 "The custom exceptions must be given AS A TUPLE."
1592 "The custom exceptions must be given AS A TUPLE."
1594
1593
1595 def dummy_handler(self,etype,value,tb,tb_offset=None):
1594 def dummy_handler(self,etype,value,tb,tb_offset=None):
1596 print('*** Simple custom exception handler ***')
1595 print('*** Simple custom exception handler ***')
1597 print('Exception type :',etype)
1596 print('Exception type :',etype)
1598 print('Exception value:',value)
1597 print('Exception value:',value)
1599 print('Traceback :',tb)
1598 print('Traceback :',tb)
1600 #print 'Source code :','\n'.join(self.buffer)
1599 #print 'Source code :','\n'.join(self.buffer)
1601
1600
1602 def validate_stb(stb):
1601 def validate_stb(stb):
1603 """validate structured traceback return type
1602 """validate structured traceback return type
1604
1603
1605 return type of CustomTB *should* be a list of strings, but allow
1604 return type of CustomTB *should* be a list of strings, but allow
1606 single strings or None, which are harmless.
1605 single strings or None, which are harmless.
1607
1606
1608 This function will *always* return a list of strings,
1607 This function will *always* return a list of strings,
1609 and will raise a TypeError if stb is inappropriate.
1608 and will raise a TypeError if stb is inappropriate.
1610 """
1609 """
1611 msg = "CustomTB must return list of strings, not %r" % stb
1610 msg = "CustomTB must return list of strings, not %r" % stb
1612 if stb is None:
1611 if stb is None:
1613 return []
1612 return []
1614 elif isinstance(stb, string_types):
1613 elif isinstance(stb, string_types):
1615 return [stb]
1614 return [stb]
1616 elif not isinstance(stb, list):
1615 elif not isinstance(stb, list):
1617 raise TypeError(msg)
1616 raise TypeError(msg)
1618 # it's a list
1617 # it's a list
1619 for line in stb:
1618 for line in stb:
1620 # check every element
1619 # check every element
1621 if not isinstance(line, string_types):
1620 if not isinstance(line, string_types):
1622 raise TypeError(msg)
1621 raise TypeError(msg)
1623 return stb
1622 return stb
1624
1623
1625 if handler is None:
1624 if handler is None:
1626 wrapped = dummy_handler
1625 wrapped = dummy_handler
1627 else:
1626 else:
1628 def wrapped(self,etype,value,tb,tb_offset=None):
1627 def wrapped(self,etype,value,tb,tb_offset=None):
1629 """wrap CustomTB handler, to protect IPython from user code
1628 """wrap CustomTB handler, to protect IPython from user code
1630
1629
1631 This makes it harder (but not impossible) for custom exception
1630 This makes it harder (but not impossible) for custom exception
1632 handlers to crash IPython.
1631 handlers to crash IPython.
1633 """
1632 """
1634 try:
1633 try:
1635 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1634 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1636 return validate_stb(stb)
1635 return validate_stb(stb)
1637 except:
1636 except:
1638 # clear custom handler immediately
1637 # clear custom handler immediately
1639 self.set_custom_exc((), None)
1638 self.set_custom_exc((), None)
1640 print("Custom TB Handler failed, unregistering", file=io.stderr)
1639 print("Custom TB Handler failed, unregistering", file=io.stderr)
1641 # show the exception in handler first
1640 # show the exception in handler first
1642 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1641 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1643 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1642 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1644 print("The original exception:", file=io.stdout)
1643 print("The original exception:", file=io.stdout)
1645 stb = self.InteractiveTB.structured_traceback(
1644 stb = self.InteractiveTB.structured_traceback(
1646 (etype,value,tb), tb_offset=tb_offset
1645 (etype,value,tb), tb_offset=tb_offset
1647 )
1646 )
1648 return stb
1647 return stb
1649
1648
1650 self.CustomTB = types.MethodType(wrapped,self)
1649 self.CustomTB = types.MethodType(wrapped,self)
1651 self.custom_exceptions = exc_tuple
1650 self.custom_exceptions = exc_tuple
1652
1651
1653 def excepthook(self, etype, value, tb):
1652 def excepthook(self, etype, value, tb):
1654 """One more defense for GUI apps that call sys.excepthook.
1653 """One more defense for GUI apps that call sys.excepthook.
1655
1654
1656 GUI frameworks like wxPython trap exceptions and call
1655 GUI frameworks like wxPython trap exceptions and call
1657 sys.excepthook themselves. I guess this is a feature that
1656 sys.excepthook themselves. I guess this is a feature that
1658 enables them to keep running after exceptions that would
1657 enables them to keep running after exceptions that would
1659 otherwise kill their mainloop. This is a bother for IPython
1658 otherwise kill their mainloop. This is a bother for IPython
1660 which excepts to catch all of the program exceptions with a try:
1659 which excepts to catch all of the program exceptions with a try:
1661 except: statement.
1660 except: statement.
1662
1661
1663 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1662 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1664 any app directly invokes sys.excepthook, it will look to the user like
1663 any app directly invokes sys.excepthook, it will look to the user like
1665 IPython crashed. In order to work around this, we can disable the
1664 IPython crashed. In order to work around this, we can disable the
1666 CrashHandler and replace it with this excepthook instead, which prints a
1665 CrashHandler and replace it with this excepthook instead, which prints a
1667 regular traceback using our InteractiveTB. In this fashion, apps which
1666 regular traceback using our InteractiveTB. In this fashion, apps which
1668 call sys.excepthook will generate a regular-looking exception from
1667 call sys.excepthook will generate a regular-looking exception from
1669 IPython, and the CrashHandler will only be triggered by real IPython
1668 IPython, and the CrashHandler will only be triggered by real IPython
1670 crashes.
1669 crashes.
1671
1670
1672 This hook should be used sparingly, only in places which are not likely
1671 This hook should be used sparingly, only in places which are not likely
1673 to be true IPython errors.
1672 to be true IPython errors.
1674 """
1673 """
1675 self.showtraceback((etype,value,tb),tb_offset=0)
1674 self.showtraceback((etype,value,tb),tb_offset=0)
1676
1675
1677 def _get_exc_info(self, exc_tuple=None):
1676 def _get_exc_info(self, exc_tuple=None):
1678 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1677 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1679
1678
1680 Ensures sys.last_type,value,traceback hold the exc_info we found,
1679 Ensures sys.last_type,value,traceback hold the exc_info we found,
1681 from whichever source.
1680 from whichever source.
1682
1681
1683 raises ValueError if none of these contain any information
1682 raises ValueError if none of these contain any information
1684 """
1683 """
1685 if exc_tuple is None:
1684 if exc_tuple is None:
1686 etype, value, tb = sys.exc_info()
1685 etype, value, tb = sys.exc_info()
1687 else:
1686 else:
1688 etype, value, tb = exc_tuple
1687 etype, value, tb = exc_tuple
1689
1688
1690 if etype is None:
1689 if etype is None:
1691 if hasattr(sys, 'last_type'):
1690 if hasattr(sys, 'last_type'):
1692 etype, value, tb = sys.last_type, sys.last_value, \
1691 etype, value, tb = sys.last_type, sys.last_value, \
1693 sys.last_traceback
1692 sys.last_traceback
1694
1693
1695 if etype is None:
1694 if etype is None:
1696 raise ValueError("No exception to find")
1695 raise ValueError("No exception to find")
1697
1696
1698 # Now store the exception info in sys.last_type etc.
1697 # Now store the exception info in sys.last_type etc.
1699 # WARNING: these variables are somewhat deprecated and not
1698 # WARNING: these variables are somewhat deprecated and not
1700 # necessarily safe to use in a threaded environment, but tools
1699 # necessarily safe to use in a threaded environment, but tools
1701 # like pdb depend on their existence, so let's set them. If we
1700 # like pdb depend on their existence, so let's set them. If we
1702 # find problems in the field, we'll need to revisit their use.
1701 # find problems in the field, we'll need to revisit their use.
1703 sys.last_type = etype
1702 sys.last_type = etype
1704 sys.last_value = value
1703 sys.last_value = value
1705 sys.last_traceback = tb
1704 sys.last_traceback = tb
1706
1705
1707 return etype, value, tb
1706 return etype, value, tb
1708
1707
1709 def show_usage_error(self, exc):
1708 def show_usage_error(self, exc):
1710 """Show a short message for UsageErrors
1709 """Show a short message for UsageErrors
1711
1710
1712 These are special exceptions that shouldn't show a traceback.
1711 These are special exceptions that shouldn't show a traceback.
1713 """
1712 """
1714 self.write_err("UsageError: %s" % exc)
1713 self.write_err("UsageError: %s" % exc)
1715
1714
1716 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1715 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1717 exception_only=False):
1716 exception_only=False):
1718 """Display the exception that just occurred.
1717 """Display the exception that just occurred.
1719
1718
1720 If nothing is known about the exception, this is the method which
1719 If nothing is known about the exception, this is the method which
1721 should be used throughout the code for presenting user tracebacks,
1720 should be used throughout the code for presenting user tracebacks,
1722 rather than directly invoking the InteractiveTB object.
1721 rather than directly invoking the InteractiveTB object.
1723
1722
1724 A specific showsyntaxerror() also exists, but this method can take
1723 A specific showsyntaxerror() also exists, but this method can take
1725 care of calling it if needed, so unless you are explicitly catching a
1724 care of calling it if needed, so unless you are explicitly catching a
1726 SyntaxError exception, don't try to analyze the stack manually and
1725 SyntaxError exception, don't try to analyze the stack manually and
1727 simply call this method."""
1726 simply call this method."""
1728
1727
1729 try:
1728 try:
1730 try:
1729 try:
1731 etype, value, tb = self._get_exc_info(exc_tuple)
1730 etype, value, tb = self._get_exc_info(exc_tuple)
1732 except ValueError:
1731 except ValueError:
1733 self.write_err('No traceback available to show.\n')
1732 self.write_err('No traceback available to show.\n')
1734 return
1733 return
1735
1734
1736 if issubclass(etype, SyntaxError):
1735 if issubclass(etype, SyntaxError):
1737 # Though this won't be called by syntax errors in the input
1736 # Though this won't be called by syntax errors in the input
1738 # line, there may be SyntaxError cases with imported code.
1737 # line, there may be SyntaxError cases with imported code.
1739 self.showsyntaxerror(filename)
1738 self.showsyntaxerror(filename)
1740 elif etype is UsageError:
1739 elif etype is UsageError:
1741 self.show_usage_error(value)
1740 self.show_usage_error(value)
1742 else:
1741 else:
1743 if exception_only:
1742 if exception_only:
1744 stb = ['An exception has occurred, use %tb to see '
1743 stb = ['An exception has occurred, use %tb to see '
1745 'the full traceback.\n']
1744 'the full traceback.\n']
1746 stb.extend(self.InteractiveTB.get_exception_only(etype,
1745 stb.extend(self.InteractiveTB.get_exception_only(etype,
1747 value))
1746 value))
1748 else:
1747 else:
1749 try:
1748 try:
1750 # Exception classes can customise their traceback - we
1749 # Exception classes can customise their traceback - we
1751 # use this in IPython.parallel for exceptions occurring
1750 # use this in IPython.parallel for exceptions occurring
1752 # in the engines. This should return a list of strings.
1751 # in the engines. This should return a list of strings.
1753 stb = value._render_traceback_()
1752 stb = value._render_traceback_()
1754 except Exception:
1753 except Exception:
1755 stb = self.InteractiveTB.structured_traceback(etype,
1754 stb = self.InteractiveTB.structured_traceback(etype,
1756 value, tb, tb_offset=tb_offset)
1755 value, tb, tb_offset=tb_offset)
1757
1756
1758 self._showtraceback(etype, value, stb)
1757 self._showtraceback(etype, value, stb)
1759 if self.call_pdb:
1758 if self.call_pdb:
1760 # drop into debugger
1759 # drop into debugger
1761 self.debugger(force=True)
1760 self.debugger(force=True)
1762 return
1761 return
1763
1762
1764 # Actually show the traceback
1763 # Actually show the traceback
1765 self._showtraceback(etype, value, stb)
1764 self._showtraceback(etype, value, stb)
1766
1765
1767 except KeyboardInterrupt:
1766 except KeyboardInterrupt:
1768 self.write_err("\nKeyboardInterrupt\n")
1767 self.write_err("\nKeyboardInterrupt\n")
1769
1768
1770 def _showtraceback(self, etype, evalue, stb):
1769 def _showtraceback(self, etype, evalue, stb):
1771 """Actually show a traceback.
1770 """Actually show a traceback.
1772
1771
1773 Subclasses may override this method to put the traceback on a different
1772 Subclasses may override this method to put the traceback on a different
1774 place, like a side channel.
1773 place, like a side channel.
1775 """
1774 """
1776 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1775 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1777
1776
1778 def showsyntaxerror(self, filename=None):
1777 def showsyntaxerror(self, filename=None):
1779 """Display the syntax error that just occurred.
1778 """Display the syntax error that just occurred.
1780
1779
1781 This doesn't display a stack trace because there isn't one.
1780 This doesn't display a stack trace because there isn't one.
1782
1781
1783 If a filename is given, it is stuffed in the exception instead
1782 If a filename is given, it is stuffed in the exception instead
1784 of what was there before (because Python's parser always uses
1783 of what was there before (because Python's parser always uses
1785 "<string>" when reading from a string).
1784 "<string>" when reading from a string).
1786 """
1785 """
1787 etype, value, last_traceback = self._get_exc_info()
1786 etype, value, last_traceback = self._get_exc_info()
1788
1787
1789 if filename and issubclass(etype, SyntaxError):
1788 if filename and issubclass(etype, SyntaxError):
1790 try:
1789 try:
1791 value.filename = filename
1790 value.filename = filename
1792 except:
1791 except:
1793 # Not the format we expect; leave it alone
1792 # Not the format we expect; leave it alone
1794 pass
1793 pass
1795
1794
1796 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1795 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1797 self._showtraceback(etype, value, stb)
1796 self._showtraceback(etype, value, stb)
1798
1797
1799 # This is overridden in TerminalInteractiveShell to show a message about
1798 # This is overridden in TerminalInteractiveShell to show a message about
1800 # the %paste magic.
1799 # the %paste magic.
1801 def showindentationerror(self):
1800 def showindentationerror(self):
1802 """Called by run_cell when there's an IndentationError in code entered
1801 """Called by run_cell when there's an IndentationError in code entered
1803 at the prompt.
1802 at the prompt.
1804
1803
1805 This is overridden in TerminalInteractiveShell to show a message about
1804 This is overridden in TerminalInteractiveShell to show a message about
1806 the %paste magic."""
1805 the %paste magic."""
1807 self.showsyntaxerror()
1806 self.showsyntaxerror()
1808
1807
1809 #-------------------------------------------------------------------------
1808 #-------------------------------------------------------------------------
1810 # Things related to readline
1809 # Things related to readline
1811 #-------------------------------------------------------------------------
1810 #-------------------------------------------------------------------------
1812
1811
1813 def init_readline(self):
1812 def init_readline(self):
1814 """Command history completion/saving/reloading."""
1813 """Command history completion/saving/reloading."""
1815
1814
1816 if self.readline_use:
1815 if self.readline_use:
1817 import IPython.utils.rlineimpl as readline
1816 import IPython.utils.rlineimpl as readline
1818
1817
1819 self.rl_next_input = None
1818 self.rl_next_input = None
1820 self.rl_do_indent = False
1819 self.rl_do_indent = False
1821
1820
1822 if not self.readline_use or not readline.have_readline:
1821 if not self.readline_use or not readline.have_readline:
1823 self.has_readline = False
1822 self.has_readline = False
1824 self.readline = None
1823 self.readline = None
1825 # Set a number of methods that depend on readline to be no-op
1824 # Set a number of methods that depend on readline to be no-op
1826 self.readline_no_record = no_op_context
1825 self.readline_no_record = no_op_context
1827 self.set_readline_completer = no_op
1826 self.set_readline_completer = no_op
1828 self.set_custom_completer = no_op
1827 self.set_custom_completer = no_op
1829 if self.readline_use:
1828 if self.readline_use:
1830 warn('Readline services not available or not loaded.')
1829 warn('Readline services not available or not loaded.')
1831 else:
1830 else:
1832 self.has_readline = True
1831 self.has_readline = True
1833 self.readline = readline
1832 self.readline = readline
1834 sys.modules['readline'] = readline
1833 sys.modules['readline'] = readline
1835
1834
1836 # Platform-specific configuration
1835 # Platform-specific configuration
1837 if os.name == 'nt':
1836 if os.name == 'nt':
1838 # FIXME - check with Frederick to see if we can harmonize
1837 # FIXME - check with Frederick to see if we can harmonize
1839 # naming conventions with pyreadline to avoid this
1838 # naming conventions with pyreadline to avoid this
1840 # platform-dependent check
1839 # platform-dependent check
1841 self.readline_startup_hook = readline.set_pre_input_hook
1840 self.readline_startup_hook = readline.set_pre_input_hook
1842 else:
1841 else:
1843 self.readline_startup_hook = readline.set_startup_hook
1842 self.readline_startup_hook = readline.set_startup_hook
1844
1843
1845 # Load user's initrc file (readline config)
1844 # Load user's initrc file (readline config)
1846 # Or if libedit is used, load editrc.
1845 # Or if libedit is used, load editrc.
1847 inputrc_name = os.environ.get('INPUTRC')
1846 inputrc_name = os.environ.get('INPUTRC')
1848 if inputrc_name is None:
1847 if inputrc_name is None:
1849 inputrc_name = '.inputrc'
1848 inputrc_name = '.inputrc'
1850 if readline.uses_libedit:
1849 if readline.uses_libedit:
1851 inputrc_name = '.editrc'
1850 inputrc_name = '.editrc'
1852 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1851 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1853 if os.path.isfile(inputrc_name):
1852 if os.path.isfile(inputrc_name):
1854 try:
1853 try:
1855 readline.read_init_file(inputrc_name)
1854 readline.read_init_file(inputrc_name)
1856 except:
1855 except:
1857 warn('Problems reading readline initialization file <%s>'
1856 warn('Problems reading readline initialization file <%s>'
1858 % inputrc_name)
1857 % inputrc_name)
1859
1858
1860 # Configure readline according to user's prefs
1859 # Configure readline according to user's prefs
1861 # This is only done if GNU readline is being used. If libedit
1860 # This is only done if GNU readline is being used. If libedit
1862 # is being used (as on Leopard) the readline config is
1861 # is being used (as on Leopard) the readline config is
1863 # not run as the syntax for libedit is different.
1862 # not run as the syntax for libedit is different.
1864 if not readline.uses_libedit:
1863 if not readline.uses_libedit:
1865 for rlcommand in self.readline_parse_and_bind:
1864 for rlcommand in self.readline_parse_and_bind:
1866 #print "loading rl:",rlcommand # dbg
1865 #print "loading rl:",rlcommand # dbg
1867 readline.parse_and_bind(rlcommand)
1866 readline.parse_and_bind(rlcommand)
1868
1867
1869 # Remove some chars from the delimiters list. If we encounter
1868 # Remove some chars from the delimiters list. If we encounter
1870 # unicode chars, discard them.
1869 # unicode chars, discard them.
1871 delims = readline.get_completer_delims()
1870 delims = readline.get_completer_delims()
1872 if not py3compat.PY3:
1871 if not py3compat.PY3:
1873 delims = delims.encode("ascii", "ignore")
1872 delims = delims.encode("ascii", "ignore")
1874 for d in self.readline_remove_delims:
1873 for d in self.readline_remove_delims:
1875 delims = delims.replace(d, "")
1874 delims = delims.replace(d, "")
1876 delims = delims.replace(ESC_MAGIC, '')
1875 delims = delims.replace(ESC_MAGIC, '')
1877 readline.set_completer_delims(delims)
1876 readline.set_completer_delims(delims)
1878 # Store these so we can restore them if something like rpy2 modifies
1877 # Store these so we can restore them if something like rpy2 modifies
1879 # them.
1878 # them.
1880 self.readline_delims = delims
1879 self.readline_delims = delims
1881 # otherwise we end up with a monster history after a while:
1880 # otherwise we end up with a monster history after a while:
1882 readline.set_history_length(self.history_length)
1881 readline.set_history_length(self.history_length)
1883
1882
1884 self.refill_readline_hist()
1883 self.refill_readline_hist()
1885 self.readline_no_record = ReadlineNoRecord(self)
1884 self.readline_no_record = ReadlineNoRecord(self)
1886
1885
1887 # Configure auto-indent for all platforms
1886 # Configure auto-indent for all platforms
1888 self.set_autoindent(self.autoindent)
1887 self.set_autoindent(self.autoindent)
1889
1888
1890 def refill_readline_hist(self):
1889 def refill_readline_hist(self):
1891 # Load the last 1000 lines from history
1890 # Load the last 1000 lines from history
1892 self.readline.clear_history()
1891 self.readline.clear_history()
1893 stdin_encoding = sys.stdin.encoding or "utf-8"
1892 stdin_encoding = sys.stdin.encoding or "utf-8"
1894 last_cell = u""
1893 last_cell = u""
1895 for _, _, cell in self.history_manager.get_tail(1000,
1894 for _, _, cell in self.history_manager.get_tail(1000,
1896 include_latest=True):
1895 include_latest=True):
1897 # Ignore blank lines and consecutive duplicates
1896 # Ignore blank lines and consecutive duplicates
1898 cell = cell.rstrip()
1897 cell = cell.rstrip()
1899 if cell and (cell != last_cell):
1898 if cell and (cell != last_cell):
1900 try:
1899 try:
1901 if self.multiline_history:
1900 if self.multiline_history:
1902 self.readline.add_history(py3compat.unicode_to_str(cell,
1901 self.readline.add_history(py3compat.unicode_to_str(cell,
1903 stdin_encoding))
1902 stdin_encoding))
1904 else:
1903 else:
1905 for line in cell.splitlines():
1904 for line in cell.splitlines():
1906 self.readline.add_history(py3compat.unicode_to_str(line,
1905 self.readline.add_history(py3compat.unicode_to_str(line,
1907 stdin_encoding))
1906 stdin_encoding))
1908 last_cell = cell
1907 last_cell = cell
1909
1908
1910 except TypeError:
1909 except TypeError:
1911 # The history DB can get corrupted so it returns strings
1910 # The history DB can get corrupted so it returns strings
1912 # containing null bytes, which readline objects to.
1911 # containing null bytes, which readline objects to.
1913 continue
1912 continue
1914
1913
1915 @skip_doctest
1914 @skip_doctest
1916 def set_next_input(self, s):
1915 def set_next_input(self, s):
1917 """ Sets the 'default' input string for the next command line.
1916 """ Sets the 'default' input string for the next command line.
1918
1917
1919 Requires readline.
1918 Requires readline.
1920
1919
1921 Example::
1920 Example::
1922
1921
1923 In [1]: _ip.set_next_input("Hello Word")
1922 In [1]: _ip.set_next_input("Hello Word")
1924 In [2]: Hello Word_ # cursor is here
1923 In [2]: Hello Word_ # cursor is here
1925 """
1924 """
1926 self.rl_next_input = py3compat.cast_bytes_py2(s)
1925 self.rl_next_input = py3compat.cast_bytes_py2(s)
1927
1926
1928 # Maybe move this to the terminal subclass?
1927 # Maybe move this to the terminal subclass?
1929 def pre_readline(self):
1928 def pre_readline(self):
1930 """readline hook to be used at the start of each line.
1929 """readline hook to be used at the start of each line.
1931
1930
1932 Currently it handles auto-indent only."""
1931 Currently it handles auto-indent only."""
1933
1932
1934 if self.rl_do_indent:
1933 if self.rl_do_indent:
1935 self.readline.insert_text(self._indent_current_str())
1934 self.readline.insert_text(self._indent_current_str())
1936 if self.rl_next_input is not None:
1935 if self.rl_next_input is not None:
1937 self.readline.insert_text(self.rl_next_input)
1936 self.readline.insert_text(self.rl_next_input)
1938 self.rl_next_input = None
1937 self.rl_next_input = None
1939
1938
1940 def _indent_current_str(self):
1939 def _indent_current_str(self):
1941 """return the current level of indentation as a string"""
1940 """return the current level of indentation as a string"""
1942 return self.input_splitter.indent_spaces * ' '
1941 return self.input_splitter.indent_spaces * ' '
1943
1942
1944 #-------------------------------------------------------------------------
1943 #-------------------------------------------------------------------------
1945 # Things related to text completion
1944 # Things related to text completion
1946 #-------------------------------------------------------------------------
1945 #-------------------------------------------------------------------------
1947
1946
1948 def init_completer(self):
1947 def init_completer(self):
1949 """Initialize the completion machinery.
1948 """Initialize the completion machinery.
1950
1949
1951 This creates completion machinery that can be used by client code,
1950 This creates completion machinery that can be used by client code,
1952 either interactively in-process (typically triggered by the readline
1951 either interactively in-process (typically triggered by the readline
1953 library), programatically (such as in test suites) or out-of-prcess
1952 library), programatically (such as in test suites) or out-of-prcess
1954 (typically over the network by remote frontends).
1953 (typically over the network by remote frontends).
1955 """
1954 """
1956 from IPython.core.completer import IPCompleter
1955 from IPython.core.completer import IPCompleter
1957 from IPython.core.completerlib import (module_completer,
1956 from IPython.core.completerlib import (module_completer,
1958 magic_run_completer, cd_completer, reset_completer)
1957 magic_run_completer, cd_completer, reset_completer)
1959
1958
1960 self.Completer = IPCompleter(shell=self,
1959 self.Completer = IPCompleter(shell=self,
1961 namespace=self.user_ns,
1960 namespace=self.user_ns,
1962 global_namespace=self.user_global_ns,
1961 global_namespace=self.user_global_ns,
1963 use_readline=self.has_readline,
1962 use_readline=self.has_readline,
1964 parent=self,
1963 parent=self,
1965 )
1964 )
1966 self.configurables.append(self.Completer)
1965 self.configurables.append(self.Completer)
1967
1966
1968 # Add custom completers to the basic ones built into IPCompleter
1967 # Add custom completers to the basic ones built into IPCompleter
1969 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1968 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1970 self.strdispatchers['complete_command'] = sdisp
1969 self.strdispatchers['complete_command'] = sdisp
1971 self.Completer.custom_completers = sdisp
1970 self.Completer.custom_completers = sdisp
1972
1971
1973 self.set_hook('complete_command', module_completer, str_key = 'import')
1972 self.set_hook('complete_command', module_completer, str_key = 'import')
1974 self.set_hook('complete_command', module_completer, str_key = 'from')
1973 self.set_hook('complete_command', module_completer, str_key = 'from')
1975 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1974 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1976 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1975 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1977 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1976 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1978
1977
1979 # Only configure readline if we truly are using readline. IPython can
1978 # Only configure readline if we truly are using readline. IPython can
1980 # do tab-completion over the network, in GUIs, etc, where readline
1979 # do tab-completion over the network, in GUIs, etc, where readline
1981 # itself may be absent
1980 # itself may be absent
1982 if self.has_readline:
1981 if self.has_readline:
1983 self.set_readline_completer()
1982 self.set_readline_completer()
1984
1983
1985 def complete(self, text, line=None, cursor_pos=None):
1984 def complete(self, text, line=None, cursor_pos=None):
1986 """Return the completed text and a list of completions.
1985 """Return the completed text and a list of completions.
1987
1986
1988 Parameters
1987 Parameters
1989 ----------
1988 ----------
1990
1989
1991 text : string
1990 text : string
1992 A string of text to be completed on. It can be given as empty and
1991 A string of text to be completed on. It can be given as empty and
1993 instead a line/position pair are given. In this case, the
1992 instead a line/position pair are given. In this case, the
1994 completer itself will split the line like readline does.
1993 completer itself will split the line like readline does.
1995
1994
1996 line : string, optional
1995 line : string, optional
1997 The complete line that text is part of.
1996 The complete line that text is part of.
1998
1997
1999 cursor_pos : int, optional
1998 cursor_pos : int, optional
2000 The position of the cursor on the input line.
1999 The position of the cursor on the input line.
2001
2000
2002 Returns
2001 Returns
2003 -------
2002 -------
2004 text : string
2003 text : string
2005 The actual text that was completed.
2004 The actual text that was completed.
2006
2005
2007 matches : list
2006 matches : list
2008 A sorted list with all possible completions.
2007 A sorted list with all possible completions.
2009
2008
2010 The optional arguments allow the completion to take more context into
2009 The optional arguments allow the completion to take more context into
2011 account, and are part of the low-level completion API.
2010 account, and are part of the low-level completion API.
2012
2011
2013 This is a wrapper around the completion mechanism, similar to what
2012 This is a wrapper around the completion mechanism, similar to what
2014 readline does at the command line when the TAB key is hit. By
2013 readline does at the command line when the TAB key is hit. By
2015 exposing it as a method, it can be used by other non-readline
2014 exposing it as a method, it can be used by other non-readline
2016 environments (such as GUIs) for text completion.
2015 environments (such as GUIs) for text completion.
2017
2016
2018 Simple usage example:
2017 Simple usage example:
2019
2018
2020 In [1]: x = 'hello'
2019 In [1]: x = 'hello'
2021
2020
2022 In [2]: _ip.complete('x.l')
2021 In [2]: _ip.complete('x.l')
2023 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2022 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2024 """
2023 """
2025
2024
2026 # Inject names into __builtin__ so we can complete on the added names.
2025 # Inject names into __builtin__ so we can complete on the added names.
2027 with self.builtin_trap:
2026 with self.builtin_trap:
2028 return self.Completer.complete(text, line, cursor_pos)
2027 return self.Completer.complete(text, line, cursor_pos)
2029
2028
2030 def set_custom_completer(self, completer, pos=0):
2029 def set_custom_completer(self, completer, pos=0):
2031 """Adds a new custom completer function.
2030 """Adds a new custom completer function.
2032
2031
2033 The position argument (defaults to 0) is the index in the completers
2032 The position argument (defaults to 0) is the index in the completers
2034 list where you want the completer to be inserted."""
2033 list where you want the completer to be inserted."""
2035
2034
2036 newcomp = types.MethodType(completer,self.Completer)
2035 newcomp = types.MethodType(completer,self.Completer)
2037 self.Completer.matchers.insert(pos,newcomp)
2036 self.Completer.matchers.insert(pos,newcomp)
2038
2037
2039 def set_readline_completer(self):
2038 def set_readline_completer(self):
2040 """Reset readline's completer to be our own."""
2039 """Reset readline's completer to be our own."""
2041 self.readline.set_completer(self.Completer.rlcomplete)
2040 self.readline.set_completer(self.Completer.rlcomplete)
2042
2041
2043 def set_completer_frame(self, frame=None):
2042 def set_completer_frame(self, frame=None):
2044 """Set the frame of the completer."""
2043 """Set the frame of the completer."""
2045 if frame:
2044 if frame:
2046 self.Completer.namespace = frame.f_locals
2045 self.Completer.namespace = frame.f_locals
2047 self.Completer.global_namespace = frame.f_globals
2046 self.Completer.global_namespace = frame.f_globals
2048 else:
2047 else:
2049 self.Completer.namespace = self.user_ns
2048 self.Completer.namespace = self.user_ns
2050 self.Completer.global_namespace = self.user_global_ns
2049 self.Completer.global_namespace = self.user_global_ns
2051
2050
2052 #-------------------------------------------------------------------------
2051 #-------------------------------------------------------------------------
2053 # Things related to magics
2052 # Things related to magics
2054 #-------------------------------------------------------------------------
2053 #-------------------------------------------------------------------------
2055
2054
2056 def init_magics(self):
2055 def init_magics(self):
2057 from IPython.core import magics as m
2056 from IPython.core import magics as m
2058 self.magics_manager = magic.MagicsManager(shell=self,
2057 self.magics_manager = magic.MagicsManager(shell=self,
2059 parent=self,
2058 parent=self,
2060 user_magics=m.UserMagics(self))
2059 user_magics=m.UserMagics(self))
2061 self.configurables.append(self.magics_manager)
2060 self.configurables.append(self.magics_manager)
2062
2061
2063 # Expose as public API from the magics manager
2062 # Expose as public API from the magics manager
2064 self.register_magics = self.magics_manager.register
2063 self.register_magics = self.magics_manager.register
2065 self.define_magic = self.magics_manager.define_magic
2064 self.define_magic = self.magics_manager.define_magic
2066
2065
2067 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2066 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2068 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2067 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2069 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2068 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2070 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2069 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2071 )
2070 )
2072
2071
2073 # Register Magic Aliases
2072 # Register Magic Aliases
2074 mman = self.magics_manager
2073 mman = self.magics_manager
2075 # FIXME: magic aliases should be defined by the Magics classes
2074 # FIXME: magic aliases should be defined by the Magics classes
2076 # or in MagicsManager, not here
2075 # or in MagicsManager, not here
2077 mman.register_alias('ed', 'edit')
2076 mman.register_alias('ed', 'edit')
2078 mman.register_alias('hist', 'history')
2077 mman.register_alias('hist', 'history')
2079 mman.register_alias('rep', 'recall')
2078 mman.register_alias('rep', 'recall')
2080 mman.register_alias('SVG', 'svg', 'cell')
2079 mman.register_alias('SVG', 'svg', 'cell')
2081 mman.register_alias('HTML', 'html', 'cell')
2080 mman.register_alias('HTML', 'html', 'cell')
2082 mman.register_alias('file', 'writefile', 'cell')
2081 mman.register_alias('file', 'writefile', 'cell')
2083
2082
2084 # FIXME: Move the color initialization to the DisplayHook, which
2083 # FIXME: Move the color initialization to the DisplayHook, which
2085 # should be split into a prompt manager and displayhook. We probably
2084 # should be split into a prompt manager and displayhook. We probably
2086 # even need a centralize colors management object.
2085 # even need a centralize colors management object.
2087 self.magic('colors %s' % self.colors)
2086 self.magic('colors %s' % self.colors)
2088
2087
2089 # Defined here so that it's included in the documentation
2088 # Defined here so that it's included in the documentation
2090 @functools.wraps(magic.MagicsManager.register_function)
2089 @functools.wraps(magic.MagicsManager.register_function)
2091 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2090 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2092 self.magics_manager.register_function(func,
2091 self.magics_manager.register_function(func,
2093 magic_kind=magic_kind, magic_name=magic_name)
2092 magic_kind=magic_kind, magic_name=magic_name)
2094
2093
2095 def run_line_magic(self, magic_name, line):
2094 def run_line_magic(self, magic_name, line):
2096 """Execute the given line magic.
2095 """Execute the given line magic.
2097
2096
2098 Parameters
2097 Parameters
2099 ----------
2098 ----------
2100 magic_name : str
2099 magic_name : str
2101 Name of the desired magic function, without '%' prefix.
2100 Name of the desired magic function, without '%' prefix.
2102
2101
2103 line : str
2102 line : str
2104 The rest of the input line as a single string.
2103 The rest of the input line as a single string.
2105 """
2104 """
2106 fn = self.find_line_magic(magic_name)
2105 fn = self.find_line_magic(magic_name)
2107 if fn is None:
2106 if fn is None:
2108 cm = self.find_cell_magic(magic_name)
2107 cm = self.find_cell_magic(magic_name)
2109 etpl = "Line magic function `%%%s` not found%s."
2108 etpl = "Line magic function `%%%s` not found%s."
2110 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2109 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2111 'did you mean that instead?)' % magic_name )
2110 'did you mean that instead?)' % magic_name )
2112 error(etpl % (magic_name, extra))
2111 error(etpl % (magic_name, extra))
2113 else:
2112 else:
2114 # Note: this is the distance in the stack to the user's frame.
2113 # Note: this is the distance in the stack to the user's frame.
2115 # This will need to be updated if the internal calling logic gets
2114 # This will need to be updated if the internal calling logic gets
2116 # refactored, or else we'll be expanding the wrong variables.
2115 # refactored, or else we'll be expanding the wrong variables.
2117 stack_depth = 2
2116 stack_depth = 2
2118 magic_arg_s = self.var_expand(line, stack_depth)
2117 magic_arg_s = self.var_expand(line, stack_depth)
2119 # Put magic args in a list so we can call with f(*a) syntax
2118 # Put magic args in a list so we can call with f(*a) syntax
2120 args = [magic_arg_s]
2119 args = [magic_arg_s]
2121 kwargs = {}
2120 kwargs = {}
2122 # Grab local namespace if we need it:
2121 # Grab local namespace if we need it:
2123 if getattr(fn, "needs_local_scope", False):
2122 if getattr(fn, "needs_local_scope", False):
2124 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2123 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2125 with self.builtin_trap:
2124 with self.builtin_trap:
2126 result = fn(*args,**kwargs)
2125 result = fn(*args,**kwargs)
2127 return result
2126 return result
2128
2127
2129 def run_cell_magic(self, magic_name, line, cell):
2128 def run_cell_magic(self, magic_name, line, cell):
2130 """Execute the given cell magic.
2129 """Execute the given cell magic.
2131
2130
2132 Parameters
2131 Parameters
2133 ----------
2132 ----------
2134 magic_name : str
2133 magic_name : str
2135 Name of the desired magic function, without '%' prefix.
2134 Name of the desired magic function, without '%' prefix.
2136
2135
2137 line : str
2136 line : str
2138 The rest of the first input line as a single string.
2137 The rest of the first input line as a single string.
2139
2138
2140 cell : str
2139 cell : str
2141 The body of the cell as a (possibly multiline) string.
2140 The body of the cell as a (possibly multiline) string.
2142 """
2141 """
2143 fn = self.find_cell_magic(magic_name)
2142 fn = self.find_cell_magic(magic_name)
2144 if fn is None:
2143 if fn is None:
2145 lm = self.find_line_magic(magic_name)
2144 lm = self.find_line_magic(magic_name)
2146 etpl = "Cell magic `%%{0}` not found{1}."
2145 etpl = "Cell magic `%%{0}` not found{1}."
2147 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2146 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2148 'did you mean that instead?)'.format(magic_name))
2147 'did you mean that instead?)'.format(magic_name))
2149 error(etpl.format(magic_name, extra))
2148 error(etpl.format(magic_name, extra))
2150 elif cell == '':
2149 elif cell == '':
2151 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2150 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2152 if self.find_line_magic(magic_name) is not None:
2151 if self.find_line_magic(magic_name) is not None:
2153 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2152 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2154 raise UsageError(message)
2153 raise UsageError(message)
2155 else:
2154 else:
2156 # Note: this is the distance in the stack to the user's frame.
2155 # Note: this is the distance in the stack to the user's frame.
2157 # This will need to be updated if the internal calling logic gets
2156 # This will need to be updated if the internal calling logic gets
2158 # refactored, or else we'll be expanding the wrong variables.
2157 # refactored, or else we'll be expanding the wrong variables.
2159 stack_depth = 2
2158 stack_depth = 2
2160 magic_arg_s = self.var_expand(line, stack_depth)
2159 magic_arg_s = self.var_expand(line, stack_depth)
2161 with self.builtin_trap:
2160 with self.builtin_trap:
2162 result = fn(magic_arg_s, cell)
2161 result = fn(magic_arg_s, cell)
2163 return result
2162 return result
2164
2163
2165 def find_line_magic(self, magic_name):
2164 def find_line_magic(self, magic_name):
2166 """Find and return a line magic by name.
2165 """Find and return a line magic by name.
2167
2166
2168 Returns None if the magic isn't found."""
2167 Returns None if the magic isn't found."""
2169 return self.magics_manager.magics['line'].get(magic_name)
2168 return self.magics_manager.magics['line'].get(magic_name)
2170
2169
2171 def find_cell_magic(self, magic_name):
2170 def find_cell_magic(self, magic_name):
2172 """Find and return a cell magic by name.
2171 """Find and return a cell magic by name.
2173
2172
2174 Returns None if the magic isn't found."""
2173 Returns None if the magic isn't found."""
2175 return self.magics_manager.magics['cell'].get(magic_name)
2174 return self.magics_manager.magics['cell'].get(magic_name)
2176
2175
2177 def find_magic(self, magic_name, magic_kind='line'):
2176 def find_magic(self, magic_name, magic_kind='line'):
2178 """Find and return a magic of the given type by name.
2177 """Find and return a magic of the given type by name.
2179
2178
2180 Returns None if the magic isn't found."""
2179 Returns None if the magic isn't found."""
2181 return self.magics_manager.magics[magic_kind].get(magic_name)
2180 return self.magics_manager.magics[magic_kind].get(magic_name)
2182
2181
2183 def magic(self, arg_s):
2182 def magic(self, arg_s):
2184 """DEPRECATED. Use run_line_magic() instead.
2183 """DEPRECATED. Use run_line_magic() instead.
2185
2184
2186 Call a magic function by name.
2185 Call a magic function by name.
2187
2186
2188 Input: a string containing the name of the magic function to call and
2187 Input: a string containing the name of the magic function to call and
2189 any additional arguments to be passed to the magic.
2188 any additional arguments to be passed to the magic.
2190
2189
2191 magic('name -opt foo bar') is equivalent to typing at the ipython
2190 magic('name -opt foo bar') is equivalent to typing at the ipython
2192 prompt:
2191 prompt:
2193
2192
2194 In[1]: %name -opt foo bar
2193 In[1]: %name -opt foo bar
2195
2194
2196 To call a magic without arguments, simply use magic('name').
2195 To call a magic without arguments, simply use magic('name').
2197
2196
2198 This provides a proper Python function to call IPython's magics in any
2197 This provides a proper Python function to call IPython's magics in any
2199 valid Python code you can type at the interpreter, including loops and
2198 valid Python code you can type at the interpreter, including loops and
2200 compound statements.
2199 compound statements.
2201 """
2200 """
2202 # TODO: should we issue a loud deprecation warning here?
2201 # TODO: should we issue a loud deprecation warning here?
2203 magic_name, _, magic_arg_s = arg_s.partition(' ')
2202 magic_name, _, magic_arg_s = arg_s.partition(' ')
2204 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2203 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2205 return self.run_line_magic(magic_name, magic_arg_s)
2204 return self.run_line_magic(magic_name, magic_arg_s)
2206
2205
2207 #-------------------------------------------------------------------------
2206 #-------------------------------------------------------------------------
2208 # Things related to macros
2207 # Things related to macros
2209 #-------------------------------------------------------------------------
2208 #-------------------------------------------------------------------------
2210
2209
2211 def define_macro(self, name, themacro):
2210 def define_macro(self, name, themacro):
2212 """Define a new macro
2211 """Define a new macro
2213
2212
2214 Parameters
2213 Parameters
2215 ----------
2214 ----------
2216 name : str
2215 name : str
2217 The name of the macro.
2216 The name of the macro.
2218 themacro : str or Macro
2217 themacro : str or Macro
2219 The action to do upon invoking the macro. If a string, a new
2218 The action to do upon invoking the macro. If a string, a new
2220 Macro object is created by passing the string to it.
2219 Macro object is created by passing the string to it.
2221 """
2220 """
2222
2221
2223 from IPython.core import macro
2222 from IPython.core import macro
2224
2223
2225 if isinstance(themacro, string_types):
2224 if isinstance(themacro, string_types):
2226 themacro = macro.Macro(themacro)
2225 themacro = macro.Macro(themacro)
2227 if not isinstance(themacro, macro.Macro):
2226 if not isinstance(themacro, macro.Macro):
2228 raise ValueError('A macro must be a string or a Macro instance.')
2227 raise ValueError('A macro must be a string or a Macro instance.')
2229 self.user_ns[name] = themacro
2228 self.user_ns[name] = themacro
2230
2229
2231 #-------------------------------------------------------------------------
2230 #-------------------------------------------------------------------------
2232 # Things related to the running of system commands
2231 # Things related to the running of system commands
2233 #-------------------------------------------------------------------------
2232 #-------------------------------------------------------------------------
2234
2233
2235 def system_piped(self, cmd):
2234 def system_piped(self, cmd):
2236 """Call the given cmd in a subprocess, piping stdout/err
2235 """Call the given cmd in a subprocess, piping stdout/err
2237
2236
2238 Parameters
2237 Parameters
2239 ----------
2238 ----------
2240 cmd : str
2239 cmd : str
2241 Command to execute (can not end in '&', as background processes are
2240 Command to execute (can not end in '&', as background processes are
2242 not supported. Should not be a command that expects input
2241 not supported. Should not be a command that expects input
2243 other than simple text.
2242 other than simple text.
2244 """
2243 """
2245 if cmd.rstrip().endswith('&'):
2244 if cmd.rstrip().endswith('&'):
2246 # this is *far* from a rigorous test
2245 # this is *far* from a rigorous test
2247 # We do not support backgrounding processes because we either use
2246 # We do not support backgrounding processes because we either use
2248 # pexpect or pipes to read from. Users can always just call
2247 # pexpect or pipes to read from. Users can always just call
2249 # os.system() or use ip.system=ip.system_raw
2248 # os.system() or use ip.system=ip.system_raw
2250 # if they really want a background process.
2249 # if they really want a background process.
2251 raise OSError("Background processes not supported.")
2250 raise OSError("Background processes not supported.")
2252
2251
2253 # we explicitly do NOT return the subprocess status code, because
2252 # we explicitly do NOT return the subprocess status code, because
2254 # a non-None value would trigger :func:`sys.displayhook` calls.
2253 # a non-None value would trigger :func:`sys.displayhook` calls.
2255 # Instead, we store the exit_code in user_ns.
2254 # Instead, we store the exit_code in user_ns.
2256 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2255 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2257
2256
2258 def system_raw(self, cmd):
2257 def system_raw(self, cmd):
2259 """Call the given cmd in a subprocess using os.system on Windows or
2258 """Call the given cmd in a subprocess using os.system on Windows or
2260 subprocess.call using the system shell on other platforms.
2259 subprocess.call using the system shell on other platforms.
2261
2260
2262 Parameters
2261 Parameters
2263 ----------
2262 ----------
2264 cmd : str
2263 cmd : str
2265 Command to execute.
2264 Command to execute.
2266 """
2265 """
2267 cmd = self.var_expand(cmd, depth=1)
2266 cmd = self.var_expand(cmd, depth=1)
2268 # protect os.system from UNC paths on Windows, which it can't handle:
2267 # protect os.system from UNC paths on Windows, which it can't handle:
2269 if sys.platform == 'win32':
2268 if sys.platform == 'win32':
2270 from IPython.utils._process_win32 import AvoidUNCPath
2269 from IPython.utils._process_win32 import AvoidUNCPath
2271 with AvoidUNCPath() as path:
2270 with AvoidUNCPath() as path:
2272 if path is not None:
2271 if path is not None:
2273 cmd = '"pushd %s &&"%s' % (path, cmd)
2272 cmd = '"pushd %s &&"%s' % (path, cmd)
2274 cmd = py3compat.unicode_to_str(cmd)
2273 cmd = py3compat.unicode_to_str(cmd)
2275 ec = os.system(cmd)
2274 ec = os.system(cmd)
2276 else:
2275 else:
2277 cmd = py3compat.unicode_to_str(cmd)
2276 cmd = py3compat.unicode_to_str(cmd)
2278 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2277 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2279 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2278 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2280 # exit code is positive for program failure, or negative for
2279 # exit code is positive for program failure, or negative for
2281 # terminating signal number.
2280 # terminating signal number.
2282
2281
2283 # We explicitly do NOT return the subprocess status code, because
2282 # We explicitly do NOT return the subprocess status code, because
2284 # a non-None value would trigger :func:`sys.displayhook` calls.
2283 # a non-None value would trigger :func:`sys.displayhook` calls.
2285 # Instead, we store the exit_code in user_ns.
2284 # Instead, we store the exit_code in user_ns.
2286 self.user_ns['_exit_code'] = ec
2285 self.user_ns['_exit_code'] = ec
2287
2286
2288 # use piped system by default, because it is better behaved
2287 # use piped system by default, because it is better behaved
2289 system = system_piped
2288 system = system_piped
2290
2289
2291 def getoutput(self, cmd, split=True, depth=0):
2290 def getoutput(self, cmd, split=True, depth=0):
2292 """Get output (possibly including stderr) from a subprocess.
2291 """Get output (possibly including stderr) from a subprocess.
2293
2292
2294 Parameters
2293 Parameters
2295 ----------
2294 ----------
2296 cmd : str
2295 cmd : str
2297 Command to execute (can not end in '&', as background processes are
2296 Command to execute (can not end in '&', as background processes are
2298 not supported.
2297 not supported.
2299 split : bool, optional
2298 split : bool, optional
2300 If True, split the output into an IPython SList. Otherwise, an
2299 If True, split the output into an IPython SList. Otherwise, an
2301 IPython LSString is returned. These are objects similar to normal
2300 IPython LSString is returned. These are objects similar to normal
2302 lists and strings, with a few convenience attributes for easier
2301 lists and strings, with a few convenience attributes for easier
2303 manipulation of line-based output. You can use '?' on them for
2302 manipulation of line-based output. You can use '?' on them for
2304 details.
2303 details.
2305 depth : int, optional
2304 depth : int, optional
2306 How many frames above the caller are the local variables which should
2305 How many frames above the caller are the local variables which should
2307 be expanded in the command string? The default (0) assumes that the
2306 be expanded in the command string? The default (0) assumes that the
2308 expansion variables are in the stack frame calling this function.
2307 expansion variables are in the stack frame calling this function.
2309 """
2308 """
2310 if cmd.rstrip().endswith('&'):
2309 if cmd.rstrip().endswith('&'):
2311 # this is *far* from a rigorous test
2310 # this is *far* from a rigorous test
2312 raise OSError("Background processes not supported.")
2311 raise OSError("Background processes not supported.")
2313 out = getoutput(self.var_expand(cmd, depth=depth+1))
2312 out = getoutput(self.var_expand(cmd, depth=depth+1))
2314 if split:
2313 if split:
2315 out = SList(out.splitlines())
2314 out = SList(out.splitlines())
2316 else:
2315 else:
2317 out = LSString(out)
2316 out = LSString(out)
2318 return out
2317 return out
2319
2318
2320 #-------------------------------------------------------------------------
2319 #-------------------------------------------------------------------------
2321 # Things related to aliases
2320 # Things related to aliases
2322 #-------------------------------------------------------------------------
2321 #-------------------------------------------------------------------------
2323
2322
2324 def init_alias(self):
2323 def init_alias(self):
2325 self.alias_manager = AliasManager(shell=self, parent=self)
2324 self.alias_manager = AliasManager(shell=self, parent=self)
2326 self.configurables.append(self.alias_manager)
2325 self.configurables.append(self.alias_manager)
2327
2326
2328 #-------------------------------------------------------------------------
2327 #-------------------------------------------------------------------------
2329 # Things related to extensions
2328 # Things related to extensions
2330 #-------------------------------------------------------------------------
2329 #-------------------------------------------------------------------------
2331
2330
2332 def init_extension_manager(self):
2331 def init_extension_manager(self):
2333 self.extension_manager = ExtensionManager(shell=self, parent=self)
2332 self.extension_manager = ExtensionManager(shell=self, parent=self)
2334 self.configurables.append(self.extension_manager)
2333 self.configurables.append(self.extension_manager)
2335
2334
2336 #-------------------------------------------------------------------------
2335 #-------------------------------------------------------------------------
2337 # Things related to payloads
2336 # Things related to payloads
2338 #-------------------------------------------------------------------------
2337 #-------------------------------------------------------------------------
2339
2338
2340 def init_payload(self):
2339 def init_payload(self):
2341 self.payload_manager = PayloadManager(parent=self)
2340 self.payload_manager = PayloadManager(parent=self)
2342 self.configurables.append(self.payload_manager)
2341 self.configurables.append(self.payload_manager)
2343
2342
2344 #-------------------------------------------------------------------------
2343 #-------------------------------------------------------------------------
2345 # Things related to widgets
2344 # Things related to widgets
2346 #-------------------------------------------------------------------------
2345 #-------------------------------------------------------------------------
2347
2346
2348 def init_comms(self):
2347 def init_comms(self):
2349 # not implemented in the base class
2348 # not implemented in the base class
2350 pass
2349 pass
2351
2350
2352 #-------------------------------------------------------------------------
2351 #-------------------------------------------------------------------------
2353 # Things related to the prefilter
2352 # Things related to the prefilter
2354 #-------------------------------------------------------------------------
2353 #-------------------------------------------------------------------------
2355
2354
2356 def init_prefilter(self):
2355 def init_prefilter(self):
2357 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2356 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2358 self.configurables.append(self.prefilter_manager)
2357 self.configurables.append(self.prefilter_manager)
2359 # Ultimately this will be refactored in the new interpreter code, but
2358 # Ultimately this will be refactored in the new interpreter code, but
2360 # for now, we should expose the main prefilter method (there's legacy
2359 # for now, we should expose the main prefilter method (there's legacy
2361 # code out there that may rely on this).
2360 # code out there that may rely on this).
2362 self.prefilter = self.prefilter_manager.prefilter_lines
2361 self.prefilter = self.prefilter_manager.prefilter_lines
2363
2362
2364 def auto_rewrite_input(self, cmd):
2363 def auto_rewrite_input(self, cmd):
2365 """Print to the screen the rewritten form of the user's command.
2364 """Print to the screen the rewritten form of the user's command.
2366
2365
2367 This shows visual feedback by rewriting input lines that cause
2366 This shows visual feedback by rewriting input lines that cause
2368 automatic calling to kick in, like::
2367 automatic calling to kick in, like::
2369
2368
2370 /f x
2369 /f x
2371
2370
2372 into::
2371 into::
2373
2372
2374 ------> f(x)
2373 ------> f(x)
2375
2374
2376 after the user's input prompt. This helps the user understand that the
2375 after the user's input prompt. This helps the user understand that the
2377 input line was transformed automatically by IPython.
2376 input line was transformed automatically by IPython.
2378 """
2377 """
2379 if not self.show_rewritten_input:
2378 if not self.show_rewritten_input:
2380 return
2379 return
2381
2380
2382 rw = self.prompt_manager.render('rewrite') + cmd
2381 rw = self.prompt_manager.render('rewrite') + cmd
2383
2382
2384 try:
2383 try:
2385 # plain ascii works better w/ pyreadline, on some machines, so
2384 # plain ascii works better w/ pyreadline, on some machines, so
2386 # we use it and only print uncolored rewrite if we have unicode
2385 # we use it and only print uncolored rewrite if we have unicode
2387 rw = str(rw)
2386 rw = str(rw)
2388 print(rw, file=io.stdout)
2387 print(rw, file=io.stdout)
2389 except UnicodeEncodeError:
2388 except UnicodeEncodeError:
2390 print("------> " + cmd)
2389 print("------> " + cmd)
2391
2390
2392 #-------------------------------------------------------------------------
2391 #-------------------------------------------------------------------------
2393 # Things related to extracting values/expressions from kernel and user_ns
2392 # Things related to extracting values/expressions from kernel and user_ns
2394 #-------------------------------------------------------------------------
2393 #-------------------------------------------------------------------------
2395
2394
2396 def _user_obj_error(self):
2395 def _user_obj_error(self):
2397 """return simple exception dict
2396 """return simple exception dict
2398
2397
2399 for use in user_variables / expressions
2398 for use in user_variables / expressions
2400 """
2399 """
2401
2400
2402 etype, evalue, tb = self._get_exc_info()
2401 etype, evalue, tb = self._get_exc_info()
2403 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2402 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2404
2403
2405 exc_info = {
2404 exc_info = {
2406 u'status' : 'error',
2405 u'status' : 'error',
2407 u'traceback' : stb,
2406 u'traceback' : stb,
2408 u'ename' : unicode_type(etype.__name__),
2407 u'ename' : unicode_type(etype.__name__),
2409 u'evalue' : py3compat.safe_unicode(evalue),
2408 u'evalue' : py3compat.safe_unicode(evalue),
2410 }
2409 }
2411
2410
2412 return exc_info
2411 return exc_info
2413
2412
2414 def _format_user_obj(self, obj):
2413 def _format_user_obj(self, obj):
2415 """format a user object to display dict
2414 """format a user object to display dict
2416
2415
2417 for use in user_expressions / variables
2416 for use in user_expressions / variables
2418 """
2417 """
2419
2418
2420 data, md = self.display_formatter.format(obj)
2419 data, md = self.display_formatter.format(obj)
2421 value = {
2420 value = {
2422 'status' : 'ok',
2421 'status' : 'ok',
2423 'data' : data,
2422 'data' : data,
2424 'metadata' : md,
2423 'metadata' : md,
2425 }
2424 }
2426 return value
2425 return value
2427
2426
2428 def user_variables(self, names):
2427 def user_variables(self, names):
2429 """Get a list of variable names from the user's namespace.
2428 """Get a list of variable names from the user's namespace.
2430
2429
2431 Parameters
2430 Parameters
2432 ----------
2431 ----------
2433 names : list of strings
2432 names : list of strings
2434 A list of names of variables to be read from the user namespace.
2433 A list of names of variables to be read from the user namespace.
2435
2434
2436 Returns
2435 Returns
2437 -------
2436 -------
2438 A dict, keyed by the input names and with the rich mime-type repr(s) of each value.
2437 A dict, keyed by the input names and with the rich mime-type repr(s) of each value.
2439 Each element will be a sub-dict of the same form as a display_data message.
2438 Each element will be a sub-dict of the same form as a display_data message.
2440 """
2439 """
2441 out = {}
2440 out = {}
2442 user_ns = self.user_ns
2441 user_ns = self.user_ns
2443
2442
2444 for varname in names:
2443 for varname in names:
2445 try:
2444 try:
2446 value = self._format_user_obj(user_ns[varname])
2445 value = self._format_user_obj(user_ns[varname])
2447 except:
2446 except:
2448 value = self._user_obj_error()
2447 value = self._user_obj_error()
2449 out[varname] = value
2448 out[varname] = value
2450 return out
2449 return out
2451
2450
2452 def user_expressions(self, expressions):
2451 def user_expressions(self, expressions):
2453 """Evaluate a dict of expressions in the user's namespace.
2452 """Evaluate a dict of expressions in the user's namespace.
2454
2453
2455 Parameters
2454 Parameters
2456 ----------
2455 ----------
2457 expressions : dict
2456 expressions : dict
2458 A dict with string keys and string values. The expression values
2457 A dict with string keys and string values. The expression values
2459 should be valid Python expressions, each of which will be evaluated
2458 should be valid Python expressions, each of which will be evaluated
2460 in the user namespace.
2459 in the user namespace.
2461
2460
2462 Returns
2461 Returns
2463 -------
2462 -------
2464 A dict, keyed like the input expressions dict, with the rich mime-typed
2463 A dict, keyed like the input expressions dict, with the rich mime-typed
2465 display_data of each value.
2464 display_data of each value.
2466 """
2465 """
2467 out = {}
2466 out = {}
2468 user_ns = self.user_ns
2467 user_ns = self.user_ns
2469 global_ns = self.user_global_ns
2468 global_ns = self.user_global_ns
2470
2469
2471 for key, expr in iteritems(expressions):
2470 for key, expr in iteritems(expressions):
2472 try:
2471 try:
2473 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2472 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2474 except:
2473 except:
2475 value = self._user_obj_error()
2474 value = self._user_obj_error()
2476 out[key] = value
2475 out[key] = value
2477 return out
2476 return out
2478
2477
2479 #-------------------------------------------------------------------------
2478 #-------------------------------------------------------------------------
2480 # Things related to the running of code
2479 # Things related to the running of code
2481 #-------------------------------------------------------------------------
2480 #-------------------------------------------------------------------------
2482
2481
2483 def ex(self, cmd):
2482 def ex(self, cmd):
2484 """Execute a normal python statement in user namespace."""
2483 """Execute a normal python statement in user namespace."""
2485 with self.builtin_trap:
2484 with self.builtin_trap:
2486 exec(cmd, self.user_global_ns, self.user_ns)
2485 exec(cmd, self.user_global_ns, self.user_ns)
2487
2486
2488 def ev(self, expr):
2487 def ev(self, expr):
2489 """Evaluate python expression expr in user namespace.
2488 """Evaluate python expression expr in user namespace.
2490
2489
2491 Returns the result of evaluation
2490 Returns the result of evaluation
2492 """
2491 """
2493 with self.builtin_trap:
2492 with self.builtin_trap:
2494 return eval(expr, self.user_global_ns, self.user_ns)
2493 return eval(expr, self.user_global_ns, self.user_ns)
2495
2494
2496 def safe_execfile(self, fname, *where, **kw):
2495 def safe_execfile(self, fname, *where, **kw):
2497 """A safe version of the builtin execfile().
2496 """A safe version of the builtin execfile().
2498
2497
2499 This version will never throw an exception, but instead print
2498 This version will never throw an exception, but instead print
2500 helpful error messages to the screen. This only works on pure
2499 helpful error messages to the screen. This only works on pure
2501 Python files with the .py extension.
2500 Python files with the .py extension.
2502
2501
2503 Parameters
2502 Parameters
2504 ----------
2503 ----------
2505 fname : string
2504 fname : string
2506 The name of the file to be executed.
2505 The name of the file to be executed.
2507 where : tuple
2506 where : tuple
2508 One or two namespaces, passed to execfile() as (globals,locals).
2507 One or two namespaces, passed to execfile() as (globals,locals).
2509 If only one is given, it is passed as both.
2508 If only one is given, it is passed as both.
2510 exit_ignore : bool (False)
2509 exit_ignore : bool (False)
2511 If True, then silence SystemExit for non-zero status (it is always
2510 If True, then silence SystemExit for non-zero status (it is always
2512 silenced for zero status, as it is so common).
2511 silenced for zero status, as it is so common).
2513 raise_exceptions : bool (False)
2512 raise_exceptions : bool (False)
2514 If True raise exceptions everywhere. Meant for testing.
2513 If True raise exceptions everywhere. Meant for testing.
2515
2514
2516 """
2515 """
2517 kw.setdefault('exit_ignore', False)
2516 kw.setdefault('exit_ignore', False)
2518 kw.setdefault('raise_exceptions', False)
2517 kw.setdefault('raise_exceptions', False)
2519
2518
2520 fname = os.path.abspath(os.path.expanduser(fname))
2519 fname = os.path.abspath(os.path.expanduser(fname))
2521
2520
2522 # Make sure we can open the file
2521 # Make sure we can open the file
2523 try:
2522 try:
2524 with open(fname) as thefile:
2523 with open(fname) as thefile:
2525 pass
2524 pass
2526 except:
2525 except:
2527 warn('Could not open file <%s> for safe execution.' % fname)
2526 warn('Could not open file <%s> for safe execution.' % fname)
2528 return
2527 return
2529
2528
2530 # Find things also in current directory. This is needed to mimic the
2529 # Find things also in current directory. This is needed to mimic the
2531 # behavior of running a script from the system command line, where
2530 # behavior of running a script from the system command line, where
2532 # Python inserts the script's directory into sys.path
2531 # Python inserts the script's directory into sys.path
2533 dname = os.path.dirname(fname)
2532 dname = os.path.dirname(fname)
2534
2533
2535 with prepended_to_syspath(dname):
2534 with prepended_to_syspath(dname):
2536 try:
2535 try:
2537 py3compat.execfile(fname,*where)
2536 py3compat.execfile(fname,*where)
2538 except SystemExit as status:
2537 except SystemExit as status:
2539 # If the call was made with 0 or None exit status (sys.exit(0)
2538 # If the call was made with 0 or None exit status (sys.exit(0)
2540 # or sys.exit() ), don't bother showing a traceback, as both of
2539 # or sys.exit() ), don't bother showing a traceback, as both of
2541 # these are considered normal by the OS:
2540 # these are considered normal by the OS:
2542 # > python -c'import sys;sys.exit(0)'; echo $?
2541 # > python -c'import sys;sys.exit(0)'; echo $?
2543 # 0
2542 # 0
2544 # > python -c'import sys;sys.exit()'; echo $?
2543 # > python -c'import sys;sys.exit()'; echo $?
2545 # 0
2544 # 0
2546 # For other exit status, we show the exception unless
2545 # For other exit status, we show the exception unless
2547 # explicitly silenced, but only in short form.
2546 # explicitly silenced, but only in short form.
2548 if kw['raise_exceptions']:
2547 if kw['raise_exceptions']:
2549 raise
2548 raise
2550 if status.code and not kw['exit_ignore']:
2549 if status.code and not kw['exit_ignore']:
2551 self.showtraceback(exception_only=True)
2550 self.showtraceback(exception_only=True)
2552 except:
2551 except:
2553 if kw['raise_exceptions']:
2552 if kw['raise_exceptions']:
2554 raise
2553 raise
2555 # tb offset is 2 because we wrap execfile
2554 # tb offset is 2 because we wrap execfile
2556 self.showtraceback(tb_offset=2)
2555 self.showtraceback(tb_offset=2)
2557
2556
2558 def safe_execfile_ipy(self, fname):
2557 def safe_execfile_ipy(self, fname):
2559 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2558 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2560
2559
2561 Parameters
2560 Parameters
2562 ----------
2561 ----------
2563 fname : str
2562 fname : str
2564 The name of the file to execute. The filename must have a
2563 The name of the file to execute. The filename must have a
2565 .ipy or .ipynb extension.
2564 .ipy or .ipynb extension.
2566 """
2565 """
2567 fname = os.path.abspath(os.path.expanduser(fname))
2566 fname = os.path.abspath(os.path.expanduser(fname))
2568
2567
2569 # Make sure we can open the file
2568 # Make sure we can open the file
2570 try:
2569 try:
2571 with open(fname) as thefile:
2570 with open(fname) as thefile:
2572 pass
2571 pass
2573 except:
2572 except:
2574 warn('Could not open file <%s> for safe execution.' % fname)
2573 warn('Could not open file <%s> for safe execution.' % fname)
2575 return
2574 return
2576
2575
2577 # Find things also in current directory. This is needed to mimic the
2576 # Find things also in current directory. This is needed to mimic the
2578 # behavior of running a script from the system command line, where
2577 # behavior of running a script from the system command line, where
2579 # Python inserts the script's directory into sys.path
2578 # Python inserts the script's directory into sys.path
2580 dname = os.path.dirname(fname)
2579 dname = os.path.dirname(fname)
2581
2580
2582 def get_cells():
2581 def get_cells():
2583 """generator for sequence of code blocks to run"""
2582 """generator for sequence of code blocks to run"""
2584 if fname.endswith('.ipynb'):
2583 if fname.endswith('.ipynb'):
2585 from IPython.nbformat import current
2584 from IPython.nbformat import current
2586 with open(fname) as f:
2585 with open(fname) as f:
2587 nb = current.read(f, 'json')
2586 nb = current.read(f, 'json')
2588 if not nb.worksheets:
2587 if not nb.worksheets:
2589 return
2588 return
2590 for cell in nb.worksheets[0].cells:
2589 for cell in nb.worksheets[0].cells:
2591 if cell.cell_type == 'code':
2590 if cell.cell_type == 'code':
2592 yield cell.input
2591 yield cell.input
2593 else:
2592 else:
2594 with open(fname) as f:
2593 with open(fname) as f:
2595 yield f.read()
2594 yield f.read()
2596
2595
2597 with prepended_to_syspath(dname):
2596 with prepended_to_syspath(dname):
2598 try:
2597 try:
2599 for cell in get_cells():
2598 for cell in get_cells():
2600 # self.run_cell currently captures all exceptions
2599 # self.run_cell currently captures all exceptions
2601 # raised in user code. It would be nice if there were
2600 # raised in user code. It would be nice if there were
2602 # versions of run_cell that did raise, so
2601 # versions of run_cell that did raise, so
2603 # we could catch the errors.
2602 # we could catch the errors.
2604 self.run_cell(cell, store_history=False, shell_futures=False)
2603 self.run_cell(cell, store_history=False, shell_futures=False)
2605 except:
2604 except:
2606 self.showtraceback()
2605 self.showtraceback()
2607 warn('Unknown failure executing file: <%s>' % fname)
2606 warn('Unknown failure executing file: <%s>' % fname)
2608
2607
2609 def safe_run_module(self, mod_name, where):
2608 def safe_run_module(self, mod_name, where):
2610 """A safe version of runpy.run_module().
2609 """A safe version of runpy.run_module().
2611
2610
2612 This version will never throw an exception, but instead print
2611 This version will never throw an exception, but instead print
2613 helpful error messages to the screen.
2612 helpful error messages to the screen.
2614
2613
2615 `SystemExit` exceptions with status code 0 or None are ignored.
2614 `SystemExit` exceptions with status code 0 or None are ignored.
2616
2615
2617 Parameters
2616 Parameters
2618 ----------
2617 ----------
2619 mod_name : string
2618 mod_name : string
2620 The name of the module to be executed.
2619 The name of the module to be executed.
2621 where : dict
2620 where : dict
2622 The globals namespace.
2621 The globals namespace.
2623 """
2622 """
2624 try:
2623 try:
2625 try:
2624 try:
2626 where.update(
2625 where.update(
2627 runpy.run_module(str(mod_name), run_name="__main__",
2626 runpy.run_module(str(mod_name), run_name="__main__",
2628 alter_sys=True)
2627 alter_sys=True)
2629 )
2628 )
2630 except SystemExit as status:
2629 except SystemExit as status:
2631 if status.code:
2630 if status.code:
2632 raise
2631 raise
2633 except:
2632 except:
2634 self.showtraceback()
2633 self.showtraceback()
2635 warn('Unknown failure executing module: <%s>' % mod_name)
2634 warn('Unknown failure executing module: <%s>' % mod_name)
2636
2635
2637 def _run_cached_cell_magic(self, magic_name, line):
2636 def _run_cached_cell_magic(self, magic_name, line):
2638 """Special method to call a cell magic with the data stored in self.
2637 """Special method to call a cell magic with the data stored in self.
2639 """
2638 """
2640 cell = self._current_cell_magic_body
2639 cell = self._current_cell_magic_body
2641 self._current_cell_magic_body = None
2640 self._current_cell_magic_body = None
2642 return self.run_cell_magic(magic_name, line, cell)
2641 return self.run_cell_magic(magic_name, line, cell)
2643
2642
2644 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2643 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2645 """Run a complete IPython cell.
2644 """Run a complete IPython cell.
2646
2645
2647 Parameters
2646 Parameters
2648 ----------
2647 ----------
2649 raw_cell : str
2648 raw_cell : str
2650 The code (including IPython code such as %magic functions) to run.
2649 The code (including IPython code such as %magic functions) to run.
2651 store_history : bool
2650 store_history : bool
2652 If True, the raw and translated cell will be stored in IPython's
2651 If True, the raw and translated cell will be stored in IPython's
2653 history. For user code calling back into IPython's machinery, this
2652 history. For user code calling back into IPython's machinery, this
2654 should be set to False.
2653 should be set to False.
2655 silent : bool
2654 silent : bool
2656 If True, avoid side-effects, such as implicit displayhooks and
2655 If True, avoid side-effects, such as implicit displayhooks and
2657 and logging. silent=True forces store_history=False.
2656 and logging. silent=True forces store_history=False.
2658 shell_futures : bool
2657 shell_futures : bool
2659 If True, the code will share future statements with the interactive
2658 If True, the code will share future statements with the interactive
2660 shell. It will both be affected by previous __future__ imports, and
2659 shell. It will both be affected by previous __future__ imports, and
2661 any __future__ imports in the code will affect the shell. If False,
2660 any __future__ imports in the code will affect the shell. If False,
2662 __future__ imports are not shared in either direction.
2661 __future__ imports are not shared in either direction.
2663 """
2662 """
2664 if (not raw_cell) or raw_cell.isspace():
2663 if (not raw_cell) or raw_cell.isspace():
2665 return
2664 return
2666
2665
2667 if silent:
2666 if silent:
2668 store_history = False
2667 store_history = False
2669
2668
2670 self.events.trigger('pre_execute')
2669 self.events.trigger('pre_execute')
2671 if not silent:
2670 if not silent:
2672 self.events.trigger('pre_run_cell')
2671 self.events.trigger('pre_run_cell')
2673
2672
2674 # If any of our input transformation (input_transformer_manager or
2673 # If any of our input transformation (input_transformer_manager or
2675 # prefilter_manager) raises an exception, we store it in this variable
2674 # prefilter_manager) raises an exception, we store it in this variable
2676 # so that we can display the error after logging the input and storing
2675 # so that we can display the error after logging the input and storing
2677 # it in the history.
2676 # it in the history.
2678 preprocessing_exc_tuple = None
2677 preprocessing_exc_tuple = None
2679 try:
2678 try:
2680 # Static input transformations
2679 # Static input transformations
2681 cell = self.input_transformer_manager.transform_cell(raw_cell)
2680 cell = self.input_transformer_manager.transform_cell(raw_cell)
2682 except SyntaxError:
2681 except SyntaxError:
2683 preprocessing_exc_tuple = sys.exc_info()
2682 preprocessing_exc_tuple = sys.exc_info()
2684 cell = raw_cell # cell has to exist so it can be stored/logged
2683 cell = raw_cell # cell has to exist so it can be stored/logged
2685 else:
2684 else:
2686 if len(cell.splitlines()) == 1:
2685 if len(cell.splitlines()) == 1:
2687 # Dynamic transformations - only applied for single line commands
2686 # Dynamic transformations - only applied for single line commands
2688 with self.builtin_trap:
2687 with self.builtin_trap:
2689 try:
2688 try:
2690 # use prefilter_lines to handle trailing newlines
2689 # use prefilter_lines to handle trailing newlines
2691 # restore trailing newline for ast.parse
2690 # restore trailing newline for ast.parse
2692 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2691 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2693 except Exception:
2692 except Exception:
2694 # don't allow prefilter errors to crash IPython
2693 # don't allow prefilter errors to crash IPython
2695 preprocessing_exc_tuple = sys.exc_info()
2694 preprocessing_exc_tuple = sys.exc_info()
2696
2695
2697 # Store raw and processed history
2696 # Store raw and processed history
2698 if store_history:
2697 if store_history:
2699 self.history_manager.store_inputs(self.execution_count,
2698 self.history_manager.store_inputs(self.execution_count,
2700 cell, raw_cell)
2699 cell, raw_cell)
2701 if not silent:
2700 if not silent:
2702 self.logger.log(cell, raw_cell)
2701 self.logger.log(cell, raw_cell)
2703
2702
2704 # Display the exception if input processing failed.
2703 # Display the exception if input processing failed.
2705 if preprocessing_exc_tuple is not None:
2704 if preprocessing_exc_tuple is not None:
2706 self.showtraceback(preprocessing_exc_tuple)
2705 self.showtraceback(preprocessing_exc_tuple)
2707 if store_history:
2706 if store_history:
2708 self.execution_count += 1
2707 self.execution_count += 1
2709 return
2708 return
2710
2709
2711 # Our own compiler remembers the __future__ environment. If we want to
2710 # Our own compiler remembers the __future__ environment. If we want to
2712 # run code with a separate __future__ environment, use the default
2711 # run code with a separate __future__ environment, use the default
2713 # compiler
2712 # compiler
2714 compiler = self.compile if shell_futures else CachingCompiler()
2713 compiler = self.compile if shell_futures else CachingCompiler()
2715
2714
2716 with self.builtin_trap:
2715 with self.builtin_trap:
2717 cell_name = self.compile.cache(cell, self.execution_count)
2716 cell_name = self.compile.cache(cell, self.execution_count)
2718
2717
2719 with self.display_trap:
2718 with self.display_trap:
2720 # Compile to bytecode
2719 # Compile to bytecode
2721 try:
2720 try:
2722 code_ast = compiler.ast_parse(cell, filename=cell_name)
2721 code_ast = compiler.ast_parse(cell, filename=cell_name)
2723 except IndentationError:
2722 except IndentationError:
2724 self.showindentationerror()
2723 self.showindentationerror()
2725 if store_history:
2724 if store_history:
2726 self.execution_count += 1
2725 self.execution_count += 1
2727 return None
2726 return None
2728 except (OverflowError, SyntaxError, ValueError, TypeError,
2727 except (OverflowError, SyntaxError, ValueError, TypeError,
2729 MemoryError):
2728 MemoryError):
2730 self.showsyntaxerror()
2729 self.showsyntaxerror()
2731 if store_history:
2730 if store_history:
2732 self.execution_count += 1
2731 self.execution_count += 1
2733 return None
2732 return None
2734
2733
2735 # Apply AST transformations
2734 # Apply AST transformations
2736 code_ast = self.transform_ast(code_ast)
2735 code_ast = self.transform_ast(code_ast)
2737
2736
2738 # Execute the user code
2737 # Execute the user code
2739 interactivity = "none" if silent else self.ast_node_interactivity
2738 interactivity = "none" if silent else self.ast_node_interactivity
2740 self.run_ast_nodes(code_ast.body, cell_name,
2739 self.run_ast_nodes(code_ast.body, cell_name,
2741 interactivity=interactivity, compiler=compiler)
2740 interactivity=interactivity, compiler=compiler)
2742
2741
2743 self.events.trigger('post_execute')
2742 self.events.trigger('post_execute')
2744 if not silent:
2743 if not silent:
2745 self.events.trigger('post_run_cell')
2744 self.events.trigger('post_run_cell')
2746
2745
2747 if store_history:
2746 if store_history:
2748 # Write output to the database. Does nothing unless
2747 # Write output to the database. Does nothing unless
2749 # history output logging is enabled.
2748 # history output logging is enabled.
2750 self.history_manager.store_output(self.execution_count)
2749 self.history_manager.store_output(self.execution_count)
2751 # Each cell is a *single* input, regardless of how many lines it has
2750 # Each cell is a *single* input, regardless of how many lines it has
2752 self.execution_count += 1
2751 self.execution_count += 1
2753
2752
2754 def transform_ast(self, node):
2753 def transform_ast(self, node):
2755 """Apply the AST transformations from self.ast_transformers
2754 """Apply the AST transformations from self.ast_transformers
2756
2755
2757 Parameters
2756 Parameters
2758 ----------
2757 ----------
2759 node : ast.Node
2758 node : ast.Node
2760 The root node to be transformed. Typically called with the ast.Module
2759 The root node to be transformed. Typically called with the ast.Module
2761 produced by parsing user input.
2760 produced by parsing user input.
2762
2761
2763 Returns
2762 Returns
2764 -------
2763 -------
2765 An ast.Node corresponding to the node it was called with. Note that it
2764 An ast.Node corresponding to the node it was called with. Note that it
2766 may also modify the passed object, so don't rely on references to the
2765 may also modify the passed object, so don't rely on references to the
2767 original AST.
2766 original AST.
2768 """
2767 """
2769 for transformer in self.ast_transformers:
2768 for transformer in self.ast_transformers:
2770 try:
2769 try:
2771 node = transformer.visit(node)
2770 node = transformer.visit(node)
2772 except Exception:
2771 except Exception:
2773 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2772 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2774 self.ast_transformers.remove(transformer)
2773 self.ast_transformers.remove(transformer)
2775
2774
2776 if self.ast_transformers:
2775 if self.ast_transformers:
2777 ast.fix_missing_locations(node)
2776 ast.fix_missing_locations(node)
2778 return node
2777 return node
2779
2778
2780
2779
2781 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2780 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2782 compiler=compile):
2781 compiler=compile):
2783 """Run a sequence of AST nodes. The execution mode depends on the
2782 """Run a sequence of AST nodes. The execution mode depends on the
2784 interactivity parameter.
2783 interactivity parameter.
2785
2784
2786 Parameters
2785 Parameters
2787 ----------
2786 ----------
2788 nodelist : list
2787 nodelist : list
2789 A sequence of AST nodes to run.
2788 A sequence of AST nodes to run.
2790 cell_name : str
2789 cell_name : str
2791 Will be passed to the compiler as the filename of the cell. Typically
2790 Will be passed to the compiler as the filename of the cell. Typically
2792 the value returned by ip.compile.cache(cell).
2791 the value returned by ip.compile.cache(cell).
2793 interactivity : str
2792 interactivity : str
2794 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2793 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2795 run interactively (displaying output from expressions). 'last_expr'
2794 run interactively (displaying output from expressions). 'last_expr'
2796 will run the last node interactively only if it is an expression (i.e.
2795 will run the last node interactively only if it is an expression (i.e.
2797 expressions in loops or other blocks are not displayed. Other values
2796 expressions in loops or other blocks are not displayed. Other values
2798 for this parameter will raise a ValueError.
2797 for this parameter will raise a ValueError.
2799 compiler : callable
2798 compiler : callable
2800 A function with the same interface as the built-in compile(), to turn
2799 A function with the same interface as the built-in compile(), to turn
2801 the AST nodes into code objects. Default is the built-in compile().
2800 the AST nodes into code objects. Default is the built-in compile().
2802 """
2801 """
2803 if not nodelist:
2802 if not nodelist:
2804 return
2803 return
2805
2804
2806 if interactivity == 'last_expr':
2805 if interactivity == 'last_expr':
2807 if isinstance(nodelist[-1], ast.Expr):
2806 if isinstance(nodelist[-1], ast.Expr):
2808 interactivity = "last"
2807 interactivity = "last"
2809 else:
2808 else:
2810 interactivity = "none"
2809 interactivity = "none"
2811
2810
2812 if interactivity == 'none':
2811 if interactivity == 'none':
2813 to_run_exec, to_run_interactive = nodelist, []
2812 to_run_exec, to_run_interactive = nodelist, []
2814 elif interactivity == 'last':
2813 elif interactivity == 'last':
2815 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2814 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2816 elif interactivity == 'all':
2815 elif interactivity == 'all':
2817 to_run_exec, to_run_interactive = [], nodelist
2816 to_run_exec, to_run_interactive = [], nodelist
2818 else:
2817 else:
2819 raise ValueError("Interactivity was %r" % interactivity)
2818 raise ValueError("Interactivity was %r" % interactivity)
2820
2819
2821 exec_count = self.execution_count
2820 exec_count = self.execution_count
2822
2821
2823 try:
2822 try:
2824 for i, node in enumerate(to_run_exec):
2823 for i, node in enumerate(to_run_exec):
2825 mod = ast.Module([node])
2824 mod = ast.Module([node])
2826 code = compiler(mod, cell_name, "exec")
2825 code = compiler(mod, cell_name, "exec")
2827 if self.run_code(code):
2826 if self.run_code(code):
2828 return True
2827 return True
2829
2828
2830 for i, node in enumerate(to_run_interactive):
2829 for i, node in enumerate(to_run_interactive):
2831 mod = ast.Interactive([node])
2830 mod = ast.Interactive([node])
2832 code = compiler(mod, cell_name, "single")
2831 code = compiler(mod, cell_name, "single")
2833 if self.run_code(code):
2832 if self.run_code(code):
2834 return True
2833 return True
2835
2834
2836 # Flush softspace
2835 # Flush softspace
2837 if softspace(sys.stdout, 0):
2836 if softspace(sys.stdout, 0):
2838 print()
2837 print()
2839
2838
2840 except:
2839 except:
2841 # It's possible to have exceptions raised here, typically by
2840 # It's possible to have exceptions raised here, typically by
2842 # compilation of odd code (such as a naked 'return' outside a
2841 # compilation of odd code (such as a naked 'return' outside a
2843 # function) that did parse but isn't valid. Typically the exception
2842 # function) that did parse but isn't valid. Typically the exception
2844 # is a SyntaxError, but it's safest just to catch anything and show
2843 # is a SyntaxError, but it's safest just to catch anything and show
2845 # the user a traceback.
2844 # the user a traceback.
2846
2845
2847 # We do only one try/except outside the loop to minimize the impact
2846 # We do only one try/except outside the loop to minimize the impact
2848 # on runtime, and also because if any node in the node list is
2847 # on runtime, and also because if any node in the node list is
2849 # broken, we should stop execution completely.
2848 # broken, we should stop execution completely.
2850 self.showtraceback()
2849 self.showtraceback()
2851
2850
2852 return False
2851 return False
2853
2852
2854 def run_code(self, code_obj):
2853 def run_code(self, code_obj):
2855 """Execute a code object.
2854 """Execute a code object.
2856
2855
2857 When an exception occurs, self.showtraceback() is called to display a
2856 When an exception occurs, self.showtraceback() is called to display a
2858 traceback.
2857 traceback.
2859
2858
2860 Parameters
2859 Parameters
2861 ----------
2860 ----------
2862 code_obj : code object
2861 code_obj : code object
2863 A compiled code object, to be executed
2862 A compiled code object, to be executed
2864
2863
2865 Returns
2864 Returns
2866 -------
2865 -------
2867 False : successful execution.
2866 False : successful execution.
2868 True : an error occurred.
2867 True : an error occurred.
2869 """
2868 """
2870
2869
2871 # Set our own excepthook in case the user code tries to call it
2870 # Set our own excepthook in case the user code tries to call it
2872 # directly, so that the IPython crash handler doesn't get triggered
2871 # directly, so that the IPython crash handler doesn't get triggered
2873 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2872 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2874
2873
2875 # we save the original sys.excepthook in the instance, in case config
2874 # we save the original sys.excepthook in the instance, in case config
2876 # code (such as magics) needs access to it.
2875 # code (such as magics) needs access to it.
2877 self.sys_excepthook = old_excepthook
2876 self.sys_excepthook = old_excepthook
2878 outflag = 1 # happens in more places, so it's easier as default
2877 outflag = 1 # happens in more places, so it's easier as default
2879 try:
2878 try:
2880 try:
2879 try:
2881 self.hooks.pre_run_code_hook()
2880 self.hooks.pre_run_code_hook()
2882 #rprint('Running code', repr(code_obj)) # dbg
2881 #rprint('Running code', repr(code_obj)) # dbg
2883 exec(code_obj, self.user_global_ns, self.user_ns)
2882 exec(code_obj, self.user_global_ns, self.user_ns)
2884 finally:
2883 finally:
2885 # Reset our crash handler in place
2884 # Reset our crash handler in place
2886 sys.excepthook = old_excepthook
2885 sys.excepthook = old_excepthook
2887 except SystemExit:
2886 except SystemExit:
2888 self.showtraceback(exception_only=True)
2887 self.showtraceback(exception_only=True)
2889 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2888 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2890 except self.custom_exceptions:
2889 except self.custom_exceptions:
2891 etype,value,tb = sys.exc_info()
2890 etype,value,tb = sys.exc_info()
2892 self.CustomTB(etype,value,tb)
2891 self.CustomTB(etype,value,tb)
2893 except:
2892 except:
2894 self.showtraceback()
2893 self.showtraceback()
2895 else:
2894 else:
2896 outflag = 0
2895 outflag = 0
2897 return outflag
2896 return outflag
2898
2897
2899 # For backwards compatibility
2898 # For backwards compatibility
2900 runcode = run_code
2899 runcode = run_code
2901
2900
2902 #-------------------------------------------------------------------------
2901 #-------------------------------------------------------------------------
2903 # Things related to GUI support and pylab
2902 # Things related to GUI support and pylab
2904 #-------------------------------------------------------------------------
2903 #-------------------------------------------------------------------------
2905
2904
2906 def enable_gui(self, gui=None):
2905 def enable_gui(self, gui=None):
2907 raise NotImplementedError('Implement enable_gui in a subclass')
2906 raise NotImplementedError('Implement enable_gui in a subclass')
2908
2907
2909 def enable_matplotlib(self, gui=None):
2908 def enable_matplotlib(self, gui=None):
2910 """Enable interactive matplotlib and inline figure support.
2909 """Enable interactive matplotlib and inline figure support.
2911
2910
2912 This takes the following steps:
2911 This takes the following steps:
2913
2912
2914 1. select the appropriate eventloop and matplotlib backend
2913 1. select the appropriate eventloop and matplotlib backend
2915 2. set up matplotlib for interactive use with that backend
2914 2. set up matplotlib for interactive use with that backend
2916 3. configure formatters for inline figure display
2915 3. configure formatters for inline figure display
2917 4. enable the selected gui eventloop
2916 4. enable the selected gui eventloop
2918
2917
2919 Parameters
2918 Parameters
2920 ----------
2919 ----------
2921 gui : optional, string
2920 gui : optional, string
2922 If given, dictates the choice of matplotlib GUI backend to use
2921 If given, dictates the choice of matplotlib GUI backend to use
2923 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2922 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2924 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2923 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2925 matplotlib (as dictated by the matplotlib build-time options plus the
2924 matplotlib (as dictated by the matplotlib build-time options plus the
2926 user's matplotlibrc configuration file). Note that not all backends
2925 user's matplotlibrc configuration file). Note that not all backends
2927 make sense in all contexts, for example a terminal ipython can't
2926 make sense in all contexts, for example a terminal ipython can't
2928 display figures inline.
2927 display figures inline.
2929 """
2928 """
2930 from IPython.core import pylabtools as pt
2929 from IPython.core import pylabtools as pt
2931 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2930 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2932
2931
2933 if gui != 'inline':
2932 if gui != 'inline':
2934 # If we have our first gui selection, store it
2933 # If we have our first gui selection, store it
2935 if self.pylab_gui_select is None:
2934 if self.pylab_gui_select is None:
2936 self.pylab_gui_select = gui
2935 self.pylab_gui_select = gui
2937 # Otherwise if they are different
2936 # Otherwise if they are different
2938 elif gui != self.pylab_gui_select:
2937 elif gui != self.pylab_gui_select:
2939 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2938 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2940 ' Using %s instead.' % (gui, self.pylab_gui_select))
2939 ' Using %s instead.' % (gui, self.pylab_gui_select))
2941 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2940 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2942
2941
2943 pt.activate_matplotlib(backend)
2942 pt.activate_matplotlib(backend)
2944 pt.configure_inline_support(self, backend)
2943 pt.configure_inline_support(self, backend)
2945
2944
2946 # Now we must activate the gui pylab wants to use, and fix %run to take
2945 # Now we must activate the gui pylab wants to use, and fix %run to take
2947 # plot updates into account
2946 # plot updates into account
2948 self.enable_gui(gui)
2947 self.enable_gui(gui)
2949 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2948 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2950 pt.mpl_runner(self.safe_execfile)
2949 pt.mpl_runner(self.safe_execfile)
2951
2950
2952 return gui, backend
2951 return gui, backend
2953
2952
2954 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
2953 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
2955 """Activate pylab support at runtime.
2954 """Activate pylab support at runtime.
2956
2955
2957 This turns on support for matplotlib, preloads into the interactive
2956 This turns on support for matplotlib, preloads into the interactive
2958 namespace all of numpy and pylab, and configures IPython to correctly
2957 namespace all of numpy and pylab, and configures IPython to correctly
2959 interact with the GUI event loop. The GUI backend to be used can be
2958 interact with the GUI event loop. The GUI backend to be used can be
2960 optionally selected with the optional ``gui`` argument.
2959 optionally selected with the optional ``gui`` argument.
2961
2960
2962 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
2961 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
2963
2962
2964 Parameters
2963 Parameters
2965 ----------
2964 ----------
2966 gui : optional, string
2965 gui : optional, string
2967 If given, dictates the choice of matplotlib GUI backend to use
2966 If given, dictates the choice of matplotlib GUI backend to use
2968 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2967 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2969 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2968 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2970 matplotlib (as dictated by the matplotlib build-time options plus the
2969 matplotlib (as dictated by the matplotlib build-time options plus the
2971 user's matplotlibrc configuration file). Note that not all backends
2970 user's matplotlibrc configuration file). Note that not all backends
2972 make sense in all contexts, for example a terminal ipython can't
2971 make sense in all contexts, for example a terminal ipython can't
2973 display figures inline.
2972 display figures inline.
2974 import_all : optional, bool, default: True
2973 import_all : optional, bool, default: True
2975 Whether to do `from numpy import *` and `from pylab import *`
2974 Whether to do `from numpy import *` and `from pylab import *`
2976 in addition to module imports.
2975 in addition to module imports.
2977 welcome_message : deprecated
2976 welcome_message : deprecated
2978 This argument is ignored, no welcome message will be displayed.
2977 This argument is ignored, no welcome message will be displayed.
2979 """
2978 """
2980 from IPython.core.pylabtools import import_pylab
2979 from IPython.core.pylabtools import import_pylab
2981
2980
2982 gui, backend = self.enable_matplotlib(gui)
2981 gui, backend = self.enable_matplotlib(gui)
2983
2982
2984 # We want to prevent the loading of pylab to pollute the user's
2983 # We want to prevent the loading of pylab to pollute the user's
2985 # namespace as shown by the %who* magics, so we execute the activation
2984 # namespace as shown by the %who* magics, so we execute the activation
2986 # code in an empty namespace, and we update *both* user_ns and
2985 # code in an empty namespace, and we update *both* user_ns and
2987 # user_ns_hidden with this information.
2986 # user_ns_hidden with this information.
2988 ns = {}
2987 ns = {}
2989 import_pylab(ns, import_all)
2988 import_pylab(ns, import_all)
2990 # warn about clobbered names
2989 # warn about clobbered names
2991 ignored = set(["__builtins__"])
2990 ignored = set(["__builtins__"])
2992 both = set(ns).intersection(self.user_ns).difference(ignored)
2991 both = set(ns).intersection(self.user_ns).difference(ignored)
2993 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
2992 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
2994 self.user_ns.update(ns)
2993 self.user_ns.update(ns)
2995 self.user_ns_hidden.update(ns)
2994 self.user_ns_hidden.update(ns)
2996 return gui, backend, clobbered
2995 return gui, backend, clobbered
2997
2996
2998 #-------------------------------------------------------------------------
2997 #-------------------------------------------------------------------------
2999 # Utilities
2998 # Utilities
3000 #-------------------------------------------------------------------------
2999 #-------------------------------------------------------------------------
3001
3000
3002 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3001 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3003 """Expand python variables in a string.
3002 """Expand python variables in a string.
3004
3003
3005 The depth argument indicates how many frames above the caller should
3004 The depth argument indicates how many frames above the caller should
3006 be walked to look for the local namespace where to expand variables.
3005 be walked to look for the local namespace where to expand variables.
3007
3006
3008 The global namespace for expansion is always the user's interactive
3007 The global namespace for expansion is always the user's interactive
3009 namespace.
3008 namespace.
3010 """
3009 """
3011 ns = self.user_ns.copy()
3010 ns = self.user_ns.copy()
3012 ns.update(sys._getframe(depth+1).f_locals)
3011 ns.update(sys._getframe(depth+1).f_locals)
3013 try:
3012 try:
3014 # We have to use .vformat() here, because 'self' is a valid and common
3013 # We have to use .vformat() here, because 'self' is a valid and common
3015 # name, and expanding **ns for .format() would make it collide with
3014 # name, and expanding **ns for .format() would make it collide with
3016 # the 'self' argument of the method.
3015 # the 'self' argument of the method.
3017 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3016 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3018 except Exception:
3017 except Exception:
3019 # if formatter couldn't format, just let it go untransformed
3018 # if formatter couldn't format, just let it go untransformed
3020 pass
3019 pass
3021 return cmd
3020 return cmd
3022
3021
3023 def mktempfile(self, data=None, prefix='ipython_edit_'):
3022 def mktempfile(self, data=None, prefix='ipython_edit_'):
3024 """Make a new tempfile and return its filename.
3023 """Make a new tempfile and return its filename.
3025
3024
3026 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3025 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3027 but it registers the created filename internally so ipython cleans it up
3026 but it registers the created filename internally so ipython cleans it up
3028 at exit time.
3027 at exit time.
3029
3028
3030 Optional inputs:
3029 Optional inputs:
3031
3030
3032 - data(None): if data is given, it gets written out to the temp file
3031 - data(None): if data is given, it gets written out to the temp file
3033 immediately, and the file is closed again."""
3032 immediately, and the file is closed again."""
3034
3033
3035 dirname = tempfile.mkdtemp(prefix=prefix)
3034 dirname = tempfile.mkdtemp(prefix=prefix)
3036 self.tempdirs.append(dirname)
3035 self.tempdirs.append(dirname)
3037
3036
3038 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3037 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3039 self.tempfiles.append(filename)
3038 self.tempfiles.append(filename)
3040
3039
3041 if data:
3040 if data:
3042 tmp_file = open(filename,'w')
3041 tmp_file = open(filename,'w')
3043 tmp_file.write(data)
3042 tmp_file.write(data)
3044 tmp_file.close()
3043 tmp_file.close()
3045 return filename
3044 return filename
3046
3045
3047 # TODO: This should be removed when Term is refactored.
3046 # TODO: This should be removed when Term is refactored.
3048 def write(self,data):
3047 def write(self,data):
3049 """Write a string to the default output"""
3048 """Write a string to the default output"""
3050 io.stdout.write(data)
3049 io.stdout.write(data)
3051
3050
3052 # TODO: This should be removed when Term is refactored.
3051 # TODO: This should be removed when Term is refactored.
3053 def write_err(self,data):
3052 def write_err(self,data):
3054 """Write a string to the default error output"""
3053 """Write a string to the default error output"""
3055 io.stderr.write(data)
3054 io.stderr.write(data)
3056
3055
3057 def ask_yes_no(self, prompt, default=None):
3056 def ask_yes_no(self, prompt, default=None):
3058 if self.quiet:
3057 if self.quiet:
3059 return True
3058 return True
3060 return ask_yes_no(prompt,default)
3059 return ask_yes_no(prompt,default)
3061
3060
3062 def show_usage(self):
3061 def show_usage(self):
3063 """Show a usage message"""
3062 """Show a usage message"""
3064 page.page(IPython.core.usage.interactive_usage)
3063 page.page(IPython.core.usage.interactive_usage)
3065
3064
3066 def extract_input_lines(self, range_str, raw=False):
3065 def extract_input_lines(self, range_str, raw=False):
3067 """Return as a string a set of input history slices.
3066 """Return as a string a set of input history slices.
3068
3067
3069 Parameters
3068 Parameters
3070 ----------
3069 ----------
3071 range_str : string
3070 range_str : string
3072 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3071 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3073 since this function is for use by magic functions which get their
3072 since this function is for use by magic functions which get their
3074 arguments as strings. The number before the / is the session
3073 arguments as strings. The number before the / is the session
3075 number: ~n goes n back from the current session.
3074 number: ~n goes n back from the current session.
3076
3075
3077 raw : bool, optional
3076 raw : bool, optional
3078 By default, the processed input is used. If this is true, the raw
3077 By default, the processed input is used. If this is true, the raw
3079 input history is used instead.
3078 input history is used instead.
3080
3079
3081 Notes
3080 Notes
3082 -----
3081 -----
3083
3082
3084 Slices can be described with two notations:
3083 Slices can be described with two notations:
3085
3084
3086 * ``N:M`` -> standard python form, means including items N...(M-1).
3085 * ``N:M`` -> standard python form, means including items N...(M-1).
3087 * ``N-M`` -> include items N..M (closed endpoint).
3086 * ``N-M`` -> include items N..M (closed endpoint).
3088 """
3087 """
3089 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3088 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3090 return "\n".join(x for _, _, x in lines)
3089 return "\n".join(x for _, _, x in lines)
3091
3090
3092 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3091 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3093 """Get a code string from history, file, url, or a string or macro.
3092 """Get a code string from history, file, url, or a string or macro.
3094
3093
3095 This is mainly used by magic functions.
3094 This is mainly used by magic functions.
3096
3095
3097 Parameters
3096 Parameters
3098 ----------
3097 ----------
3099
3098
3100 target : str
3099 target : str
3101
3100
3102 A string specifying code to retrieve. This will be tried respectively
3101 A string specifying code to retrieve. This will be tried respectively
3103 as: ranges of input history (see %history for syntax), url,
3102 as: ranges of input history (see %history for syntax), url,
3104 correspnding .py file, filename, or an expression evaluating to a
3103 correspnding .py file, filename, or an expression evaluating to a
3105 string or Macro in the user namespace.
3104 string or Macro in the user namespace.
3106
3105
3107 raw : bool
3106 raw : bool
3108 If true (default), retrieve raw history. Has no effect on the other
3107 If true (default), retrieve raw history. Has no effect on the other
3109 retrieval mechanisms.
3108 retrieval mechanisms.
3110
3109
3111 py_only : bool (default False)
3110 py_only : bool (default False)
3112 Only try to fetch python code, do not try alternative methods to decode file
3111 Only try to fetch python code, do not try alternative methods to decode file
3113 if unicode fails.
3112 if unicode fails.
3114
3113
3115 Returns
3114 Returns
3116 -------
3115 -------
3117 A string of code.
3116 A string of code.
3118
3117
3119 ValueError is raised if nothing is found, and TypeError if it evaluates
3118 ValueError is raised if nothing is found, and TypeError if it evaluates
3120 to an object of another type. In each case, .args[0] is a printable
3119 to an object of another type. In each case, .args[0] is a printable
3121 message.
3120 message.
3122 """
3121 """
3123 code = self.extract_input_lines(target, raw=raw) # Grab history
3122 code = self.extract_input_lines(target, raw=raw) # Grab history
3124 if code:
3123 if code:
3125 return code
3124 return code
3126 utarget = unquote_filename(target)
3125 utarget = unquote_filename(target)
3127 try:
3126 try:
3128 if utarget.startswith(('http://', 'https://')):
3127 if utarget.startswith(('http://', 'https://')):
3129 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3128 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3130 except UnicodeDecodeError:
3129 except UnicodeDecodeError:
3131 if not py_only :
3130 if not py_only :
3132 # Deferred import
3131 # Deferred import
3133 try:
3132 try:
3134 from urllib.request import urlopen # Py3
3133 from urllib.request import urlopen # Py3
3135 except ImportError:
3134 except ImportError:
3136 from urllib import urlopen
3135 from urllib import urlopen
3137 response = urlopen(target)
3136 response = urlopen(target)
3138 return response.read().decode('latin1')
3137 return response.read().decode('latin1')
3139 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3138 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3140
3139
3141 potential_target = [target]
3140 potential_target = [target]
3142 try :
3141 try :
3143 potential_target.insert(0,get_py_filename(target))
3142 potential_target.insert(0,get_py_filename(target))
3144 except IOError:
3143 except IOError:
3145 pass
3144 pass
3146
3145
3147 for tgt in potential_target :
3146 for tgt in potential_target :
3148 if os.path.isfile(tgt): # Read file
3147 if os.path.isfile(tgt): # Read file
3149 try :
3148 try :
3150 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3149 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3151 except UnicodeDecodeError :
3150 except UnicodeDecodeError :
3152 if not py_only :
3151 if not py_only :
3153 with io_open(tgt,'r', encoding='latin1') as f :
3152 with io_open(tgt,'r', encoding='latin1') as f :
3154 return f.read()
3153 return f.read()
3155 raise ValueError(("'%s' seem to be unreadable.") % target)
3154 raise ValueError(("'%s' seem to be unreadable.") % target)
3156 elif os.path.isdir(os.path.expanduser(tgt)):
3155 elif os.path.isdir(os.path.expanduser(tgt)):
3157 raise ValueError("'%s' is a directory, not a regular file." % target)
3156 raise ValueError("'%s' is a directory, not a regular file." % target)
3158
3157
3159 if search_ns:
3158 if search_ns:
3160 # Inspect namespace to load object source
3159 # Inspect namespace to load object source
3161 object_info = self.object_inspect(target, detail_level=1)
3160 object_info = self.object_inspect(target, detail_level=1)
3162 if object_info['found'] and object_info['source']:
3161 if object_info['found'] and object_info['source']:
3163 return object_info['source']
3162 return object_info['source']
3164
3163
3165 try: # User namespace
3164 try: # User namespace
3166 codeobj = eval(target, self.user_ns)
3165 codeobj = eval(target, self.user_ns)
3167 except Exception:
3166 except Exception:
3168 raise ValueError(("'%s' was not found in history, as a file, url, "
3167 raise ValueError(("'%s' was not found in history, as a file, url, "
3169 "nor in the user namespace.") % target)
3168 "nor in the user namespace.") % target)
3170
3169
3171 if isinstance(codeobj, string_types):
3170 if isinstance(codeobj, string_types):
3172 return codeobj
3171 return codeobj
3173 elif isinstance(codeobj, Macro):
3172 elif isinstance(codeobj, Macro):
3174 return codeobj.value
3173 return codeobj.value
3175
3174
3176 raise TypeError("%s is neither a string nor a macro." % target,
3175 raise TypeError("%s is neither a string nor a macro." % target,
3177 codeobj)
3176 codeobj)
3178
3177
3179 #-------------------------------------------------------------------------
3178 #-------------------------------------------------------------------------
3180 # Things related to IPython exiting
3179 # Things related to IPython exiting
3181 #-------------------------------------------------------------------------
3180 #-------------------------------------------------------------------------
3182 def atexit_operations(self):
3181 def atexit_operations(self):
3183 """This will be executed at the time of exit.
3182 """This will be executed at the time of exit.
3184
3183
3185 Cleanup operations and saving of persistent data that is done
3184 Cleanup operations and saving of persistent data that is done
3186 unconditionally by IPython should be performed here.
3185 unconditionally by IPython should be performed here.
3187
3186
3188 For things that may depend on startup flags or platform specifics (such
3187 For things that may depend on startup flags or platform specifics (such
3189 as having readline or not), register a separate atexit function in the
3188 as having readline or not), register a separate atexit function in the
3190 code that has the appropriate information, rather than trying to
3189 code that has the appropriate information, rather than trying to
3191 clutter
3190 clutter
3192 """
3191 """
3193 # Close the history session (this stores the end time and line count)
3192 # Close the history session (this stores the end time and line count)
3194 # this must be *before* the tempfile cleanup, in case of temporary
3193 # this must be *before* the tempfile cleanup, in case of temporary
3195 # history db
3194 # history db
3196 self.history_manager.end_session()
3195 self.history_manager.end_session()
3197
3196
3198 # Cleanup all tempfiles and folders left around
3197 # Cleanup all tempfiles and folders left around
3199 for tfile in self.tempfiles:
3198 for tfile in self.tempfiles:
3200 try:
3199 try:
3201 os.unlink(tfile)
3200 os.unlink(tfile)
3202 except OSError:
3201 except OSError:
3203 pass
3202 pass
3204
3203
3205 for tdir in self.tempdirs:
3204 for tdir in self.tempdirs:
3206 try:
3205 try:
3207 os.rmdir(tdir)
3206 os.rmdir(tdir)
3208 except OSError:
3207 except OSError:
3209 pass
3208 pass
3210
3209
3211 # Clear all user namespaces to release all references cleanly.
3210 # Clear all user namespaces to release all references cleanly.
3212 self.reset(new_session=False)
3211 self.reset(new_session=False)
3213
3212
3214 # Run user hooks
3213 # Run user hooks
3215 self.hooks.shutdown_hook()
3214 self.hooks.shutdown_hook()
3216
3215
3217 def cleanup(self):
3216 def cleanup(self):
3218 self.restore_sys_module_state()
3217 self.restore_sys_module_state()
3219
3218
3220
3219
3221 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3220 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3222 """An abstract base class for InteractiveShell."""
3221 """An abstract base class for InteractiveShell."""
3223
3222
3224 InteractiveShellABC.register(InteractiveShell)
3223 InteractiveShellABC.register(InteractiveShell)
@@ -1,281 +1,250 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """An object for managing IPython profile directories."""
3 An object for managing IPython profile directories.
4
5 Authors:
6
3
7 * Brian Granger
4 # Copyright (c) IPython Development Team.
8 * Fernando Perez
5 # Distributed under the terms of the Modified BSD License.
9 * Min RK
10
11 """
12
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2011 The IPython Development Team
15 #
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
19
20 #-----------------------------------------------------------------------------
21 # Imports
22 #-----------------------------------------------------------------------------
23
6
24 import os
7 import os
25 import shutil
8 import shutil
26 import errno
9 import errno
27 import time
10 import time
28
11
29 from IPython.config.configurable import LoggingConfigurable
12 from IPython.config.configurable import LoggingConfigurable
30 from IPython.utils.path import get_ipython_package_dir, expand_path
13 from IPython.utils.path import get_ipython_package_dir, expand_path, ensure_dir_exists
31 from IPython.utils import py3compat
14 from IPython.utils import py3compat
32 from IPython.utils.traitlets import Unicode, Bool
15 from IPython.utils.traitlets import Unicode, Bool
33
16
34 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
35 # Classes and functions
36 #-----------------------------------------------------------------------------
37
38
39 #-----------------------------------------------------------------------------
40 # Module errors
18 # Module errors
41 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
42
20
43 class ProfileDirError(Exception):
21 class ProfileDirError(Exception):
44 pass
22 pass
45
23
46
24
47 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
48 # Class for managing profile directories
26 # Class for managing profile directories
49 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
50
28
51 class ProfileDir(LoggingConfigurable):
29 class ProfileDir(LoggingConfigurable):
52 """An object to manage the profile directory and its resources.
30 """An object to manage the profile directory and its resources.
53
31
54 The profile directory is used by all IPython applications, to manage
32 The profile directory is used by all IPython applications, to manage
55 configuration, logging and security.
33 configuration, logging and security.
56
34
57 This object knows how to find, create and manage these directories. This
35 This object knows how to find, create and manage these directories. This
58 should be used by any code that wants to handle profiles.
36 should be used by any code that wants to handle profiles.
59 """
37 """
60
38
61 security_dir_name = Unicode('security')
39 security_dir_name = Unicode('security')
62 log_dir_name = Unicode('log')
40 log_dir_name = Unicode('log')
63 startup_dir_name = Unicode('startup')
41 startup_dir_name = Unicode('startup')
64 pid_dir_name = Unicode('pid')
42 pid_dir_name = Unicode('pid')
65 static_dir_name = Unicode('static')
43 static_dir_name = Unicode('static')
66 security_dir = Unicode(u'')
44 security_dir = Unicode(u'')
67 log_dir = Unicode(u'')
45 log_dir = Unicode(u'')
68 startup_dir = Unicode(u'')
46 startup_dir = Unicode(u'')
69 pid_dir = Unicode(u'')
47 pid_dir = Unicode(u'')
70 static_dir = Unicode(u'')
48 static_dir = Unicode(u'')
71
49
72 location = Unicode(u'', config=True,
50 location = Unicode(u'', config=True,
73 help="""Set the profile location directly. This overrides the logic used by the
51 help="""Set the profile location directly. This overrides the logic used by the
74 `profile` option.""",
52 `profile` option.""",
75 )
53 )
76
54
77 _location_isset = Bool(False) # flag for detecting multiply set location
55 _location_isset = Bool(False) # flag for detecting multiply set location
78
56
79 def _location_changed(self, name, old, new):
57 def _location_changed(self, name, old, new):
80 if self._location_isset:
58 if self._location_isset:
81 raise RuntimeError("Cannot set profile location more than once.")
59 raise RuntimeError("Cannot set profile location more than once.")
82 self._location_isset = True
60 self._location_isset = True
83 num_tries = 0
61 ensure_dir_exists(new)
84 max_tries = 5
85 while not os.path.isdir(new):
86 try:
87 os.makedirs(new)
88 except OSError:
89 if num_tries > max_tries:
90 raise
91 num_tries += 1
92 time.sleep(0.5)
93
62
94 # ensure config files exist:
63 # ensure config files exist:
95 self.security_dir = os.path.join(new, self.security_dir_name)
64 self.security_dir = os.path.join(new, self.security_dir_name)
96 self.log_dir = os.path.join(new, self.log_dir_name)
65 self.log_dir = os.path.join(new, self.log_dir_name)
97 self.startup_dir = os.path.join(new, self.startup_dir_name)
66 self.startup_dir = os.path.join(new, self.startup_dir_name)
98 self.pid_dir = os.path.join(new, self.pid_dir_name)
67 self.pid_dir = os.path.join(new, self.pid_dir_name)
99 self.static_dir = os.path.join(new, self.static_dir_name)
68 self.static_dir = os.path.join(new, self.static_dir_name)
100 self.check_dirs()
69 self.check_dirs()
101
70
102 def _log_dir_changed(self, name, old, new):
71 def _log_dir_changed(self, name, old, new):
103 self.check_log_dir()
72 self.check_log_dir()
104
73
105 def _mkdir(self, path, mode=None):
74 def _mkdir(self, path, mode=None):
106 """ensure a directory exists at a given path
75 """ensure a directory exists at a given path
107
76
108 This is a version of os.mkdir, with the following differences:
77 This is a version of os.mkdir, with the following differences:
109
78
110 - returns True if it created the directory, False otherwise
79 - returns True if it created the directory, False otherwise
111 - ignores EEXIST, protecting against race conditions where
80 - ignores EEXIST, protecting against race conditions where
112 the dir may have been created in between the check and
81 the dir may have been created in between the check and
113 the creation
82 the creation
114 - sets permissions if requested and the dir already exists
83 - sets permissions if requested and the dir already exists
115 """
84 """
116 if os.path.exists(path):
85 if os.path.exists(path):
117 if mode and os.stat(path).st_mode != mode:
86 if mode and os.stat(path).st_mode != mode:
118 try:
87 try:
119 os.chmod(path, mode)
88 os.chmod(path, mode)
120 except OSError:
89 except OSError:
121 self.log.warn(
90 self.log.warn(
122 "Could not set permissions on %s",
91 "Could not set permissions on %s",
123 path
92 path
124 )
93 )
125 return False
94 return False
126 try:
95 try:
127 if mode:
96 if mode:
128 os.mkdir(path, mode)
97 os.mkdir(path, mode)
129 else:
98 else:
130 os.mkdir(path)
99 os.mkdir(path)
131 except OSError as e:
100 except OSError as e:
132 if e.errno == errno.EEXIST:
101 if e.errno == errno.EEXIST:
133 return False
102 return False
134 else:
103 else:
135 raise
104 raise
136
105
137 return True
106 return True
138
107
139 def check_log_dir(self):
108 def check_log_dir(self):
140 self._mkdir(self.log_dir)
109 self._mkdir(self.log_dir)
141
110
142 def _startup_dir_changed(self, name, old, new):
111 def _startup_dir_changed(self, name, old, new):
143 self.check_startup_dir()
112 self.check_startup_dir()
144
113
145 def check_startup_dir(self):
114 def check_startup_dir(self):
146 self._mkdir(self.startup_dir)
115 self._mkdir(self.startup_dir)
147
116
148 readme = os.path.join(self.startup_dir, 'README')
117 readme = os.path.join(self.startup_dir, 'README')
149 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
118 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
150
119
151 if not os.path.exists(src):
120 if not os.path.exists(src):
152 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
121 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
153
122
154 if os.path.exists(src) and not os.path.exists(readme):
123 if os.path.exists(src) and not os.path.exists(readme):
155 shutil.copy(src, readme)
124 shutil.copy(src, readme)
156
125
157 def _security_dir_changed(self, name, old, new):
126 def _security_dir_changed(self, name, old, new):
158 self.check_security_dir()
127 self.check_security_dir()
159
128
160 def check_security_dir(self):
129 def check_security_dir(self):
161 self._mkdir(self.security_dir, 0o40700)
130 self._mkdir(self.security_dir, 0o40700)
162
131
163 def _pid_dir_changed(self, name, old, new):
132 def _pid_dir_changed(self, name, old, new):
164 self.check_pid_dir()
133 self.check_pid_dir()
165
134
166 def check_pid_dir(self):
135 def check_pid_dir(self):
167 self._mkdir(self.pid_dir, 0o40700)
136 self._mkdir(self.pid_dir, 0o40700)
168
137
169 def _static_dir_changed(self, name, old, new):
138 def _static_dir_changed(self, name, old, new):
170 self.check_startup_dir()
139 self.check_startup_dir()
171
140
172 def check_static_dir(self):
141 def check_static_dir(self):
173 self._mkdir(self.static_dir)
142 self._mkdir(self.static_dir)
174 custom = os.path.join(self.static_dir, 'custom')
143 custom = os.path.join(self.static_dir, 'custom')
175 self._mkdir(custom)
144 self._mkdir(custom)
176 from IPython.html import DEFAULT_STATIC_FILES_PATH
145 from IPython.html import DEFAULT_STATIC_FILES_PATH
177 for fname in ('custom.js', 'custom.css'):
146 for fname in ('custom.js', 'custom.css'):
178 src = os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', fname)
147 src = os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', fname)
179 dest = os.path.join(custom, fname)
148 dest = os.path.join(custom, fname)
180 if not os.path.exists(src):
149 if not os.path.exists(src):
181 self.log.warn("Could not copy default file to static dir. Source file %s does not exist.", src)
150 self.log.warn("Could not copy default file to static dir. Source file %s does not exist.", src)
182 continue
151 continue
183 if not os.path.exists(dest):
152 if not os.path.exists(dest):
184 shutil.copy(src, dest)
153 shutil.copy(src, dest)
185
154
186 def check_dirs(self):
155 def check_dirs(self):
187 self.check_security_dir()
156 self.check_security_dir()
188 self.check_log_dir()
157 self.check_log_dir()
189 self.check_pid_dir()
158 self.check_pid_dir()
190 self.check_startup_dir()
159 self.check_startup_dir()
191 self.check_static_dir()
160 self.check_static_dir()
192
161
193 def copy_config_file(self, config_file, path=None, overwrite=False):
162 def copy_config_file(self, config_file, path=None, overwrite=False):
194 """Copy a default config file into the active profile directory.
163 """Copy a default config file into the active profile directory.
195
164
196 Default configuration files are kept in :mod:`IPython.config.default`.
165 Default configuration files are kept in :mod:`IPython.config.default`.
197 This function moves these from that location to the working profile
166 This function moves these from that location to the working profile
198 directory.
167 directory.
199 """
168 """
200 dst = os.path.join(self.location, config_file)
169 dst = os.path.join(self.location, config_file)
201 if os.path.isfile(dst) and not overwrite:
170 if os.path.isfile(dst) and not overwrite:
202 return False
171 return False
203 if path is None:
172 if path is None:
204 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
173 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
205 src = os.path.join(path, config_file)
174 src = os.path.join(path, config_file)
206 shutil.copy(src, dst)
175 shutil.copy(src, dst)
207 return True
176 return True
208
177
209 @classmethod
178 @classmethod
210 def create_profile_dir(cls, profile_dir, config=None):
179 def create_profile_dir(cls, profile_dir, config=None):
211 """Create a new profile directory given a full path.
180 """Create a new profile directory given a full path.
212
181
213 Parameters
182 Parameters
214 ----------
183 ----------
215 profile_dir : str
184 profile_dir : str
216 The full path to the profile directory. If it does exist, it will
185 The full path to the profile directory. If it does exist, it will
217 be used. If not, it will be created.
186 be used. If not, it will be created.
218 """
187 """
219 return cls(location=profile_dir, config=config)
188 return cls(location=profile_dir, config=config)
220
189
221 @classmethod
190 @classmethod
222 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
191 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
223 """Create a profile dir by profile name and path.
192 """Create a profile dir by profile name and path.
224
193
225 Parameters
194 Parameters
226 ----------
195 ----------
227 path : unicode
196 path : unicode
228 The path (directory) to put the profile directory in.
197 The path (directory) to put the profile directory in.
229 name : unicode
198 name : unicode
230 The name of the profile. The name of the profile directory will
199 The name of the profile. The name of the profile directory will
231 be "profile_<profile>".
200 be "profile_<profile>".
232 """
201 """
233 if not os.path.isdir(path):
202 if not os.path.isdir(path):
234 raise ProfileDirError('Directory not found: %s' % path)
203 raise ProfileDirError('Directory not found: %s' % path)
235 profile_dir = os.path.join(path, u'profile_' + name)
204 profile_dir = os.path.join(path, u'profile_' + name)
236 return cls(location=profile_dir, config=config)
205 return cls(location=profile_dir, config=config)
237
206
238 @classmethod
207 @classmethod
239 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
208 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
240 """Find an existing profile dir by profile name, return its ProfileDir.
209 """Find an existing profile dir by profile name, return its ProfileDir.
241
210
242 This searches through a sequence of paths for a profile dir. If it
211 This searches through a sequence of paths for a profile dir. If it
243 is not found, a :class:`ProfileDirError` exception will be raised.
212 is not found, a :class:`ProfileDirError` exception will be raised.
244
213
245 The search path algorithm is:
214 The search path algorithm is:
246 1. ``py3compat.getcwd()``
215 1. ``py3compat.getcwd()``
247 2. ``ipython_dir``
216 2. ``ipython_dir``
248
217
249 Parameters
218 Parameters
250 ----------
219 ----------
251 ipython_dir : unicode or str
220 ipython_dir : unicode or str
252 The IPython directory to use.
221 The IPython directory to use.
253 name : unicode or str
222 name : unicode or str
254 The name of the profile. The name of the profile directory
223 The name of the profile. The name of the profile directory
255 will be "profile_<profile>".
224 will be "profile_<profile>".
256 """
225 """
257 dirname = u'profile_' + name
226 dirname = u'profile_' + name
258 paths = [py3compat.getcwd(), ipython_dir]
227 paths = [py3compat.getcwd(), ipython_dir]
259 for p in paths:
228 for p in paths:
260 profile_dir = os.path.join(p, dirname)
229 profile_dir = os.path.join(p, dirname)
261 if os.path.isdir(profile_dir):
230 if os.path.isdir(profile_dir):
262 return cls(location=profile_dir, config=config)
231 return cls(location=profile_dir, config=config)
263 else:
232 else:
264 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
233 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
265
234
266 @classmethod
235 @classmethod
267 def find_profile_dir(cls, profile_dir, config=None):
236 def find_profile_dir(cls, profile_dir, config=None):
268 """Find/create a profile dir and return its ProfileDir.
237 """Find/create a profile dir and return its ProfileDir.
269
238
270 This will create the profile directory if it doesn't exist.
239 This will create the profile directory if it doesn't exist.
271
240
272 Parameters
241 Parameters
273 ----------
242 ----------
274 profile_dir : unicode or str
243 profile_dir : unicode or str
275 The path of the profile directory. This is expanded using
244 The path of the profile directory. This is expanded using
276 :func:`IPython.utils.genutils.expand_path`.
245 :func:`IPython.utils.genutils.expand_path`.
277 """
246 """
278 profile_dir = expand_path(profile_dir)
247 profile_dir = expand_path(profile_dir)
279 if not os.path.isdir(profile_dir):
248 if not os.path.isdir(profile_dir):
280 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
249 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
281 return cls(location=profile_dir, config=config)
250 return cls(location=profile_dir, config=config)
@@ -1,268 +1,263 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Utilities for installing Javascript extensions for the notebook"""
2 """Utilities for installing Javascript extensions for the notebook"""
3
3
4 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Copyright (C) 2014 The IPython Development Team
5 # Distributed under the terms of the Modified BSD License.
6 #
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
10
6
11 from __future__ import print_function
7 from __future__ import print_function
12
8
13 import os
9 import os
14 import shutil
10 import shutil
15 import tarfile
11 import tarfile
16 import zipfile
12 import zipfile
17 from os.path import basename, join as pjoin
13 from os.path import basename, join as pjoin
18
14
19 # Deferred imports
15 # Deferred imports
20 try:
16 try:
21 from urllib.parse import urlparse # Py3
17 from urllib.parse import urlparse # Py3
22 from urllib.request import urlretrieve
18 from urllib.request import urlretrieve
23 except ImportError:
19 except ImportError:
24 from urlparse import urlparse
20 from urlparse import urlparse
25 from urllib import urlretrieve
21 from urllib import urlretrieve
26
22
27 from IPython.utils.path import get_ipython_dir
23 from IPython.utils.path import get_ipython_dir, ensure_dir_exists
28 from IPython.utils.py3compat import string_types, cast_unicode_py2
24 from IPython.utils.py3compat import string_types, cast_unicode_py2
29 from IPython.utils.tempdir import TemporaryDirectory
25 from IPython.utils.tempdir import TemporaryDirectory
30
26
31
27
32 def _should_copy(src, dest, verbose=1):
28 def _should_copy(src, dest, verbose=1):
33 """should a file be copied?"""
29 """should a file be copied?"""
34 if not os.path.exists(dest):
30 if not os.path.exists(dest):
35 return True
31 return True
36 if os.stat(dest).st_mtime < os.stat(src).st_mtime:
32 if os.stat(dest).st_mtime < os.stat(src).st_mtime:
37 if verbose >= 2:
33 if verbose >= 2:
38 print("%s is out of date" % dest)
34 print("%s is out of date" % dest)
39 return True
35 return True
40 if verbose >= 2:
36 if verbose >= 2:
41 print("%s is up to date" % dest)
37 print("%s is up to date" % dest)
42 return False
38 return False
43
39
44
40
45 def _maybe_copy(src, dest, verbose=1):
41 def _maybe_copy(src, dest, verbose=1):
46 """copy a file if it needs updating"""
42 """copy a file if it needs updating"""
47 if _should_copy(src, dest, verbose):
43 if _should_copy(src, dest, verbose):
48 if verbose >= 1:
44 if verbose >= 1:
49 print("copying %s -> %s" % (src, dest))
45 print("copying %s -> %s" % (src, dest))
50 shutil.copy2(src, dest)
46 shutil.copy2(src, dest)
51
47
52
48
53 def _safe_is_tarfile(path):
49 def _safe_is_tarfile(path):
54 """safe version of is_tarfile, return False on IOError"""
50 """safe version of is_tarfile, return False on IOError"""
55 try:
51 try:
56 return tarfile.is_tarfile(path)
52 return tarfile.is_tarfile(path)
57 except IOError:
53 except IOError:
58 return False
54 return False
59
55
60
56
61 def check_nbextension(files, ipython_dir=None):
57 def check_nbextension(files, ipython_dir=None):
62 """Check whether nbextension files have been installed
58 """Check whether nbextension files have been installed
63
59
64 files should be a list of relative paths within nbextensions.
60 files should be a list of relative paths within nbextensions.
65
61
66 Returns True if all files are found, False if any are missing.
62 Returns True if all files are found, False if any are missing.
67 """
63 """
68 ipython_dir = ipython_dir or get_ipython_dir()
64 ipython_dir = ipython_dir or get_ipython_dir()
69 nbext = pjoin(ipython_dir, u'nbextensions')
65 nbext = pjoin(ipython_dir, u'nbextensions')
70 # make sure nbextensions dir exists
66 # make sure nbextensions dir exists
71 if not os.path.exists(nbext):
67 if not os.path.exists(nbext):
72 return False
68 return False
73
69
74 if isinstance(files, string_types):
70 if isinstance(files, string_types):
75 # one file given, turn it into a list
71 # one file given, turn it into a list
76 files = [files]
72 files = [files]
77
73
78 return all(os.path.exists(pjoin(nbext, f)) for f in files)
74 return all(os.path.exists(pjoin(nbext, f)) for f in files)
79
75
80
76
81 def install_nbextension(files, overwrite=False, symlink=False, ipython_dir=None, verbose=1):
77 def install_nbextension(files, overwrite=False, symlink=False, ipython_dir=None, verbose=1):
82 """Install a Javascript extension for the notebook
78 """Install a Javascript extension for the notebook
83
79
84 Stages files and/or directories into IPYTHONDIR/nbextensions.
80 Stages files and/or directories into IPYTHONDIR/nbextensions.
85 By default, this compares modification time, and only stages files that need updating.
81 By default, this compares modification time, and only stages files that need updating.
86 If `overwrite` is specified, matching files are purged before proceeding.
82 If `overwrite` is specified, matching files are purged before proceeding.
87
83
88 Parameters
84 Parameters
89 ----------
85 ----------
90
86
91 files : list(paths or URLs)
87 files : list(paths or URLs)
92 One or more paths or URLs to existing files directories to install.
88 One or more paths or URLs to existing files directories to install.
93 These will be installed with their base name, so '/path/to/foo'
89 These will be installed with their base name, so '/path/to/foo'
94 will install to 'nbextensions/foo'.
90 will install to 'nbextensions/foo'.
95 Archives (zip or tarballs) will be extracted into the nbextensions directory.
91 Archives (zip or tarballs) will be extracted into the nbextensions directory.
96 overwrite : bool [default: False]
92 overwrite : bool [default: False]
97 If True, always install the files, regardless of what may already be installed.
93 If True, always install the files, regardless of what may already be installed.
98 symlink : bool [default: False]
94 symlink : bool [default: False]
99 If True, create a symlink in nbextensions, rather than copying files.
95 If True, create a symlink in nbextensions, rather than copying files.
100 Not allowed with URLs or archives.
96 Not allowed with URLs or archives.
101 ipython_dir : str [optional]
97 ipython_dir : str [optional]
102 The path to an IPython directory, if the default value is not desired.
98 The path to an IPython directory, if the default value is not desired.
103 get_ipython_dir() is used by default.
99 get_ipython_dir() is used by default.
104 verbose : int [default: 1]
100 verbose : int [default: 1]
105 Set verbosity level. The default is 1, where file actions are printed.
101 Set verbosity level. The default is 1, where file actions are printed.
106 set verbose=2 for more output, or verbose=0 for silence.
102 set verbose=2 for more output, or verbose=0 for silence.
107 """
103 """
108
104
109 ipython_dir = ipython_dir or get_ipython_dir()
105 ipython_dir = ipython_dir or get_ipython_dir()
110 nbext = pjoin(ipython_dir, u'nbextensions')
106 nbext = pjoin(ipython_dir, u'nbextensions')
111 # make sure nbextensions dir exists
107 # make sure nbextensions dir exists
112 if not os.path.exists(nbext):
108 ensure_dir_exists(nbext)
113 os.makedirs(nbext)
114
109
115 if isinstance(files, string_types):
110 if isinstance(files, string_types):
116 # one file given, turn it into a list
111 # one file given, turn it into a list
117 files = [files]
112 files = [files]
118
113
119 for path in map(cast_unicode_py2, files):
114 for path in map(cast_unicode_py2, files):
120
115
121 if path.startswith(('https://', 'http://')):
116 if path.startswith(('https://', 'http://')):
122 if symlink:
117 if symlink:
123 raise ValueError("Cannot symlink from URLs")
118 raise ValueError("Cannot symlink from URLs")
124 # Given a URL, download it
119 # Given a URL, download it
125 with TemporaryDirectory() as td:
120 with TemporaryDirectory() as td:
126 filename = urlparse(path).path.split('/')[-1]
121 filename = urlparse(path).path.split('/')[-1]
127 local_path = os.path.join(td, filename)
122 local_path = os.path.join(td, filename)
128 if verbose >= 1:
123 if verbose >= 1:
129 print("downloading %s to %s" % (path, local_path))
124 print("downloading %s to %s" % (path, local_path))
130 urlretrieve(path, local_path)
125 urlretrieve(path, local_path)
131 # now install from the local copy
126 # now install from the local copy
132 install_nbextension(local_path, overwrite, symlink, ipython_dir, verbose)
127 install_nbextension(local_path, overwrite, symlink, ipython_dir, verbose)
133 continue
128 continue
134
129
135 # handle archives
130 # handle archives
136 archive = None
131 archive = None
137 if path.endswith('.zip'):
132 if path.endswith('.zip'):
138 archive = zipfile.ZipFile(path)
133 archive = zipfile.ZipFile(path)
139 elif _safe_is_tarfile(path):
134 elif _safe_is_tarfile(path):
140 archive = tarfile.open(path)
135 archive = tarfile.open(path)
141
136
142 if archive:
137 if archive:
143 if symlink:
138 if symlink:
144 raise ValueError("Cannot symlink from archives")
139 raise ValueError("Cannot symlink from archives")
145 if verbose >= 1:
140 if verbose >= 1:
146 print("extracting %s to %s" % (path, nbext))
141 print("extracting %s to %s" % (path, nbext))
147 archive.extractall(nbext)
142 archive.extractall(nbext)
148 archive.close()
143 archive.close()
149 continue
144 continue
150
145
151 dest = pjoin(nbext, basename(path))
146 dest = pjoin(nbext, basename(path))
152 if overwrite and os.path.exists(dest):
147 if overwrite and os.path.exists(dest):
153 if verbose >= 1:
148 if verbose >= 1:
154 print("removing %s" % dest)
149 print("removing %s" % dest)
155 if os.path.isdir(dest):
150 if os.path.isdir(dest):
156 shutil.rmtree(dest)
151 shutil.rmtree(dest)
157 else:
152 else:
158 os.remove(dest)
153 os.remove(dest)
159
154
160 if symlink:
155 if symlink:
161 path = os.path.abspath(path)
156 path = os.path.abspath(path)
162 if not os.path.exists(dest):
157 if not os.path.exists(dest):
163 if verbose >= 1:
158 if verbose >= 1:
164 print("symlink %s -> %s" % (dest, path))
159 print("symlink %s -> %s" % (dest, path))
165 os.symlink(path, dest)
160 os.symlink(path, dest)
166 continue
161 continue
167
162
168 if os.path.isdir(path):
163 if os.path.isdir(path):
169 strip_prefix_len = len(path) - len(basename(path))
164 strip_prefix_len = len(path) - len(basename(path))
170 for parent, dirs, files in os.walk(path):
165 for parent, dirs, files in os.walk(path):
171 dest_dir = pjoin(nbext, parent[strip_prefix_len:])
166 dest_dir = pjoin(nbext, parent[strip_prefix_len:])
172 if not os.path.exists(dest_dir):
167 if not os.path.exists(dest_dir):
173 if verbose >= 2:
168 if verbose >= 2:
174 print("making directory %s" % dest_dir)
169 print("making directory %s" % dest_dir)
175 os.makedirs(dest_dir)
170 os.makedirs(dest_dir)
176 for file in files:
171 for file in files:
177 src = pjoin(parent, file)
172 src = pjoin(parent, file)
178 # print("%r, %r" % (dest_dir, file))
173 # print("%r, %r" % (dest_dir, file))
179 dest = pjoin(dest_dir, file)
174 dest = pjoin(dest_dir, file)
180 _maybe_copy(src, dest, verbose)
175 _maybe_copy(src, dest, verbose)
181 else:
176 else:
182 src = path
177 src = path
183 _maybe_copy(src, dest, verbose)
178 _maybe_copy(src, dest, verbose)
184
179
185 #----------------------------------------------------------------------
180 #----------------------------------------------------------------------
186 # install nbextension app
181 # install nbextension app
187 #----------------------------------------------------------------------
182 #----------------------------------------------------------------------
188
183
189 from IPython.utils.traitlets import Bool, Enum
184 from IPython.utils.traitlets import Bool, Enum
190 from IPython.core.application import BaseIPythonApplication
185 from IPython.core.application import BaseIPythonApplication
191
186
192 flags = {
187 flags = {
193 "overwrite" : ({
188 "overwrite" : ({
194 "NBExtensionApp" : {
189 "NBExtensionApp" : {
195 "overwrite" : True,
190 "overwrite" : True,
196 }}, "Force overwrite of existing files"
191 }}, "Force overwrite of existing files"
197 ),
192 ),
198 "debug" : ({
193 "debug" : ({
199 "NBExtensionApp" : {
194 "NBExtensionApp" : {
200 "verbose" : 2,
195 "verbose" : 2,
201 }}, "Extra output"
196 }}, "Extra output"
202 ),
197 ),
203 "quiet" : ({
198 "quiet" : ({
204 "NBExtensionApp" : {
199 "NBExtensionApp" : {
205 "verbose" : 0,
200 "verbose" : 0,
206 }}, "Minimal output"
201 }}, "Minimal output"
207 ),
202 ),
208 "symlink" : ({
203 "symlink" : ({
209 "NBExtensionApp" : {
204 "NBExtensionApp" : {
210 "symlink" : True,
205 "symlink" : True,
211 }}, "Create symlinks instead of copying files"
206 }}, "Create symlinks instead of copying files"
212 ),
207 ),
213 }
208 }
214 flags['s'] = flags['symlink']
209 flags['s'] = flags['symlink']
215
210
216 aliases = {
211 aliases = {
217 "ipython-dir" : "NBExtensionApp.ipython_dir"
212 "ipython-dir" : "NBExtensionApp.ipython_dir"
218 }
213 }
219
214
220 class NBExtensionApp(BaseIPythonApplication):
215 class NBExtensionApp(BaseIPythonApplication):
221 """Entry point for installing notebook extensions"""
216 """Entry point for installing notebook extensions"""
222
217
223 description = """Install IPython notebook extensions
218 description = """Install IPython notebook extensions
224
219
225 Usage
220 Usage
226
221
227 ipython install-nbextension file [more files, folders, archives or urls]
222 ipython install-nbextension file [more files, folders, archives or urls]
228
223
229 This copies files and/or folders into the IPython nbextensions directory.
224 This copies files and/or folders into the IPython nbextensions directory.
230 If a URL is given, it will be downloaded.
225 If a URL is given, it will be downloaded.
231 If an archive is given, it will be extracted into nbextensions.
226 If an archive is given, it will be extracted into nbextensions.
232 If the requested files are already up to date, no action is taken
227 If the requested files are already up to date, no action is taken
233 unless --overwrite is specified.
228 unless --overwrite is specified.
234 """
229 """
235
230
236 examples = """
231 examples = """
237 ipython install-nbextension /path/to/d3.js /path/to/myextension
232 ipython install-nbextension /path/to/d3.js /path/to/myextension
238 """
233 """
239 aliases = aliases
234 aliases = aliases
240 flags = flags
235 flags = flags
241
236
242 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
237 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
243 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
238 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
244 verbose = Enum((0,1,2), default_value=1, config=True,
239 verbose = Enum((0,1,2), default_value=1, config=True,
245 help="Verbosity level"
240 help="Verbosity level"
246 )
241 )
247
242
248 def install_extensions(self):
243 def install_extensions(self):
249 install_nbextension(self.extra_args,
244 install_nbextension(self.extra_args,
250 overwrite=self.overwrite,
245 overwrite=self.overwrite,
251 symlink=self.symlink,
246 symlink=self.symlink,
252 verbose=self.verbose,
247 verbose=self.verbose,
253 ipython_dir=self.ipython_dir,
248 ipython_dir=self.ipython_dir,
254 )
249 )
255
250
256 def start(self):
251 def start(self):
257 if not self.extra_args:
252 if not self.extra_args:
258 nbext = pjoin(self.ipython_dir, u'nbextensions')
253 nbext = pjoin(self.ipython_dir, u'nbextensions')
259 print("Notebook extensions in %s:" % nbext)
254 print("Notebook extensions in %s:" % nbext)
260 for ext in os.listdir(nbext):
255 for ext in os.listdir(nbext):
261 print(u" %s" % ext)
256 print(u" %s" % ext)
262 else:
257 else:
263 self.install_extensions()
258 self.install_extensions()
264
259
265
260
266 if __name__ == '__main__':
261 if __name__ == '__main__':
267 NBExtensionApp.launch_instance()
262 NBExtensionApp.launch_instance()
268 No newline at end of file
263
@@ -1,486 +1,470 b''
1 """A notebook manager that uses the local file system for storage.
1 """A notebook manager that uses the local file system for storage."""
2
2
3 Authors:
3 # Copyright (c) IPython Development Team.
4
4 # Distributed under the terms of the Modified BSD License.
5 * Brian Granger
6 * Zach Sailer
7 """
8
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
11 #
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
17 # Imports
18 #-----------------------------------------------------------------------------
19
5
20 import io
6 import io
21 import os
7 import os
22 import glob
8 import glob
23 import shutil
9 import shutil
24
10
25 from tornado import web
11 from tornado import web
26
12
27 from .nbmanager import NotebookManager
13 from .nbmanager import NotebookManager
28 from IPython.nbformat import current
14 from IPython.nbformat import current
15 from IPython.utils.path import ensure_dir_exists
29 from IPython.utils.traitlets import Unicode, Bool, TraitError
16 from IPython.utils.traitlets import Unicode, Bool, TraitError
30 from IPython.utils.py3compat import getcwd
17 from IPython.utils.py3compat import getcwd
31 from IPython.utils import tz
18 from IPython.utils import tz
32 from IPython.html.utils import is_hidden, to_os_path
19 from IPython.html.utils import is_hidden, to_os_path
33
20
34 def sort_key(item):
21 def sort_key(item):
35 """Case-insensitive sorting."""
22 """Case-insensitive sorting."""
36 return item['name'].lower()
23 return item['name'].lower()
37
24
38 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
39 # Classes
26 # Classes
40 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
41
28
42 class FileNotebookManager(NotebookManager):
29 class FileNotebookManager(NotebookManager):
43
30
44 save_script = Bool(False, config=True,
31 save_script = Bool(False, config=True,
45 help="""Automatically create a Python script when saving the notebook.
32 help="""Automatically create a Python script when saving the notebook.
46
33
47 For easier use of import, %run and %load across notebooks, a
34 For easier use of import, %run and %load across notebooks, a
48 <notebook-name>.py script will be created next to any
35 <notebook-name>.py script will be created next to any
49 <notebook-name>.ipynb on each save. This can also be set with the
36 <notebook-name>.ipynb on each save. This can also be set with the
50 short `--script` flag.
37 short `--script` flag.
51 """
38 """
52 )
39 )
53 notebook_dir = Unicode(getcwd(), config=True)
40 notebook_dir = Unicode(getcwd(), config=True)
54
41
55 def _notebook_dir_changed(self, name, old, new):
42 def _notebook_dir_changed(self, name, old, new):
56 """Do a bit of validation of the notebook dir."""
43 """Do a bit of validation of the notebook dir."""
57 if not os.path.isabs(new):
44 if not os.path.isabs(new):
58 # If we receive a non-absolute path, make it absolute.
45 # If we receive a non-absolute path, make it absolute.
59 self.notebook_dir = os.path.abspath(new)
46 self.notebook_dir = os.path.abspath(new)
60 return
47 return
61 if not os.path.exists(new) or not os.path.isdir(new):
48 if not os.path.exists(new) or not os.path.isdir(new):
62 raise TraitError("notebook dir %r is not a directory" % new)
49 raise TraitError("notebook dir %r is not a directory" % new)
63
50
64 checkpoint_dir = Unicode('.ipynb_checkpoints', config=True,
51 checkpoint_dir = Unicode('.ipynb_checkpoints', config=True,
65 help="""The directory name in which to keep notebook checkpoints
52 help="""The directory name in which to keep notebook checkpoints
66
53
67 This is a path relative to the notebook's own directory.
54 This is a path relative to the notebook's own directory.
68
55
69 By default, it is .ipynb_checkpoints
56 By default, it is .ipynb_checkpoints
70 """
57 """
71 )
58 )
72
59
73 def _copy(self, src, dest):
60 def _copy(self, src, dest):
74 """copy src to dest
61 """copy src to dest
75
62
76 like shutil.copy2, but log errors in copystat
63 like shutil.copy2, but log errors in copystat
77 """
64 """
78 shutil.copyfile(src, dest)
65 shutil.copyfile(src, dest)
79 try:
66 try:
80 shutil.copystat(src, dest)
67 shutil.copystat(src, dest)
81 except OSError as e:
68 except OSError as e:
82 self.log.debug("copystat on %s failed", dest, exc_info=True)
69 self.log.debug("copystat on %s failed", dest, exc_info=True)
83
70
84 def get_notebook_names(self, path=''):
71 def get_notebook_names(self, path=''):
85 """List all notebook names in the notebook dir and path."""
72 """List all notebook names in the notebook dir and path."""
86 path = path.strip('/')
73 path = path.strip('/')
87 if not os.path.isdir(self._get_os_path(path=path)):
74 if not os.path.isdir(self._get_os_path(path=path)):
88 raise web.HTTPError(404, 'Directory not found: ' + path)
75 raise web.HTTPError(404, 'Directory not found: ' + path)
89 names = glob.glob(self._get_os_path('*'+self.filename_ext, path))
76 names = glob.glob(self._get_os_path('*'+self.filename_ext, path))
90 names = [os.path.basename(name)
77 names = [os.path.basename(name)
91 for name in names]
78 for name in names]
92 return names
79 return names
93
80
94 def path_exists(self, path):
81 def path_exists(self, path):
95 """Does the API-style path (directory) actually exist?
82 """Does the API-style path (directory) actually exist?
96
83
97 Parameters
84 Parameters
98 ----------
85 ----------
99 path : string
86 path : string
100 The path to check. This is an API path (`/` separated,
87 The path to check. This is an API path (`/` separated,
101 relative to base notebook-dir).
88 relative to base notebook-dir).
102
89
103 Returns
90 Returns
104 -------
91 -------
105 exists : bool
92 exists : bool
106 Whether the path is indeed a directory.
93 Whether the path is indeed a directory.
107 """
94 """
108 path = path.strip('/')
95 path = path.strip('/')
109 os_path = self._get_os_path(path=path)
96 os_path = self._get_os_path(path=path)
110 return os.path.isdir(os_path)
97 return os.path.isdir(os_path)
111
98
112 def is_hidden(self, path):
99 def is_hidden(self, path):
113 """Does the API style path correspond to a hidden directory or file?
100 """Does the API style path correspond to a hidden directory or file?
114
101
115 Parameters
102 Parameters
116 ----------
103 ----------
117 path : string
104 path : string
118 The path to check. This is an API path (`/` separated,
105 The path to check. This is an API path (`/` separated,
119 relative to base notebook-dir).
106 relative to base notebook-dir).
120
107
121 Returns
108 Returns
122 -------
109 -------
123 exists : bool
110 exists : bool
124 Whether the path is hidden.
111 Whether the path is hidden.
125
112
126 """
113 """
127 path = path.strip('/')
114 path = path.strip('/')
128 os_path = self._get_os_path(path=path)
115 os_path = self._get_os_path(path=path)
129 return is_hidden(os_path, self.notebook_dir)
116 return is_hidden(os_path, self.notebook_dir)
130
117
131 def _get_os_path(self, name=None, path=''):
118 def _get_os_path(self, name=None, path=''):
132 """Given a notebook name and a URL path, return its file system
119 """Given a notebook name and a URL path, return its file system
133 path.
120 path.
134
121
135 Parameters
122 Parameters
136 ----------
123 ----------
137 name : string
124 name : string
138 The name of a notebook file with the .ipynb extension
125 The name of a notebook file with the .ipynb extension
139 path : string
126 path : string
140 The relative URL path (with '/' as separator) to the named
127 The relative URL path (with '/' as separator) to the named
141 notebook.
128 notebook.
142
129
143 Returns
130 Returns
144 -------
131 -------
145 path : string
132 path : string
146 A file system path that combines notebook_dir (location where
133 A file system path that combines notebook_dir (location where
147 server started), the relative path, and the filename with the
134 server started), the relative path, and the filename with the
148 current operating system's url.
135 current operating system's url.
149 """
136 """
150 if name is not None:
137 if name is not None:
151 path = path + '/' + name
138 path = path + '/' + name
152 return to_os_path(path, self.notebook_dir)
139 return to_os_path(path, self.notebook_dir)
153
140
154 def notebook_exists(self, name, path=''):
141 def notebook_exists(self, name, path=''):
155 """Returns a True if the notebook exists. Else, returns False.
142 """Returns a True if the notebook exists. Else, returns False.
156
143
157 Parameters
144 Parameters
158 ----------
145 ----------
159 name : string
146 name : string
160 The name of the notebook you are checking.
147 The name of the notebook you are checking.
161 path : string
148 path : string
162 The relative path to the notebook (with '/' as separator)
149 The relative path to the notebook (with '/' as separator)
163
150
164 Returns
151 Returns
165 -------
152 -------
166 bool
153 bool
167 """
154 """
168 path = path.strip('/')
155 path = path.strip('/')
169 nbpath = self._get_os_path(name, path=path)
156 nbpath = self._get_os_path(name, path=path)
170 return os.path.isfile(nbpath)
157 return os.path.isfile(nbpath)
171
158
172 # TODO: Remove this after we create the contents web service and directories are
159 # TODO: Remove this after we create the contents web service and directories are
173 # no longer listed by the notebook web service.
160 # no longer listed by the notebook web service.
174 def list_dirs(self, path):
161 def list_dirs(self, path):
175 """List the directories for a given API style path."""
162 """List the directories for a given API style path."""
176 path = path.strip('/')
163 path = path.strip('/')
177 os_path = self._get_os_path('', path)
164 os_path = self._get_os_path('', path)
178 if not os.path.isdir(os_path):
165 if not os.path.isdir(os_path):
179 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
166 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
180 elif is_hidden(os_path, self.notebook_dir):
167 elif is_hidden(os_path, self.notebook_dir):
181 self.log.info("Refusing to serve hidden directory, via 404 Error")
168 self.log.info("Refusing to serve hidden directory, via 404 Error")
182 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
169 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
183 dir_names = os.listdir(os_path)
170 dir_names = os.listdir(os_path)
184 dirs = []
171 dirs = []
185 for name in dir_names:
172 for name in dir_names:
186 os_path = self._get_os_path(name, path)
173 os_path = self._get_os_path(name, path)
187 if os.path.isdir(os_path) and not is_hidden(os_path, self.notebook_dir)\
174 if os.path.isdir(os_path) and not is_hidden(os_path, self.notebook_dir)\
188 and self.should_list(name):
175 and self.should_list(name):
189 try:
176 try:
190 model = self.get_dir_model(name, path)
177 model = self.get_dir_model(name, path)
191 except IOError:
178 except IOError:
192 pass
179 pass
193 dirs.append(model)
180 dirs.append(model)
194 dirs = sorted(dirs, key=sort_key)
181 dirs = sorted(dirs, key=sort_key)
195 return dirs
182 return dirs
196
183
197 # TODO: Remove this after we create the contents web service and directories are
184 # TODO: Remove this after we create the contents web service and directories are
198 # no longer listed by the notebook web service.
185 # no longer listed by the notebook web service.
199 def get_dir_model(self, name, path=''):
186 def get_dir_model(self, name, path=''):
200 """Get the directory model given a directory name and its API style path"""
187 """Get the directory model given a directory name and its API style path"""
201 path = path.strip('/')
188 path = path.strip('/')
202 os_path = self._get_os_path(name, path)
189 os_path = self._get_os_path(name, path)
203 if not os.path.isdir(os_path):
190 if not os.path.isdir(os_path):
204 raise IOError('directory does not exist: %r' % os_path)
191 raise IOError('directory does not exist: %r' % os_path)
205 info = os.stat(os_path)
192 info = os.stat(os_path)
206 last_modified = tz.utcfromtimestamp(info.st_mtime)
193 last_modified = tz.utcfromtimestamp(info.st_mtime)
207 created = tz.utcfromtimestamp(info.st_ctime)
194 created = tz.utcfromtimestamp(info.st_ctime)
208 # Create the notebook model.
195 # Create the notebook model.
209 model ={}
196 model ={}
210 model['name'] = name
197 model['name'] = name
211 model['path'] = path
198 model['path'] = path
212 model['last_modified'] = last_modified
199 model['last_modified'] = last_modified
213 model['created'] = created
200 model['created'] = created
214 model['type'] = 'directory'
201 model['type'] = 'directory'
215 return model
202 return model
216
203
217 def list_notebooks(self, path):
204 def list_notebooks(self, path):
218 """Returns a list of dictionaries that are the standard model
205 """Returns a list of dictionaries that are the standard model
219 for all notebooks in the relative 'path'.
206 for all notebooks in the relative 'path'.
220
207
221 Parameters
208 Parameters
222 ----------
209 ----------
223 path : str
210 path : str
224 the URL path that describes the relative path for the
211 the URL path that describes the relative path for the
225 listed notebooks
212 listed notebooks
226
213
227 Returns
214 Returns
228 -------
215 -------
229 notebooks : list of dicts
216 notebooks : list of dicts
230 a list of the notebook models without 'content'
217 a list of the notebook models without 'content'
231 """
218 """
232 path = path.strip('/')
219 path = path.strip('/')
233 notebook_names = self.get_notebook_names(path)
220 notebook_names = self.get_notebook_names(path)
234 notebooks = [self.get_notebook(name, path, content=False)
221 notebooks = [self.get_notebook(name, path, content=False)
235 for name in notebook_names if self.should_list(name)]
222 for name in notebook_names if self.should_list(name)]
236 notebooks = sorted(notebooks, key=sort_key)
223 notebooks = sorted(notebooks, key=sort_key)
237 return notebooks
224 return notebooks
238
225
239 def get_notebook(self, name, path='', content=True):
226 def get_notebook(self, name, path='', content=True):
240 """ Takes a path and name for a notebook and returns its model
227 """ Takes a path and name for a notebook and returns its model
241
228
242 Parameters
229 Parameters
243 ----------
230 ----------
244 name : str
231 name : str
245 the name of the notebook
232 the name of the notebook
246 path : str
233 path : str
247 the URL path that describes the relative path for
234 the URL path that describes the relative path for
248 the notebook
235 the notebook
249
236
250 Returns
237 Returns
251 -------
238 -------
252 model : dict
239 model : dict
253 the notebook model. If contents=True, returns the 'contents'
240 the notebook model. If contents=True, returns the 'contents'
254 dict in the model as well.
241 dict in the model as well.
255 """
242 """
256 path = path.strip('/')
243 path = path.strip('/')
257 if not self.notebook_exists(name=name, path=path):
244 if not self.notebook_exists(name=name, path=path):
258 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
245 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
259 os_path = self._get_os_path(name, path)
246 os_path = self._get_os_path(name, path)
260 info = os.stat(os_path)
247 info = os.stat(os_path)
261 last_modified = tz.utcfromtimestamp(info.st_mtime)
248 last_modified = tz.utcfromtimestamp(info.st_mtime)
262 created = tz.utcfromtimestamp(info.st_ctime)
249 created = tz.utcfromtimestamp(info.st_ctime)
263 # Create the notebook model.
250 # Create the notebook model.
264 model ={}
251 model ={}
265 model['name'] = name
252 model['name'] = name
266 model['path'] = path
253 model['path'] = path
267 model['last_modified'] = last_modified
254 model['last_modified'] = last_modified
268 model['created'] = created
255 model['created'] = created
269 model['type'] = 'notebook'
256 model['type'] = 'notebook'
270 if content:
257 if content:
271 with io.open(os_path, 'r', encoding='utf-8') as f:
258 with io.open(os_path, 'r', encoding='utf-8') as f:
272 try:
259 try:
273 nb = current.read(f, u'json')
260 nb = current.read(f, u'json')
274 except Exception as e:
261 except Exception as e:
275 raise web.HTTPError(400, u"Unreadable Notebook: %s %s" % (os_path, e))
262 raise web.HTTPError(400, u"Unreadable Notebook: %s %s" % (os_path, e))
276 self.mark_trusted_cells(nb, name, path)
263 self.mark_trusted_cells(nb, name, path)
277 model['content'] = nb
264 model['content'] = nb
278 return model
265 return model
279
266
280 def save_notebook(self, model, name='', path=''):
267 def save_notebook(self, model, name='', path=''):
281 """Save the notebook model and return the model with no content."""
268 """Save the notebook model and return the model with no content."""
282 path = path.strip('/')
269 path = path.strip('/')
283
270
284 if 'content' not in model:
271 if 'content' not in model:
285 raise web.HTTPError(400, u'No notebook JSON data provided')
272 raise web.HTTPError(400, u'No notebook JSON data provided')
286
273
287 # One checkpoint should always exist
274 # One checkpoint should always exist
288 if self.notebook_exists(name, path) and not self.list_checkpoints(name, path):
275 if self.notebook_exists(name, path) and not self.list_checkpoints(name, path):
289 self.create_checkpoint(name, path)
276 self.create_checkpoint(name, path)
290
277
291 new_path = model.get('path', path).strip('/')
278 new_path = model.get('path', path).strip('/')
292 new_name = model.get('name', name)
279 new_name = model.get('name', name)
293
280
294 if path != new_path or name != new_name:
281 if path != new_path or name != new_name:
295 self.rename_notebook(name, path, new_name, new_path)
282 self.rename_notebook(name, path, new_name, new_path)
296
283
297 # Save the notebook file
284 # Save the notebook file
298 os_path = self._get_os_path(new_name, new_path)
285 os_path = self._get_os_path(new_name, new_path)
299 nb = current.to_notebook_json(model['content'])
286 nb = current.to_notebook_json(model['content'])
300
287
301 self.check_and_sign(nb, new_name, new_path)
288 self.check_and_sign(nb, new_name, new_path)
302
289
303 if 'name' in nb['metadata']:
290 if 'name' in nb['metadata']:
304 nb['metadata']['name'] = u''
291 nb['metadata']['name'] = u''
305 try:
292 try:
306 self.log.debug("Autosaving notebook %s", os_path)
293 self.log.debug("Autosaving notebook %s", os_path)
307 with io.open(os_path, 'w', encoding='utf-8') as f:
294 with io.open(os_path, 'w', encoding='utf-8') as f:
308 current.write(nb, f, u'json')
295 current.write(nb, f, u'json')
309 except Exception as e:
296 except Exception as e:
310 raise web.HTTPError(400, u'Unexpected error while autosaving notebook: %s %s' % (os_path, e))
297 raise web.HTTPError(400, u'Unexpected error while autosaving notebook: %s %s' % (os_path, e))
311
298
312 # Save .py script as well
299 # Save .py script as well
313 if self.save_script:
300 if self.save_script:
314 py_path = os.path.splitext(os_path)[0] + '.py'
301 py_path = os.path.splitext(os_path)[0] + '.py'
315 self.log.debug("Writing script %s", py_path)
302 self.log.debug("Writing script %s", py_path)
316 try:
303 try:
317 with io.open(py_path, 'w', encoding='utf-8') as f:
304 with io.open(py_path, 'w', encoding='utf-8') as f:
318 current.write(nb, f, u'py')
305 current.write(nb, f, u'py')
319 except Exception as e:
306 except Exception as e:
320 raise web.HTTPError(400, u'Unexpected error while saving notebook as script: %s %s' % (py_path, e))
307 raise web.HTTPError(400, u'Unexpected error while saving notebook as script: %s %s' % (py_path, e))
321
308
322 model = self.get_notebook(new_name, new_path, content=False)
309 model = self.get_notebook(new_name, new_path, content=False)
323 return model
310 return model
324
311
325 def update_notebook(self, model, name, path=''):
312 def update_notebook(self, model, name, path=''):
326 """Update the notebook's path and/or name"""
313 """Update the notebook's path and/or name"""
327 path = path.strip('/')
314 path = path.strip('/')
328 new_name = model.get('name', name)
315 new_name = model.get('name', name)
329 new_path = model.get('path', path).strip('/')
316 new_path = model.get('path', path).strip('/')
330 if path != new_path or name != new_name:
317 if path != new_path or name != new_name:
331 self.rename_notebook(name, path, new_name, new_path)
318 self.rename_notebook(name, path, new_name, new_path)
332 model = self.get_notebook(new_name, new_path, content=False)
319 model = self.get_notebook(new_name, new_path, content=False)
333 return model
320 return model
334
321
335 def delete_notebook(self, name, path=''):
322 def delete_notebook(self, name, path=''):
336 """Delete notebook by name and path."""
323 """Delete notebook by name and path."""
337 path = path.strip('/')
324 path = path.strip('/')
338 os_path = self._get_os_path(name, path)
325 os_path = self._get_os_path(name, path)
339 if not os.path.isfile(os_path):
326 if not os.path.isfile(os_path):
340 raise web.HTTPError(404, u'Notebook does not exist: %s' % os_path)
327 raise web.HTTPError(404, u'Notebook does not exist: %s' % os_path)
341
328
342 # clear checkpoints
329 # clear checkpoints
343 for checkpoint in self.list_checkpoints(name, path):
330 for checkpoint in self.list_checkpoints(name, path):
344 checkpoint_id = checkpoint['id']
331 checkpoint_id = checkpoint['id']
345 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
332 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
346 if os.path.isfile(cp_path):
333 if os.path.isfile(cp_path):
347 self.log.debug("Unlinking checkpoint %s", cp_path)
334 self.log.debug("Unlinking checkpoint %s", cp_path)
348 os.unlink(cp_path)
335 os.unlink(cp_path)
349
336
350 self.log.debug("Unlinking notebook %s", os_path)
337 self.log.debug("Unlinking notebook %s", os_path)
351 os.unlink(os_path)
338 os.unlink(os_path)
352
339
353 def rename_notebook(self, old_name, old_path, new_name, new_path):
340 def rename_notebook(self, old_name, old_path, new_name, new_path):
354 """Rename a notebook."""
341 """Rename a notebook."""
355 old_path = old_path.strip('/')
342 old_path = old_path.strip('/')
356 new_path = new_path.strip('/')
343 new_path = new_path.strip('/')
357 if new_name == old_name and new_path == old_path:
344 if new_name == old_name and new_path == old_path:
358 return
345 return
359
346
360 new_os_path = self._get_os_path(new_name, new_path)
347 new_os_path = self._get_os_path(new_name, new_path)
361 old_os_path = self._get_os_path(old_name, old_path)
348 old_os_path = self._get_os_path(old_name, old_path)
362
349
363 # Should we proceed with the move?
350 # Should we proceed with the move?
364 if os.path.isfile(new_os_path):
351 if os.path.isfile(new_os_path):
365 raise web.HTTPError(409, u'Notebook with name already exists: %s' % new_os_path)
352 raise web.HTTPError(409, u'Notebook with name already exists: %s' % new_os_path)
366 if self.save_script:
353 if self.save_script:
367 old_py_path = os.path.splitext(old_os_path)[0] + '.py'
354 old_py_path = os.path.splitext(old_os_path)[0] + '.py'
368 new_py_path = os.path.splitext(new_os_path)[0] + '.py'
355 new_py_path = os.path.splitext(new_os_path)[0] + '.py'
369 if os.path.isfile(new_py_path):
356 if os.path.isfile(new_py_path):
370 raise web.HTTPError(409, u'Python script with name already exists: %s' % new_py_path)
357 raise web.HTTPError(409, u'Python script with name already exists: %s' % new_py_path)
371
358
372 # Move the notebook file
359 # Move the notebook file
373 try:
360 try:
374 shutil.move(old_os_path, new_os_path)
361 shutil.move(old_os_path, new_os_path)
375 except Exception as e:
362 except Exception as e:
376 raise web.HTTPError(500, u'Unknown error renaming notebook: %s %s' % (old_os_path, e))
363 raise web.HTTPError(500, u'Unknown error renaming notebook: %s %s' % (old_os_path, e))
377
364
378 # Move the checkpoints
365 # Move the checkpoints
379 old_checkpoints = self.list_checkpoints(old_name, old_path)
366 old_checkpoints = self.list_checkpoints(old_name, old_path)
380 for cp in old_checkpoints:
367 for cp in old_checkpoints:
381 checkpoint_id = cp['id']
368 checkpoint_id = cp['id']
382 old_cp_path = self.get_checkpoint_path(checkpoint_id, old_name, old_path)
369 old_cp_path = self.get_checkpoint_path(checkpoint_id, old_name, old_path)
383 new_cp_path = self.get_checkpoint_path(checkpoint_id, new_name, new_path)
370 new_cp_path = self.get_checkpoint_path(checkpoint_id, new_name, new_path)
384 if os.path.isfile(old_cp_path):
371 if os.path.isfile(old_cp_path):
385 self.log.debug("Renaming checkpoint %s -> %s", old_cp_path, new_cp_path)
372 self.log.debug("Renaming checkpoint %s -> %s", old_cp_path, new_cp_path)
386 shutil.move(old_cp_path, new_cp_path)
373 shutil.move(old_cp_path, new_cp_path)
387
374
388 # Move the .py script
375 # Move the .py script
389 if self.save_script:
376 if self.save_script:
390 shutil.move(old_py_path, new_py_path)
377 shutil.move(old_py_path, new_py_path)
391
378
392 # Checkpoint-related utilities
379 # Checkpoint-related utilities
393
380
394 def get_checkpoint_path(self, checkpoint_id, name, path=''):
381 def get_checkpoint_path(self, checkpoint_id, name, path=''):
395 """find the path to a checkpoint"""
382 """find the path to a checkpoint"""
396 path = path.strip('/')
383 path = path.strip('/')
397 basename, _ = os.path.splitext(name)
384 basename, _ = os.path.splitext(name)
398 filename = u"{name}-{checkpoint_id}{ext}".format(
385 filename = u"{name}-{checkpoint_id}{ext}".format(
399 name=basename,
386 name=basename,
400 checkpoint_id=checkpoint_id,
387 checkpoint_id=checkpoint_id,
401 ext=self.filename_ext,
388 ext=self.filename_ext,
402 )
389 )
403 os_path = self._get_os_path(path=path)
390 os_path = self._get_os_path(path=path)
404 cp_dir = os.path.join(os_path, self.checkpoint_dir)
391 cp_dir = os.path.join(os_path, self.checkpoint_dir)
405 if not os.path.exists(cp_dir):
392 ensure_dir_exists(cp_dir)
406 os.mkdir(cp_dir)
407 cp_path = os.path.join(cp_dir, filename)
393 cp_path = os.path.join(cp_dir, filename)
408 return cp_path
394 return cp_path
409
395
410 def get_checkpoint_model(self, checkpoint_id, name, path=''):
396 def get_checkpoint_model(self, checkpoint_id, name, path=''):
411 """construct the info dict for a given checkpoint"""
397 """construct the info dict for a given checkpoint"""
412 path = path.strip('/')
398 path = path.strip('/')
413 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
399 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
414 stats = os.stat(cp_path)
400 stats = os.stat(cp_path)
415 last_modified = tz.utcfromtimestamp(stats.st_mtime)
401 last_modified = tz.utcfromtimestamp(stats.st_mtime)
416 info = dict(
402 info = dict(
417 id = checkpoint_id,
403 id = checkpoint_id,
418 last_modified = last_modified,
404 last_modified = last_modified,
419 )
405 )
420 return info
406 return info
421
407
422 # public checkpoint API
408 # public checkpoint API
423
409
424 def create_checkpoint(self, name, path=''):
410 def create_checkpoint(self, name, path=''):
425 """Create a checkpoint from the current state of a notebook"""
411 """Create a checkpoint from the current state of a notebook"""
426 path = path.strip('/')
412 path = path.strip('/')
427 nb_path = self._get_os_path(name, path)
413 nb_path = self._get_os_path(name, path)
428 # only the one checkpoint ID:
414 # only the one checkpoint ID:
429 checkpoint_id = u"checkpoint"
415 checkpoint_id = u"checkpoint"
430 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
416 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
431 self.log.debug("creating checkpoint for notebook %s", name)
417 self.log.debug("creating checkpoint for notebook %s", name)
432 if not os.path.exists(self.checkpoint_dir):
433 os.mkdir(self.checkpoint_dir)
434 self._copy(nb_path, cp_path)
418 self._copy(nb_path, cp_path)
435
419
436 # return the checkpoint info
420 # return the checkpoint info
437 return self.get_checkpoint_model(checkpoint_id, name, path)
421 return self.get_checkpoint_model(checkpoint_id, name, path)
438
422
439 def list_checkpoints(self, name, path=''):
423 def list_checkpoints(self, name, path=''):
440 """list the checkpoints for a given notebook
424 """list the checkpoints for a given notebook
441
425
442 This notebook manager currently only supports one checkpoint per notebook.
426 This notebook manager currently only supports one checkpoint per notebook.
443 """
427 """
444 path = path.strip('/')
428 path = path.strip('/')
445 checkpoint_id = "checkpoint"
429 checkpoint_id = "checkpoint"
446 os_path = self.get_checkpoint_path(checkpoint_id, name, path)
430 os_path = self.get_checkpoint_path(checkpoint_id, name, path)
447 if not os.path.exists(os_path):
431 if not os.path.exists(os_path):
448 return []
432 return []
449 else:
433 else:
450 return [self.get_checkpoint_model(checkpoint_id, name, path)]
434 return [self.get_checkpoint_model(checkpoint_id, name, path)]
451
435
452
436
453 def restore_checkpoint(self, checkpoint_id, name, path=''):
437 def restore_checkpoint(self, checkpoint_id, name, path=''):
454 """restore a notebook to a checkpointed state"""
438 """restore a notebook to a checkpointed state"""
455 path = path.strip('/')
439 path = path.strip('/')
456 self.log.info("restoring Notebook %s from checkpoint %s", name, checkpoint_id)
440 self.log.info("restoring Notebook %s from checkpoint %s", name, checkpoint_id)
457 nb_path = self._get_os_path(name, path)
441 nb_path = self._get_os_path(name, path)
458 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
442 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
459 if not os.path.isfile(cp_path):
443 if not os.path.isfile(cp_path):
460 self.log.debug("checkpoint file does not exist: %s", cp_path)
444 self.log.debug("checkpoint file does not exist: %s", cp_path)
461 raise web.HTTPError(404,
445 raise web.HTTPError(404,
462 u'Notebook checkpoint does not exist: %s-%s' % (name, checkpoint_id)
446 u'Notebook checkpoint does not exist: %s-%s' % (name, checkpoint_id)
463 )
447 )
464 # ensure notebook is readable (never restore from an unreadable notebook)
448 # ensure notebook is readable (never restore from an unreadable notebook)
465 with io.open(cp_path, 'r', encoding='utf-8') as f:
449 with io.open(cp_path, 'r', encoding='utf-8') as f:
466 current.read(f, u'json')
450 current.read(f, u'json')
467 self._copy(cp_path, nb_path)
451 self._copy(cp_path, nb_path)
468 self.log.debug("copying %s -> %s", cp_path, nb_path)
452 self.log.debug("copying %s -> %s", cp_path, nb_path)
469
453
470 def delete_checkpoint(self, checkpoint_id, name, path=''):
454 def delete_checkpoint(self, checkpoint_id, name, path=''):
471 """delete a notebook's checkpoint"""
455 """delete a notebook's checkpoint"""
472 path = path.strip('/')
456 path = path.strip('/')
473 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
457 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
474 if not os.path.isfile(cp_path):
458 if not os.path.isfile(cp_path):
475 raise web.HTTPError(404,
459 raise web.HTTPError(404,
476 u'Notebook checkpoint does not exist: %s%s-%s' % (path, name, checkpoint_id)
460 u'Notebook checkpoint does not exist: %s%s-%s' % (path, name, checkpoint_id)
477 )
461 )
478 self.log.debug("unlinking %s", cp_path)
462 self.log.debug("unlinking %s", cp_path)
479 os.unlink(cp_path)
463 os.unlink(cp_path)
480
464
481 def info_string(self):
465 def info_string(self):
482 return "Serving notebooks from local directory: %s" % self.notebook_dir
466 return "Serving notebooks from local directory: %s" % self.notebook_dir
483
467
484 def get_kernel_path(self, name, path='', model=None):
468 def get_kernel_path(self, name, path='', model=None):
485 """ Return the path to start kernel in """
469 """ Return the path to start kernel in """
486 return os.path.join(self.notebook_dir, path)
470 return os.path.join(self.notebook_dir, path)
@@ -1,111 +1,111 b''
1 """Contains writer for writing nbconvert output to filesystem."""
1 """Contains writer for writing nbconvert output to filesystem."""
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 io
6 import io
7 import os
7 import os
8 import glob
8 import glob
9
9
10 from IPython.utils.traitlets import Unicode
10 from IPython.utils.traitlets import Unicode
11 from IPython.utils.path import link_or_copy
11 from IPython.utils.path import link_or_copy, ensure_dir_exists
12 from IPython.utils.py3compat import unicode_type
12 from IPython.utils.py3compat import unicode_type
13
13
14 from .base import WriterBase
14 from .base import WriterBase
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Classes
17 # Classes
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 class FilesWriter(WriterBase):
20 class FilesWriter(WriterBase):
21 """Consumes nbconvert output and produces files."""
21 """Consumes nbconvert output and produces files."""
22
22
23
23
24 build_directory = Unicode("", config=True,
24 build_directory = Unicode("", config=True,
25 help="""Directory to write output to. Leave blank
25 help="""Directory to write output to. Leave blank
26 to output to the current directory""")
26 to output to the current directory""")
27
27
28
28
29 # Make sure that the output directory exists.
29 # Make sure that the output directory exists.
30 def _build_directory_changed(self, name, old, new):
30 def _build_directory_changed(self, name, old, new):
31 if new and not os.path.isdir(new):
31 if new:
32 os.makedirs(new)
32 ensure_dir_exists(new)
33
33
34
34
35 def __init__(self, **kw):
35 def __init__(self, **kw):
36 super(FilesWriter, self).__init__(**kw)
36 super(FilesWriter, self).__init__(**kw)
37 self._build_directory_changed('build_directory', self.build_directory,
37 self._build_directory_changed('build_directory', self.build_directory,
38 self.build_directory)
38 self.build_directory)
39
39
40 def _makedir(self, path):
40 def _makedir(self, path):
41 """Make a directory if it doesn't already exist"""
41 """Make a directory if it doesn't already exist"""
42 if path and not os.path.isdir(path):
42 if path:
43 self.log.info("Making directory %s", path)
43 self.log.info("Making directory %s", path)
44 os.makedirs(path)
44 ensure_dir_exists(path)
45
45
46 def write(self, output, resources, notebook_name=None, **kw):
46 def write(self, output, resources, notebook_name=None, **kw):
47 """
47 """
48 Consume and write Jinja output to the file system. Output directory
48 Consume and write Jinja output to the file system. Output directory
49 is set via the 'build_directory' variable of this instance (a
49 is set via the 'build_directory' variable of this instance (a
50 configurable).
50 configurable).
51
51
52 See base for more...
52 See base for more...
53 """
53 """
54
54
55 # Verify that a notebook name is provided.
55 # Verify that a notebook name is provided.
56 if notebook_name is None:
56 if notebook_name is None:
57 raise TypeError('notebook_name')
57 raise TypeError('notebook_name')
58
58
59 # Pull the extension and subdir from the resources dict.
59 # Pull the extension and subdir from the resources dict.
60 output_extension = resources.get('output_extension', None)
60 output_extension = resources.get('output_extension', None)
61
61
62 # Write all of the extracted resources to the destination directory.
62 # Write all of the extracted resources to the destination directory.
63 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
63 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
64 # PREPROCESSOR SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
64 # PREPROCESSOR SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
65 for filename, data in resources.get('outputs', {}).items():
65 for filename, data in resources.get('outputs', {}).items():
66
66
67 # Determine where to write the file to
67 # Determine where to write the file to
68 dest = os.path.join(self.build_directory, filename)
68 dest = os.path.join(self.build_directory, filename)
69 path = os.path.dirname(dest)
69 path = os.path.dirname(dest)
70 self._makedir(path)
70 self._makedir(path)
71
71
72 # Write file
72 # Write file
73 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
73 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
74 with io.open(dest, 'wb') as f:
74 with io.open(dest, 'wb') as f:
75 f.write(data)
75 f.write(data)
76
76
77 # Copy referenced files to output directory
77 # Copy referenced files to output directory
78 if self.build_directory:
78 if self.build_directory:
79 for filename in self.files:
79 for filename in self.files:
80
80
81 # Copy files that match search pattern
81 # Copy files that match search pattern
82 for matching_filename in glob.glob(filename):
82 for matching_filename in glob.glob(filename):
83
83
84 # Make sure folder exists.
84 # Make sure folder exists.
85 dest = os.path.join(self.build_directory, filename)
85 dest = os.path.join(self.build_directory, filename)
86 path = os.path.dirname(dest)
86 path = os.path.dirname(dest)
87 self._makedir(path)
87 self._makedir(path)
88
88
89 # Copy if destination is different.
89 # Copy if destination is different.
90 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
90 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
91 self.log.info("Linking %s -> %s", matching_filename, dest)
91 self.log.info("Linking %s -> %s", matching_filename, dest)
92 link_or_copy(matching_filename, dest)
92 link_or_copy(matching_filename, dest)
93
93
94 # Determine where to write conversion results.
94 # Determine where to write conversion results.
95 if output_extension is not None:
95 if output_extension is not None:
96 dest = notebook_name + '.' + output_extension
96 dest = notebook_name + '.' + output_extension
97 else:
97 else:
98 dest = notebook_name
98 dest = notebook_name
99 if self.build_directory:
99 if self.build_directory:
100 dest = os.path.join(self.build_directory, dest)
100 dest = os.path.join(self.build_directory, dest)
101
101
102 # Write conversion results.
102 # Write conversion results.
103 self.log.info("Writing %i bytes to %s", len(output), dest)
103 self.log.info("Writing %i bytes to %s", len(output), dest)
104 if isinstance(output, unicode_type):
104 if isinstance(output, unicode_type):
105 with io.open(dest, 'w', encoding='utf-8') as f:
105 with io.open(dest, 'w', encoding='utf-8') as f:
106 f.write(output)
106 f.write(output)
107 else:
107 else:
108 with io.open(dest, 'wb') as f:
108 with io.open(dest, 'wb') as f:
109 f.write(output)
109 f.write(output)
110
110
111 return dest
111 return dest
@@ -1,1463 +1,1447 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """Facilities for launching IPython processes asynchronously."""
3 Facilities for launching IPython processes asynchronously.
4
5 Authors:
6
3
7 * Brian Granger
4 # Copyright (c) IPython Development Team.
8 * MinRK
5 # Distributed under the terms of the Modified BSD License.
9 """
10
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
6
22 import copy
7 import copy
23 import logging
8 import logging
24 import os
9 import os
25 import pipes
10 import pipes
26 import stat
11 import stat
27 import sys
12 import sys
28 import time
13 import time
29
14
30 # signal imports, handling various platforms, versions
15 # signal imports, handling various platforms, versions
31
16
32 from signal import SIGINT, SIGTERM
17 from signal import SIGINT, SIGTERM
33 try:
18 try:
34 from signal import SIGKILL
19 from signal import SIGKILL
35 except ImportError:
20 except ImportError:
36 # Windows
21 # Windows
37 SIGKILL=SIGTERM
22 SIGKILL=SIGTERM
38
23
39 try:
24 try:
40 # Windows >= 2.7, 3.2
25 # Windows >= 2.7, 3.2
41 from signal import CTRL_C_EVENT as SIGINT
26 from signal import CTRL_C_EVENT as SIGINT
42 except ImportError:
27 except ImportError:
43 pass
28 pass
44
29
45 from subprocess import Popen, PIPE, STDOUT
30 from subprocess import Popen, PIPE, STDOUT
46 try:
31 try:
47 from subprocess import check_output
32 from subprocess import check_output
48 except ImportError:
33 except ImportError:
49 # pre-2.7, define check_output with Popen
34 # pre-2.7, define check_output with Popen
50 def check_output(*args, **kwargs):
35 def check_output(*args, **kwargs):
51 kwargs.update(dict(stdout=PIPE))
36 kwargs.update(dict(stdout=PIPE))
52 p = Popen(*args, **kwargs)
37 p = Popen(*args, **kwargs)
53 out,err = p.communicate()
38 out,err = p.communicate()
54 return out
39 return out
55
40
56 from zmq.eventloop import ioloop
41 from zmq.eventloop import ioloop
57
42
58 from IPython.config.application import Application
43 from IPython.config.application import Application
59 from IPython.config.configurable import LoggingConfigurable
44 from IPython.config.configurable import LoggingConfigurable
60 from IPython.utils.text import EvalFormatter
45 from IPython.utils.text import EvalFormatter
61 from IPython.utils.traitlets import (
46 from IPython.utils.traitlets import (
62 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
47 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
63 )
48 )
64 from IPython.utils.encoding import DEFAULT_ENCODING
49 from IPython.utils.encoding import DEFAULT_ENCODING
65 from IPython.utils.path import get_home_dir
50 from IPython.utils.path import get_home_dir, ensure_dir_exists
66 from IPython.utils.process import find_cmd, FindCmdError
51 from IPython.utils.process import find_cmd, FindCmdError
67 from IPython.utils.py3compat import iteritems, itervalues
52 from IPython.utils.py3compat import iteritems, itervalues
68
53
69 from .win32support import forward_read_events
54 from .win32support import forward_read_events
70
55
71 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
56 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
72
57
73 WINDOWS = os.name == 'nt'
58 WINDOWS = os.name == 'nt'
74
59
75 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
76 # Paths to the kernel apps
61 # Paths to the kernel apps
77 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
78
63
79 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
64 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
80
65
81 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
66 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
82
67
83 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
68 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
84
69
85 if WINDOWS and sys.version_info < (3,):
70 if WINDOWS and sys.version_info < (3,):
86 # `python -m package` doesn't work on Windows Python 2,
71 # `python -m package` doesn't work on Windows Python 2,
87 # but `python -m module` does.
72 # but `python -m module` does.
88 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
73 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
89 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
74 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
90
75
91 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
92 # Base launchers and errors
77 # Base launchers and errors
93 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
94
79
95 class LauncherError(Exception):
80 class LauncherError(Exception):
96 pass
81 pass
97
82
98
83
99 class ProcessStateError(LauncherError):
84 class ProcessStateError(LauncherError):
100 pass
85 pass
101
86
102
87
103 class UnknownStatus(LauncherError):
88 class UnknownStatus(LauncherError):
104 pass
89 pass
105
90
106
91
107 class BaseLauncher(LoggingConfigurable):
92 class BaseLauncher(LoggingConfigurable):
108 """An asbtraction for starting, stopping and signaling a process."""
93 """An asbtraction for starting, stopping and signaling a process."""
109
94
110 # In all of the launchers, the work_dir is where child processes will be
95 # In all of the launchers, the work_dir is where child processes will be
111 # run. This will usually be the profile_dir, but may not be. any work_dir
96 # run. This will usually be the profile_dir, but may not be. any work_dir
112 # passed into the __init__ method will override the config value.
97 # passed into the __init__ method will override the config value.
113 # This should not be used to set the work_dir for the actual engine
98 # This should not be used to set the work_dir for the actual engine
114 # and controller. Instead, use their own config files or the
99 # and controller. Instead, use their own config files or the
115 # controller_args, engine_args attributes of the launchers to add
100 # controller_args, engine_args attributes of the launchers to add
116 # the work_dir option.
101 # the work_dir option.
117 work_dir = Unicode(u'.')
102 work_dir = Unicode(u'.')
118 loop = Instance('zmq.eventloop.ioloop.IOLoop')
103 loop = Instance('zmq.eventloop.ioloop.IOLoop')
119
104
120 start_data = Any()
105 start_data = Any()
121 stop_data = Any()
106 stop_data = Any()
122
107
123 def _loop_default(self):
108 def _loop_default(self):
124 return ioloop.IOLoop.instance()
109 return ioloop.IOLoop.instance()
125
110
126 def __init__(self, work_dir=u'.', config=None, **kwargs):
111 def __init__(self, work_dir=u'.', config=None, **kwargs):
127 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
112 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
128 self.state = 'before' # can be before, running, after
113 self.state = 'before' # can be before, running, after
129 self.stop_callbacks = []
114 self.stop_callbacks = []
130 self.start_data = None
115 self.start_data = None
131 self.stop_data = None
116 self.stop_data = None
132
117
133 @property
118 @property
134 def args(self):
119 def args(self):
135 """A list of cmd and args that will be used to start the process.
120 """A list of cmd and args that will be used to start the process.
136
121
137 This is what is passed to :func:`spawnProcess` and the first element
122 This is what is passed to :func:`spawnProcess` and the first element
138 will be the process name.
123 will be the process name.
139 """
124 """
140 return self.find_args()
125 return self.find_args()
141
126
142 def find_args(self):
127 def find_args(self):
143 """The ``.args`` property calls this to find the args list.
128 """The ``.args`` property calls this to find the args list.
144
129
145 Subcommand should implement this to construct the cmd and args.
130 Subcommand should implement this to construct the cmd and args.
146 """
131 """
147 raise NotImplementedError('find_args must be implemented in a subclass')
132 raise NotImplementedError('find_args must be implemented in a subclass')
148
133
149 @property
134 @property
150 def arg_str(self):
135 def arg_str(self):
151 """The string form of the program arguments."""
136 """The string form of the program arguments."""
152 return ' '.join(self.args)
137 return ' '.join(self.args)
153
138
154 @property
139 @property
155 def running(self):
140 def running(self):
156 """Am I running."""
141 """Am I running."""
157 if self.state == 'running':
142 if self.state == 'running':
158 return True
143 return True
159 else:
144 else:
160 return False
145 return False
161
146
162 def start(self):
147 def start(self):
163 """Start the process."""
148 """Start the process."""
164 raise NotImplementedError('start must be implemented in a subclass')
149 raise NotImplementedError('start must be implemented in a subclass')
165
150
166 def stop(self):
151 def stop(self):
167 """Stop the process and notify observers of stopping.
152 """Stop the process and notify observers of stopping.
168
153
169 This method will return None immediately.
154 This method will return None immediately.
170 To observe the actual process stopping, see :meth:`on_stop`.
155 To observe the actual process stopping, see :meth:`on_stop`.
171 """
156 """
172 raise NotImplementedError('stop must be implemented in a subclass')
157 raise NotImplementedError('stop must be implemented in a subclass')
173
158
174 def on_stop(self, f):
159 def on_stop(self, f):
175 """Register a callback to be called with this Launcher's stop_data
160 """Register a callback to be called with this Launcher's stop_data
176 when the process actually finishes.
161 when the process actually finishes.
177 """
162 """
178 if self.state=='after':
163 if self.state=='after':
179 return f(self.stop_data)
164 return f(self.stop_data)
180 else:
165 else:
181 self.stop_callbacks.append(f)
166 self.stop_callbacks.append(f)
182
167
183 def notify_start(self, data):
168 def notify_start(self, data):
184 """Call this to trigger startup actions.
169 """Call this to trigger startup actions.
185
170
186 This logs the process startup and sets the state to 'running'. It is
171 This logs the process startup and sets the state to 'running'. It is
187 a pass-through so it can be used as a callback.
172 a pass-through so it can be used as a callback.
188 """
173 """
189
174
190 self.log.debug('Process %r started: %r', self.args[0], data)
175 self.log.debug('Process %r started: %r', self.args[0], data)
191 self.start_data = data
176 self.start_data = data
192 self.state = 'running'
177 self.state = 'running'
193 return data
178 return data
194
179
195 def notify_stop(self, data):
180 def notify_stop(self, data):
196 """Call this to trigger process stop actions.
181 """Call this to trigger process stop actions.
197
182
198 This logs the process stopping and sets the state to 'after'. Call
183 This logs the process stopping and sets the state to 'after'. Call
199 this to trigger callbacks registered via :meth:`on_stop`."""
184 this to trigger callbacks registered via :meth:`on_stop`."""
200
185
201 self.log.debug('Process %r stopped: %r', self.args[0], data)
186 self.log.debug('Process %r stopped: %r', self.args[0], data)
202 self.stop_data = data
187 self.stop_data = data
203 self.state = 'after'
188 self.state = 'after'
204 for i in range(len(self.stop_callbacks)):
189 for i in range(len(self.stop_callbacks)):
205 d = self.stop_callbacks.pop()
190 d = self.stop_callbacks.pop()
206 d(data)
191 d(data)
207 return data
192 return data
208
193
209 def signal(self, sig):
194 def signal(self, sig):
210 """Signal the process.
195 """Signal the process.
211
196
212 Parameters
197 Parameters
213 ----------
198 ----------
214 sig : str or int
199 sig : str or int
215 'KILL', 'INT', etc., or any signal number
200 'KILL', 'INT', etc., or any signal number
216 """
201 """
217 raise NotImplementedError('signal must be implemented in a subclass')
202 raise NotImplementedError('signal must be implemented in a subclass')
218
203
219 class ClusterAppMixin(HasTraits):
204 class ClusterAppMixin(HasTraits):
220 """MixIn for cluster args as traits"""
205 """MixIn for cluster args as traits"""
221 profile_dir=Unicode('')
206 profile_dir=Unicode('')
222 cluster_id=Unicode('')
207 cluster_id=Unicode('')
223
208
224 @property
209 @property
225 def cluster_args(self):
210 def cluster_args(self):
226 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
211 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
227
212
228 class ControllerMixin(ClusterAppMixin):
213 class ControllerMixin(ClusterAppMixin):
229 controller_cmd = List(ipcontroller_cmd_argv, config=True,
214 controller_cmd = List(ipcontroller_cmd_argv, config=True,
230 help="""Popen command to launch ipcontroller.""")
215 help="""Popen command to launch ipcontroller.""")
231 # Command line arguments to ipcontroller.
216 # Command line arguments to ipcontroller.
232 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
217 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
233 help="""command-line args to pass to ipcontroller""")
218 help="""command-line args to pass to ipcontroller""")
234
219
235 class EngineMixin(ClusterAppMixin):
220 class EngineMixin(ClusterAppMixin):
236 engine_cmd = List(ipengine_cmd_argv, config=True,
221 engine_cmd = List(ipengine_cmd_argv, config=True,
237 help="""command to launch the Engine.""")
222 help="""command to launch the Engine.""")
238 # Command line arguments for ipengine.
223 # Command line arguments for ipengine.
239 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
224 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
240 help="command-line arguments to pass to ipengine"
225 help="command-line arguments to pass to ipengine"
241 )
226 )
242
227
243
228
244 #-----------------------------------------------------------------------------
229 #-----------------------------------------------------------------------------
245 # Local process launchers
230 # Local process launchers
246 #-----------------------------------------------------------------------------
231 #-----------------------------------------------------------------------------
247
232
248
233
249 class LocalProcessLauncher(BaseLauncher):
234 class LocalProcessLauncher(BaseLauncher):
250 """Start and stop an external process in an asynchronous manner.
235 """Start and stop an external process in an asynchronous manner.
251
236
252 This will launch the external process with a working directory of
237 This will launch the external process with a working directory of
253 ``self.work_dir``.
238 ``self.work_dir``.
254 """
239 """
255
240
256 # This is used to to construct self.args, which is passed to
241 # This is used to to construct self.args, which is passed to
257 # spawnProcess.
242 # spawnProcess.
258 cmd_and_args = List([])
243 cmd_and_args = List([])
259 poll_frequency = Integer(100) # in ms
244 poll_frequency = Integer(100) # in ms
260
245
261 def __init__(self, work_dir=u'.', config=None, **kwargs):
246 def __init__(self, work_dir=u'.', config=None, **kwargs):
262 super(LocalProcessLauncher, self).__init__(
247 super(LocalProcessLauncher, self).__init__(
263 work_dir=work_dir, config=config, **kwargs
248 work_dir=work_dir, config=config, **kwargs
264 )
249 )
265 self.process = None
250 self.process = None
266 self.poller = None
251 self.poller = None
267
252
268 def find_args(self):
253 def find_args(self):
269 return self.cmd_and_args
254 return self.cmd_and_args
270
255
271 def start(self):
256 def start(self):
272 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
257 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
273 if self.state == 'before':
258 if self.state == 'before':
274 self.process = Popen(self.args,
259 self.process = Popen(self.args,
275 stdout=PIPE,stderr=PIPE,stdin=PIPE,
260 stdout=PIPE,stderr=PIPE,stdin=PIPE,
276 env=os.environ,
261 env=os.environ,
277 cwd=self.work_dir
262 cwd=self.work_dir
278 )
263 )
279 if WINDOWS:
264 if WINDOWS:
280 self.stdout = forward_read_events(self.process.stdout)
265 self.stdout = forward_read_events(self.process.stdout)
281 self.stderr = forward_read_events(self.process.stderr)
266 self.stderr = forward_read_events(self.process.stderr)
282 else:
267 else:
283 self.stdout = self.process.stdout.fileno()
268 self.stdout = self.process.stdout.fileno()
284 self.stderr = self.process.stderr.fileno()
269 self.stderr = self.process.stderr.fileno()
285 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
270 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
286 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
271 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
287 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
272 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
288 self.poller.start()
273 self.poller.start()
289 self.notify_start(self.process.pid)
274 self.notify_start(self.process.pid)
290 else:
275 else:
291 s = 'The process was already started and has state: %r' % self.state
276 s = 'The process was already started and has state: %r' % self.state
292 raise ProcessStateError(s)
277 raise ProcessStateError(s)
293
278
294 def stop(self):
279 def stop(self):
295 return self.interrupt_then_kill()
280 return self.interrupt_then_kill()
296
281
297 def signal(self, sig):
282 def signal(self, sig):
298 if self.state == 'running':
283 if self.state == 'running':
299 if WINDOWS and sig != SIGINT:
284 if WINDOWS and sig != SIGINT:
300 # use Windows tree-kill for better child cleanup
285 # use Windows tree-kill for better child cleanup
301 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
286 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
302 else:
287 else:
303 self.process.send_signal(sig)
288 self.process.send_signal(sig)
304
289
305 def interrupt_then_kill(self, delay=2.0):
290 def interrupt_then_kill(self, delay=2.0):
306 """Send INT, wait a delay and then send KILL."""
291 """Send INT, wait a delay and then send KILL."""
307 try:
292 try:
308 self.signal(SIGINT)
293 self.signal(SIGINT)
309 except Exception:
294 except Exception:
310 self.log.debug("interrupt failed")
295 self.log.debug("interrupt failed")
311 pass
296 pass
312 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
297 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
313 self.killer.start()
298 self.killer.start()
314
299
315 # callbacks, etc:
300 # callbacks, etc:
316
301
317 def handle_stdout(self, fd, events):
302 def handle_stdout(self, fd, events):
318 if WINDOWS:
303 if WINDOWS:
319 line = self.stdout.recv()
304 line = self.stdout.recv()
320 else:
305 else:
321 line = self.process.stdout.readline()
306 line = self.process.stdout.readline()
322 # a stopped process will be readable but return empty strings
307 # a stopped process will be readable but return empty strings
323 if line:
308 if line:
324 self.log.debug(line[:-1])
309 self.log.debug(line[:-1])
325 else:
310 else:
326 self.poll()
311 self.poll()
327
312
328 def handle_stderr(self, fd, events):
313 def handle_stderr(self, fd, events):
329 if WINDOWS:
314 if WINDOWS:
330 line = self.stderr.recv()
315 line = self.stderr.recv()
331 else:
316 else:
332 line = self.process.stderr.readline()
317 line = self.process.stderr.readline()
333 # a stopped process will be readable but return empty strings
318 # a stopped process will be readable but return empty strings
334 if line:
319 if line:
335 self.log.debug(line[:-1])
320 self.log.debug(line[:-1])
336 else:
321 else:
337 self.poll()
322 self.poll()
338
323
339 def poll(self):
324 def poll(self):
340 status = self.process.poll()
325 status = self.process.poll()
341 if status is not None:
326 if status is not None:
342 self.poller.stop()
327 self.poller.stop()
343 self.loop.remove_handler(self.stdout)
328 self.loop.remove_handler(self.stdout)
344 self.loop.remove_handler(self.stderr)
329 self.loop.remove_handler(self.stderr)
345 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
330 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
346 return status
331 return status
347
332
348 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
333 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
349 """Launch a controller as a regular external process."""
334 """Launch a controller as a regular external process."""
350
335
351 def find_args(self):
336 def find_args(self):
352 return self.controller_cmd + self.cluster_args + self.controller_args
337 return self.controller_cmd + self.cluster_args + self.controller_args
353
338
354 def start(self):
339 def start(self):
355 """Start the controller by profile_dir."""
340 """Start the controller by profile_dir."""
356 return super(LocalControllerLauncher, self).start()
341 return super(LocalControllerLauncher, self).start()
357
342
358
343
359 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
344 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
360 """Launch a single engine as a regular externall process."""
345 """Launch a single engine as a regular externall process."""
361
346
362 def find_args(self):
347 def find_args(self):
363 return self.engine_cmd + self.cluster_args + self.engine_args
348 return self.engine_cmd + self.cluster_args + self.engine_args
364
349
365
350
366 class LocalEngineSetLauncher(LocalEngineLauncher):
351 class LocalEngineSetLauncher(LocalEngineLauncher):
367 """Launch a set of engines as regular external processes."""
352 """Launch a set of engines as regular external processes."""
368
353
369 delay = CFloat(0.1, config=True,
354 delay = CFloat(0.1, config=True,
370 help="""delay (in seconds) between starting each engine after the first.
355 help="""delay (in seconds) between starting each engine after the first.
371 This can help force the engines to get their ids in order, or limit
356 This can help force the engines to get their ids in order, or limit
372 process flood when starting many engines."""
357 process flood when starting many engines."""
373 )
358 )
374
359
375 # launcher class
360 # launcher class
376 launcher_class = LocalEngineLauncher
361 launcher_class = LocalEngineLauncher
377
362
378 launchers = Dict()
363 launchers = Dict()
379 stop_data = Dict()
364 stop_data = Dict()
380
365
381 def __init__(self, work_dir=u'.', config=None, **kwargs):
366 def __init__(self, work_dir=u'.', config=None, **kwargs):
382 super(LocalEngineSetLauncher, self).__init__(
367 super(LocalEngineSetLauncher, self).__init__(
383 work_dir=work_dir, config=config, **kwargs
368 work_dir=work_dir, config=config, **kwargs
384 )
369 )
385 self.stop_data = {}
370 self.stop_data = {}
386
371
387 def start(self, n):
372 def start(self, n):
388 """Start n engines by profile or profile_dir."""
373 """Start n engines by profile or profile_dir."""
389 dlist = []
374 dlist = []
390 for i in range(n):
375 for i in range(n):
391 if i > 0:
376 if i > 0:
392 time.sleep(self.delay)
377 time.sleep(self.delay)
393 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
378 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
394 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
379 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
395 )
380 )
396
381
397 # Copy the engine args over to each engine launcher.
382 # Copy the engine args over to each engine launcher.
398 el.engine_cmd = copy.deepcopy(self.engine_cmd)
383 el.engine_cmd = copy.deepcopy(self.engine_cmd)
399 el.engine_args = copy.deepcopy(self.engine_args)
384 el.engine_args = copy.deepcopy(self.engine_args)
400 el.on_stop(self._notice_engine_stopped)
385 el.on_stop(self._notice_engine_stopped)
401 d = el.start()
386 d = el.start()
402 self.launchers[i] = el
387 self.launchers[i] = el
403 dlist.append(d)
388 dlist.append(d)
404 self.notify_start(dlist)
389 self.notify_start(dlist)
405 return dlist
390 return dlist
406
391
407 def find_args(self):
392 def find_args(self):
408 return ['engine set']
393 return ['engine set']
409
394
410 def signal(self, sig):
395 def signal(self, sig):
411 dlist = []
396 dlist = []
412 for el in itervalues(self.launchers):
397 for el in itervalues(self.launchers):
413 d = el.signal(sig)
398 d = el.signal(sig)
414 dlist.append(d)
399 dlist.append(d)
415 return dlist
400 return dlist
416
401
417 def interrupt_then_kill(self, delay=1.0):
402 def interrupt_then_kill(self, delay=1.0):
418 dlist = []
403 dlist = []
419 for el in itervalues(self.launchers):
404 for el in itervalues(self.launchers):
420 d = el.interrupt_then_kill(delay)
405 d = el.interrupt_then_kill(delay)
421 dlist.append(d)
406 dlist.append(d)
422 return dlist
407 return dlist
423
408
424 def stop(self):
409 def stop(self):
425 return self.interrupt_then_kill()
410 return self.interrupt_then_kill()
426
411
427 def _notice_engine_stopped(self, data):
412 def _notice_engine_stopped(self, data):
428 pid = data['pid']
413 pid = data['pid']
429 for idx,el in iteritems(self.launchers):
414 for idx,el in iteritems(self.launchers):
430 if el.process.pid == pid:
415 if el.process.pid == pid:
431 break
416 break
432 self.launchers.pop(idx)
417 self.launchers.pop(idx)
433 self.stop_data[idx] = data
418 self.stop_data[idx] = data
434 if not self.launchers:
419 if not self.launchers:
435 self.notify_stop(self.stop_data)
420 self.notify_stop(self.stop_data)
436
421
437
422
438 #-----------------------------------------------------------------------------
423 #-----------------------------------------------------------------------------
439 # MPI launchers
424 # MPI launchers
440 #-----------------------------------------------------------------------------
425 #-----------------------------------------------------------------------------
441
426
442
427
443 class MPILauncher(LocalProcessLauncher):
428 class MPILauncher(LocalProcessLauncher):
444 """Launch an external process using mpiexec."""
429 """Launch an external process using mpiexec."""
445
430
446 mpi_cmd = List(['mpiexec'], config=True,
431 mpi_cmd = List(['mpiexec'], config=True,
447 help="The mpiexec command to use in starting the process."
432 help="The mpiexec command to use in starting the process."
448 )
433 )
449 mpi_args = List([], config=True,
434 mpi_args = List([], config=True,
450 help="The command line arguments to pass to mpiexec."
435 help="The command line arguments to pass to mpiexec."
451 )
436 )
452 program = List(['date'],
437 program = List(['date'],
453 help="The program to start via mpiexec.")
438 help="The program to start via mpiexec.")
454 program_args = List([],
439 program_args = List([],
455 help="The command line argument to the program."
440 help="The command line argument to the program."
456 )
441 )
457 n = Integer(1)
442 n = Integer(1)
458
443
459 def __init__(self, *args, **kwargs):
444 def __init__(self, *args, **kwargs):
460 # deprecation for old MPIExec names:
445 # deprecation for old MPIExec names:
461 config = kwargs.get('config', {})
446 config = kwargs.get('config', {})
462 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
447 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
463 deprecated = config.get(oldname)
448 deprecated = config.get(oldname)
464 if deprecated:
449 if deprecated:
465 newname = oldname.replace('MPIExec', 'MPI')
450 newname = oldname.replace('MPIExec', 'MPI')
466 config[newname].update(deprecated)
451 config[newname].update(deprecated)
467 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
452 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
468
453
469 super(MPILauncher, self).__init__(*args, **kwargs)
454 super(MPILauncher, self).__init__(*args, **kwargs)
470
455
471 def find_args(self):
456 def find_args(self):
472 """Build self.args using all the fields."""
457 """Build self.args using all the fields."""
473 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
458 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
474 self.program + self.program_args
459 self.program + self.program_args
475
460
476 def start(self, n):
461 def start(self, n):
477 """Start n instances of the program using mpiexec."""
462 """Start n instances of the program using mpiexec."""
478 self.n = n
463 self.n = n
479 return super(MPILauncher, self).start()
464 return super(MPILauncher, self).start()
480
465
481
466
482 class MPIControllerLauncher(MPILauncher, ControllerMixin):
467 class MPIControllerLauncher(MPILauncher, ControllerMixin):
483 """Launch a controller using mpiexec."""
468 """Launch a controller using mpiexec."""
484
469
485 # alias back to *non-configurable* program[_args] for use in find_args()
470 # alias back to *non-configurable* program[_args] for use in find_args()
486 # this way all Controller/EngineSetLaunchers have the same form, rather
471 # this way all Controller/EngineSetLaunchers have the same form, rather
487 # than *some* having `program_args` and others `controller_args`
472 # than *some* having `program_args` and others `controller_args`
488 @property
473 @property
489 def program(self):
474 def program(self):
490 return self.controller_cmd
475 return self.controller_cmd
491
476
492 @property
477 @property
493 def program_args(self):
478 def program_args(self):
494 return self.cluster_args + self.controller_args
479 return self.cluster_args + self.controller_args
495
480
496 def start(self):
481 def start(self):
497 """Start the controller by profile_dir."""
482 """Start the controller by profile_dir."""
498 return super(MPIControllerLauncher, self).start(1)
483 return super(MPIControllerLauncher, self).start(1)
499
484
500
485
501 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
486 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
502 """Launch engines using mpiexec"""
487 """Launch engines using mpiexec"""
503
488
504 # alias back to *non-configurable* program[_args] for use in find_args()
489 # alias back to *non-configurable* program[_args] for use in find_args()
505 # this way all Controller/EngineSetLaunchers have the same form, rather
490 # this way all Controller/EngineSetLaunchers have the same form, rather
506 # than *some* having `program_args` and others `controller_args`
491 # than *some* having `program_args` and others `controller_args`
507 @property
492 @property
508 def program(self):
493 def program(self):
509 return self.engine_cmd
494 return self.engine_cmd
510
495
511 @property
496 @property
512 def program_args(self):
497 def program_args(self):
513 return self.cluster_args + self.engine_args
498 return self.cluster_args + self.engine_args
514
499
515 def start(self, n):
500 def start(self, n):
516 """Start n engines by profile or profile_dir."""
501 """Start n engines by profile or profile_dir."""
517 self.n = n
502 self.n = n
518 return super(MPIEngineSetLauncher, self).start(n)
503 return super(MPIEngineSetLauncher, self).start(n)
519
504
520 # deprecated MPIExec names
505 # deprecated MPIExec names
521 class DeprecatedMPILauncher(object):
506 class DeprecatedMPILauncher(object):
522 def warn(self):
507 def warn(self):
523 oldname = self.__class__.__name__
508 oldname = self.__class__.__name__
524 newname = oldname.replace('MPIExec', 'MPI')
509 newname = oldname.replace('MPIExec', 'MPI')
525 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
510 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
526
511
527 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
512 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
528 """Deprecated, use MPILauncher"""
513 """Deprecated, use MPILauncher"""
529 def __init__(self, *args, **kwargs):
514 def __init__(self, *args, **kwargs):
530 super(MPIExecLauncher, self).__init__(*args, **kwargs)
515 super(MPIExecLauncher, self).__init__(*args, **kwargs)
531 self.warn()
516 self.warn()
532
517
533 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
518 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
534 """Deprecated, use MPIControllerLauncher"""
519 """Deprecated, use MPIControllerLauncher"""
535 def __init__(self, *args, **kwargs):
520 def __init__(self, *args, **kwargs):
536 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
521 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
537 self.warn()
522 self.warn()
538
523
539 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
524 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
540 """Deprecated, use MPIEngineSetLauncher"""
525 """Deprecated, use MPIEngineSetLauncher"""
541 def __init__(self, *args, **kwargs):
526 def __init__(self, *args, **kwargs):
542 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
527 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
543 self.warn()
528 self.warn()
544
529
545
530
546 #-----------------------------------------------------------------------------
531 #-----------------------------------------------------------------------------
547 # SSH launchers
532 # SSH launchers
548 #-----------------------------------------------------------------------------
533 #-----------------------------------------------------------------------------
549
534
550 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
535 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
551
536
552 class SSHLauncher(LocalProcessLauncher):
537 class SSHLauncher(LocalProcessLauncher):
553 """A minimal launcher for ssh.
538 """A minimal launcher for ssh.
554
539
555 To be useful this will probably have to be extended to use the ``sshx``
540 To be useful this will probably have to be extended to use the ``sshx``
556 idea for environment variables. There could be other things this needs
541 idea for environment variables. There could be other things this needs
557 as well.
542 as well.
558 """
543 """
559
544
560 ssh_cmd = List(['ssh'], config=True,
545 ssh_cmd = List(['ssh'], config=True,
561 help="command for starting ssh")
546 help="command for starting ssh")
562 ssh_args = List(['-tt'], config=True,
547 ssh_args = List(['-tt'], config=True,
563 help="args to pass to ssh")
548 help="args to pass to ssh")
564 scp_cmd = List(['scp'], config=True,
549 scp_cmd = List(['scp'], config=True,
565 help="command for sending files")
550 help="command for sending files")
566 program = List(['date'],
551 program = List(['date'],
567 help="Program to launch via ssh")
552 help="Program to launch via ssh")
568 program_args = List([],
553 program_args = List([],
569 help="args to pass to remote program")
554 help="args to pass to remote program")
570 hostname = Unicode('', config=True,
555 hostname = Unicode('', config=True,
571 help="hostname on which to launch the program")
556 help="hostname on which to launch the program")
572 user = Unicode('', config=True,
557 user = Unicode('', config=True,
573 help="username for ssh")
558 help="username for ssh")
574 location = Unicode('', config=True,
559 location = Unicode('', config=True,
575 help="user@hostname location for ssh in one setting")
560 help="user@hostname location for ssh in one setting")
576 to_fetch = List([], config=True,
561 to_fetch = List([], config=True,
577 help="List of (remote, local) files to fetch after starting")
562 help="List of (remote, local) files to fetch after starting")
578 to_send = List([], config=True,
563 to_send = List([], config=True,
579 help="List of (local, remote) files to send before starting")
564 help="List of (local, remote) files to send before starting")
580
565
581 def _hostname_changed(self, name, old, new):
566 def _hostname_changed(self, name, old, new):
582 if self.user:
567 if self.user:
583 self.location = u'%s@%s' % (self.user, new)
568 self.location = u'%s@%s' % (self.user, new)
584 else:
569 else:
585 self.location = new
570 self.location = new
586
571
587 def _user_changed(self, name, old, new):
572 def _user_changed(self, name, old, new):
588 self.location = u'%s@%s' % (new, self.hostname)
573 self.location = u'%s@%s' % (new, self.hostname)
589
574
590 def find_args(self):
575 def find_args(self):
591 return self.ssh_cmd + self.ssh_args + [self.location] + \
576 return self.ssh_cmd + self.ssh_args + [self.location] + \
592 list(map(pipes.quote, self.program + self.program_args))
577 list(map(pipes.quote, self.program + self.program_args))
593
578
594 def _send_file(self, local, remote):
579 def _send_file(self, local, remote):
595 """send a single file"""
580 """send a single file"""
596 full_remote = "%s:%s" % (self.location, remote)
581 full_remote = "%s:%s" % (self.location, remote)
597 for i in range(10):
582 for i in range(10):
598 if not os.path.exists(local):
583 if not os.path.exists(local):
599 self.log.debug("waiting for %s" % local)
584 self.log.debug("waiting for %s" % local)
600 time.sleep(1)
585 time.sleep(1)
601 else:
586 else:
602 break
587 break
603 remote_dir = os.path.dirname(remote)
588 remote_dir = os.path.dirname(remote)
604 self.log.info("ensuring remote %s:%s/ exists", self.location, remote_dir)
589 self.log.info("ensuring remote %s:%s/ exists", self.location, remote_dir)
605 check_output(self.ssh_cmd + self.ssh_args + \
590 check_output(self.ssh_cmd + self.ssh_args + \
606 [self.location, 'mkdir', '-p', '--', remote_dir]
591 [self.location, 'mkdir', '-p', '--', remote_dir]
607 )
592 )
608 self.log.info("sending %s to %s", local, full_remote)
593 self.log.info("sending %s to %s", local, full_remote)
609 check_output(self.scp_cmd + [local, full_remote])
594 check_output(self.scp_cmd + [local, full_remote])
610
595
611 def send_files(self):
596 def send_files(self):
612 """send our files (called before start)"""
597 """send our files (called before start)"""
613 if not self.to_send:
598 if not self.to_send:
614 return
599 return
615 for local_file, remote_file in self.to_send:
600 for local_file, remote_file in self.to_send:
616 self._send_file(local_file, remote_file)
601 self._send_file(local_file, remote_file)
617
602
618 def _fetch_file(self, remote, local):
603 def _fetch_file(self, remote, local):
619 """fetch a single file"""
604 """fetch a single file"""
620 full_remote = "%s:%s" % (self.location, remote)
605 full_remote = "%s:%s" % (self.location, remote)
621 self.log.info("fetching %s from %s", local, full_remote)
606 self.log.info("fetching %s from %s", local, full_remote)
622 for i in range(10):
607 for i in range(10):
623 # wait up to 10s for remote file to exist
608 # wait up to 10s for remote file to exist
624 check = check_output(self.ssh_cmd + self.ssh_args + \
609 check = check_output(self.ssh_cmd + self.ssh_args + \
625 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
610 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
626 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
611 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
627 if check == u'no':
612 if check == u'no':
628 time.sleep(1)
613 time.sleep(1)
629 elif check == u'yes':
614 elif check == u'yes':
630 break
615 break
631 local_dir = os.path.dirname(local)
616 local_dir = os.path.dirname(local)
632 if not os.path.exists(local_dir):
617 ensure_dir_exists(local_dir, 775)
633 os.makedirs(local_dir, 775)
634 check_output(self.scp_cmd + [full_remote, local])
618 check_output(self.scp_cmd + [full_remote, local])
635
619
636 def fetch_files(self):
620 def fetch_files(self):
637 """fetch remote files (called after start)"""
621 """fetch remote files (called after start)"""
638 if not self.to_fetch:
622 if not self.to_fetch:
639 return
623 return
640 for remote_file, local_file in self.to_fetch:
624 for remote_file, local_file in self.to_fetch:
641 self._fetch_file(remote_file, local_file)
625 self._fetch_file(remote_file, local_file)
642
626
643 def start(self, hostname=None, user=None):
627 def start(self, hostname=None, user=None):
644 if hostname is not None:
628 if hostname is not None:
645 self.hostname = hostname
629 self.hostname = hostname
646 if user is not None:
630 if user is not None:
647 self.user = user
631 self.user = user
648
632
649 self.send_files()
633 self.send_files()
650 super(SSHLauncher, self).start()
634 super(SSHLauncher, self).start()
651 self.fetch_files()
635 self.fetch_files()
652
636
653 def signal(self, sig):
637 def signal(self, sig):
654 if self.state == 'running':
638 if self.state == 'running':
655 # send escaped ssh connection-closer
639 # send escaped ssh connection-closer
656 self.process.stdin.write('~.')
640 self.process.stdin.write('~.')
657 self.process.stdin.flush()
641 self.process.stdin.flush()
658
642
659 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
643 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
660
644
661 remote_profile_dir = Unicode('', config=True,
645 remote_profile_dir = Unicode('', config=True,
662 help="""The remote profile_dir to use.
646 help="""The remote profile_dir to use.
663
647
664 If not specified, use calling profile, stripping out possible leading homedir.
648 If not specified, use calling profile, stripping out possible leading homedir.
665 """)
649 """)
666
650
667 def _profile_dir_changed(self, name, old, new):
651 def _profile_dir_changed(self, name, old, new):
668 if not self.remote_profile_dir:
652 if not self.remote_profile_dir:
669 # trigger remote_profile_dir_default logic again,
653 # trigger remote_profile_dir_default logic again,
670 # in case it was already triggered before profile_dir was set
654 # in case it was already triggered before profile_dir was set
671 self.remote_profile_dir = self._strip_home(new)
655 self.remote_profile_dir = self._strip_home(new)
672
656
673 @staticmethod
657 @staticmethod
674 def _strip_home(path):
658 def _strip_home(path):
675 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
659 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
676 home = get_home_dir()
660 home = get_home_dir()
677 if not home.endswith('/'):
661 if not home.endswith('/'):
678 home = home+'/'
662 home = home+'/'
679
663
680 if path.startswith(home):
664 if path.startswith(home):
681 return path[len(home):]
665 return path[len(home):]
682 else:
666 else:
683 return path
667 return path
684
668
685 def _remote_profile_dir_default(self):
669 def _remote_profile_dir_default(self):
686 return self._strip_home(self.profile_dir)
670 return self._strip_home(self.profile_dir)
687
671
688 def _cluster_id_changed(self, name, old, new):
672 def _cluster_id_changed(self, name, old, new):
689 if new:
673 if new:
690 raise ValueError("cluster id not supported by SSH launchers")
674 raise ValueError("cluster id not supported by SSH launchers")
691
675
692 @property
676 @property
693 def cluster_args(self):
677 def cluster_args(self):
694 return ['--profile-dir', self.remote_profile_dir]
678 return ['--profile-dir', self.remote_profile_dir]
695
679
696 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
680 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
697
681
698 # alias back to *non-configurable* program[_args] for use in find_args()
682 # alias back to *non-configurable* program[_args] for use in find_args()
699 # this way all Controller/EngineSetLaunchers have the same form, rather
683 # this way all Controller/EngineSetLaunchers have the same form, rather
700 # than *some* having `program_args` and others `controller_args`
684 # than *some* having `program_args` and others `controller_args`
701
685
702 def _controller_cmd_default(self):
686 def _controller_cmd_default(self):
703 return ['ipcontroller']
687 return ['ipcontroller']
704
688
705 @property
689 @property
706 def program(self):
690 def program(self):
707 return self.controller_cmd
691 return self.controller_cmd
708
692
709 @property
693 @property
710 def program_args(self):
694 def program_args(self):
711 return self.cluster_args + self.controller_args
695 return self.cluster_args + self.controller_args
712
696
713 def _to_fetch_default(self):
697 def _to_fetch_default(self):
714 return [
698 return [
715 (os.path.join(self.remote_profile_dir, 'security', cf),
699 (os.path.join(self.remote_profile_dir, 'security', cf),
716 os.path.join(self.profile_dir, 'security', cf),)
700 os.path.join(self.profile_dir, 'security', cf),)
717 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
701 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
718 ]
702 ]
719
703
720 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
704 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
721
705
722 # alias back to *non-configurable* program[_args] for use in find_args()
706 # alias back to *non-configurable* program[_args] for use in find_args()
723 # this way all Controller/EngineSetLaunchers have the same form, rather
707 # this way all Controller/EngineSetLaunchers have the same form, rather
724 # than *some* having `program_args` and others `controller_args`
708 # than *some* having `program_args` and others `controller_args`
725
709
726 def _engine_cmd_default(self):
710 def _engine_cmd_default(self):
727 return ['ipengine']
711 return ['ipengine']
728
712
729 @property
713 @property
730 def program(self):
714 def program(self):
731 return self.engine_cmd
715 return self.engine_cmd
732
716
733 @property
717 @property
734 def program_args(self):
718 def program_args(self):
735 return self.cluster_args + self.engine_args
719 return self.cluster_args + self.engine_args
736
720
737 def _to_send_default(self):
721 def _to_send_default(self):
738 return [
722 return [
739 (os.path.join(self.profile_dir, 'security', cf),
723 (os.path.join(self.profile_dir, 'security', cf),
740 os.path.join(self.remote_profile_dir, 'security', cf))
724 os.path.join(self.remote_profile_dir, 'security', cf))
741 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
725 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
742 ]
726 ]
743
727
744
728
745 class SSHEngineSetLauncher(LocalEngineSetLauncher):
729 class SSHEngineSetLauncher(LocalEngineSetLauncher):
746 launcher_class = SSHEngineLauncher
730 launcher_class = SSHEngineLauncher
747 engines = Dict(config=True,
731 engines = Dict(config=True,
748 help="""dict of engines to launch. This is a dict by hostname of ints,
732 help="""dict of engines to launch. This is a dict by hostname of ints,
749 corresponding to the number of engines to start on that host.""")
733 corresponding to the number of engines to start on that host.""")
750
734
751 def _engine_cmd_default(self):
735 def _engine_cmd_default(self):
752 return ['ipengine']
736 return ['ipengine']
753
737
754 @property
738 @property
755 def engine_count(self):
739 def engine_count(self):
756 """determine engine count from `engines` dict"""
740 """determine engine count from `engines` dict"""
757 count = 0
741 count = 0
758 for n in itervalues(self.engines):
742 for n in itervalues(self.engines):
759 if isinstance(n, (tuple,list)):
743 if isinstance(n, (tuple,list)):
760 n,args = n
744 n,args = n
761 count += n
745 count += n
762 return count
746 return count
763
747
764 def start(self, n):
748 def start(self, n):
765 """Start engines by profile or profile_dir.
749 """Start engines by profile or profile_dir.
766 `n` is ignored, and the `engines` config property is used instead.
750 `n` is ignored, and the `engines` config property is used instead.
767 """
751 """
768
752
769 dlist = []
753 dlist = []
770 for host, n in iteritems(self.engines):
754 for host, n in iteritems(self.engines):
771 if isinstance(n, (tuple, list)):
755 if isinstance(n, (tuple, list)):
772 n, args = n
756 n, args = n
773 else:
757 else:
774 args = copy.deepcopy(self.engine_args)
758 args = copy.deepcopy(self.engine_args)
775
759
776 if '@' in host:
760 if '@' in host:
777 user,host = host.split('@',1)
761 user,host = host.split('@',1)
778 else:
762 else:
779 user=None
763 user=None
780 for i in range(n):
764 for i in range(n):
781 if i > 0:
765 if i > 0:
782 time.sleep(self.delay)
766 time.sleep(self.delay)
783 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
767 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
784 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
768 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
785 )
769 )
786 if i > 0:
770 if i > 0:
787 # only send files for the first engine on each host
771 # only send files for the first engine on each host
788 el.to_send = []
772 el.to_send = []
789
773
790 # Copy the engine args over to each engine launcher.
774 # Copy the engine args over to each engine launcher.
791 el.engine_cmd = self.engine_cmd
775 el.engine_cmd = self.engine_cmd
792 el.engine_args = args
776 el.engine_args = args
793 el.on_stop(self._notice_engine_stopped)
777 el.on_stop(self._notice_engine_stopped)
794 d = el.start(user=user, hostname=host)
778 d = el.start(user=user, hostname=host)
795 self.launchers[ "%s/%i" % (host,i) ] = el
779 self.launchers[ "%s/%i" % (host,i) ] = el
796 dlist.append(d)
780 dlist.append(d)
797 self.notify_start(dlist)
781 self.notify_start(dlist)
798 return dlist
782 return dlist
799
783
800
784
801 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
785 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
802 """Launcher for calling
786 """Launcher for calling
803 `ipcluster engines` on a remote machine.
787 `ipcluster engines` on a remote machine.
804
788
805 Requires that remote profile is already configured.
789 Requires that remote profile is already configured.
806 """
790 """
807
791
808 n = Integer()
792 n = Integer()
809 ipcluster_cmd = List(['ipcluster'], config=True)
793 ipcluster_cmd = List(['ipcluster'], config=True)
810
794
811 @property
795 @property
812 def program(self):
796 def program(self):
813 return self.ipcluster_cmd + ['engines']
797 return self.ipcluster_cmd + ['engines']
814
798
815 @property
799 @property
816 def program_args(self):
800 def program_args(self):
817 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
801 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
818
802
819 def _to_send_default(self):
803 def _to_send_default(self):
820 return [
804 return [
821 (os.path.join(self.profile_dir, 'security', cf),
805 (os.path.join(self.profile_dir, 'security', cf),
822 os.path.join(self.remote_profile_dir, 'security', cf))
806 os.path.join(self.remote_profile_dir, 'security', cf))
823 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
807 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
824 ]
808 ]
825
809
826 def start(self, n):
810 def start(self, n):
827 self.n = n
811 self.n = n
828 super(SSHProxyEngineSetLauncher, self).start()
812 super(SSHProxyEngineSetLauncher, self).start()
829
813
830
814
831 #-----------------------------------------------------------------------------
815 #-----------------------------------------------------------------------------
832 # Windows HPC Server 2008 scheduler launchers
816 # Windows HPC Server 2008 scheduler launchers
833 #-----------------------------------------------------------------------------
817 #-----------------------------------------------------------------------------
834
818
835
819
836 # This is only used on Windows.
820 # This is only used on Windows.
837 def find_job_cmd():
821 def find_job_cmd():
838 if WINDOWS:
822 if WINDOWS:
839 try:
823 try:
840 return find_cmd('job')
824 return find_cmd('job')
841 except (FindCmdError, ImportError):
825 except (FindCmdError, ImportError):
842 # ImportError will be raised if win32api is not installed
826 # ImportError will be raised if win32api is not installed
843 return 'job'
827 return 'job'
844 else:
828 else:
845 return 'job'
829 return 'job'
846
830
847
831
848 class WindowsHPCLauncher(BaseLauncher):
832 class WindowsHPCLauncher(BaseLauncher):
849
833
850 job_id_regexp = CRegExp(r'\d+', config=True,
834 job_id_regexp = CRegExp(r'\d+', config=True,
851 help="""A regular expression used to get the job id from the output of the
835 help="""A regular expression used to get the job id from the output of the
852 submit_command. """
836 submit_command. """
853 )
837 )
854 job_file_name = Unicode(u'ipython_job.xml', config=True,
838 job_file_name = Unicode(u'ipython_job.xml', config=True,
855 help="The filename of the instantiated job script.")
839 help="The filename of the instantiated job script.")
856 # The full path to the instantiated job script. This gets made dynamically
840 # The full path to the instantiated job script. This gets made dynamically
857 # by combining the work_dir with the job_file_name.
841 # by combining the work_dir with the job_file_name.
858 job_file = Unicode(u'')
842 job_file = Unicode(u'')
859 scheduler = Unicode('', config=True,
843 scheduler = Unicode('', config=True,
860 help="The hostname of the scheduler to submit the job to.")
844 help="The hostname of the scheduler to submit the job to.")
861 job_cmd = Unicode(find_job_cmd(), config=True,
845 job_cmd = Unicode(find_job_cmd(), config=True,
862 help="The command for submitting jobs.")
846 help="The command for submitting jobs.")
863
847
864 def __init__(self, work_dir=u'.', config=None, **kwargs):
848 def __init__(self, work_dir=u'.', config=None, **kwargs):
865 super(WindowsHPCLauncher, self).__init__(
849 super(WindowsHPCLauncher, self).__init__(
866 work_dir=work_dir, config=config, **kwargs
850 work_dir=work_dir, config=config, **kwargs
867 )
851 )
868
852
869 @property
853 @property
870 def job_file(self):
854 def job_file(self):
871 return os.path.join(self.work_dir, self.job_file_name)
855 return os.path.join(self.work_dir, self.job_file_name)
872
856
873 def write_job_file(self, n):
857 def write_job_file(self, n):
874 raise NotImplementedError("Implement write_job_file in a subclass.")
858 raise NotImplementedError("Implement write_job_file in a subclass.")
875
859
876 def find_args(self):
860 def find_args(self):
877 return [u'job.exe']
861 return [u'job.exe']
878
862
879 def parse_job_id(self, output):
863 def parse_job_id(self, output):
880 """Take the output of the submit command and return the job id."""
864 """Take the output of the submit command and return the job id."""
881 m = self.job_id_regexp.search(output)
865 m = self.job_id_regexp.search(output)
882 if m is not None:
866 if m is not None:
883 job_id = m.group()
867 job_id = m.group()
884 else:
868 else:
885 raise LauncherError("Job id couldn't be determined: %s" % output)
869 raise LauncherError("Job id couldn't be determined: %s" % output)
886 self.job_id = job_id
870 self.job_id = job_id
887 self.log.info('Job started with id: %r', job_id)
871 self.log.info('Job started with id: %r', job_id)
888 return job_id
872 return job_id
889
873
890 def start(self, n):
874 def start(self, n):
891 """Start n copies of the process using the Win HPC job scheduler."""
875 """Start n copies of the process using the Win HPC job scheduler."""
892 self.write_job_file(n)
876 self.write_job_file(n)
893 args = [
877 args = [
894 'submit',
878 'submit',
895 '/jobfile:%s' % self.job_file,
879 '/jobfile:%s' % self.job_file,
896 '/scheduler:%s' % self.scheduler
880 '/scheduler:%s' % self.scheduler
897 ]
881 ]
898 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
882 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
899
883
900 output = check_output([self.job_cmd]+args,
884 output = check_output([self.job_cmd]+args,
901 env=os.environ,
885 env=os.environ,
902 cwd=self.work_dir,
886 cwd=self.work_dir,
903 stderr=STDOUT
887 stderr=STDOUT
904 )
888 )
905 output = output.decode(DEFAULT_ENCODING, 'replace')
889 output = output.decode(DEFAULT_ENCODING, 'replace')
906 job_id = self.parse_job_id(output)
890 job_id = self.parse_job_id(output)
907 self.notify_start(job_id)
891 self.notify_start(job_id)
908 return job_id
892 return job_id
909
893
910 def stop(self):
894 def stop(self):
911 args = [
895 args = [
912 'cancel',
896 'cancel',
913 self.job_id,
897 self.job_id,
914 '/scheduler:%s' % self.scheduler
898 '/scheduler:%s' % self.scheduler
915 ]
899 ]
916 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
900 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
917 try:
901 try:
918 output = check_output([self.job_cmd]+args,
902 output = check_output([self.job_cmd]+args,
919 env=os.environ,
903 env=os.environ,
920 cwd=self.work_dir,
904 cwd=self.work_dir,
921 stderr=STDOUT
905 stderr=STDOUT
922 )
906 )
923 output = output.decode(DEFAULT_ENCODING, 'replace')
907 output = output.decode(DEFAULT_ENCODING, 'replace')
924 except:
908 except:
925 output = u'The job already appears to be stopped: %r' % self.job_id
909 output = u'The job already appears to be stopped: %r' % self.job_id
926 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
910 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
927 return output
911 return output
928
912
929
913
930 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
914 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
931
915
932 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
916 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
933 help="WinHPC xml job file.")
917 help="WinHPC xml job file.")
934 controller_args = List([], config=False,
918 controller_args = List([], config=False,
935 help="extra args to pass to ipcontroller")
919 help="extra args to pass to ipcontroller")
936
920
937 def write_job_file(self, n):
921 def write_job_file(self, n):
938 job = IPControllerJob(parent=self)
922 job = IPControllerJob(parent=self)
939
923
940 t = IPControllerTask(parent=self)
924 t = IPControllerTask(parent=self)
941 # The tasks work directory is *not* the actual work directory of
925 # The tasks work directory is *not* the actual work directory of
942 # the controller. It is used as the base path for the stdout/stderr
926 # the controller. It is used as the base path for the stdout/stderr
943 # files that the scheduler redirects to.
927 # files that the scheduler redirects to.
944 t.work_directory = self.profile_dir
928 t.work_directory = self.profile_dir
945 # Add the profile_dir and from self.start().
929 # Add the profile_dir and from self.start().
946 t.controller_args.extend(self.cluster_args)
930 t.controller_args.extend(self.cluster_args)
947 t.controller_args.extend(self.controller_args)
931 t.controller_args.extend(self.controller_args)
948 job.add_task(t)
932 job.add_task(t)
949
933
950 self.log.debug("Writing job description file: %s", self.job_file)
934 self.log.debug("Writing job description file: %s", self.job_file)
951 job.write(self.job_file)
935 job.write(self.job_file)
952
936
953 @property
937 @property
954 def job_file(self):
938 def job_file(self):
955 return os.path.join(self.profile_dir, self.job_file_name)
939 return os.path.join(self.profile_dir, self.job_file_name)
956
940
957 def start(self):
941 def start(self):
958 """Start the controller by profile_dir."""
942 """Start the controller by profile_dir."""
959 return super(WindowsHPCControllerLauncher, self).start(1)
943 return super(WindowsHPCControllerLauncher, self).start(1)
960
944
961
945
962 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
946 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
963
947
964 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
948 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
965 help="jobfile for ipengines job")
949 help="jobfile for ipengines job")
966 engine_args = List([], config=False,
950 engine_args = List([], config=False,
967 help="extra args to pas to ipengine")
951 help="extra args to pas to ipengine")
968
952
969 def write_job_file(self, n):
953 def write_job_file(self, n):
970 job = IPEngineSetJob(parent=self)
954 job = IPEngineSetJob(parent=self)
971
955
972 for i in range(n):
956 for i in range(n):
973 t = IPEngineTask(parent=self)
957 t = IPEngineTask(parent=self)
974 # The tasks work directory is *not* the actual work directory of
958 # The tasks work directory is *not* the actual work directory of
975 # the engine. It is used as the base path for the stdout/stderr
959 # the engine. It is used as the base path for the stdout/stderr
976 # files that the scheduler redirects to.
960 # files that the scheduler redirects to.
977 t.work_directory = self.profile_dir
961 t.work_directory = self.profile_dir
978 # Add the profile_dir and from self.start().
962 # Add the profile_dir and from self.start().
979 t.engine_args.extend(self.cluster_args)
963 t.engine_args.extend(self.cluster_args)
980 t.engine_args.extend(self.engine_args)
964 t.engine_args.extend(self.engine_args)
981 job.add_task(t)
965 job.add_task(t)
982
966
983 self.log.debug("Writing job description file: %s", self.job_file)
967 self.log.debug("Writing job description file: %s", self.job_file)
984 job.write(self.job_file)
968 job.write(self.job_file)
985
969
986 @property
970 @property
987 def job_file(self):
971 def job_file(self):
988 return os.path.join(self.profile_dir, self.job_file_name)
972 return os.path.join(self.profile_dir, self.job_file_name)
989
973
990 def start(self, n):
974 def start(self, n):
991 """Start the controller by profile_dir."""
975 """Start the controller by profile_dir."""
992 return super(WindowsHPCEngineSetLauncher, self).start(n)
976 return super(WindowsHPCEngineSetLauncher, self).start(n)
993
977
994
978
995 #-----------------------------------------------------------------------------
979 #-----------------------------------------------------------------------------
996 # Batch (PBS) system launchers
980 # Batch (PBS) system launchers
997 #-----------------------------------------------------------------------------
981 #-----------------------------------------------------------------------------
998
982
999 class BatchClusterAppMixin(ClusterAppMixin):
983 class BatchClusterAppMixin(ClusterAppMixin):
1000 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
984 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
1001 def _profile_dir_changed(self, name, old, new):
985 def _profile_dir_changed(self, name, old, new):
1002 self.context[name] = new
986 self.context[name] = new
1003 _cluster_id_changed = _profile_dir_changed
987 _cluster_id_changed = _profile_dir_changed
1004
988
1005 def _profile_dir_default(self):
989 def _profile_dir_default(self):
1006 self.context['profile_dir'] = ''
990 self.context['profile_dir'] = ''
1007 return ''
991 return ''
1008 def _cluster_id_default(self):
992 def _cluster_id_default(self):
1009 self.context['cluster_id'] = ''
993 self.context['cluster_id'] = ''
1010 return ''
994 return ''
1011
995
1012
996
1013 class BatchSystemLauncher(BaseLauncher):
997 class BatchSystemLauncher(BaseLauncher):
1014 """Launch an external process using a batch system.
998 """Launch an external process using a batch system.
1015
999
1016 This class is designed to work with UNIX batch systems like PBS, LSF,
1000 This class is designed to work with UNIX batch systems like PBS, LSF,
1017 GridEngine, etc. The overall model is that there are different commands
1001 GridEngine, etc. The overall model is that there are different commands
1018 like qsub, qdel, etc. that handle the starting and stopping of the process.
1002 like qsub, qdel, etc. that handle the starting and stopping of the process.
1019
1003
1020 This class also has the notion of a batch script. The ``batch_template``
1004 This class also has the notion of a batch script. The ``batch_template``
1021 attribute can be set to a string that is a template for the batch script.
1005 attribute can be set to a string that is a template for the batch script.
1022 This template is instantiated using string formatting. Thus the template can
1006 This template is instantiated using string formatting. Thus the template can
1023 use {n} fot the number of instances. Subclasses can add additional variables
1007 use {n} fot the number of instances. Subclasses can add additional variables
1024 to the template dict.
1008 to the template dict.
1025 """
1009 """
1026
1010
1027 # Subclasses must fill these in. See PBSEngineSet
1011 # Subclasses must fill these in. See PBSEngineSet
1028 submit_command = List([''], config=True,
1012 submit_command = List([''], config=True,
1029 help="The name of the command line program used to submit jobs.")
1013 help="The name of the command line program used to submit jobs.")
1030 delete_command = List([''], config=True,
1014 delete_command = List([''], config=True,
1031 help="The name of the command line program used to delete jobs.")
1015 help="The name of the command line program used to delete jobs.")
1032 job_id_regexp = CRegExp('', config=True,
1016 job_id_regexp = CRegExp('', config=True,
1033 help="""A regular expression used to get the job id from the output of the
1017 help="""A regular expression used to get the job id from the output of the
1034 submit_command.""")
1018 submit_command.""")
1035 job_id_regexp_group = Integer(0, config=True,
1019 job_id_regexp_group = Integer(0, config=True,
1036 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1020 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1037 batch_template = Unicode('', config=True,
1021 batch_template = Unicode('', config=True,
1038 help="The string that is the batch script template itself.")
1022 help="The string that is the batch script template itself.")
1039 batch_template_file = Unicode(u'', config=True,
1023 batch_template_file = Unicode(u'', config=True,
1040 help="The file that contains the batch template.")
1024 help="The file that contains the batch template.")
1041 batch_file_name = Unicode(u'batch_script', config=True,
1025 batch_file_name = Unicode(u'batch_script', config=True,
1042 help="The filename of the instantiated batch script.")
1026 help="The filename of the instantiated batch script.")
1043 queue = Unicode(u'', config=True,
1027 queue = Unicode(u'', config=True,
1044 help="The PBS Queue.")
1028 help="The PBS Queue.")
1045
1029
1046 def _queue_changed(self, name, old, new):
1030 def _queue_changed(self, name, old, new):
1047 self.context[name] = new
1031 self.context[name] = new
1048
1032
1049 n = Integer(1)
1033 n = Integer(1)
1050 _n_changed = _queue_changed
1034 _n_changed = _queue_changed
1051
1035
1052 # not configurable, override in subclasses
1036 # not configurable, override in subclasses
1053 # PBS Job Array regex
1037 # PBS Job Array regex
1054 job_array_regexp = CRegExp('')
1038 job_array_regexp = CRegExp('')
1055 job_array_template = Unicode('')
1039 job_array_template = Unicode('')
1056 # PBS Queue regex
1040 # PBS Queue regex
1057 queue_regexp = CRegExp('')
1041 queue_regexp = CRegExp('')
1058 queue_template = Unicode('')
1042 queue_template = Unicode('')
1059 # The default batch template, override in subclasses
1043 # The default batch template, override in subclasses
1060 default_template = Unicode('')
1044 default_template = Unicode('')
1061 # The full path to the instantiated batch script.
1045 # The full path to the instantiated batch script.
1062 batch_file = Unicode(u'')
1046 batch_file = Unicode(u'')
1063 # the format dict used with batch_template:
1047 # the format dict used with batch_template:
1064 context = Dict()
1048 context = Dict()
1065
1049
1066 def _context_default(self):
1050 def _context_default(self):
1067 """load the default context with the default values for the basic keys
1051 """load the default context with the default values for the basic keys
1068
1052
1069 because the _trait_changed methods only load the context if they
1053 because the _trait_changed methods only load the context if they
1070 are set to something other than the default value.
1054 are set to something other than the default value.
1071 """
1055 """
1072 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1056 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1073
1057
1074 # the Formatter instance for rendering the templates:
1058 # the Formatter instance for rendering the templates:
1075 formatter = Instance(EvalFormatter, (), {})
1059 formatter = Instance(EvalFormatter, (), {})
1076
1060
1077 def find_args(self):
1061 def find_args(self):
1078 return self.submit_command + [self.batch_file]
1062 return self.submit_command + [self.batch_file]
1079
1063
1080 def __init__(self, work_dir=u'.', config=None, **kwargs):
1064 def __init__(self, work_dir=u'.', config=None, **kwargs):
1081 super(BatchSystemLauncher, self).__init__(
1065 super(BatchSystemLauncher, self).__init__(
1082 work_dir=work_dir, config=config, **kwargs
1066 work_dir=work_dir, config=config, **kwargs
1083 )
1067 )
1084 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1068 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1085
1069
1086 def parse_job_id(self, output):
1070 def parse_job_id(self, output):
1087 """Take the output of the submit command and return the job id."""
1071 """Take the output of the submit command and return the job id."""
1088 m = self.job_id_regexp.search(output)
1072 m = self.job_id_regexp.search(output)
1089 if m is not None:
1073 if m is not None:
1090 job_id = m.group(self.job_id_regexp_group)
1074 job_id = m.group(self.job_id_regexp_group)
1091 else:
1075 else:
1092 raise LauncherError("Job id couldn't be determined: %s" % output)
1076 raise LauncherError("Job id couldn't be determined: %s" % output)
1093 self.job_id = job_id
1077 self.job_id = job_id
1094 self.log.info('Job submitted with job id: %r', job_id)
1078 self.log.info('Job submitted with job id: %r', job_id)
1095 return job_id
1079 return job_id
1096
1080
1097 def write_batch_script(self, n):
1081 def write_batch_script(self, n):
1098 """Instantiate and write the batch script to the work_dir."""
1082 """Instantiate and write the batch script to the work_dir."""
1099 self.n = n
1083 self.n = n
1100 # first priority is batch_template if set
1084 # first priority is batch_template if set
1101 if self.batch_template_file and not self.batch_template:
1085 if self.batch_template_file and not self.batch_template:
1102 # second priority is batch_template_file
1086 # second priority is batch_template_file
1103 with open(self.batch_template_file) as f:
1087 with open(self.batch_template_file) as f:
1104 self.batch_template = f.read()
1088 self.batch_template = f.read()
1105 if not self.batch_template:
1089 if not self.batch_template:
1106 # third (last) priority is default_template
1090 # third (last) priority is default_template
1107 self.batch_template = self.default_template
1091 self.batch_template = self.default_template
1108 # add jobarray or queue lines to user-specified template
1092 # add jobarray or queue lines to user-specified template
1109 # note that this is *only* when user did not specify a template.
1093 # note that this is *only* when user did not specify a template.
1110 self._insert_queue_in_script()
1094 self._insert_queue_in_script()
1111 self._insert_job_array_in_script()
1095 self._insert_job_array_in_script()
1112 script_as_string = self.formatter.format(self.batch_template, **self.context)
1096 script_as_string = self.formatter.format(self.batch_template, **self.context)
1113 self.log.debug('Writing batch script: %s', self.batch_file)
1097 self.log.debug('Writing batch script: %s', self.batch_file)
1114 with open(self.batch_file, 'w') as f:
1098 with open(self.batch_file, 'w') as f:
1115 f.write(script_as_string)
1099 f.write(script_as_string)
1116 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1100 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1117
1101
1118 def _insert_queue_in_script(self):
1102 def _insert_queue_in_script(self):
1119 """Inserts a queue if required into the batch script.
1103 """Inserts a queue if required into the batch script.
1120 """
1104 """
1121 if self.queue and not self.queue_regexp.search(self.batch_template):
1105 if self.queue and not self.queue_regexp.search(self.batch_template):
1122 self.log.debug("adding PBS queue settings to batch script")
1106 self.log.debug("adding PBS queue settings to batch script")
1123 firstline, rest = self.batch_template.split('\n',1)
1107 firstline, rest = self.batch_template.split('\n',1)
1124 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1108 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1125
1109
1126 def _insert_job_array_in_script(self):
1110 def _insert_job_array_in_script(self):
1127 """Inserts a job array if required into the batch script.
1111 """Inserts a job array if required into the batch script.
1128 """
1112 """
1129 if not self.job_array_regexp.search(self.batch_template):
1113 if not self.job_array_regexp.search(self.batch_template):
1130 self.log.debug("adding job array settings to batch script")
1114 self.log.debug("adding job array settings to batch script")
1131 firstline, rest = self.batch_template.split('\n',1)
1115 firstline, rest = self.batch_template.split('\n',1)
1132 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1116 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1133
1117
1134 def start(self, n):
1118 def start(self, n):
1135 """Start n copies of the process using a batch system."""
1119 """Start n copies of the process using a batch system."""
1136 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1120 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1137 # Here we save profile_dir in the context so they
1121 # Here we save profile_dir in the context so they
1138 # can be used in the batch script template as {profile_dir}
1122 # can be used in the batch script template as {profile_dir}
1139 self.write_batch_script(n)
1123 self.write_batch_script(n)
1140 output = check_output(self.args, env=os.environ)
1124 output = check_output(self.args, env=os.environ)
1141 output = output.decode(DEFAULT_ENCODING, 'replace')
1125 output = output.decode(DEFAULT_ENCODING, 'replace')
1142
1126
1143 job_id = self.parse_job_id(output)
1127 job_id = self.parse_job_id(output)
1144 self.notify_start(job_id)
1128 self.notify_start(job_id)
1145 return job_id
1129 return job_id
1146
1130
1147 def stop(self):
1131 def stop(self):
1148 try:
1132 try:
1149 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1133 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1150 stdout=PIPE, stderr=PIPE)
1134 stdout=PIPE, stderr=PIPE)
1151 out, err = p.communicate()
1135 out, err = p.communicate()
1152 output = out + err
1136 output = out + err
1153 except:
1137 except:
1154 self.log.exception("Problem stopping cluster with command: %s" %
1138 self.log.exception("Problem stopping cluster with command: %s" %
1155 (self.delete_command + [self.job_id]))
1139 (self.delete_command + [self.job_id]))
1156 output = ""
1140 output = ""
1157 output = output.decode(DEFAULT_ENCODING, 'replace')
1141 output = output.decode(DEFAULT_ENCODING, 'replace')
1158 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1142 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1159 return output
1143 return output
1160
1144
1161
1145
1162 class PBSLauncher(BatchSystemLauncher):
1146 class PBSLauncher(BatchSystemLauncher):
1163 """A BatchSystemLauncher subclass for PBS."""
1147 """A BatchSystemLauncher subclass for PBS."""
1164
1148
1165 submit_command = List(['qsub'], config=True,
1149 submit_command = List(['qsub'], config=True,
1166 help="The PBS submit command ['qsub']")
1150 help="The PBS submit command ['qsub']")
1167 delete_command = List(['qdel'], config=True,
1151 delete_command = List(['qdel'], config=True,
1168 help="The PBS delete command ['qsub']")
1152 help="The PBS delete command ['qsub']")
1169 job_id_regexp = CRegExp(r'\d+', config=True,
1153 job_id_regexp = CRegExp(r'\d+', config=True,
1170 help="Regular expresion for identifying the job ID [r'\d+']")
1154 help="Regular expresion for identifying the job ID [r'\d+']")
1171
1155
1172 batch_file = Unicode(u'')
1156 batch_file = Unicode(u'')
1173 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1157 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1174 job_array_template = Unicode('#PBS -t 1-{n}')
1158 job_array_template = Unicode('#PBS -t 1-{n}')
1175 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1159 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1176 queue_template = Unicode('#PBS -q {queue}')
1160 queue_template = Unicode('#PBS -q {queue}')
1177
1161
1178
1162
1179 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1163 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1180 """Launch a controller using PBS."""
1164 """Launch a controller using PBS."""
1181
1165
1182 batch_file_name = Unicode(u'pbs_controller', config=True,
1166 batch_file_name = Unicode(u'pbs_controller', config=True,
1183 help="batch file name for the controller job.")
1167 help="batch file name for the controller job.")
1184 default_template= Unicode("""#!/bin/sh
1168 default_template= Unicode("""#!/bin/sh
1185 #PBS -V
1169 #PBS -V
1186 #PBS -N ipcontroller
1170 #PBS -N ipcontroller
1187 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1171 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1188 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1172 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1189
1173
1190 def start(self):
1174 def start(self):
1191 """Start the controller by profile or profile_dir."""
1175 """Start the controller by profile or profile_dir."""
1192 return super(PBSControllerLauncher, self).start(1)
1176 return super(PBSControllerLauncher, self).start(1)
1193
1177
1194
1178
1195 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1179 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1196 """Launch Engines using PBS"""
1180 """Launch Engines using PBS"""
1197 batch_file_name = Unicode(u'pbs_engines', config=True,
1181 batch_file_name = Unicode(u'pbs_engines', config=True,
1198 help="batch file name for the engine(s) job.")
1182 help="batch file name for the engine(s) job.")
1199 default_template= Unicode(u"""#!/bin/sh
1183 default_template= Unicode(u"""#!/bin/sh
1200 #PBS -V
1184 #PBS -V
1201 #PBS -N ipengine
1185 #PBS -N ipengine
1202 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1186 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1203 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1187 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1204
1188
1205
1189
1206 #SGE is very similar to PBS
1190 #SGE is very similar to PBS
1207
1191
1208 class SGELauncher(PBSLauncher):
1192 class SGELauncher(PBSLauncher):
1209 """Sun GridEngine is a PBS clone with slightly different syntax"""
1193 """Sun GridEngine is a PBS clone with slightly different syntax"""
1210 job_array_regexp = CRegExp('#\$\W+\-t')
1194 job_array_regexp = CRegExp('#\$\W+\-t')
1211 job_array_template = Unicode('#$ -t 1-{n}')
1195 job_array_template = Unicode('#$ -t 1-{n}')
1212 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1196 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1213 queue_template = Unicode('#$ -q {queue}')
1197 queue_template = Unicode('#$ -q {queue}')
1214
1198
1215
1199
1216 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1200 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1217 """Launch a controller using SGE."""
1201 """Launch a controller using SGE."""
1218
1202
1219 batch_file_name = Unicode(u'sge_controller', config=True,
1203 batch_file_name = Unicode(u'sge_controller', config=True,
1220 help="batch file name for the ipontroller job.")
1204 help="batch file name for the ipontroller job.")
1221 default_template= Unicode(u"""#$ -V
1205 default_template= Unicode(u"""#$ -V
1222 #$ -S /bin/sh
1206 #$ -S /bin/sh
1223 #$ -N ipcontroller
1207 #$ -N ipcontroller
1224 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1208 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1225 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1209 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1226
1210
1227 def start(self):
1211 def start(self):
1228 """Start the controller by profile or profile_dir."""
1212 """Start the controller by profile or profile_dir."""
1229 return super(SGEControllerLauncher, self).start(1)
1213 return super(SGEControllerLauncher, self).start(1)
1230
1214
1231
1215
1232 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1216 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1233 """Launch Engines with SGE"""
1217 """Launch Engines with SGE"""
1234 batch_file_name = Unicode(u'sge_engines', config=True,
1218 batch_file_name = Unicode(u'sge_engines', config=True,
1235 help="batch file name for the engine(s) job.")
1219 help="batch file name for the engine(s) job.")
1236 default_template = Unicode("""#$ -V
1220 default_template = Unicode("""#$ -V
1237 #$ -S /bin/sh
1221 #$ -S /bin/sh
1238 #$ -N ipengine
1222 #$ -N ipengine
1239 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1223 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1240 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1224 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1241
1225
1242
1226
1243 # LSF launchers
1227 # LSF launchers
1244
1228
1245 class LSFLauncher(BatchSystemLauncher):
1229 class LSFLauncher(BatchSystemLauncher):
1246 """A BatchSystemLauncher subclass for LSF."""
1230 """A BatchSystemLauncher subclass for LSF."""
1247
1231
1248 submit_command = List(['bsub'], config=True,
1232 submit_command = List(['bsub'], config=True,
1249 help="The PBS submit command ['bsub']")
1233 help="The PBS submit command ['bsub']")
1250 delete_command = List(['bkill'], config=True,
1234 delete_command = List(['bkill'], config=True,
1251 help="The PBS delete command ['bkill']")
1235 help="The PBS delete command ['bkill']")
1252 job_id_regexp = CRegExp(r'\d+', config=True,
1236 job_id_regexp = CRegExp(r'\d+', config=True,
1253 help="Regular expresion for identifying the job ID [r'\d+']")
1237 help="Regular expresion for identifying the job ID [r'\d+']")
1254
1238
1255 batch_file = Unicode(u'')
1239 batch_file = Unicode(u'')
1256 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1240 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1257 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1241 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1258 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1242 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1259 queue_template = Unicode('#BSUB -q {queue}')
1243 queue_template = Unicode('#BSUB -q {queue}')
1260
1244
1261 def start(self, n):
1245 def start(self, n):
1262 """Start n copies of the process using LSF batch system.
1246 """Start n copies of the process using LSF batch system.
1263 This cant inherit from the base class because bsub expects
1247 This cant inherit from the base class because bsub expects
1264 to be piped a shell script in order to honor the #BSUB directives :
1248 to be piped a shell script in order to honor the #BSUB directives :
1265 bsub < script
1249 bsub < script
1266 """
1250 """
1267 # Here we save profile_dir in the context so they
1251 # Here we save profile_dir in the context so they
1268 # can be used in the batch script template as {profile_dir}
1252 # can be used in the batch script template as {profile_dir}
1269 self.write_batch_script(n)
1253 self.write_batch_script(n)
1270 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1254 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1271 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1255 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1272 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1256 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1273 output,err = p.communicate()
1257 output,err = p.communicate()
1274 output = output.decode(DEFAULT_ENCODING, 'replace')
1258 output = output.decode(DEFAULT_ENCODING, 'replace')
1275 job_id = self.parse_job_id(output)
1259 job_id = self.parse_job_id(output)
1276 self.notify_start(job_id)
1260 self.notify_start(job_id)
1277 return job_id
1261 return job_id
1278
1262
1279
1263
1280 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1264 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1281 """Launch a controller using LSF."""
1265 """Launch a controller using LSF."""
1282
1266
1283 batch_file_name = Unicode(u'lsf_controller', config=True,
1267 batch_file_name = Unicode(u'lsf_controller', config=True,
1284 help="batch file name for the controller job.")
1268 help="batch file name for the controller job.")
1285 default_template= Unicode("""#!/bin/sh
1269 default_template= Unicode("""#!/bin/sh
1286 #BSUB -J ipcontroller
1270 #BSUB -J ipcontroller
1287 #BSUB -oo ipcontroller.o.%%J
1271 #BSUB -oo ipcontroller.o.%%J
1288 #BSUB -eo ipcontroller.e.%%J
1272 #BSUB -eo ipcontroller.e.%%J
1289 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1273 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1290 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1274 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1291
1275
1292 def start(self):
1276 def start(self):
1293 """Start the controller by profile or profile_dir."""
1277 """Start the controller by profile or profile_dir."""
1294 return super(LSFControllerLauncher, self).start(1)
1278 return super(LSFControllerLauncher, self).start(1)
1295
1279
1296
1280
1297 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1281 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1298 """Launch Engines using LSF"""
1282 """Launch Engines using LSF"""
1299 batch_file_name = Unicode(u'lsf_engines', config=True,
1283 batch_file_name = Unicode(u'lsf_engines', config=True,
1300 help="batch file name for the engine(s) job.")
1284 help="batch file name for the engine(s) job.")
1301 default_template= Unicode(u"""#!/bin/sh
1285 default_template= Unicode(u"""#!/bin/sh
1302 #BSUB -oo ipengine.o.%%J
1286 #BSUB -oo ipengine.o.%%J
1303 #BSUB -eo ipengine.e.%%J
1287 #BSUB -eo ipengine.e.%%J
1304 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1288 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1305 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1289 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1306
1290
1307
1291
1308
1292
1309 class HTCondorLauncher(BatchSystemLauncher):
1293 class HTCondorLauncher(BatchSystemLauncher):
1310 """A BatchSystemLauncher subclass for HTCondor.
1294 """A BatchSystemLauncher subclass for HTCondor.
1311
1295
1312 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1296 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1313 that the python instance but otherwise is very similar to PBS. This is because
1297 that the python instance but otherwise is very similar to PBS. This is because
1314 HTCondor destroys sys.executable when launching remote processes - a launched
1298 HTCondor destroys sys.executable when launching remote processes - a launched
1315 python process depends on sys.executable to effectively evaluate its
1299 python process depends on sys.executable to effectively evaluate its
1316 module search paths. Without it, regardless of which python interpreter you launch
1300 module search paths. Without it, regardless of which python interpreter you launch
1317 you will get the to built in module search paths.
1301 you will get the to built in module search paths.
1318
1302
1319 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1303 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1320 this - the mechanism of shebanged scripts means that the python binary will be
1304 this - the mechanism of shebanged scripts means that the python binary will be
1321 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1305 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1322 scripts on the remote node*. This means you need to take care that:
1306 scripts on the remote node*. This means you need to take care that:
1323
1307
1324 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1308 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1325 of the python environment you wish to execute code in having top precedence.
1309 of the python environment you wish to execute code in having top precedence.
1326 b. This functionality is untested on Windows.
1310 b. This functionality is untested on Windows.
1327
1311
1328 If you need different behavior, consider making you own template.
1312 If you need different behavior, consider making you own template.
1329 """
1313 """
1330
1314
1331 submit_command = List(['condor_submit'], config=True,
1315 submit_command = List(['condor_submit'], config=True,
1332 help="The HTCondor submit command ['condor_submit']")
1316 help="The HTCondor submit command ['condor_submit']")
1333 delete_command = List(['condor_rm'], config=True,
1317 delete_command = List(['condor_rm'], config=True,
1334 help="The HTCondor delete command ['condor_rm']")
1318 help="The HTCondor delete command ['condor_rm']")
1335 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1319 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1336 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1320 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1337 job_id_regexp_group = Integer(1, config=True,
1321 job_id_regexp_group = Integer(1, config=True,
1338 help="""The group we wish to match in job_id_regexp [1]""")
1322 help="""The group we wish to match in job_id_regexp [1]""")
1339
1323
1340 job_array_regexp = CRegExp('queue\W+\$')
1324 job_array_regexp = CRegExp('queue\W+\$')
1341 job_array_template = Unicode('queue {n}')
1325 job_array_template = Unicode('queue {n}')
1342
1326
1343
1327
1344 def _insert_job_array_in_script(self):
1328 def _insert_job_array_in_script(self):
1345 """Inserts a job array if required into the batch script.
1329 """Inserts a job array if required into the batch script.
1346 """
1330 """
1347 if not self.job_array_regexp.search(self.batch_template):
1331 if not self.job_array_regexp.search(self.batch_template):
1348 self.log.debug("adding job array settings to batch script")
1332 self.log.debug("adding job array settings to batch script")
1349 #HTCondor requires that the job array goes at the bottom of the script
1333 #HTCondor requires that the job array goes at the bottom of the script
1350 self.batch_template = '\n'.join([self.batch_template,
1334 self.batch_template = '\n'.join([self.batch_template,
1351 self.job_array_template])
1335 self.job_array_template])
1352
1336
1353 def _insert_queue_in_script(self):
1337 def _insert_queue_in_script(self):
1354 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1338 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1355 specified in the script.
1339 specified in the script.
1356 """
1340 """
1357 pass
1341 pass
1358
1342
1359
1343
1360 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1344 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1361 """Launch a controller using HTCondor."""
1345 """Launch a controller using HTCondor."""
1362
1346
1363 batch_file_name = Unicode(u'htcondor_controller', config=True,
1347 batch_file_name = Unicode(u'htcondor_controller', config=True,
1364 help="batch file name for the controller job.")
1348 help="batch file name for the controller job.")
1365 default_template = Unicode(r"""
1349 default_template = Unicode(r"""
1366 universe = vanilla
1350 universe = vanilla
1367 executable = ipcontroller
1351 executable = ipcontroller
1368 # by default we expect a shared file system
1352 # by default we expect a shared file system
1369 transfer_executable = False
1353 transfer_executable = False
1370 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1354 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1371 """)
1355 """)
1372
1356
1373 def start(self):
1357 def start(self):
1374 """Start the controller by profile or profile_dir."""
1358 """Start the controller by profile or profile_dir."""
1375 return super(HTCondorControllerLauncher, self).start(1)
1359 return super(HTCondorControllerLauncher, self).start(1)
1376
1360
1377
1361
1378 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1362 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1379 """Launch Engines using HTCondor"""
1363 """Launch Engines using HTCondor"""
1380 batch_file_name = Unicode(u'htcondor_engines', config=True,
1364 batch_file_name = Unicode(u'htcondor_engines', config=True,
1381 help="batch file name for the engine(s) job.")
1365 help="batch file name for the engine(s) job.")
1382 default_template = Unicode("""
1366 default_template = Unicode("""
1383 universe = vanilla
1367 universe = vanilla
1384 executable = ipengine
1368 executable = ipengine
1385 # by default we expect a shared file system
1369 # by default we expect a shared file system
1386 transfer_executable = False
1370 transfer_executable = False
1387 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1371 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1388 """)
1372 """)
1389
1373
1390
1374
1391 #-----------------------------------------------------------------------------
1375 #-----------------------------------------------------------------------------
1392 # A launcher for ipcluster itself!
1376 # A launcher for ipcluster itself!
1393 #-----------------------------------------------------------------------------
1377 #-----------------------------------------------------------------------------
1394
1378
1395
1379
1396 class IPClusterLauncher(LocalProcessLauncher):
1380 class IPClusterLauncher(LocalProcessLauncher):
1397 """Launch the ipcluster program in an external process."""
1381 """Launch the ipcluster program in an external process."""
1398
1382
1399 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1383 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1400 help="Popen command for ipcluster")
1384 help="Popen command for ipcluster")
1401 ipcluster_args = List(
1385 ipcluster_args = List(
1402 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1386 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1403 help="Command line arguments to pass to ipcluster.")
1387 help="Command line arguments to pass to ipcluster.")
1404 ipcluster_subcommand = Unicode('start')
1388 ipcluster_subcommand = Unicode('start')
1405 profile = Unicode('default')
1389 profile = Unicode('default')
1406 n = Integer(2)
1390 n = Integer(2)
1407
1391
1408 def find_args(self):
1392 def find_args(self):
1409 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1393 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1410 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1394 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1411 self.ipcluster_args
1395 self.ipcluster_args
1412
1396
1413 def start(self):
1397 def start(self):
1414 return super(IPClusterLauncher, self).start()
1398 return super(IPClusterLauncher, self).start()
1415
1399
1416 #-----------------------------------------------------------------------------
1400 #-----------------------------------------------------------------------------
1417 # Collections of launchers
1401 # Collections of launchers
1418 #-----------------------------------------------------------------------------
1402 #-----------------------------------------------------------------------------
1419
1403
1420 local_launchers = [
1404 local_launchers = [
1421 LocalControllerLauncher,
1405 LocalControllerLauncher,
1422 LocalEngineLauncher,
1406 LocalEngineLauncher,
1423 LocalEngineSetLauncher,
1407 LocalEngineSetLauncher,
1424 ]
1408 ]
1425 mpi_launchers = [
1409 mpi_launchers = [
1426 MPILauncher,
1410 MPILauncher,
1427 MPIControllerLauncher,
1411 MPIControllerLauncher,
1428 MPIEngineSetLauncher,
1412 MPIEngineSetLauncher,
1429 ]
1413 ]
1430 ssh_launchers = [
1414 ssh_launchers = [
1431 SSHLauncher,
1415 SSHLauncher,
1432 SSHControllerLauncher,
1416 SSHControllerLauncher,
1433 SSHEngineLauncher,
1417 SSHEngineLauncher,
1434 SSHEngineSetLauncher,
1418 SSHEngineSetLauncher,
1435 SSHProxyEngineSetLauncher,
1419 SSHProxyEngineSetLauncher,
1436 ]
1420 ]
1437 winhpc_launchers = [
1421 winhpc_launchers = [
1438 WindowsHPCLauncher,
1422 WindowsHPCLauncher,
1439 WindowsHPCControllerLauncher,
1423 WindowsHPCControllerLauncher,
1440 WindowsHPCEngineSetLauncher,
1424 WindowsHPCEngineSetLauncher,
1441 ]
1425 ]
1442 pbs_launchers = [
1426 pbs_launchers = [
1443 PBSLauncher,
1427 PBSLauncher,
1444 PBSControllerLauncher,
1428 PBSControllerLauncher,
1445 PBSEngineSetLauncher,
1429 PBSEngineSetLauncher,
1446 ]
1430 ]
1447 sge_launchers = [
1431 sge_launchers = [
1448 SGELauncher,
1432 SGELauncher,
1449 SGEControllerLauncher,
1433 SGEControllerLauncher,
1450 SGEEngineSetLauncher,
1434 SGEEngineSetLauncher,
1451 ]
1435 ]
1452 lsf_launchers = [
1436 lsf_launchers = [
1453 LSFLauncher,
1437 LSFLauncher,
1454 LSFControllerLauncher,
1438 LSFControllerLauncher,
1455 LSFEngineSetLauncher,
1439 LSFEngineSetLauncher,
1456 ]
1440 ]
1457 htcondor_launchers = [
1441 htcondor_launchers = [
1458 HTCondorLauncher,
1442 HTCondorLauncher,
1459 HTCondorControllerLauncher,
1443 HTCondorControllerLauncher,
1460 HTCondorEngineSetLauncher,
1444 HTCondorEngineSetLauncher,
1461 ]
1445 ]
1462 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1446 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1463 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
1447 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
@@ -1,343 +1,335 b''
1 #-----------------------------------------------------------------------------
1 # Copyright (c) IPython Development Team.
2 # Copyright (c) 2010, IPython Development Team.
3 #
4 # Distributed under the terms of the Modified BSD License.
2 # Distributed under the terms of the Modified BSD License.
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
8
3
9 # Standard libary imports.
10 from base64 import decodestring
4 from base64 import decodestring
11 import os
5 import os
12 import re
6 import re
13
7
14 # System libary imports.
15 from IPython.external.qt import QtCore, QtGui
8 from IPython.external.qt import QtCore, QtGui
16
9
17 # Local imports
10 from IPython.utils.path import ensure_dir_exists
18 from IPython.utils.traitlets import Bool
11 from IPython.utils.traitlets import Bool
19 from IPython.qt.svg import save_svg, svg_to_clipboard, svg_to_image
12 from IPython.qt.svg import save_svg, svg_to_clipboard, svg_to_image
20 from .ipython_widget import IPythonWidget
13 from .ipython_widget import IPythonWidget
21
14
22
15
23 class RichIPythonWidget(IPythonWidget):
16 class RichIPythonWidget(IPythonWidget):
24 """ An IPythonWidget that supports rich text, including lists, images, and
17 """ An IPythonWidget that supports rich text, including lists, images, and
25 tables. Note that raw performance will be reduced compared to the plain
18 tables. Note that raw performance will be reduced compared to the plain
26 text version.
19 text version.
27 """
20 """
28
21
29 # RichIPythonWidget protected class variables.
22 # RichIPythonWidget protected class variables.
30 _payload_source_plot = 'IPython.kernel.zmq.pylab.backend_payload.add_plot_payload'
23 _payload_source_plot = 'IPython.kernel.zmq.pylab.backend_payload.add_plot_payload'
31 _jpg_supported = Bool(False)
24 _jpg_supported = Bool(False)
32
25
33 # Used to determine whether a given html export attempt has already
26 # Used to determine whether a given html export attempt has already
34 # displayed a warning about being unable to convert a png to svg.
27 # displayed a warning about being unable to convert a png to svg.
35 _svg_warning_displayed = False
28 _svg_warning_displayed = False
36
29
37 #---------------------------------------------------------------------------
30 #---------------------------------------------------------------------------
38 # 'object' interface
31 # 'object' interface
39 #---------------------------------------------------------------------------
32 #---------------------------------------------------------------------------
40
33
41 def __init__(self, *args, **kw):
34 def __init__(self, *args, **kw):
42 """ Create a RichIPythonWidget.
35 """ Create a RichIPythonWidget.
43 """
36 """
44 kw['kind'] = 'rich'
37 kw['kind'] = 'rich'
45 super(RichIPythonWidget, self).__init__(*args, **kw)
38 super(RichIPythonWidget, self).__init__(*args, **kw)
46
39
47 # Configure the ConsoleWidget HTML exporter for our formats.
40 # Configure the ConsoleWidget HTML exporter for our formats.
48 self._html_exporter.image_tag = self._get_image_tag
41 self._html_exporter.image_tag = self._get_image_tag
49
42
50 # Dictionary for resolving document resource names to SVG data.
43 # Dictionary for resolving document resource names to SVG data.
51 self._name_to_svg_map = {}
44 self._name_to_svg_map = {}
52
45
53 # Do we support jpg ?
46 # Do we support jpg ?
54 # it seems that sometime jpg support is a plugin of QT, so try to assume
47 # it seems that sometime jpg support is a plugin of QT, so try to assume
55 # it is not always supported.
48 # it is not always supported.
56 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
49 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
57 self._jpg_supported = 'jpeg' in _supported_format
50 self._jpg_supported = 'jpeg' in _supported_format
58
51
59
52
60 #---------------------------------------------------------------------------
53 #---------------------------------------------------------------------------
61 # 'ConsoleWidget' public interface overides
54 # 'ConsoleWidget' public interface overides
62 #---------------------------------------------------------------------------
55 #---------------------------------------------------------------------------
63
56
64 def export_html(self):
57 def export_html(self):
65 """ Shows a dialog to export HTML/XML in various formats.
58 """ Shows a dialog to export HTML/XML in various formats.
66
59
67 Overridden in order to reset the _svg_warning_displayed flag prior
60 Overridden in order to reset the _svg_warning_displayed flag prior
68 to the export running.
61 to the export running.
69 """
62 """
70 self._svg_warning_displayed = False
63 self._svg_warning_displayed = False
71 super(RichIPythonWidget, self).export_html()
64 super(RichIPythonWidget, self).export_html()
72
65
73
66
74 #---------------------------------------------------------------------------
67 #---------------------------------------------------------------------------
75 # 'ConsoleWidget' protected interface
68 # 'ConsoleWidget' protected interface
76 #---------------------------------------------------------------------------
69 #---------------------------------------------------------------------------
77
70
78 def _context_menu_make(self, pos):
71 def _context_menu_make(self, pos):
79 """ Reimplemented to return a custom context menu for images.
72 """ Reimplemented to return a custom context menu for images.
80 """
73 """
81 format = self._control.cursorForPosition(pos).charFormat()
74 format = self._control.cursorForPosition(pos).charFormat()
82 name = format.stringProperty(QtGui.QTextFormat.ImageName)
75 name = format.stringProperty(QtGui.QTextFormat.ImageName)
83 if name:
76 if name:
84 menu = QtGui.QMenu()
77 menu = QtGui.QMenu()
85
78
86 menu.addAction('Copy Image', lambda: self._copy_image(name))
79 menu.addAction('Copy Image', lambda: self._copy_image(name))
87 menu.addAction('Save Image As...', lambda: self._save_image(name))
80 menu.addAction('Save Image As...', lambda: self._save_image(name))
88 menu.addSeparator()
81 menu.addSeparator()
89
82
90 svg = self._name_to_svg_map.get(name, None)
83 svg = self._name_to_svg_map.get(name, None)
91 if svg is not None:
84 if svg is not None:
92 menu.addSeparator()
85 menu.addSeparator()
93 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
86 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
94 menu.addAction('Save SVG As...',
87 menu.addAction('Save SVG As...',
95 lambda: save_svg(svg, self._control))
88 lambda: save_svg(svg, self._control))
96 else:
89 else:
97 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
90 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
98 return menu
91 return menu
99
92
100 #---------------------------------------------------------------------------
93 #---------------------------------------------------------------------------
101 # 'BaseFrontendMixin' abstract interface
94 # 'BaseFrontendMixin' abstract interface
102 #---------------------------------------------------------------------------
95 #---------------------------------------------------------------------------
103 def _pre_image_append(self, msg, prompt_number):
96 def _pre_image_append(self, msg, prompt_number):
104 """ Append the Out[] prompt and make the output nicer
97 """ Append the Out[] prompt and make the output nicer
105
98
106 Shared code for some the following if statement
99 Shared code for some the following if statement
107 """
100 """
108 self.log.debug("pyout: %s", msg.get('content', ''))
101 self.log.debug("pyout: %s", msg.get('content', ''))
109 self._append_plain_text(self.output_sep, True)
102 self._append_plain_text(self.output_sep, True)
110 self._append_html(self._make_out_prompt(prompt_number), True)
103 self._append_html(self._make_out_prompt(prompt_number), True)
111 self._append_plain_text('\n', True)
104 self._append_plain_text('\n', True)
112
105
113 def _handle_pyout(self, msg):
106 def _handle_pyout(self, msg):
114 """ Overridden to handle rich data types, like SVG.
107 """ Overridden to handle rich data types, like SVG.
115 """
108 """
116 if not self._hidden and self._is_from_this_session(msg):
109 if not self._hidden and self._is_from_this_session(msg):
117 self.flush_clearoutput()
110 self.flush_clearoutput()
118 content = msg['content']
111 content = msg['content']
119 prompt_number = content.get('execution_count', 0)
112 prompt_number = content.get('execution_count', 0)
120 data = content['data']
113 data = content['data']
121 metadata = msg['content']['metadata']
114 metadata = msg['content']['metadata']
122 if 'image/svg+xml' in data:
115 if 'image/svg+xml' in data:
123 self._pre_image_append(msg, prompt_number)
116 self._pre_image_append(msg, prompt_number)
124 self._append_svg(data['image/svg+xml'], True)
117 self._append_svg(data['image/svg+xml'], True)
125 self._append_html(self.output_sep2, True)
118 self._append_html(self.output_sep2, True)
126 elif 'image/png' in data:
119 elif 'image/png' in data:
127 self._pre_image_append(msg, prompt_number)
120 self._pre_image_append(msg, prompt_number)
128 png = decodestring(data['image/png'].encode('ascii'))
121 png = decodestring(data['image/png'].encode('ascii'))
129 self._append_png(png, True, metadata=metadata.get('image/png', None))
122 self._append_png(png, True, metadata=metadata.get('image/png', None))
130 self._append_html(self.output_sep2, True)
123 self._append_html(self.output_sep2, True)
131 elif 'image/jpeg' in data and self._jpg_supported:
124 elif 'image/jpeg' in data and self._jpg_supported:
132 self._pre_image_append(msg, prompt_number)
125 self._pre_image_append(msg, prompt_number)
133 jpg = decodestring(data['image/jpeg'].encode('ascii'))
126 jpg = decodestring(data['image/jpeg'].encode('ascii'))
134 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
127 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
135 self._append_html(self.output_sep2, True)
128 self._append_html(self.output_sep2, True)
136 else:
129 else:
137 # Default back to the plain text representation.
130 # Default back to the plain text representation.
138 return super(RichIPythonWidget, self)._handle_pyout(msg)
131 return super(RichIPythonWidget, self)._handle_pyout(msg)
139
132
140 def _handle_display_data(self, msg):
133 def _handle_display_data(self, msg):
141 """ Overridden to handle rich data types, like SVG.
134 """ Overridden to handle rich data types, like SVG.
142 """
135 """
143 if not self._hidden and self._is_from_this_session(msg):
136 if not self._hidden and self._is_from_this_session(msg):
144 self.flush_clearoutput()
137 self.flush_clearoutput()
145 source = msg['content']['source']
138 source = msg['content']['source']
146 data = msg['content']['data']
139 data = msg['content']['data']
147 metadata = msg['content']['metadata']
140 metadata = msg['content']['metadata']
148 # Try to use the svg or html representations.
141 # Try to use the svg or html representations.
149 # FIXME: Is this the right ordering of things to try?
142 # FIXME: Is this the right ordering of things to try?
150 if 'image/svg+xml' in data:
143 if 'image/svg+xml' in data:
151 self.log.debug("display: %s", msg.get('content', ''))
144 self.log.debug("display: %s", msg.get('content', ''))
152 svg = data['image/svg+xml']
145 svg = data['image/svg+xml']
153 self._append_svg(svg, True)
146 self._append_svg(svg, True)
154 elif 'image/png' in data:
147 elif 'image/png' in data:
155 self.log.debug("display: %s", msg.get('content', ''))
148 self.log.debug("display: %s", msg.get('content', ''))
156 # PNG data is base64 encoded as it passes over the network
149 # PNG data is base64 encoded as it passes over the network
157 # in a JSON structure so we decode it.
150 # in a JSON structure so we decode it.
158 png = decodestring(data['image/png'].encode('ascii'))
151 png = decodestring(data['image/png'].encode('ascii'))
159 self._append_png(png, True, metadata=metadata.get('image/png', None))
152 self._append_png(png, True, metadata=metadata.get('image/png', None))
160 elif 'image/jpeg' in data and self._jpg_supported:
153 elif 'image/jpeg' in data and self._jpg_supported:
161 self.log.debug("display: %s", msg.get('content', ''))
154 self.log.debug("display: %s", msg.get('content', ''))
162 jpg = decodestring(data['image/jpeg'].encode('ascii'))
155 jpg = decodestring(data['image/jpeg'].encode('ascii'))
163 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
156 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
164 else:
157 else:
165 # Default back to the plain text representation.
158 # Default back to the plain text representation.
166 return super(RichIPythonWidget, self)._handle_display_data(msg)
159 return super(RichIPythonWidget, self)._handle_display_data(msg)
167
160
168 #---------------------------------------------------------------------------
161 #---------------------------------------------------------------------------
169 # 'RichIPythonWidget' protected interface
162 # 'RichIPythonWidget' protected interface
170 #---------------------------------------------------------------------------
163 #---------------------------------------------------------------------------
171
164
172 def _append_jpg(self, jpg, before_prompt=False, metadata=None):
165 def _append_jpg(self, jpg, before_prompt=False, metadata=None):
173 """ Append raw JPG data to the widget."""
166 """ Append raw JPG data to the widget."""
174 self._append_custom(self._insert_jpg, jpg, before_prompt, metadata=metadata)
167 self._append_custom(self._insert_jpg, jpg, before_prompt, metadata=metadata)
175
168
176 def _append_png(self, png, before_prompt=False, metadata=None):
169 def _append_png(self, png, before_prompt=False, metadata=None):
177 """ Append raw PNG data to the widget.
170 """ Append raw PNG data to the widget.
178 """
171 """
179 self._append_custom(self._insert_png, png, before_prompt, metadata=metadata)
172 self._append_custom(self._insert_png, png, before_prompt, metadata=metadata)
180
173
181 def _append_svg(self, svg, before_prompt=False):
174 def _append_svg(self, svg, before_prompt=False):
182 """ Append raw SVG data to the widget.
175 """ Append raw SVG data to the widget.
183 """
176 """
184 self._append_custom(self._insert_svg, svg, before_prompt)
177 self._append_custom(self._insert_svg, svg, before_prompt)
185
178
186 def _add_image(self, image):
179 def _add_image(self, image):
187 """ Adds the specified QImage to the document and returns a
180 """ Adds the specified QImage to the document and returns a
188 QTextImageFormat that references it.
181 QTextImageFormat that references it.
189 """
182 """
190 document = self._control.document()
183 document = self._control.document()
191 name = str(image.cacheKey())
184 name = str(image.cacheKey())
192 document.addResource(QtGui.QTextDocument.ImageResource,
185 document.addResource(QtGui.QTextDocument.ImageResource,
193 QtCore.QUrl(name), image)
186 QtCore.QUrl(name), image)
194 format = QtGui.QTextImageFormat()
187 format = QtGui.QTextImageFormat()
195 format.setName(name)
188 format.setName(name)
196 return format
189 return format
197
190
198 def _copy_image(self, name):
191 def _copy_image(self, name):
199 """ Copies the ImageResource with 'name' to the clipboard.
192 """ Copies the ImageResource with 'name' to the clipboard.
200 """
193 """
201 image = self._get_image(name)
194 image = self._get_image(name)
202 QtGui.QApplication.clipboard().setImage(image)
195 QtGui.QApplication.clipboard().setImage(image)
203
196
204 def _get_image(self, name):
197 def _get_image(self, name):
205 """ Returns the QImage stored as the ImageResource with 'name'.
198 """ Returns the QImage stored as the ImageResource with 'name'.
206 """
199 """
207 document = self._control.document()
200 document = self._control.document()
208 image = document.resource(QtGui.QTextDocument.ImageResource,
201 image = document.resource(QtGui.QTextDocument.ImageResource,
209 QtCore.QUrl(name))
202 QtCore.QUrl(name))
210 return image
203 return image
211
204
212 def _get_image_tag(self, match, path = None, format = "png"):
205 def _get_image_tag(self, match, path = None, format = "png"):
213 """ Return (X)HTML mark-up for the image-tag given by match.
206 """ Return (X)HTML mark-up for the image-tag given by match.
214
207
215 Parameters
208 Parameters
216 ----------
209 ----------
217 match : re.SRE_Match
210 match : re.SRE_Match
218 A match to an HTML image tag as exported by Qt, with
211 A match to an HTML image tag as exported by Qt, with
219 match.group("Name") containing the matched image ID.
212 match.group("Name") containing the matched image ID.
220
213
221 path : string|None, optional [default None]
214 path : string|None, optional [default None]
222 If not None, specifies a path to which supporting files may be
215 If not None, specifies a path to which supporting files may be
223 written (e.g., for linked images). If None, all images are to be
216 written (e.g., for linked images). If None, all images are to be
224 included inline.
217 included inline.
225
218
226 format : "png"|"svg"|"jpg", optional [default "png"]
219 format : "png"|"svg"|"jpg", optional [default "png"]
227 Format for returned or referenced images.
220 Format for returned or referenced images.
228 """
221 """
229 if format in ("png","jpg"):
222 if format in ("png","jpg"):
230 try:
223 try:
231 image = self._get_image(match.group("name"))
224 image = self._get_image(match.group("name"))
232 except KeyError:
225 except KeyError:
233 return "<b>Couldn't find image %s</b>" % match.group("name")
226 return "<b>Couldn't find image %s</b>" % match.group("name")
234
227
235 if path is not None:
228 if path is not None:
236 if not os.path.exists(path):
229 ensure_dir_exists(path)
237 os.mkdir(path)
238 relpath = os.path.basename(path)
230 relpath = os.path.basename(path)
239 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
231 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
240 "PNG"):
232 "PNG"):
241 return '<img src="%s/qt_img%s.%s">' % (relpath,
233 return '<img src="%s/qt_img%s.%s">' % (relpath,
242 match.group("name"),format)
234 match.group("name"),format)
243 else:
235 else:
244 return "<b>Couldn't save image!</b>"
236 return "<b>Couldn't save image!</b>"
245 else:
237 else:
246 ba = QtCore.QByteArray()
238 ba = QtCore.QByteArray()
247 buffer_ = QtCore.QBuffer(ba)
239 buffer_ = QtCore.QBuffer(ba)
248 buffer_.open(QtCore.QIODevice.WriteOnly)
240 buffer_.open(QtCore.QIODevice.WriteOnly)
249 image.save(buffer_, format.upper())
241 image.save(buffer_, format.upper())
250 buffer_.close()
242 buffer_.close()
251 return '<img src="data:image/%s;base64,\n%s\n" />' % (
243 return '<img src="data:image/%s;base64,\n%s\n" />' % (
252 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
244 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
253
245
254 elif format == "svg":
246 elif format == "svg":
255 try:
247 try:
256 svg = str(self._name_to_svg_map[match.group("name")])
248 svg = str(self._name_to_svg_map[match.group("name")])
257 except KeyError:
249 except KeyError:
258 if not self._svg_warning_displayed:
250 if not self._svg_warning_displayed:
259 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
251 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
260 'Cannot convert PNG images to SVG, export with PNG figures instead. '
252 'Cannot convert PNG images to SVG, export with PNG figures instead. '
261 'If you want to export matplotlib figures as SVG, add '
253 'If you want to export matplotlib figures as SVG, add '
262 'to your ipython config:\n\n'
254 'to your ipython config:\n\n'
263 '\tc.InlineBackend.figure_format = \'svg\'\n\n'
255 '\tc.InlineBackend.figure_format = \'svg\'\n\n'
264 'And regenerate the figures.',
256 'And regenerate the figures.',
265 QtGui.QMessageBox.Ok)
257 QtGui.QMessageBox.Ok)
266 self._svg_warning_displayed = True
258 self._svg_warning_displayed = True
267 return ("<b>Cannot convert PNG images to SVG.</b> "
259 return ("<b>Cannot convert PNG images to SVG.</b> "
268 "You must export this session with PNG images. "
260 "You must export this session with PNG images. "
269 "If you want to export matplotlib figures as SVG, add to your config "
261 "If you want to export matplotlib figures as SVG, add to your config "
270 "<span>c.InlineBackend.figure_format = 'svg'</span> "
262 "<span>c.InlineBackend.figure_format = 'svg'</span> "
271 "and regenerate the figures.")
263 "and regenerate the figures.")
272
264
273 # Not currently checking path, because it's tricky to find a
265 # Not currently checking path, because it's tricky to find a
274 # cross-browser way to embed external SVG images (e.g., via
266 # cross-browser way to embed external SVG images (e.g., via
275 # object or embed tags).
267 # object or embed tags).
276
268
277 # Chop stand-alone header from matplotlib SVG
269 # Chop stand-alone header from matplotlib SVG
278 offset = svg.find("<svg")
270 offset = svg.find("<svg")
279 assert(offset > -1)
271 assert(offset > -1)
280
272
281 return svg[offset:]
273 return svg[offset:]
282
274
283 else:
275 else:
284 return '<b>Unrecognized image format</b>'
276 return '<b>Unrecognized image format</b>'
285
277
286 def _insert_jpg(self, cursor, jpg, metadata=None):
278 def _insert_jpg(self, cursor, jpg, metadata=None):
287 """ Insert raw PNG data into the widget."""
279 """ Insert raw PNG data into the widget."""
288 self._insert_img(cursor, jpg, 'jpg', metadata=metadata)
280 self._insert_img(cursor, jpg, 'jpg', metadata=metadata)
289
281
290 def _insert_png(self, cursor, png, metadata=None):
282 def _insert_png(self, cursor, png, metadata=None):
291 """ Insert raw PNG data into the widget.
283 """ Insert raw PNG data into the widget.
292 """
284 """
293 self._insert_img(cursor, png, 'png', metadata=metadata)
285 self._insert_img(cursor, png, 'png', metadata=metadata)
294
286
295 def _insert_img(self, cursor, img, fmt, metadata=None):
287 def _insert_img(self, cursor, img, fmt, metadata=None):
296 """ insert a raw image, jpg or png """
288 """ insert a raw image, jpg or png """
297 if metadata:
289 if metadata:
298 width = metadata.get('width', None)
290 width = metadata.get('width', None)
299 height = metadata.get('height', None)
291 height = metadata.get('height', None)
300 else:
292 else:
301 width = height = None
293 width = height = None
302 try:
294 try:
303 image = QtGui.QImage()
295 image = QtGui.QImage()
304 image.loadFromData(img, fmt.upper())
296 image.loadFromData(img, fmt.upper())
305 if width and height:
297 if width and height:
306 image = image.scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
298 image = image.scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
307 elif width and not height:
299 elif width and not height:
308 image = image.scaledToWidth(width, transformMode=QtCore.Qt.SmoothTransformation)
300 image = image.scaledToWidth(width, transformMode=QtCore.Qt.SmoothTransformation)
309 elif height and not width:
301 elif height and not width:
310 image = image.scaledToHeight(height, transformMode=QtCore.Qt.SmoothTransformation)
302 image = image.scaledToHeight(height, transformMode=QtCore.Qt.SmoothTransformation)
311 except ValueError:
303 except ValueError:
312 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
304 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
313 else:
305 else:
314 format = self._add_image(image)
306 format = self._add_image(image)
315 cursor.insertBlock()
307 cursor.insertBlock()
316 cursor.insertImage(format)
308 cursor.insertImage(format)
317 cursor.insertBlock()
309 cursor.insertBlock()
318
310
319 def _insert_svg(self, cursor, svg):
311 def _insert_svg(self, cursor, svg):
320 """ Insert raw SVG data into the widet.
312 """ Insert raw SVG data into the widet.
321 """
313 """
322 try:
314 try:
323 image = svg_to_image(svg)
315 image = svg_to_image(svg)
324 except ValueError:
316 except ValueError:
325 self._insert_plain_text(cursor, 'Received invalid SVG data.')
317 self._insert_plain_text(cursor, 'Received invalid SVG data.')
326 else:
318 else:
327 format = self._add_image(image)
319 format = self._add_image(image)
328 self._name_to_svg_map[format.name()] = svg
320 self._name_to_svg_map[format.name()] = svg
329 cursor.insertBlock()
321 cursor.insertBlock()
330 cursor.insertImage(format)
322 cursor.insertImage(format)
331 cursor.insertBlock()
323 cursor.insertBlock()
332
324
333 def _save_image(self, name, format='PNG'):
325 def _save_image(self, name, format='PNG'):
334 """ Shows a save dialog for the ImageResource with 'name'.
326 """ Shows a save dialog for the ImageResource with 'name'.
335 """
327 """
336 dialog = QtGui.QFileDialog(self._control, 'Save Image')
328 dialog = QtGui.QFileDialog(self._control, 'Save Image')
337 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
329 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
338 dialog.setDefaultSuffix(format.lower())
330 dialog.setDefaultSuffix(format.lower())
339 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
331 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
340 if dialog.exec_():
332 if dialog.exec_():
341 filename = dialog.selectedFiles()[0]
333 filename = dialog.selectedFiles()[0]
342 image = self._get_image(name)
334 image = self._get_image(name)
343 image.save(filename, format)
335 image.save(filename, format)
@@ -1,574 +1,580 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 # Copyright (c) IPython Development Team.
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
12
13 #-----------------------------------------------------------------------------
14 # Imports
15 #-----------------------------------------------------------------------------
16
8
17 import os
9 import os
18 import sys
10 import sys
19 import errno
11 import errno
20 import shutil
12 import shutil
21 import random
13 import random
22 import tempfile
14 import tempfile
23 import warnings
15 import warnings
24 from hashlib import md5
16 from hashlib import md5
25 import glob
17 import glob
26
18
27 import IPython
19 import IPython
28 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.utils.process import system
21 from IPython.utils.process import system
30 from IPython.utils.importstring import import_item
22 from IPython.utils.importstring import import_item
31 from IPython.utils import py3compat
23 from IPython.utils import py3compat
32 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
33 # Code
25 # Code
34 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
35
27
36 fs_encoding = sys.getfilesystemencoding()
28 fs_encoding = sys.getfilesystemencoding()
37
29
38 def _get_long_path_name(path):
30 def _get_long_path_name(path):
39 """Dummy no-op."""
31 """Dummy no-op."""
40 return path
32 return path
41
33
42 def _writable_dir(path):
34 def _writable_dir(path):
43 """Whether `path` is a directory, to which the user has write access."""
35 """Whether `path` is a directory, to which the user has write access."""
44 return os.path.isdir(path) and os.access(path, os.W_OK)
36 return os.path.isdir(path) and os.access(path, os.W_OK)
45
37
46 if sys.platform == 'win32':
38 if sys.platform == 'win32':
47 @skip_doctest
39 @skip_doctest
48 def _get_long_path_name(path):
40 def _get_long_path_name(path):
49 """Get a long path name (expand ~) on Windows using ctypes.
41 """Get a long path name (expand ~) on Windows using ctypes.
50
42
51 Examples
43 Examples
52 --------
44 --------
53
45
54 >>> get_long_path_name('c:\\docume~1')
46 >>> get_long_path_name('c:\\docume~1')
55 u'c:\\\\Documents and Settings'
47 u'c:\\\\Documents and Settings'
56
48
57 """
49 """
58 try:
50 try:
59 import ctypes
51 import ctypes
60 except ImportError:
52 except ImportError:
61 raise ImportError('you need to have ctypes installed for this to work')
53 raise ImportError('you need to have ctypes installed for this to work')
62 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
54 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
63 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
55 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
64 ctypes.c_uint ]
56 ctypes.c_uint ]
65
57
66 buf = ctypes.create_unicode_buffer(260)
58 buf = ctypes.create_unicode_buffer(260)
67 rv = _GetLongPathName(path, buf, 260)
59 rv = _GetLongPathName(path, buf, 260)
68 if rv == 0 or rv > 260:
60 if rv == 0 or rv > 260:
69 return path
61 return path
70 else:
62 else:
71 return buf.value
63 return buf.value
72
64
73
65
74 def get_long_path_name(path):
66 def get_long_path_name(path):
75 """Expand a path into its long form.
67 """Expand a path into its long form.
76
68
77 On Windows this expands any ~ in the paths. On other platforms, it is
69 On Windows this expands any ~ in the paths. On other platforms, it is
78 a null operation.
70 a null operation.
79 """
71 """
80 return _get_long_path_name(path)
72 return _get_long_path_name(path)
81
73
82
74
83 def unquote_filename(name, win32=(sys.platform=='win32')):
75 def unquote_filename(name, win32=(sys.platform=='win32')):
84 """ On Windows, remove leading and trailing quotes from filenames.
76 """ On Windows, remove leading and trailing quotes from filenames.
85 """
77 """
86 if win32:
78 if win32:
87 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
79 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
88 name = name[1:-1]
80 name = name[1:-1]
89 return name
81 return name
90
82
91 def compress_user(path):
83 def compress_user(path):
92 """Reverse of :func:`os.path.expanduser`
84 """Reverse of :func:`os.path.expanduser`
93 """
85 """
94 home = os.path.expanduser('~')
86 home = os.path.expanduser('~')
95 if path.startswith(home):
87 if path.startswith(home):
96 path = "~" + path[len(home):]
88 path = "~" + path[len(home):]
97 return path
89 return path
98
90
99 def get_py_filename(name, force_win32=None):
91 def get_py_filename(name, force_win32=None):
100 """Return a valid python filename in the current directory.
92 """Return a valid python filename in the current directory.
101
93
102 If the given name is not a file, it adds '.py' and searches again.
94 If the given name is not a file, it adds '.py' and searches again.
103 Raises IOError with an informative message if the file isn't found.
95 Raises IOError with an informative message if the file isn't found.
104
96
105 On Windows, apply Windows semantics to the filename. In particular, remove
97 On Windows, apply Windows semantics to the filename. In particular, remove
106 any quoting that has been applied to it. This option can be forced for
98 any quoting that has been applied to it. This option can be forced for
107 testing purposes.
99 testing purposes.
108 """
100 """
109
101
110 name = os.path.expanduser(name)
102 name = os.path.expanduser(name)
111 if force_win32 is None:
103 if force_win32 is None:
112 win32 = (sys.platform == 'win32')
104 win32 = (sys.platform == 'win32')
113 else:
105 else:
114 win32 = force_win32
106 win32 = force_win32
115 name = unquote_filename(name, win32=win32)
107 name = unquote_filename(name, win32=win32)
116 if not os.path.isfile(name) and not name.endswith('.py'):
108 if not os.path.isfile(name) and not name.endswith('.py'):
117 name += '.py'
109 name += '.py'
118 if os.path.isfile(name):
110 if os.path.isfile(name):
119 return name
111 return name
120 else:
112 else:
121 raise IOError('File `%r` not found.' % name)
113 raise IOError('File `%r` not found.' % name)
122
114
123
115
124 def filefind(filename, path_dirs=None):
116 def filefind(filename, path_dirs=None):
125 """Find a file by looking through a sequence of paths.
117 """Find a file by looking through a sequence of paths.
126
118
127 This iterates through a sequence of paths looking for a file and returns
119 This iterates through a sequence of paths looking for a file and returns
128 the full, absolute path of the first occurence of the file. If no set of
120 the full, absolute path of the first occurence of the file. If no set of
129 path dirs is given, the filename is tested as is, after running through
121 path dirs is given, the filename is tested as is, after running through
130 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
122 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
131
123
132 filefind('myfile.txt')
124 filefind('myfile.txt')
133
125
134 will find the file in the current working dir, but::
126 will find the file in the current working dir, but::
135
127
136 filefind('~/myfile.txt')
128 filefind('~/myfile.txt')
137
129
138 Will find the file in the users home directory. This function does not
130 Will find the file in the users home directory. This function does not
139 automatically try any paths, such as the cwd or the user's home directory.
131 automatically try any paths, such as the cwd or the user's home directory.
140
132
141 Parameters
133 Parameters
142 ----------
134 ----------
143 filename : str
135 filename : str
144 The filename to look for.
136 The filename to look for.
145 path_dirs : str, None or sequence of str
137 path_dirs : str, None or sequence of str
146 The sequence of paths to look for the file in. If None, the filename
138 The sequence of paths to look for the file in. If None, the filename
147 need to be absolute or be in the cwd. If a string, the string is
139 need to be absolute or be in the cwd. If a string, the string is
148 put into a sequence and the searched. If a sequence, walk through
140 put into a sequence and the searched. If a sequence, walk through
149 each element and join with ``filename``, calling :func:`expandvars`
141 each element and join with ``filename``, calling :func:`expandvars`
150 and :func:`expanduser` before testing for existence.
142 and :func:`expanduser` before testing for existence.
151
143
152 Returns
144 Returns
153 -------
145 -------
154 Raises :exc:`IOError` or returns absolute path to file.
146 Raises :exc:`IOError` or returns absolute path to file.
155 """
147 """
156
148
157 # If paths are quoted, abspath gets confused, strip them...
149 # If paths are quoted, abspath gets confused, strip them...
158 filename = filename.strip('"').strip("'")
150 filename = filename.strip('"').strip("'")
159 # If the input is an absolute path, just check it exists
151 # If the input is an absolute path, just check it exists
160 if os.path.isabs(filename) and os.path.isfile(filename):
152 if os.path.isabs(filename) and os.path.isfile(filename):
161 return filename
153 return filename
162
154
163 if path_dirs is None:
155 if path_dirs is None:
164 path_dirs = ("",)
156 path_dirs = ("",)
165 elif isinstance(path_dirs, py3compat.string_types):
157 elif isinstance(path_dirs, py3compat.string_types):
166 path_dirs = (path_dirs,)
158 path_dirs = (path_dirs,)
167
159
168 for path in path_dirs:
160 for path in path_dirs:
169 if path == '.': path = py3compat.getcwd()
161 if path == '.': path = py3compat.getcwd()
170 testname = expand_path(os.path.join(path, filename))
162 testname = expand_path(os.path.join(path, filename))
171 if os.path.isfile(testname):
163 if os.path.isfile(testname):
172 return os.path.abspath(testname)
164 return os.path.abspath(testname)
173
165
174 raise IOError("File %r does not exist in any of the search paths: %r" %
166 raise IOError("File %r does not exist in any of the search paths: %r" %
175 (filename, path_dirs) )
167 (filename, path_dirs) )
176
168
177
169
178 class HomeDirError(Exception):
170 class HomeDirError(Exception):
179 pass
171 pass
180
172
181
173
182 def get_home_dir(require_writable=False):
174 def get_home_dir(require_writable=False):
183 """Return the 'home' directory, as a unicode string.
175 """Return the 'home' directory, as a unicode string.
184
176
185 Uses os.path.expanduser('~'), and checks for writability.
177 Uses os.path.expanduser('~'), and checks for writability.
186
178
187 See stdlib docs for how this is determined.
179 See stdlib docs for how this is determined.
188 $HOME is first priority on *ALL* platforms.
180 $HOME is first priority on *ALL* platforms.
189
181
190 Parameters
182 Parameters
191 ----------
183 ----------
192
184
193 require_writable : bool [default: False]
185 require_writable : bool [default: False]
194 if True:
186 if True:
195 guarantees the return value is a writable directory, otherwise
187 guarantees the return value is a writable directory, otherwise
196 raises HomeDirError
188 raises HomeDirError
197 if False:
189 if False:
198 The path is resolved, but it is not guaranteed to exist or be writable.
190 The path is resolved, but it is not guaranteed to exist or be writable.
199 """
191 """
200
192
201 homedir = os.path.expanduser('~')
193 homedir = os.path.expanduser('~')
202 # Next line will make things work even when /home/ is a symlink to
194 # Next line will make things work even when /home/ is a symlink to
203 # /usr/home as it is on FreeBSD, for example
195 # /usr/home as it is on FreeBSD, for example
204 homedir = os.path.realpath(homedir)
196 homedir = os.path.realpath(homedir)
205
197
206 if not _writable_dir(homedir) and os.name == 'nt':
198 if not _writable_dir(homedir) and os.name == 'nt':
207 # expanduser failed, use the registry to get the 'My Documents' folder.
199 # expanduser failed, use the registry to get the 'My Documents' folder.
208 try:
200 try:
209 try:
201 try:
210 import winreg as wreg # Py 3
202 import winreg as wreg # Py 3
211 except ImportError:
203 except ImportError:
212 import _winreg as wreg # Py 2
204 import _winreg as wreg # Py 2
213 key = wreg.OpenKey(
205 key = wreg.OpenKey(
214 wreg.HKEY_CURRENT_USER,
206 wreg.HKEY_CURRENT_USER,
215 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
207 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
216 )
208 )
217 homedir = wreg.QueryValueEx(key,'Personal')[0]
209 homedir = wreg.QueryValueEx(key,'Personal')[0]
218 key.Close()
210 key.Close()
219 except:
211 except:
220 pass
212 pass
221
213
222 if (not require_writable) or _writable_dir(homedir):
214 if (not require_writable) or _writable_dir(homedir):
223 return py3compat.cast_unicode(homedir, fs_encoding)
215 return py3compat.cast_unicode(homedir, fs_encoding)
224 else:
216 else:
225 raise HomeDirError('%s is not a writable dir, '
217 raise HomeDirError('%s is not a writable dir, '
226 'set $HOME environment variable to override' % homedir)
218 'set $HOME environment variable to override' % homedir)
227
219
228 def get_xdg_dir():
220 def get_xdg_dir():
229 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
221 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
230
222
231 This is only for non-OS X posix (Linux,Unix,etc.) systems.
223 This is only for non-OS X posix (Linux,Unix,etc.) systems.
232 """
224 """
233
225
234 env = os.environ
226 env = os.environ
235
227
236 if os.name == 'posix' and sys.platform != 'darwin':
228 if os.name == 'posix' and sys.platform != 'darwin':
237 # Linux, Unix, AIX, etc.
229 # Linux, Unix, AIX, etc.
238 # use ~/.config if empty OR not set
230 # use ~/.config if empty OR not set
239 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
231 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
240 if xdg and _writable_dir(xdg):
232 if xdg and _writable_dir(xdg):
241 return py3compat.cast_unicode(xdg, fs_encoding)
233 return py3compat.cast_unicode(xdg, fs_encoding)
242
234
243 return None
235 return None
244
236
245
237
246 def get_xdg_cache_dir():
238 def get_xdg_cache_dir():
247 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
239 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
248
240
249 This is only for non-OS X posix (Linux,Unix,etc.) systems.
241 This is only for non-OS X posix (Linux,Unix,etc.) systems.
250 """
242 """
251
243
252 env = os.environ
244 env = os.environ
253
245
254 if os.name == 'posix' and sys.platform != 'darwin':
246 if os.name == 'posix' and sys.platform != 'darwin':
255 # Linux, Unix, AIX, etc.
247 # Linux, Unix, AIX, etc.
256 # use ~/.cache if empty OR not set
248 # use ~/.cache if empty OR not set
257 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
249 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
258 if xdg and _writable_dir(xdg):
250 if xdg and _writable_dir(xdg):
259 return py3compat.cast_unicode(xdg, fs_encoding)
251 return py3compat.cast_unicode(xdg, fs_encoding)
260
252
261 return None
253 return None
262
254
263
255
264 def get_ipython_dir():
256 def get_ipython_dir():
265 """Get the IPython directory for this platform and user.
257 """Get the IPython directory for this platform and user.
266
258
267 This uses the logic in `get_home_dir` to find the home directory
259 This uses the logic in `get_home_dir` to find the home directory
268 and then adds .ipython to the end of the path.
260 and then adds .ipython to the end of the path.
269 """
261 """
270
262
271 env = os.environ
263 env = os.environ
272 pjoin = os.path.join
264 pjoin = os.path.join
273
265
274
266
275 ipdir_def = '.ipython'
267 ipdir_def = '.ipython'
276
268
277 home_dir = get_home_dir()
269 home_dir = get_home_dir()
278 xdg_dir = get_xdg_dir()
270 xdg_dir = get_xdg_dir()
279
271
280 # import pdb; pdb.set_trace() # dbg
272 # import pdb; pdb.set_trace() # dbg
281 if 'IPYTHON_DIR' in env:
273 if 'IPYTHON_DIR' in env:
282 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
274 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
283 'Please use IPYTHONDIR instead.')
275 'Please use IPYTHONDIR instead.')
284 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
276 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
285 if ipdir is None:
277 if ipdir is None:
286 # not set explicitly, use ~/.ipython
278 # not set explicitly, use ~/.ipython
287 ipdir = pjoin(home_dir, ipdir_def)
279 ipdir = pjoin(home_dir, ipdir_def)
288 if xdg_dir:
280 if xdg_dir:
289 # Several IPython versions (up to 1.x) defaulted to .config/ipython
281 # Several IPython versions (up to 1.x) defaulted to .config/ipython
290 # on Linux. We have decided to go back to using .ipython everywhere
282 # on Linux. We have decided to go back to using .ipython everywhere
291 xdg_ipdir = pjoin(xdg_dir, 'ipython')
283 xdg_ipdir = pjoin(xdg_dir, 'ipython')
292
284
293 if _writable_dir(xdg_ipdir):
285 if _writable_dir(xdg_ipdir):
294 cu = compress_user
286 cu = compress_user
295 if os.path.exists(ipdir):
287 if os.path.exists(ipdir):
296 warnings.warn(('Ignoring {0} in favour of {1}. Remove {0} '
288 warnings.warn(('Ignoring {0} in favour of {1}. Remove {0} '
297 'to get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
289 'to get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
298 else:
290 else:
299 warnings.warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
291 warnings.warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
300 os.rename(xdg_ipdir, ipdir)
292 os.rename(xdg_ipdir, ipdir)
301
293
302 ipdir = os.path.normpath(os.path.expanduser(ipdir))
294 ipdir = os.path.normpath(os.path.expanduser(ipdir))
303
295
304 if os.path.exists(ipdir) and not _writable_dir(ipdir):
296 if os.path.exists(ipdir) and not _writable_dir(ipdir):
305 # ipdir exists, but is not writable
297 # ipdir exists, but is not writable
306 warnings.warn("IPython dir '%s' is not a writable location,"
298 warnings.warn("IPython dir '%s' is not a writable location,"
307 " using a temp directory."%ipdir)
299 " using a temp directory."%ipdir)
308 ipdir = tempfile.mkdtemp()
300 ipdir = tempfile.mkdtemp()
309 elif not os.path.exists(ipdir):
301 elif not os.path.exists(ipdir):
310 parent = os.path.dirname(ipdir)
302 parent = os.path.dirname(ipdir)
311 if not _writable_dir(parent):
303 if not _writable_dir(parent):
312 # ipdir does not exist and parent isn't writable
304 # ipdir does not exist and parent isn't writable
313 warnings.warn("IPython parent '%s' is not a writable location,"
305 warnings.warn("IPython parent '%s' is not a writable location,"
314 " using a temp directory."%parent)
306 " using a temp directory."%parent)
315 ipdir = tempfile.mkdtemp()
307 ipdir = tempfile.mkdtemp()
316
308
317 return py3compat.cast_unicode(ipdir, fs_encoding)
309 return py3compat.cast_unicode(ipdir, fs_encoding)
318
310
319
311
320 def get_ipython_cache_dir():
312 def get_ipython_cache_dir():
321 """Get the cache directory it is created if it does not exist."""
313 """Get the cache directory it is created if it does not exist."""
322 xdgdir = get_xdg_cache_dir()
314 xdgdir = get_xdg_cache_dir()
323 if xdgdir is None:
315 if xdgdir is None:
324 return get_ipython_dir()
316 return get_ipython_dir()
325 ipdir = os.path.join(xdgdir, "ipython")
317 ipdir = os.path.join(xdgdir, "ipython")
326 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
318 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
327 os.makedirs(ipdir)
319 ensure_dir_exists(ipdir)
328 elif not _writable_dir(xdgdir):
320 elif not _writable_dir(xdgdir):
329 return get_ipython_dir()
321 return get_ipython_dir()
330
322
331 return py3compat.cast_unicode(ipdir, fs_encoding)
323 return py3compat.cast_unicode(ipdir, fs_encoding)
332
324
333
325
334 def get_ipython_package_dir():
326 def get_ipython_package_dir():
335 """Get the base directory where IPython itself is installed."""
327 """Get the base directory where IPython itself is installed."""
336 ipdir = os.path.dirname(IPython.__file__)
328 ipdir = os.path.dirname(IPython.__file__)
337 return py3compat.cast_unicode(ipdir, fs_encoding)
329 return py3compat.cast_unicode(ipdir, fs_encoding)
338
330
339
331
340 def get_ipython_module_path(module_str):
332 def get_ipython_module_path(module_str):
341 """Find the path to an IPython module in this version of IPython.
333 """Find the path to an IPython module in this version of IPython.
342
334
343 This will always find the version of the module that is in this importable
335 This will always find the version of the module that is in this importable
344 IPython package. This will always return the path to the ``.py``
336 IPython package. This will always return the path to the ``.py``
345 version of the module.
337 version of the module.
346 """
338 """
347 if module_str == 'IPython':
339 if module_str == 'IPython':
348 return os.path.join(get_ipython_package_dir(), '__init__.py')
340 return os.path.join(get_ipython_package_dir(), '__init__.py')
349 mod = import_item(module_str)
341 mod = import_item(module_str)
350 the_path = mod.__file__.replace('.pyc', '.py')
342 the_path = mod.__file__.replace('.pyc', '.py')
351 the_path = the_path.replace('.pyo', '.py')
343 the_path = the_path.replace('.pyo', '.py')
352 return py3compat.cast_unicode(the_path, fs_encoding)
344 return py3compat.cast_unicode(the_path, fs_encoding)
353
345
354 def locate_profile(profile='default'):
346 def locate_profile(profile='default'):
355 """Find the path to the folder associated with a given profile.
347 """Find the path to the folder associated with a given profile.
356
348
357 I.e. find $IPYTHONDIR/profile_whatever.
349 I.e. find $IPYTHONDIR/profile_whatever.
358 """
350 """
359 from IPython.core.profiledir import ProfileDir, ProfileDirError
351 from IPython.core.profiledir import ProfileDir, ProfileDirError
360 try:
352 try:
361 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
353 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
362 except ProfileDirError:
354 except ProfileDirError:
363 # IOError makes more sense when people are expecting a path
355 # IOError makes more sense when people are expecting a path
364 raise IOError("Couldn't find profile %r" % profile)
356 raise IOError("Couldn't find profile %r" % profile)
365 return pd.location
357 return pd.location
366
358
367 def expand_path(s):
359 def expand_path(s):
368 """Expand $VARS and ~names in a string, like a shell
360 """Expand $VARS and ~names in a string, like a shell
369
361
370 :Examples:
362 :Examples:
371
363
372 In [2]: os.environ['FOO']='test'
364 In [2]: os.environ['FOO']='test'
373
365
374 In [3]: expand_path('variable FOO is $FOO')
366 In [3]: expand_path('variable FOO is $FOO')
375 Out[3]: 'variable FOO is test'
367 Out[3]: 'variable FOO is test'
376 """
368 """
377 # This is a pretty subtle hack. When expand user is given a UNC path
369 # This is a pretty subtle hack. When expand user is given a UNC path
378 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
370 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
379 # the $ to get (\\server\share\%username%). I think it considered $
371 # the $ to get (\\server\share\%username%). I think it considered $
380 # alone an empty var. But, we need the $ to remains there (it indicates
372 # alone an empty var. But, we need the $ to remains there (it indicates
381 # a hidden share).
373 # a hidden share).
382 if os.name=='nt':
374 if os.name=='nt':
383 s = s.replace('$\\', 'IPYTHON_TEMP')
375 s = s.replace('$\\', 'IPYTHON_TEMP')
384 s = os.path.expandvars(os.path.expanduser(s))
376 s = os.path.expandvars(os.path.expanduser(s))
385 if os.name=='nt':
377 if os.name=='nt':
386 s = s.replace('IPYTHON_TEMP', '$\\')
378 s = s.replace('IPYTHON_TEMP', '$\\')
387 return s
379 return s
388
380
389
381
390 def unescape_glob(string):
382 def unescape_glob(string):
391 """Unescape glob pattern in `string`."""
383 """Unescape glob pattern in `string`."""
392 def unescape(s):
384 def unescape(s):
393 for pattern in '*[]!?':
385 for pattern in '*[]!?':
394 s = s.replace(r'\{0}'.format(pattern), pattern)
386 s = s.replace(r'\{0}'.format(pattern), pattern)
395 return s
387 return s
396 return '\\'.join(map(unescape, string.split('\\\\')))
388 return '\\'.join(map(unescape, string.split('\\\\')))
397
389
398
390
399 def shellglob(args):
391 def shellglob(args):
400 """
392 """
401 Do glob expansion for each element in `args` and return a flattened list.
393 Do glob expansion for each element in `args` and return a flattened list.
402
394
403 Unmatched glob pattern will remain as-is in the returned list.
395 Unmatched glob pattern will remain as-is in the returned list.
404
396
405 """
397 """
406 expanded = []
398 expanded = []
407 # Do not unescape backslash in Windows as it is interpreted as
399 # Do not unescape backslash in Windows as it is interpreted as
408 # path separator:
400 # path separator:
409 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
401 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
410 for a in args:
402 for a in args:
411 expanded.extend(glob.glob(a) or [unescape(a)])
403 expanded.extend(glob.glob(a) or [unescape(a)])
412 return expanded
404 return expanded
413
405
414
406
415 def target_outdated(target,deps):
407 def target_outdated(target,deps):
416 """Determine whether a target is out of date.
408 """Determine whether a target is out of date.
417
409
418 target_outdated(target,deps) -> 1/0
410 target_outdated(target,deps) -> 1/0
419
411
420 deps: list of filenames which MUST exist.
412 deps: list of filenames which MUST exist.
421 target: single filename which may or may not exist.
413 target: single filename which may or may not exist.
422
414
423 If target doesn't exist or is older than any file listed in deps, return
415 If target doesn't exist or is older than any file listed in deps, return
424 true, otherwise return false.
416 true, otherwise return false.
425 """
417 """
426 try:
418 try:
427 target_time = os.path.getmtime(target)
419 target_time = os.path.getmtime(target)
428 except os.error:
420 except os.error:
429 return 1
421 return 1
430 for dep in deps:
422 for dep in deps:
431 dep_time = os.path.getmtime(dep)
423 dep_time = os.path.getmtime(dep)
432 if dep_time > target_time:
424 if dep_time > target_time:
433 #print "For target",target,"Dep failed:",dep # dbg
425 #print "For target",target,"Dep failed:",dep # dbg
434 #print "times (dep,tar):",dep_time,target_time # dbg
426 #print "times (dep,tar):",dep_time,target_time # dbg
435 return 1
427 return 1
436 return 0
428 return 0
437
429
438
430
439 def target_update(target,deps,cmd):
431 def target_update(target,deps,cmd):
440 """Update a target with a given command given a list of dependencies.
432 """Update a target with a given command given a list of dependencies.
441
433
442 target_update(target,deps,cmd) -> runs cmd if target is outdated.
434 target_update(target,deps,cmd) -> runs cmd if target is outdated.
443
435
444 This is just a wrapper around target_outdated() which calls the given
436 This is just a wrapper around target_outdated() which calls the given
445 command if target is outdated."""
437 command if target is outdated."""
446
438
447 if target_outdated(target,deps):
439 if target_outdated(target,deps):
448 system(cmd)
440 system(cmd)
449
441
450 def filehash(path):
442 def filehash(path):
451 """Make an MD5 hash of a file, ignoring any differences in line
443 """Make an MD5 hash of a file, ignoring any differences in line
452 ending characters."""
444 ending characters."""
453 with open(path, "rU") as f:
445 with open(path, "rU") as f:
454 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
446 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
455
447
456 # If the config is unmodified from the default, we'll just delete it.
448 # If the config is unmodified from the default, we'll just delete it.
457 # These are consistent for 0.10.x, thankfully. We're not going to worry about
449 # These are consistent for 0.10.x, thankfully. We're not going to worry about
458 # older versions.
450 # older versions.
459 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
451 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
460 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
452 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
461
453
462 def check_for_old_config(ipython_dir=None):
454 def check_for_old_config(ipython_dir=None):
463 """Check for old config files, and present a warning if they exist.
455 """Check for old config files, and present a warning if they exist.
464
456
465 A link to the docs of the new config is included in the message.
457 A link to the docs of the new config is included in the message.
466
458
467 This should mitigate confusion with the transition to the new
459 This should mitigate confusion with the transition to the new
468 config system in 0.11.
460 config system in 0.11.
469 """
461 """
470 if ipython_dir is None:
462 if ipython_dir is None:
471 ipython_dir = get_ipython_dir()
463 ipython_dir = get_ipython_dir()
472
464
473 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
465 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
474 warned = False
466 warned = False
475 for cfg in old_configs:
467 for cfg in old_configs:
476 f = os.path.join(ipython_dir, cfg)
468 f = os.path.join(ipython_dir, cfg)
477 if os.path.exists(f):
469 if os.path.exists(f):
478 if filehash(f) == old_config_md5.get(cfg, ''):
470 if filehash(f) == old_config_md5.get(cfg, ''):
479 os.unlink(f)
471 os.unlink(f)
480 else:
472 else:
481 warnings.warn("Found old IPython config file %r (modified by user)"%f)
473 warnings.warn("Found old IPython config file %r (modified by user)"%f)
482 warned = True
474 warned = True
483
475
484 if warned:
476 if warned:
485 warnings.warn("""
477 warnings.warn("""
486 The IPython configuration system has changed as of 0.11, and these files will
478 The IPython configuration system has changed as of 0.11, and these files will
487 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
479 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
488 of the new config system.
480 of the new config system.
489 To start configuring IPython, do `ipython profile create`, and edit
481 To start configuring IPython, do `ipython profile create`, and edit
490 `ipython_config.py` in <ipython_dir>/profile_default.
482 `ipython_config.py` in <ipython_dir>/profile_default.
491 If you need to leave the old config files in place for an older version of
483 If you need to leave the old config files in place for an older version of
492 IPython and want to suppress this warning message, set
484 IPython and want to suppress this warning message, set
493 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
485 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
494
486
495 def get_security_file(filename, profile='default'):
487 def get_security_file(filename, profile='default'):
496 """Return the absolute path of a security file given by filename and profile
488 """Return the absolute path of a security file given by filename and profile
497
489
498 This allows users and developers to find security files without
490 This allows users and developers to find security files without
499 knowledge of the IPython directory structure. The search path
491 knowledge of the IPython directory structure. The search path
500 will be ['.', profile.security_dir]
492 will be ['.', profile.security_dir]
501
493
502 Parameters
494 Parameters
503 ----------
495 ----------
504
496
505 filename : str
497 filename : str
506 The file to be found. If it is passed as an absolute path, it will
498 The file to be found. If it is passed as an absolute path, it will
507 simply be returned.
499 simply be returned.
508 profile : str [default: 'default']
500 profile : str [default: 'default']
509 The name of the profile to search. Leaving this unspecified
501 The name of the profile to search. Leaving this unspecified
510 The file to be found. If it is passed as an absolute path, fname will
502 The file to be found. If it is passed as an absolute path, fname will
511 simply be returned.
503 simply be returned.
512
504
513 Returns
505 Returns
514 -------
506 -------
515 Raises :exc:`IOError` if file not found or returns absolute path to file.
507 Raises :exc:`IOError` if file not found or returns absolute path to file.
516 """
508 """
517 # import here, because profiledir also imports from utils.path
509 # import here, because profiledir also imports from utils.path
518 from IPython.core.profiledir import ProfileDir
510 from IPython.core.profiledir import ProfileDir
519 try:
511 try:
520 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
512 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
521 except Exception:
513 except Exception:
522 # will raise ProfileDirError if no such profile
514 # will raise ProfileDirError if no such profile
523 raise IOError("Profile %r not found")
515 raise IOError("Profile %r not found")
524 return filefind(filename, ['.', pd.security_dir])
516 return filefind(filename, ['.', pd.security_dir])
525
517
526
518
527 ENOLINK = 1998
519 ENOLINK = 1998
528
520
529 def link(src, dst):
521 def link(src, dst):
530 """Hard links ``src`` to ``dst``, returning 0 or errno.
522 """Hard links ``src`` to ``dst``, returning 0 or errno.
531
523
532 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
524 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
533 supported by the operating system.
525 supported by the operating system.
534 """
526 """
535
527
536 if not hasattr(os, "link"):
528 if not hasattr(os, "link"):
537 return ENOLINK
529 return ENOLINK
538 link_errno = 0
530 link_errno = 0
539 try:
531 try:
540 os.link(src, dst)
532 os.link(src, dst)
541 except OSError as e:
533 except OSError as e:
542 link_errno = e.errno
534 link_errno = e.errno
543 return link_errno
535 return link_errno
544
536
545
537
546 def link_or_copy(src, dst):
538 def link_or_copy(src, dst):
547 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
539 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
548
540
549 Attempts to maintain the semantics of ``shutil.copy``.
541 Attempts to maintain the semantics of ``shutil.copy``.
550
542
551 Because ``os.link`` does not overwrite files, a unique temporary file
543 Because ``os.link`` does not overwrite files, a unique temporary file
552 will be used if the target already exists, then that file will be moved
544 will be used if the target already exists, then that file will be moved
553 into place.
545 into place.
554 """
546 """
555
547
556 if os.path.isdir(dst):
548 if os.path.isdir(dst):
557 dst = os.path.join(dst, os.path.basename(src))
549 dst = os.path.join(dst, os.path.basename(src))
558
550
559 link_errno = link(src, dst)
551 link_errno = link(src, dst)
560 if link_errno == errno.EEXIST:
552 if link_errno == errno.EEXIST:
561 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
553 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
562 try:
554 try:
563 link_or_copy(src, new_dst)
555 link_or_copy(src, new_dst)
564 except:
556 except:
565 try:
557 try:
566 os.remove(new_dst)
558 os.remove(new_dst)
567 except OSError:
559 except OSError:
568 pass
560 pass
569 raise
561 raise
570 os.rename(new_dst, dst)
562 os.rename(new_dst, dst)
571 elif link_errno != 0:
563 elif link_errno != 0:
572 # Either link isn't supported, or the filesystem doesn't support
564 # Either link isn't supported, or the filesystem doesn't support
573 # linking, or 'src' and 'dst' are on different filesystems.
565 # linking, or 'src' and 'dst' are on different filesystems.
574 shutil.copy(src, dst)
566 shutil.copy(src, dst)
567
568 def ensure_dir_exists(path, mode=0o777):
569 """ensure that a directory exists
570
571 If it doesn't exist, try to create it and protect against a race condition
572 if another process is doing the same.
573 """
574 if not os.path.exists(path):
575 try:
576 os.makedirs(path, mode=mode)
577 except OSError as e:
578 if e.errno != errno.EEXIST:
579 raise
580 No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now