##// END OF EJS Templates
add utils.path.ensure_dir_exists...
MinRK -
Show More
@@ -1,392 +1,390
1 1 # encoding: utf-8
2 2 """
3 3 An application for IPython.
4 4
5 5 All top-level applications should use the classes in this module for
6 6 handling configuration and creating configurables.
7 7
8 8 The job of an :class:`Application` is to create the master configuration
9 9 object and then create the configurable objects, passing the config to them.
10 10
11 11 Authors:
12 12
13 13 * Brian Granger
14 14 * Fernando Perez
15 15 * Min RK
16 16
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Copyright (C) 2008 The IPython Development Team
21 21 #
22 22 # Distributed under the terms of the BSD License. The full license is in
23 23 # the file COPYING, distributed as part of this software.
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports
28 28 #-----------------------------------------------------------------------------
29 29
30 30 import atexit
31 31 import errno
32 32 import glob
33 33 import logging
34 34 import os
35 35 import shutil
36 36 import sys
37 37
38 38 from IPython.config.application import Application, catch_config_error
39 39 from IPython.config.loader import ConfigFileNotFound
40 40 from IPython.core import release, crashhandler
41 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 43 from IPython.utils import py3compat
44 44 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Classes and functions
48 48 #-----------------------------------------------------------------------------
49 49
50 50
51 51 #-----------------------------------------------------------------------------
52 52 # Base Application Class
53 53 #-----------------------------------------------------------------------------
54 54
55 55 # aliases and flags
56 56
57 57 base_aliases = {
58 58 'profile-dir' : 'ProfileDir.location',
59 59 'profile' : 'BaseIPythonApplication.profile',
60 60 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
61 61 'log-level' : 'Application.log_level',
62 62 'config' : 'BaseIPythonApplication.extra_config_file',
63 63 }
64 64
65 65 base_flags = dict(
66 66 debug = ({'Application' : {'log_level' : logging.DEBUG}},
67 67 "set log level to logging.DEBUG (maximize logging output)"),
68 68 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
69 69 "set log level to logging.CRITICAL (minimize logging output)"),
70 70 init = ({'BaseIPythonApplication' : {
71 71 'copy_config_files' : True,
72 72 'auto_create' : True}
73 73 }, """Initialize profile with default config files. This is equivalent
74 74 to running `ipython profile create <profile>` prior to startup.
75 75 """)
76 76 )
77 77
78 78
79 79 class BaseIPythonApplication(Application):
80 80
81 81 name = Unicode(u'ipython')
82 82 description = Unicode(u'IPython: an enhanced interactive Python shell.')
83 83 version = Unicode(release.version)
84 84
85 85 aliases = Dict(base_aliases)
86 86 flags = Dict(base_flags)
87 87 classes = List([ProfileDir])
88 88
89 89 # Track whether the config_file has changed,
90 90 # because some logic happens only if we aren't using the default.
91 91 config_file_specified = Set()
92 92
93 93 config_file_name = Unicode()
94 94 def _config_file_name_default(self):
95 95 return self.name.replace('-','_') + u'_config.py'
96 96 def _config_file_name_changed(self, name, old, new):
97 97 if new != old:
98 98 self.config_file_specified.add(new)
99 99
100 100 # The directory that contains IPython's builtin profiles.
101 101 builtin_profile_dir = Unicode(
102 102 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
103 103 )
104 104
105 105 config_file_paths = List(Unicode)
106 106 def _config_file_paths_default(self):
107 107 return [py3compat.getcwd()]
108 108
109 109 extra_config_file = Unicode(config=True,
110 110 help="""Path to an extra config file to load.
111 111
112 112 If specified, load this config file in addition to any other IPython config.
113 113 """)
114 114 def _extra_config_file_changed(self, name, old, new):
115 115 try:
116 116 self.config_files.remove(old)
117 117 except ValueError:
118 118 pass
119 119 self.config_file_specified.add(new)
120 120 self.config_files.append(new)
121 121
122 122 profile = Unicode(u'default', config=True,
123 123 help="""The IPython profile to use."""
124 124 )
125 125
126 126 def _profile_changed(self, name, old, new):
127 127 self.builtin_profile_dir = os.path.join(
128 128 get_ipython_package_dir(), u'config', u'profile', new
129 129 )
130 130
131 131 ipython_dir = Unicode(config=True,
132 132 help="""
133 133 The name of the IPython directory. This directory is used for logging
134 134 configuration (through profiles), history storage, etc. The default
135 135 is usually $HOME/.ipython. This options can also be specified through
136 136 the environment variable IPYTHONDIR.
137 137 """
138 138 )
139 139 def _ipython_dir_default(self):
140 140 d = get_ipython_dir()
141 141 self._ipython_dir_changed('ipython_dir', d, d)
142 142 return d
143 143
144 144 _in_init_profile_dir = False
145 145 profile_dir = Instance(ProfileDir)
146 146 def _profile_dir_default(self):
147 147 # avoid recursion
148 148 if self._in_init_profile_dir:
149 149 return
150 150 # profile_dir requested early, force initialization
151 151 self.init_profile_dir()
152 152 return self.profile_dir
153 153
154 154 overwrite = Bool(False, config=True,
155 155 help="""Whether to overwrite existing config files when copying""")
156 156 auto_create = Bool(False, config=True,
157 157 help="""Whether to create profile dir if it doesn't exist""")
158 158
159 159 config_files = List(Unicode)
160 160 def _config_files_default(self):
161 161 return [self.config_file_name]
162 162
163 163 copy_config_files = Bool(False, config=True,
164 164 help="""Whether to install the default config files into the profile dir.
165 165 If a new profile is being created, and IPython contains config files for that
166 166 profile, then they will be staged into the new directory. Otherwise,
167 167 default config files will be automatically generated.
168 168 """)
169 169
170 170 verbose_crash = Bool(False, config=True,
171 171 help="""Create a massive crash report when IPython encounters what may be an
172 172 internal error. The default is to append a short message to the
173 173 usual traceback""")
174 174
175 175 # The class to use as the crash handler.
176 176 crash_handler_class = Type(crashhandler.CrashHandler)
177 177
178 178 @catch_config_error
179 179 def __init__(self, **kwargs):
180 180 super(BaseIPythonApplication, self).__init__(**kwargs)
181 181 # ensure current working directory exists
182 182 try:
183 183 directory = py3compat.getcwd()
184 184 except:
185 185 # raise exception
186 186 self.log.error("Current working directory doesn't exist.")
187 187 raise
188 188
189 189 #-------------------------------------------------------------------------
190 190 # Various stages of Application creation
191 191 #-------------------------------------------------------------------------
192 192
193 193 def init_crash_handler(self):
194 194 """Create a crash handler, typically setting sys.excepthook to it."""
195 195 self.crash_handler = self.crash_handler_class(self)
196 196 sys.excepthook = self.excepthook
197 197 def unset_crashhandler():
198 198 sys.excepthook = sys.__excepthook__
199 199 atexit.register(unset_crashhandler)
200 200
201 201 def excepthook(self, etype, evalue, tb):
202 202 """this is sys.excepthook after init_crashhandler
203 203
204 204 set self.verbose_crash=True to use our full crashhandler, instead of
205 205 a regular traceback with a short message (crash_handler_lite)
206 206 """
207 207
208 208 if self.verbose_crash:
209 209 return self.crash_handler(etype, evalue, tb)
210 210 else:
211 211 return crashhandler.crash_handler_lite(etype, evalue, tb)
212 212
213 213 def _ipython_dir_changed(self, name, old, new):
214 214 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
215 215 sys.getfilesystemencoding()
216 216 )
217 217 if str_old in sys.path:
218 218 sys.path.remove(str_old)
219 219 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
220 220 sys.getfilesystemencoding()
221 221 )
222 222 sys.path.append(str_path)
223 if not os.path.isdir(new):
224 os.makedirs(new, mode=0o777)
223 ensure_dir_exists(new)
225 224 readme = os.path.join(new, 'README')
226 225 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
227 226 if not os.path.exists(readme) and os.path.exists(readme_src):
228 227 shutil.copy(readme_src, readme)
229 228 for d in ('extensions', 'nbextensions'):
230 229 path = os.path.join(new, d)
231 if not os.path.exists(path):
232 try:
233 os.mkdir(path)
234 except OSError as e:
235 if e.errno != errno.EEXIST:
236 self.log.error("couldn't create path %s: %s", path, e)
230 try:
231 ensure_dir_exists(path)
232 except OSError:
233 # this will not be EEXIST
234 self.log.error("couldn't create path %s: %s", path, e)
237 235 self.log.debug("IPYTHONDIR set to: %s" % new)
238 236
239 237 def load_config_file(self, suppress_errors=True):
240 238 """Load the config file.
241 239
242 240 By default, errors in loading config are handled, and a warning
243 241 printed on screen. For testing, the suppress_errors option is set
244 242 to False, so errors will make tests fail.
245 243 """
246 244 self.log.debug("Searching path %s for config files", self.config_file_paths)
247 245 base_config = 'ipython_config.py'
248 246 self.log.debug("Attempting to load config file: %s" %
249 247 base_config)
250 248 try:
251 249 Application.load_config_file(
252 250 self,
253 251 base_config,
254 252 path=self.config_file_paths
255 253 )
256 254 except ConfigFileNotFound:
257 255 # ignore errors loading parent
258 256 self.log.debug("Config file %s not found", base_config)
259 257 pass
260 258
261 259 for config_file_name in self.config_files:
262 260 if not config_file_name or config_file_name == base_config:
263 261 continue
264 262 self.log.debug("Attempting to load config file: %s" %
265 263 self.config_file_name)
266 264 try:
267 265 Application.load_config_file(
268 266 self,
269 267 config_file_name,
270 268 path=self.config_file_paths
271 269 )
272 270 except ConfigFileNotFound:
273 271 # Only warn if the default config file was NOT being used.
274 272 if config_file_name in self.config_file_specified:
275 273 msg = self.log.warn
276 274 else:
277 275 msg = self.log.debug
278 276 msg("Config file not found, skipping: %s", config_file_name)
279 277 except:
280 278 # For testing purposes.
281 279 if not suppress_errors:
282 280 raise
283 281 self.log.warn("Error loading config file: %s" %
284 282 self.config_file_name, exc_info=True)
285 283
286 284 def init_profile_dir(self):
287 285 """initialize the profile dir"""
288 286 self._in_init_profile_dir = True
289 287 if self.profile_dir is not None:
290 288 # already ran
291 289 return
292 290 if 'ProfileDir.location' not in self.config:
293 291 # location not specified, find by profile name
294 292 try:
295 293 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
296 294 except ProfileDirError:
297 295 # not found, maybe create it (always create default profile)
298 296 if self.auto_create or self.profile == 'default':
299 297 try:
300 298 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
301 299 except ProfileDirError:
302 300 self.log.fatal("Could not create profile: %r"%self.profile)
303 301 self.exit(1)
304 302 else:
305 303 self.log.info("Created profile dir: %r"%p.location)
306 304 else:
307 305 self.log.fatal("Profile %r not found."%self.profile)
308 306 self.exit(1)
309 307 else:
310 308 self.log.info("Using existing profile dir: %r"%p.location)
311 309 else:
312 310 location = self.config.ProfileDir.location
313 311 # location is fully specified
314 312 try:
315 313 p = ProfileDir.find_profile_dir(location, self.config)
316 314 except ProfileDirError:
317 315 # not found, maybe create it
318 316 if self.auto_create:
319 317 try:
320 318 p = ProfileDir.create_profile_dir(location, self.config)
321 319 except ProfileDirError:
322 320 self.log.fatal("Could not create profile directory: %r"%location)
323 321 self.exit(1)
324 322 else:
325 323 self.log.info("Creating new profile dir: %r"%location)
326 324 else:
327 325 self.log.fatal("Profile directory %r not found."%location)
328 326 self.exit(1)
329 327 else:
330 328 self.log.info("Using existing profile dir: %r"%location)
331 329 # if profile_dir is specified explicitly, set profile name
332 330 dir_name = os.path.basename(p.location)
333 331 if dir_name.startswith('profile_'):
334 332 self.profile = dir_name[8:]
335 333
336 334 self.profile_dir = p
337 335 self.config_file_paths.append(p.location)
338 336 self._in_init_profile_dir = False
339 337
340 338 def init_config_files(self):
341 339 """[optionally] copy default config files into profile dir."""
342 340 # copy config files
343 341 path = self.builtin_profile_dir
344 342 if self.copy_config_files:
345 343 src = self.profile
346 344
347 345 cfg = self.config_file_name
348 346 if path and os.path.exists(os.path.join(path, cfg)):
349 347 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
350 348 cfg, src, self.profile_dir.location, self.overwrite)
351 349 )
352 350 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
353 351 else:
354 352 self.stage_default_config_file()
355 353 else:
356 354 # Still stage *bundled* config files, but not generated ones
357 355 # This is necessary for `ipython profile=sympy` to load the profile
358 356 # on the first go
359 357 files = glob.glob(os.path.join(path, '*.py'))
360 358 for fullpath in files:
361 359 cfg = os.path.basename(fullpath)
362 360 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
363 361 # file was copied
364 362 self.log.warn("Staging bundled %s from %s into %r"%(
365 363 cfg, self.profile, self.profile_dir.location)
366 364 )
367 365
368 366
369 367 def stage_default_config_file(self):
370 368 """auto generate default config file, and stage it into the profile."""
371 369 s = self.generate_config_file()
372 370 fname = os.path.join(self.profile_dir.location, self.config_file_name)
373 371 if self.overwrite or not os.path.exists(fname):
374 372 self.log.warn("Generating default config file: %r"%(fname))
375 373 with open(fname, 'w') as f:
376 374 f.write(s)
377 375
378 376 @catch_config_error
379 377 def initialize(self, argv=None):
380 378 # don't hook up crash handler before parsing command-line
381 379 self.parse_command_line(argv)
382 380 self.init_crash_handler()
383 381 if self.subapp is not None:
384 382 # stop here if subapp is taking over
385 383 return
386 384 cl_config = self.config
387 385 self.init_profile_dir()
388 386 self.init_config_files()
389 387 self.load_config_file()
390 388 # enforce cl-opts override configfile opts:
391 389 self.update_config(cl_config)
392 390
@@ -1,189 +1,175
1 1 # encoding: utf-8
2 """A class for managing IPython extensions.
2 """A class for managing IPython extensions."""
3 3
4 Authors:
5
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 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
19 6
20 7 import os
21 8 from shutil import copyfile
22 9 import sys
23 10
24 11 from IPython.config.configurable import Configurable
12 from IPython.utils.path import ensure_dir_exists
25 13 from IPython.utils.traitlets import Instance
26 14 from IPython.utils.py3compat import PY3
27 15 if PY3:
28 16 from imp import reload
29 17
30 18 #-----------------------------------------------------------------------------
31 19 # Main class
32 20 #-----------------------------------------------------------------------------
33 21
34 22 class ExtensionManager(Configurable):
35 23 """A class to manage IPython extensions.
36 24
37 25 An IPython extension is an importable Python module that has
38 26 a function with the signature::
39 27
40 28 def load_ipython_extension(ipython):
41 29 # Do things with ipython
42 30
43 31 This function is called after your extension is imported and the
44 32 currently active :class:`InteractiveShell` instance is passed as
45 33 the only argument. You can do anything you want with IPython at
46 34 that point, including defining new magic and aliases, adding new
47 35 components, etc.
48 36
49 37 You can also optionally define an :func:`unload_ipython_extension(ipython)`
50 38 function, which will be called if the user unloads or reloads the extension.
51 39 The extension manager will only call :func:`load_ipython_extension` again
52 40 if the extension is reloaded.
53 41
54 42 You can put your extension modules anywhere you want, as long as
55 43 they can be imported by Python's standard import mechanism. However,
56 44 to make it easy to write extensions, you can also put your extensions
57 45 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
58 46 is added to ``sys.path`` automatically.
59 47 """
60 48
61 49 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
62 50
63 51 def __init__(self, shell=None, **kwargs):
64 52 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
65 53 self.shell.on_trait_change(
66 54 self._on_ipython_dir_changed, 'ipython_dir'
67 55 )
68 56 self.loaded = set()
69 57
70 58 def __del__(self):
71 59 self.shell.on_trait_change(
72 60 self._on_ipython_dir_changed, 'ipython_dir', remove=True
73 61 )
74 62
75 63 @property
76 64 def ipython_extension_dir(self):
77 65 return os.path.join(self.shell.ipython_dir, u'extensions')
78 66
79 67 def _on_ipython_dir_changed(self):
80 if not os.path.isdir(self.ipython_extension_dir):
81 os.makedirs(self.ipython_extension_dir, mode = 0o777)
68 ensure_dir_exists(self.ipython_extension_dir)
82 69
83 70 def load_extension(self, module_str):
84 71 """Load an IPython extension by its module name.
85 72
86 73 Returns the string "already loaded" if the extension is already loaded,
87 74 "no load function" if the module doesn't have a load_ipython_extension
88 75 function, or None if it succeeded.
89 76 """
90 77 if module_str in self.loaded:
91 78 return "already loaded"
92 79
93 80 from IPython.utils.syspathcontext import prepended_to_syspath
94 81
95 82 with self.shell.builtin_trap:
96 83 if module_str not in sys.modules:
97 84 with prepended_to_syspath(self.ipython_extension_dir):
98 85 __import__(module_str)
99 86 mod = sys.modules[module_str]
100 87 if self._call_load_ipython_extension(mod):
101 88 self.loaded.add(module_str)
102 89 else:
103 90 return "no load function"
104 91
105 92 def unload_extension(self, module_str):
106 93 """Unload an IPython extension by its module name.
107 94
108 95 This function looks up the extension's name in ``sys.modules`` and
109 96 simply calls ``mod.unload_ipython_extension(self)``.
110 97
111 98 Returns the string "no unload function" if the extension doesn't define
112 99 a function to unload itself, "not loaded" if the extension isn't loaded,
113 100 otherwise None.
114 101 """
115 102 if module_str not in self.loaded:
116 103 return "not loaded"
117 104
118 105 if module_str in sys.modules:
119 106 mod = sys.modules[module_str]
120 107 if self._call_unload_ipython_extension(mod):
121 108 self.loaded.discard(module_str)
122 109 else:
123 110 return "no unload function"
124 111
125 112 def reload_extension(self, module_str):
126 113 """Reload an IPython extension by calling reload.
127 114
128 115 If the module has not been loaded before,
129 116 :meth:`InteractiveShell.load_extension` is called. Otherwise
130 117 :func:`reload` is called and then the :func:`load_ipython_extension`
131 118 function of the module, if it exists is called.
132 119 """
133 120 from IPython.utils.syspathcontext import prepended_to_syspath
134 121
135 122 if (module_str in self.loaded) and (module_str in sys.modules):
136 123 self.unload_extension(module_str)
137 124 mod = sys.modules[module_str]
138 125 with prepended_to_syspath(self.ipython_extension_dir):
139 126 reload(mod)
140 127 if self._call_load_ipython_extension(mod):
141 128 self.loaded.add(module_str)
142 129 else:
143 130 self.load_extension(module_str)
144 131
145 132 def _call_load_ipython_extension(self, mod):
146 133 if hasattr(mod, 'load_ipython_extension'):
147 134 mod.load_ipython_extension(self.shell)
148 135 return True
149 136
150 137 def _call_unload_ipython_extension(self, mod):
151 138 if hasattr(mod, 'unload_ipython_extension'):
152 139 mod.unload_ipython_extension(self.shell)
153 140 return True
154 141
155 142 def install_extension(self, url, filename=None):
156 143 """Download and install an IPython extension.
157 144
158 145 If filename is given, the file will be so named (inside the extension
159 146 directory). Otherwise, the name from the URL will be used. The file must
160 147 have a .py or .zip extension; otherwise, a ValueError will be raised.
161 148
162 149 Returns the full path to the installed file.
163 150 """
164 151 # Ensure the extension directory exists
165 if not os.path.isdir(self.ipython_extension_dir):
166 os.makedirs(self.ipython_extension_dir, mode = 0o777)
152 ensure_dir_exists(self.ipython_extension_dir)
167 153
168 154 if os.path.isfile(url):
169 155 src_filename = os.path.basename(url)
170 156 copy = copyfile
171 157 else:
172 158 # Deferred imports
173 159 try:
174 160 from urllib.parse import urlparse # Py3
175 161 from urllib.request import urlretrieve
176 162 except ImportError:
177 163 from urlparse import urlparse
178 164 from urllib import urlretrieve
179 165 src_filename = urlparse(url).path.split('/')[-1]
180 166 copy = urlretrieve
181 167
182 168 if filename is None:
183 169 filename = src_filename
184 170 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
185 171 raise ValueError("The file must have a .py or .zip extension", filename)
186 172
187 173 filename = os.path.join(self.ipython_extension_dir, filename)
188 174 copy(url, filename)
189 175 return filename
@@ -1,3224 +1,3223
1 1 # -*- coding: utf-8 -*-
2 2 """Main IPython class."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from __future__ import absolute_import
18 18 from __future__ import print_function
19 19
20 20 import __future__
21 21 import abc
22 22 import ast
23 23 import atexit
24 24 import functools
25 25 import os
26 26 import re
27 27 import runpy
28 28 import sys
29 29 import tempfile
30 30 import types
31 31 import subprocess
32 32 from io import open as io_open
33 33
34 34 from IPython.config.configurable import SingletonConfigurable
35 35 from IPython.core import debugger, oinspect
36 36 from IPython.core import magic
37 37 from IPython.core import page
38 38 from IPython.core import prefilter
39 39 from IPython.core import shadowns
40 40 from IPython.core import ultratb
41 41 from IPython.core.alias import AliasManager, AliasError
42 42 from IPython.core.autocall import ExitAutocall
43 43 from IPython.core.builtin_trap import BuiltinTrap
44 44 from IPython.core.events import EventManager, available_events
45 45 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
46 46 from IPython.core.display_trap import DisplayTrap
47 47 from IPython.core.displayhook import DisplayHook
48 48 from IPython.core.displaypub import DisplayPublisher
49 49 from IPython.core.error import UsageError
50 50 from IPython.core.extensions import ExtensionManager
51 51 from IPython.core.formatters import DisplayFormatter
52 52 from IPython.core.history import HistoryManager
53 53 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
54 54 from IPython.core.logger import Logger
55 55 from IPython.core.macro import Macro
56 56 from IPython.core.payload import PayloadManager
57 57 from IPython.core.prefilter import PrefilterManager
58 58 from IPython.core.profiledir import ProfileDir
59 59 from IPython.core.prompts import PromptManager
60 60 from IPython.lib.latextools import LaTeXTool
61 61 from IPython.testing.skipdoctest import skip_doctest
62 62 from IPython.utils import PyColorize
63 63 from IPython.utils import io
64 64 from IPython.utils import py3compat
65 65 from IPython.utils import openpy
66 66 from IPython.utils.decorators import undoc
67 67 from IPython.utils.io import ask_yes_no
68 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 70 from IPython.utils.pickleshare import PickleShareDB
71 71 from IPython.utils.process import system, getoutput
72 72 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
73 73 with_metaclass, iteritems)
74 74 from IPython.utils.strdispatch import StrDispatch
75 75 from IPython.utils.syspathcontext import prepended_to_syspath
76 76 from IPython.utils.text import (format_screen, LSString, SList,
77 77 DollarFormatter)
78 78 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
79 79 List, Unicode, Instance, Type)
80 80 from IPython.utils.warn import warn, error
81 81 import IPython.core.hooks
82 82
83 83 #-----------------------------------------------------------------------------
84 84 # Globals
85 85 #-----------------------------------------------------------------------------
86 86
87 87 # compiled regexps for autoindent management
88 88 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
89 89
90 90 #-----------------------------------------------------------------------------
91 91 # Utilities
92 92 #-----------------------------------------------------------------------------
93 93
94 94 @undoc
95 95 def softspace(file, newvalue):
96 96 """Copied from code.py, to remove the dependency"""
97 97
98 98 oldvalue = 0
99 99 try:
100 100 oldvalue = file.softspace
101 101 except AttributeError:
102 102 pass
103 103 try:
104 104 file.softspace = newvalue
105 105 except (AttributeError, TypeError):
106 106 # "attribute-less object" or "read-only attributes"
107 107 pass
108 108 return oldvalue
109 109
110 110 @undoc
111 111 def no_op(*a, **kw): pass
112 112
113 113 @undoc
114 114 class NoOpContext(object):
115 115 def __enter__(self): pass
116 116 def __exit__(self, type, value, traceback): pass
117 117 no_op_context = NoOpContext()
118 118
119 119 class SpaceInInput(Exception): pass
120 120
121 121 @undoc
122 122 class Bunch: pass
123 123
124 124
125 125 def get_default_colors():
126 126 if sys.platform=='darwin':
127 127 return "LightBG"
128 128 elif os.name=='nt':
129 129 return 'Linux'
130 130 else:
131 131 return 'Linux'
132 132
133 133
134 134 class SeparateUnicode(Unicode):
135 135 r"""A Unicode subclass to validate separate_in, separate_out, etc.
136 136
137 137 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
138 138 """
139 139
140 140 def validate(self, obj, value):
141 141 if value == '0': value = ''
142 142 value = value.replace('\\n','\n')
143 143 return super(SeparateUnicode, self).validate(obj, value)
144 144
145 145
146 146 class ReadlineNoRecord(object):
147 147 """Context manager to execute some code, then reload readline history
148 148 so that interactive input to the code doesn't appear when pressing up."""
149 149 def __init__(self, shell):
150 150 self.shell = shell
151 151 self._nested_level = 0
152 152
153 153 def __enter__(self):
154 154 if self._nested_level == 0:
155 155 try:
156 156 self.orig_length = self.current_length()
157 157 self.readline_tail = self.get_readline_tail()
158 158 except (AttributeError, IndexError): # Can fail with pyreadline
159 159 self.orig_length, self.readline_tail = 999999, []
160 160 self._nested_level += 1
161 161
162 162 def __exit__(self, type, value, traceback):
163 163 self._nested_level -= 1
164 164 if self._nested_level == 0:
165 165 # Try clipping the end if it's got longer
166 166 try:
167 167 e = self.current_length() - self.orig_length
168 168 if e > 0:
169 169 for _ in range(e):
170 170 self.shell.readline.remove_history_item(self.orig_length)
171 171
172 172 # If it still doesn't match, just reload readline history.
173 173 if self.current_length() != self.orig_length \
174 174 or self.get_readline_tail() != self.readline_tail:
175 175 self.shell.refill_readline_hist()
176 176 except (AttributeError, IndexError):
177 177 pass
178 178 # Returning False will cause exceptions to propagate
179 179 return False
180 180
181 181 def current_length(self):
182 182 return self.shell.readline.get_current_history_length()
183 183
184 184 def get_readline_tail(self, n=10):
185 185 """Get the last n items in readline history."""
186 186 end = self.shell.readline.get_current_history_length() + 1
187 187 start = max(end-n, 1)
188 188 ghi = self.shell.readline.get_history_item
189 189 return [ghi(x) for x in range(start, end)]
190 190
191 191
192 192 @undoc
193 193 class DummyMod(object):
194 194 """A dummy module used for IPython's interactive module when
195 195 a namespace must be assigned to the module's __dict__."""
196 196 pass
197 197
198 198 #-----------------------------------------------------------------------------
199 199 # Main IPython class
200 200 #-----------------------------------------------------------------------------
201 201
202 202 class InteractiveShell(SingletonConfigurable):
203 203 """An enhanced, interactive shell for Python."""
204 204
205 205 _instance = None
206 206
207 207 ast_transformers = List([], config=True, help=
208 208 """
209 209 A list of ast.NodeTransformer subclass instances, which will be applied
210 210 to user input before code is run.
211 211 """
212 212 )
213 213
214 214 autocall = Enum((0,1,2), default_value=0, config=True, help=
215 215 """
216 216 Make IPython automatically call any callable object even if you didn't
217 217 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
218 218 automatically. The value can be '0' to disable the feature, '1' for
219 219 'smart' autocall, where it is not applied if there are no more
220 220 arguments on the line, and '2' for 'full' autocall, where all callable
221 221 objects are automatically called (even if no arguments are present).
222 222 """
223 223 )
224 224 # TODO: remove all autoindent logic and put into frontends.
225 225 # We can't do this yet because even runlines uses the autoindent.
226 226 autoindent = CBool(True, config=True, help=
227 227 """
228 228 Autoindent IPython code entered interactively.
229 229 """
230 230 )
231 231 automagic = CBool(True, config=True, help=
232 232 """
233 233 Enable magic commands to be called without the leading %.
234 234 """
235 235 )
236 236 cache_size = Integer(1000, config=True, help=
237 237 """
238 238 Set the size of the output cache. The default is 1000, you can
239 239 change it permanently in your config file. Setting it to 0 completely
240 240 disables the caching system, and the minimum value accepted is 20 (if
241 241 you provide a value less than 20, it is reset to 0 and a warning is
242 242 issued). This limit is defined because otherwise you'll spend more
243 243 time re-flushing a too small cache than working
244 244 """
245 245 )
246 246 color_info = CBool(True, config=True, help=
247 247 """
248 248 Use colors for displaying information about objects. Because this
249 249 information is passed through a pager (like 'less'), and some pagers
250 250 get confused with color codes, this capability can be turned off.
251 251 """
252 252 )
253 253 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
254 254 default_value=get_default_colors(), config=True,
255 255 help="Set the color scheme (NoColor, Linux, or LightBG)."
256 256 )
257 257 colors_force = CBool(False, help=
258 258 """
259 259 Force use of ANSI color codes, regardless of OS and readline
260 260 availability.
261 261 """
262 262 # FIXME: This is essentially a hack to allow ZMQShell to show colors
263 263 # without readline on Win32. When the ZMQ formatting system is
264 264 # refactored, this should be removed.
265 265 )
266 266 debug = CBool(False, config=True)
267 267 deep_reload = CBool(False, config=True, help=
268 268 """
269 269 Enable deep (recursive) reloading by default. IPython can use the
270 270 deep_reload module which reloads changes in modules recursively (it
271 271 replaces the reload() function, so you don't need to change anything to
272 272 use it). deep_reload() forces a full reload of modules whose code may
273 273 have changed, which the default reload() function does not. When
274 274 deep_reload is off, IPython will use the normal reload(), but
275 275 deep_reload will still be available as dreload().
276 276 """
277 277 )
278 278 disable_failing_post_execute = CBool(False, config=True,
279 279 help="Don't call post-execute functions that have failed in the past."
280 280 )
281 281 display_formatter = Instance(DisplayFormatter)
282 282 displayhook_class = Type(DisplayHook)
283 283 display_pub_class = Type(DisplayPublisher)
284 284 data_pub_class = None
285 285
286 286 exit_now = CBool(False)
287 287 exiter = Instance(ExitAutocall)
288 288 def _exiter_default(self):
289 289 return ExitAutocall(self)
290 290 # Monotonically increasing execution counter
291 291 execution_count = Integer(1)
292 292 filename = Unicode("<ipython console>")
293 293 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
294 294
295 295 # Input splitter, to transform input line by line and detect when a block
296 296 # is ready to be executed.
297 297 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
298 298 (), {'line_input_checker': True})
299 299
300 300 # This InputSplitter instance is used to transform completed cells before
301 301 # running them. It allows cell magics to contain blank lines.
302 302 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
303 303 (), {'line_input_checker': False})
304 304
305 305 logstart = CBool(False, config=True, help=
306 306 """
307 307 Start logging to the default log file.
308 308 """
309 309 )
310 310 logfile = Unicode('', config=True, help=
311 311 """
312 312 The name of the logfile to use.
313 313 """
314 314 )
315 315 logappend = Unicode('', config=True, help=
316 316 """
317 317 Start logging to the given file in append mode.
318 318 """
319 319 )
320 320 object_info_string_level = Enum((0,1,2), default_value=0,
321 321 config=True)
322 322 pdb = CBool(False, config=True, help=
323 323 """
324 324 Automatically call the pdb debugger after every exception.
325 325 """
326 326 )
327 327 multiline_history = CBool(sys.platform != 'win32', config=True,
328 328 help="Save multi-line entries as one entry in readline history"
329 329 )
330 330
331 331 # deprecated prompt traits:
332 332
333 333 prompt_in1 = Unicode('In [\\#]: ', config=True,
334 334 help="Deprecated, use PromptManager.in_template")
335 335 prompt_in2 = Unicode(' .\\D.: ', config=True,
336 336 help="Deprecated, use PromptManager.in2_template")
337 337 prompt_out = Unicode('Out[\\#]: ', config=True,
338 338 help="Deprecated, use PromptManager.out_template")
339 339 prompts_pad_left = CBool(True, config=True,
340 340 help="Deprecated, use PromptManager.justify")
341 341
342 342 def _prompt_trait_changed(self, name, old, new):
343 343 table = {
344 344 'prompt_in1' : 'in_template',
345 345 'prompt_in2' : 'in2_template',
346 346 'prompt_out' : 'out_template',
347 347 'prompts_pad_left' : 'justify',
348 348 }
349 349 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
350 350 name=name, newname=table[name])
351 351 )
352 352 # protect against weird cases where self.config may not exist:
353 353 if self.config is not None:
354 354 # propagate to corresponding PromptManager trait
355 355 setattr(self.config.PromptManager, table[name], new)
356 356
357 357 _prompt_in1_changed = _prompt_trait_changed
358 358 _prompt_in2_changed = _prompt_trait_changed
359 359 _prompt_out_changed = _prompt_trait_changed
360 360 _prompt_pad_left_changed = _prompt_trait_changed
361 361
362 362 show_rewritten_input = CBool(True, config=True,
363 363 help="Show rewritten input, e.g. for autocall."
364 364 )
365 365
366 366 quiet = CBool(False, config=True)
367 367
368 368 history_length = Integer(10000, config=True)
369 369
370 370 # The readline stuff will eventually be moved to the terminal subclass
371 371 # but for now, we can't do that as readline is welded in everywhere.
372 372 readline_use = CBool(True, config=True)
373 373 readline_remove_delims = Unicode('-/~', config=True)
374 374 readline_delims = Unicode() # set by init_readline()
375 375 # don't use \M- bindings by default, because they
376 376 # conflict with 8-bit encodings. See gh-58,gh-88
377 377 readline_parse_and_bind = List([
378 378 'tab: complete',
379 379 '"\C-l": clear-screen',
380 380 'set show-all-if-ambiguous on',
381 381 '"\C-o": tab-insert',
382 382 '"\C-r": reverse-search-history',
383 383 '"\C-s": forward-search-history',
384 384 '"\C-p": history-search-backward',
385 385 '"\C-n": history-search-forward',
386 386 '"\e[A": history-search-backward',
387 387 '"\e[B": history-search-forward',
388 388 '"\C-k": kill-line',
389 389 '"\C-u": unix-line-discard',
390 390 ], allow_none=False, config=True)
391 391
392 392 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
393 393 default_value='last_expr', config=True,
394 394 help="""
395 395 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
396 396 run interactively (displaying output from expressions).""")
397 397
398 398 # TODO: this part of prompt management should be moved to the frontends.
399 399 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
400 400 separate_in = SeparateUnicode('\n', config=True)
401 401 separate_out = SeparateUnicode('', config=True)
402 402 separate_out2 = SeparateUnicode('', config=True)
403 403 wildcards_case_sensitive = CBool(True, config=True)
404 404 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
405 405 default_value='Context', config=True)
406 406
407 407 # Subcomponents of InteractiveShell
408 408 alias_manager = Instance('IPython.core.alias.AliasManager')
409 409 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
410 410 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
411 411 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
412 412 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
413 413 payload_manager = Instance('IPython.core.payload.PayloadManager')
414 414 history_manager = Instance('IPython.core.history.HistoryManager')
415 415 magics_manager = Instance('IPython.core.magic.MagicsManager')
416 416
417 417 profile_dir = Instance('IPython.core.application.ProfileDir')
418 418 @property
419 419 def profile(self):
420 420 if self.profile_dir is not None:
421 421 name = os.path.basename(self.profile_dir.location)
422 422 return name.replace('profile_','')
423 423
424 424
425 425 # Private interface
426 426 _post_execute = Instance(dict)
427 427
428 428 # Tracks any GUI loop loaded for pylab
429 429 pylab_gui_select = None
430 430
431 431 def __init__(self, ipython_dir=None, profile_dir=None,
432 432 user_module=None, user_ns=None,
433 433 custom_exceptions=((), None), **kwargs):
434 434
435 435 # This is where traits with a config_key argument are updated
436 436 # from the values on config.
437 437 super(InteractiveShell, self).__init__(**kwargs)
438 438 self.configurables = [self]
439 439
440 440 # These are relatively independent and stateless
441 441 self.init_ipython_dir(ipython_dir)
442 442 self.init_profile_dir(profile_dir)
443 443 self.init_instance_attrs()
444 444 self.init_environment()
445 445
446 446 # Check if we're in a virtualenv, and set up sys.path.
447 447 self.init_virtualenv()
448 448
449 449 # Create namespaces (user_ns, user_global_ns, etc.)
450 450 self.init_create_namespaces(user_module, user_ns)
451 451 # This has to be done after init_create_namespaces because it uses
452 452 # something in self.user_ns, but before init_sys_modules, which
453 453 # is the first thing to modify sys.
454 454 # TODO: When we override sys.stdout and sys.stderr before this class
455 455 # is created, we are saving the overridden ones here. Not sure if this
456 456 # is what we want to do.
457 457 self.save_sys_module_state()
458 458 self.init_sys_modules()
459 459
460 460 # While we're trying to have each part of the code directly access what
461 461 # it needs without keeping redundant references to objects, we have too
462 462 # much legacy code that expects ip.db to exist.
463 463 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
464 464
465 465 self.init_history()
466 466 self.init_encoding()
467 467 self.init_prefilter()
468 468
469 469 self.init_syntax_highlighting()
470 470 self.init_hooks()
471 471 self.init_events()
472 472 self.init_pushd_popd_magic()
473 473 # self.init_traceback_handlers use to be here, but we moved it below
474 474 # because it and init_io have to come after init_readline.
475 475 self.init_user_ns()
476 476 self.init_logger()
477 477 self.init_builtins()
478 478
479 479 # The following was in post_config_initialization
480 480 self.init_inspector()
481 481 # init_readline() must come before init_io(), because init_io uses
482 482 # readline related things.
483 483 self.init_readline()
484 484 # We save this here in case user code replaces raw_input, but it needs
485 485 # to be after init_readline(), because PyPy's readline works by replacing
486 486 # raw_input.
487 487 if py3compat.PY3:
488 488 self.raw_input_original = input
489 489 else:
490 490 self.raw_input_original = raw_input
491 491 # init_completer must come after init_readline, because it needs to
492 492 # know whether readline is present or not system-wide to configure the
493 493 # completers, since the completion machinery can now operate
494 494 # independently of readline (e.g. over the network)
495 495 self.init_completer()
496 496 # TODO: init_io() needs to happen before init_traceback handlers
497 497 # because the traceback handlers hardcode the stdout/stderr streams.
498 498 # This logic in in debugger.Pdb and should eventually be changed.
499 499 self.init_io()
500 500 self.init_traceback_handlers(custom_exceptions)
501 501 self.init_prompts()
502 502 self.init_display_formatter()
503 503 self.init_display_pub()
504 504 self.init_data_pub()
505 505 self.init_displayhook()
506 506 self.init_latextool()
507 507 self.init_magics()
508 508 self.init_alias()
509 509 self.init_logstart()
510 510 self.init_pdb()
511 511 self.init_extension_manager()
512 512 self.init_payload()
513 513 self.init_comms()
514 514 self.hooks.late_startup_hook()
515 515 self.events.trigger('shell_initialized', self)
516 516 atexit.register(self.atexit_operations)
517 517
518 518 def get_ipython(self):
519 519 """Return the currently running IPython instance."""
520 520 return self
521 521
522 522 #-------------------------------------------------------------------------
523 523 # Trait changed handlers
524 524 #-------------------------------------------------------------------------
525 525
526 526 def _ipython_dir_changed(self, name, new):
527 if not os.path.isdir(new):
528 os.makedirs(new, mode = 0o777)
527 ensure_dir_exists(new)
529 528
530 529 def set_autoindent(self,value=None):
531 530 """Set the autoindent flag, checking for readline support.
532 531
533 532 If called with no arguments, it acts as a toggle."""
534 533
535 534 if value != 0 and not self.has_readline:
536 535 if os.name == 'posix':
537 536 warn("The auto-indent feature requires the readline library")
538 537 self.autoindent = 0
539 538 return
540 539 if value is None:
541 540 self.autoindent = not self.autoindent
542 541 else:
543 542 self.autoindent = value
544 543
545 544 #-------------------------------------------------------------------------
546 545 # init_* methods called by __init__
547 546 #-------------------------------------------------------------------------
548 547
549 548 def init_ipython_dir(self, ipython_dir):
550 549 if ipython_dir is not None:
551 550 self.ipython_dir = ipython_dir
552 551 return
553 552
554 553 self.ipython_dir = get_ipython_dir()
555 554
556 555 def init_profile_dir(self, profile_dir):
557 556 if profile_dir is not None:
558 557 self.profile_dir = profile_dir
559 558 return
560 559 self.profile_dir =\
561 560 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
562 561
563 562 def init_instance_attrs(self):
564 563 self.more = False
565 564
566 565 # command compiler
567 566 self.compile = CachingCompiler()
568 567
569 568 # Make an empty namespace, which extension writers can rely on both
570 569 # existing and NEVER being used by ipython itself. This gives them a
571 570 # convenient location for storing additional information and state
572 571 # their extensions may require, without fear of collisions with other
573 572 # ipython names that may develop later.
574 573 self.meta = Struct()
575 574
576 575 # Temporary files used for various purposes. Deleted at exit.
577 576 self.tempfiles = []
578 577 self.tempdirs = []
579 578
580 579 # Keep track of readline usage (later set by init_readline)
581 580 self.has_readline = False
582 581
583 582 # keep track of where we started running (mainly for crash post-mortem)
584 583 # This is not being used anywhere currently.
585 584 self.starting_dir = py3compat.getcwd()
586 585
587 586 # Indentation management
588 587 self.indent_current_nsp = 0
589 588
590 589 # Dict to track post-execution functions that have been registered
591 590 self._post_execute = {}
592 591
593 592 def init_environment(self):
594 593 """Any changes we need to make to the user's environment."""
595 594 pass
596 595
597 596 def init_encoding(self):
598 597 # Get system encoding at startup time. Certain terminals (like Emacs
599 598 # under Win32 have it set to None, and we need to have a known valid
600 599 # encoding to use in the raw_input() method
601 600 try:
602 601 self.stdin_encoding = sys.stdin.encoding or 'ascii'
603 602 except AttributeError:
604 603 self.stdin_encoding = 'ascii'
605 604
606 605 def init_syntax_highlighting(self):
607 606 # Python source parser/formatter for syntax highlighting
608 607 pyformat = PyColorize.Parser().format
609 608 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
610 609
611 610 def init_pushd_popd_magic(self):
612 611 # for pushd/popd management
613 612 self.home_dir = get_home_dir()
614 613
615 614 self.dir_stack = []
616 615
617 616 def init_logger(self):
618 617 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
619 618 logmode='rotate')
620 619
621 620 def init_logstart(self):
622 621 """Initialize logging in case it was requested at the command line.
623 622 """
624 623 if self.logappend:
625 624 self.magic('logstart %s append' % self.logappend)
626 625 elif self.logfile:
627 626 self.magic('logstart %s' % self.logfile)
628 627 elif self.logstart:
629 628 self.magic('logstart')
630 629
631 630 def init_builtins(self):
632 631 # A single, static flag that we set to True. Its presence indicates
633 632 # that an IPython shell has been created, and we make no attempts at
634 633 # removing on exit or representing the existence of more than one
635 634 # IPython at a time.
636 635 builtin_mod.__dict__['__IPYTHON__'] = True
637 636
638 637 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
639 638 # manage on enter/exit, but with all our shells it's virtually
640 639 # impossible to get all the cases right. We're leaving the name in for
641 640 # those who adapted their codes to check for this flag, but will
642 641 # eventually remove it after a few more releases.
643 642 builtin_mod.__dict__['__IPYTHON__active'] = \
644 643 'Deprecated, check for __IPYTHON__'
645 644
646 645 self.builtin_trap = BuiltinTrap(shell=self)
647 646
648 647 def init_inspector(self):
649 648 # Object inspector
650 649 self.inspector = oinspect.Inspector(oinspect.InspectColors,
651 650 PyColorize.ANSICodeColors,
652 651 'NoColor',
653 652 self.object_info_string_level)
654 653
655 654 def init_io(self):
656 655 # This will just use sys.stdout and sys.stderr. If you want to
657 656 # override sys.stdout and sys.stderr themselves, you need to do that
658 657 # *before* instantiating this class, because io holds onto
659 658 # references to the underlying streams.
660 659 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
661 660 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
662 661 else:
663 662 io.stdout = io.IOStream(sys.stdout)
664 663 io.stderr = io.IOStream(sys.stderr)
665 664
666 665 def init_prompts(self):
667 666 self.prompt_manager = PromptManager(shell=self, parent=self)
668 667 self.configurables.append(self.prompt_manager)
669 668 # Set system prompts, so that scripts can decide if they are running
670 669 # interactively.
671 670 sys.ps1 = 'In : '
672 671 sys.ps2 = '...: '
673 672 sys.ps3 = 'Out: '
674 673
675 674 def init_display_formatter(self):
676 675 self.display_formatter = DisplayFormatter(parent=self)
677 676 self.configurables.append(self.display_formatter)
678 677
679 678 def init_display_pub(self):
680 679 self.display_pub = self.display_pub_class(parent=self)
681 680 self.configurables.append(self.display_pub)
682 681
683 682 def init_data_pub(self):
684 683 if not self.data_pub_class:
685 684 self.data_pub = None
686 685 return
687 686 self.data_pub = self.data_pub_class(parent=self)
688 687 self.configurables.append(self.data_pub)
689 688
690 689 def init_displayhook(self):
691 690 # Initialize displayhook, set in/out prompts and printing system
692 691 self.displayhook = self.displayhook_class(
693 692 parent=self,
694 693 shell=self,
695 694 cache_size=self.cache_size,
696 695 )
697 696 self.configurables.append(self.displayhook)
698 697 # This is a context manager that installs/revmoes the displayhook at
699 698 # the appropriate time.
700 699 self.display_trap = DisplayTrap(hook=self.displayhook)
701 700
702 701 def init_latextool(self):
703 702 """Configure LaTeXTool."""
704 703 cfg = LaTeXTool.instance(parent=self)
705 704 if cfg not in self.configurables:
706 705 self.configurables.append(cfg)
707 706
708 707 def init_virtualenv(self):
709 708 """Add a virtualenv to sys.path so the user can import modules from it.
710 709 This isn't perfect: it doesn't use the Python interpreter with which the
711 710 virtualenv was built, and it ignores the --no-site-packages option. A
712 711 warning will appear suggesting the user installs IPython in the
713 712 virtualenv, but for many cases, it probably works well enough.
714 713
715 714 Adapted from code snippets online.
716 715
717 716 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
718 717 """
719 718 if 'VIRTUAL_ENV' not in os.environ:
720 719 # Not in a virtualenv
721 720 return
722 721
723 722 # venv detection:
724 723 # stdlib venv may symlink sys.executable, so we can't use realpath.
725 724 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
726 725 # So we just check every item in the symlink tree (generally <= 3)
727 726 p = sys.executable
728 727 paths = [p]
729 728 while os.path.islink(p):
730 729 p = os.path.join(os.path.dirname(p), os.readlink(p))
731 730 paths.append(p)
732 731 if any(p.startswith(os.environ['VIRTUAL_ENV']) for p in paths):
733 732 # Running properly in the virtualenv, don't need to do anything
734 733 return
735 734
736 735 warn("Attempting to work in a virtualenv. If you encounter problems, please "
737 736 "install IPython inside the virtualenv.")
738 737 if sys.platform == "win32":
739 738 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
740 739 else:
741 740 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
742 741 'python%d.%d' % sys.version_info[:2], 'site-packages')
743 742
744 743 import site
745 744 sys.path.insert(0, virtual_env)
746 745 site.addsitedir(virtual_env)
747 746
748 747 #-------------------------------------------------------------------------
749 748 # Things related to injections into the sys module
750 749 #-------------------------------------------------------------------------
751 750
752 751 def save_sys_module_state(self):
753 752 """Save the state of hooks in the sys module.
754 753
755 754 This has to be called after self.user_module is created.
756 755 """
757 756 self._orig_sys_module_state = {}
758 757 self._orig_sys_module_state['stdin'] = sys.stdin
759 758 self._orig_sys_module_state['stdout'] = sys.stdout
760 759 self._orig_sys_module_state['stderr'] = sys.stderr
761 760 self._orig_sys_module_state['excepthook'] = sys.excepthook
762 761 self._orig_sys_modules_main_name = self.user_module.__name__
763 762 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
764 763
765 764 def restore_sys_module_state(self):
766 765 """Restore the state of the sys module."""
767 766 try:
768 767 for k, v in iteritems(self._orig_sys_module_state):
769 768 setattr(sys, k, v)
770 769 except AttributeError:
771 770 pass
772 771 # Reset what what done in self.init_sys_modules
773 772 if self._orig_sys_modules_main_mod is not None:
774 773 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
775 774
776 775 #-------------------------------------------------------------------------
777 776 # Things related to hooks
778 777 #-------------------------------------------------------------------------
779 778
780 779 def init_hooks(self):
781 780 # hooks holds pointers used for user-side customizations
782 781 self.hooks = Struct()
783 782
784 783 self.strdispatchers = {}
785 784
786 785 # Set all default hooks, defined in the IPython.hooks module.
787 786 hooks = IPython.core.hooks
788 787 for hook_name in hooks.__all__:
789 788 # default hooks have priority 100, i.e. low; user hooks should have
790 789 # 0-100 priority
791 790 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
792 791
793 792 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
794 793 _warn_deprecated=True):
795 794 """set_hook(name,hook) -> sets an internal IPython hook.
796 795
797 796 IPython exposes some of its internal API as user-modifiable hooks. By
798 797 adding your function to one of these hooks, you can modify IPython's
799 798 behavior to call at runtime your own routines."""
800 799
801 800 # At some point in the future, this should validate the hook before it
802 801 # accepts it. Probably at least check that the hook takes the number
803 802 # of args it's supposed to.
804 803
805 804 f = types.MethodType(hook,self)
806 805
807 806 # check if the hook is for strdispatcher first
808 807 if str_key is not None:
809 808 sdp = self.strdispatchers.get(name, StrDispatch())
810 809 sdp.add_s(str_key, f, priority )
811 810 self.strdispatchers[name] = sdp
812 811 return
813 812 if re_key is not None:
814 813 sdp = self.strdispatchers.get(name, StrDispatch())
815 814 sdp.add_re(re.compile(re_key), f, priority )
816 815 self.strdispatchers[name] = sdp
817 816 return
818 817
819 818 dp = getattr(self.hooks, name, None)
820 819 if name not in IPython.core.hooks.__all__:
821 820 print("Warning! Hook '%s' is not one of %s" % \
822 821 (name, IPython.core.hooks.__all__ ))
823 822
824 823 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
825 824 alternative = IPython.core.hooks.deprecated[name]
826 825 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
827 826
828 827 if not dp:
829 828 dp = IPython.core.hooks.CommandChainDispatcher()
830 829
831 830 try:
832 831 dp.add(f,priority)
833 832 except AttributeError:
834 833 # it was not commandchain, plain old func - replace
835 834 dp = f
836 835
837 836 setattr(self.hooks,name, dp)
838 837
839 838 #-------------------------------------------------------------------------
840 839 # Things related to events
841 840 #-------------------------------------------------------------------------
842 841
843 842 def init_events(self):
844 843 self.events = EventManager(self, available_events)
845 844
846 845 def register_post_execute(self, func):
847 846 """DEPRECATED: Use ip.events.register('post_run_cell', func)
848 847
849 848 Register a function for calling after code execution.
850 849 """
851 850 warn("ip.register_post_execute is deprecated, use "
852 851 "ip.events.register('post_run_cell', func) instead.")
853 852 self.events.register('post_run_cell', func)
854 853
855 854 #-------------------------------------------------------------------------
856 855 # Things related to the "main" module
857 856 #-------------------------------------------------------------------------
858 857
859 858 def new_main_mod(self, filename, modname):
860 859 """Return a new 'main' module object for user code execution.
861 860
862 861 ``filename`` should be the path of the script which will be run in the
863 862 module. Requests with the same filename will get the same module, with
864 863 its namespace cleared.
865 864
866 865 ``modname`` should be the module name - normally either '__main__' or
867 866 the basename of the file without the extension.
868 867
869 868 When scripts are executed via %run, we must keep a reference to their
870 869 __main__ module around so that Python doesn't
871 870 clear it, rendering references to module globals useless.
872 871
873 872 This method keeps said reference in a private dict, keyed by the
874 873 absolute path of the script. This way, for multiple executions of the
875 874 same script we only keep one copy of the namespace (the last one),
876 875 thus preventing memory leaks from old references while allowing the
877 876 objects from the last execution to be accessible.
878 877 """
879 878 filename = os.path.abspath(filename)
880 879 try:
881 880 main_mod = self._main_mod_cache[filename]
882 881 except KeyError:
883 882 main_mod = self._main_mod_cache[filename] = types.ModuleType(modname,
884 883 doc="Module created for script run in IPython")
885 884 else:
886 885 main_mod.__dict__.clear()
887 886 main_mod.__name__ = modname
888 887
889 888 main_mod.__file__ = filename
890 889 # It seems pydoc (and perhaps others) needs any module instance to
891 890 # implement a __nonzero__ method
892 891 main_mod.__nonzero__ = lambda : True
893 892
894 893 return main_mod
895 894
896 895 def clear_main_mod_cache(self):
897 896 """Clear the cache of main modules.
898 897
899 898 Mainly for use by utilities like %reset.
900 899
901 900 Examples
902 901 --------
903 902
904 903 In [15]: import IPython
905 904
906 905 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
907 906
908 907 In [17]: len(_ip._main_mod_cache) > 0
909 908 Out[17]: True
910 909
911 910 In [18]: _ip.clear_main_mod_cache()
912 911
913 912 In [19]: len(_ip._main_mod_cache) == 0
914 913 Out[19]: True
915 914 """
916 915 self._main_mod_cache.clear()
917 916
918 917 #-------------------------------------------------------------------------
919 918 # Things related to debugging
920 919 #-------------------------------------------------------------------------
921 920
922 921 def init_pdb(self):
923 922 # Set calling of pdb on exceptions
924 923 # self.call_pdb is a property
925 924 self.call_pdb = self.pdb
926 925
927 926 def _get_call_pdb(self):
928 927 return self._call_pdb
929 928
930 929 def _set_call_pdb(self,val):
931 930
932 931 if val not in (0,1,False,True):
933 932 raise ValueError('new call_pdb value must be boolean')
934 933
935 934 # store value in instance
936 935 self._call_pdb = val
937 936
938 937 # notify the actual exception handlers
939 938 self.InteractiveTB.call_pdb = val
940 939
941 940 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
942 941 'Control auto-activation of pdb at exceptions')
943 942
944 943 def debugger(self,force=False):
945 944 """Call the pydb/pdb debugger.
946 945
947 946 Keywords:
948 947
949 948 - force(False): by default, this routine checks the instance call_pdb
950 949 flag and does not actually invoke the debugger if the flag is false.
951 950 The 'force' option forces the debugger to activate even if the flag
952 951 is false.
953 952 """
954 953
955 954 if not (force or self.call_pdb):
956 955 return
957 956
958 957 if not hasattr(sys,'last_traceback'):
959 958 error('No traceback has been produced, nothing to debug.')
960 959 return
961 960
962 961 # use pydb if available
963 962 if debugger.has_pydb:
964 963 from pydb import pm
965 964 else:
966 965 # fallback to our internal debugger
967 966 pm = lambda : self.InteractiveTB.debugger(force=True)
968 967
969 968 with self.readline_no_record:
970 969 pm()
971 970
972 971 #-------------------------------------------------------------------------
973 972 # Things related to IPython's various namespaces
974 973 #-------------------------------------------------------------------------
975 974 default_user_namespaces = True
976 975
977 976 def init_create_namespaces(self, user_module=None, user_ns=None):
978 977 # Create the namespace where the user will operate. user_ns is
979 978 # normally the only one used, and it is passed to the exec calls as
980 979 # the locals argument. But we do carry a user_global_ns namespace
981 980 # given as the exec 'globals' argument, This is useful in embedding
982 981 # situations where the ipython shell opens in a context where the
983 982 # distinction between locals and globals is meaningful. For
984 983 # non-embedded contexts, it is just the same object as the user_ns dict.
985 984
986 985 # FIXME. For some strange reason, __builtins__ is showing up at user
987 986 # level as a dict instead of a module. This is a manual fix, but I
988 987 # should really track down where the problem is coming from. Alex
989 988 # Schmolck reported this problem first.
990 989
991 990 # A useful post by Alex Martelli on this topic:
992 991 # Re: inconsistent value from __builtins__
993 992 # Von: Alex Martelli <aleaxit@yahoo.com>
994 993 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
995 994 # Gruppen: comp.lang.python
996 995
997 996 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
998 997 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
999 998 # > <type 'dict'>
1000 999 # > >>> print type(__builtins__)
1001 1000 # > <type 'module'>
1002 1001 # > Is this difference in return value intentional?
1003 1002
1004 1003 # Well, it's documented that '__builtins__' can be either a dictionary
1005 1004 # or a module, and it's been that way for a long time. Whether it's
1006 1005 # intentional (or sensible), I don't know. In any case, the idea is
1007 1006 # that if you need to access the built-in namespace directly, you
1008 1007 # should start with "import __builtin__" (note, no 's') which will
1009 1008 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1010 1009
1011 1010 # These routines return a properly built module and dict as needed by
1012 1011 # the rest of the code, and can also be used by extension writers to
1013 1012 # generate properly initialized namespaces.
1014 1013 if (user_ns is not None) or (user_module is not None):
1015 1014 self.default_user_namespaces = False
1016 1015 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1017 1016
1018 1017 # A record of hidden variables we have added to the user namespace, so
1019 1018 # we can list later only variables defined in actual interactive use.
1020 1019 self.user_ns_hidden = {}
1021 1020
1022 1021 # Now that FakeModule produces a real module, we've run into a nasty
1023 1022 # problem: after script execution (via %run), the module where the user
1024 1023 # code ran is deleted. Now that this object is a true module (needed
1025 1024 # so docetst and other tools work correctly), the Python module
1026 1025 # teardown mechanism runs over it, and sets to None every variable
1027 1026 # present in that module. Top-level references to objects from the
1028 1027 # script survive, because the user_ns is updated with them. However,
1029 1028 # calling functions defined in the script that use other things from
1030 1029 # the script will fail, because the function's closure had references
1031 1030 # to the original objects, which are now all None. So we must protect
1032 1031 # these modules from deletion by keeping a cache.
1033 1032 #
1034 1033 # To avoid keeping stale modules around (we only need the one from the
1035 1034 # last run), we use a dict keyed with the full path to the script, so
1036 1035 # only the last version of the module is held in the cache. Note,
1037 1036 # however, that we must cache the module *namespace contents* (their
1038 1037 # __dict__). Because if we try to cache the actual modules, old ones
1039 1038 # (uncached) could be destroyed while still holding references (such as
1040 1039 # those held by GUI objects that tend to be long-lived)>
1041 1040 #
1042 1041 # The %reset command will flush this cache. See the cache_main_mod()
1043 1042 # and clear_main_mod_cache() methods for details on use.
1044 1043
1045 1044 # This is the cache used for 'main' namespaces
1046 1045 self._main_mod_cache = {}
1047 1046
1048 1047 # A table holding all the namespaces IPython deals with, so that
1049 1048 # introspection facilities can search easily.
1050 1049 self.ns_table = {'user_global':self.user_module.__dict__,
1051 1050 'user_local':self.user_ns,
1052 1051 'builtin':builtin_mod.__dict__
1053 1052 }
1054 1053
1055 1054 @property
1056 1055 def user_global_ns(self):
1057 1056 return self.user_module.__dict__
1058 1057
1059 1058 def prepare_user_module(self, user_module=None, user_ns=None):
1060 1059 """Prepare the module and namespace in which user code will be run.
1061 1060
1062 1061 When IPython is started normally, both parameters are None: a new module
1063 1062 is created automatically, and its __dict__ used as the namespace.
1064 1063
1065 1064 If only user_module is provided, its __dict__ is used as the namespace.
1066 1065 If only user_ns is provided, a dummy module is created, and user_ns
1067 1066 becomes the global namespace. If both are provided (as they may be
1068 1067 when embedding), user_ns is the local namespace, and user_module
1069 1068 provides the global namespace.
1070 1069
1071 1070 Parameters
1072 1071 ----------
1073 1072 user_module : module, optional
1074 1073 The current user module in which IPython is being run. If None,
1075 1074 a clean module will be created.
1076 1075 user_ns : dict, optional
1077 1076 A namespace in which to run interactive commands.
1078 1077
1079 1078 Returns
1080 1079 -------
1081 1080 A tuple of user_module and user_ns, each properly initialised.
1082 1081 """
1083 1082 if user_module is None and user_ns is not None:
1084 1083 user_ns.setdefault("__name__", "__main__")
1085 1084 user_module = DummyMod()
1086 1085 user_module.__dict__ = user_ns
1087 1086
1088 1087 if user_module is None:
1089 1088 user_module = types.ModuleType("__main__",
1090 1089 doc="Automatically created module for IPython interactive environment")
1091 1090
1092 1091 # We must ensure that __builtin__ (without the final 's') is always
1093 1092 # available and pointing to the __builtin__ *module*. For more details:
1094 1093 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1095 1094 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1096 1095 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1097 1096
1098 1097 if user_ns is None:
1099 1098 user_ns = user_module.__dict__
1100 1099
1101 1100 return user_module, user_ns
1102 1101
1103 1102 def init_sys_modules(self):
1104 1103 # We need to insert into sys.modules something that looks like a
1105 1104 # module but which accesses the IPython namespace, for shelve and
1106 1105 # pickle to work interactively. Normally they rely on getting
1107 1106 # everything out of __main__, but for embedding purposes each IPython
1108 1107 # instance has its own private namespace, so we can't go shoving
1109 1108 # everything into __main__.
1110 1109
1111 1110 # note, however, that we should only do this for non-embedded
1112 1111 # ipythons, which really mimic the __main__.__dict__ with their own
1113 1112 # namespace. Embedded instances, on the other hand, should not do
1114 1113 # this because they need to manage the user local/global namespaces
1115 1114 # only, but they live within a 'normal' __main__ (meaning, they
1116 1115 # shouldn't overtake the execution environment of the script they're
1117 1116 # embedded in).
1118 1117
1119 1118 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1120 1119 main_name = self.user_module.__name__
1121 1120 sys.modules[main_name] = self.user_module
1122 1121
1123 1122 def init_user_ns(self):
1124 1123 """Initialize all user-visible namespaces to their minimum defaults.
1125 1124
1126 1125 Certain history lists are also initialized here, as they effectively
1127 1126 act as user namespaces.
1128 1127
1129 1128 Notes
1130 1129 -----
1131 1130 All data structures here are only filled in, they are NOT reset by this
1132 1131 method. If they were not empty before, data will simply be added to
1133 1132 therm.
1134 1133 """
1135 1134 # This function works in two parts: first we put a few things in
1136 1135 # user_ns, and we sync that contents into user_ns_hidden so that these
1137 1136 # initial variables aren't shown by %who. After the sync, we add the
1138 1137 # rest of what we *do* want the user to see with %who even on a new
1139 1138 # session (probably nothing, so theye really only see their own stuff)
1140 1139
1141 1140 # The user dict must *always* have a __builtin__ reference to the
1142 1141 # Python standard __builtin__ namespace, which must be imported.
1143 1142 # This is so that certain operations in prompt evaluation can be
1144 1143 # reliably executed with builtins. Note that we can NOT use
1145 1144 # __builtins__ (note the 's'), because that can either be a dict or a
1146 1145 # module, and can even mutate at runtime, depending on the context
1147 1146 # (Python makes no guarantees on it). In contrast, __builtin__ is
1148 1147 # always a module object, though it must be explicitly imported.
1149 1148
1150 1149 # For more details:
1151 1150 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1152 1151 ns = dict()
1153 1152
1154 1153 # make global variables for user access to the histories
1155 1154 ns['_ih'] = self.history_manager.input_hist_parsed
1156 1155 ns['_oh'] = self.history_manager.output_hist
1157 1156 ns['_dh'] = self.history_manager.dir_hist
1158 1157
1159 1158 ns['_sh'] = shadowns
1160 1159
1161 1160 # user aliases to input and output histories. These shouldn't show up
1162 1161 # in %who, as they can have very large reprs.
1163 1162 ns['In'] = self.history_manager.input_hist_parsed
1164 1163 ns['Out'] = self.history_manager.output_hist
1165 1164
1166 1165 # Store myself as the public api!!!
1167 1166 ns['get_ipython'] = self.get_ipython
1168 1167
1169 1168 ns['exit'] = self.exiter
1170 1169 ns['quit'] = self.exiter
1171 1170
1172 1171 # Sync what we've added so far to user_ns_hidden so these aren't seen
1173 1172 # by %who
1174 1173 self.user_ns_hidden.update(ns)
1175 1174
1176 1175 # Anything put into ns now would show up in %who. Think twice before
1177 1176 # putting anything here, as we really want %who to show the user their
1178 1177 # stuff, not our variables.
1179 1178
1180 1179 # Finally, update the real user's namespace
1181 1180 self.user_ns.update(ns)
1182 1181
1183 1182 @property
1184 1183 def all_ns_refs(self):
1185 1184 """Get a list of references to all the namespace dictionaries in which
1186 1185 IPython might store a user-created object.
1187 1186
1188 1187 Note that this does not include the displayhook, which also caches
1189 1188 objects from the output."""
1190 1189 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1191 1190 [m.__dict__ for m in self._main_mod_cache.values()]
1192 1191
1193 1192 def reset(self, new_session=True):
1194 1193 """Clear all internal namespaces, and attempt to release references to
1195 1194 user objects.
1196 1195
1197 1196 If new_session is True, a new history session will be opened.
1198 1197 """
1199 1198 # Clear histories
1200 1199 self.history_manager.reset(new_session)
1201 1200 # Reset counter used to index all histories
1202 1201 if new_session:
1203 1202 self.execution_count = 1
1204 1203
1205 1204 # Flush cached output items
1206 1205 if self.displayhook.do_full_cache:
1207 1206 self.displayhook.flush()
1208 1207
1209 1208 # The main execution namespaces must be cleared very carefully,
1210 1209 # skipping the deletion of the builtin-related keys, because doing so
1211 1210 # would cause errors in many object's __del__ methods.
1212 1211 if self.user_ns is not self.user_global_ns:
1213 1212 self.user_ns.clear()
1214 1213 ns = self.user_global_ns
1215 1214 drop_keys = set(ns.keys())
1216 1215 drop_keys.discard('__builtin__')
1217 1216 drop_keys.discard('__builtins__')
1218 1217 drop_keys.discard('__name__')
1219 1218 for k in drop_keys:
1220 1219 del ns[k]
1221 1220
1222 1221 self.user_ns_hidden.clear()
1223 1222
1224 1223 # Restore the user namespaces to minimal usability
1225 1224 self.init_user_ns()
1226 1225
1227 1226 # Restore the default and user aliases
1228 1227 self.alias_manager.clear_aliases()
1229 1228 self.alias_manager.init_aliases()
1230 1229
1231 1230 # Flush the private list of module references kept for script
1232 1231 # execution protection
1233 1232 self.clear_main_mod_cache()
1234 1233
1235 1234 def del_var(self, varname, by_name=False):
1236 1235 """Delete a variable from the various namespaces, so that, as
1237 1236 far as possible, we're not keeping any hidden references to it.
1238 1237
1239 1238 Parameters
1240 1239 ----------
1241 1240 varname : str
1242 1241 The name of the variable to delete.
1243 1242 by_name : bool
1244 1243 If True, delete variables with the given name in each
1245 1244 namespace. If False (default), find the variable in the user
1246 1245 namespace, and delete references to it.
1247 1246 """
1248 1247 if varname in ('__builtin__', '__builtins__'):
1249 1248 raise ValueError("Refusing to delete %s" % varname)
1250 1249
1251 1250 ns_refs = self.all_ns_refs
1252 1251
1253 1252 if by_name: # Delete by name
1254 1253 for ns in ns_refs:
1255 1254 try:
1256 1255 del ns[varname]
1257 1256 except KeyError:
1258 1257 pass
1259 1258 else: # Delete by object
1260 1259 try:
1261 1260 obj = self.user_ns[varname]
1262 1261 except KeyError:
1263 1262 raise NameError("name '%s' is not defined" % varname)
1264 1263 # Also check in output history
1265 1264 ns_refs.append(self.history_manager.output_hist)
1266 1265 for ns in ns_refs:
1267 1266 to_delete = [n for n, o in iteritems(ns) if o is obj]
1268 1267 for name in to_delete:
1269 1268 del ns[name]
1270 1269
1271 1270 # displayhook keeps extra references, but not in a dictionary
1272 1271 for name in ('_', '__', '___'):
1273 1272 if getattr(self.displayhook, name) is obj:
1274 1273 setattr(self.displayhook, name, None)
1275 1274
1276 1275 def reset_selective(self, regex=None):
1277 1276 """Clear selective variables from internal namespaces based on a
1278 1277 specified regular expression.
1279 1278
1280 1279 Parameters
1281 1280 ----------
1282 1281 regex : string or compiled pattern, optional
1283 1282 A regular expression pattern that will be used in searching
1284 1283 variable names in the users namespaces.
1285 1284 """
1286 1285 if regex is not None:
1287 1286 try:
1288 1287 m = re.compile(regex)
1289 1288 except TypeError:
1290 1289 raise TypeError('regex must be a string or compiled pattern')
1291 1290 # Search for keys in each namespace that match the given regex
1292 1291 # If a match is found, delete the key/value pair.
1293 1292 for ns in self.all_ns_refs:
1294 1293 for var in ns:
1295 1294 if m.search(var):
1296 1295 del ns[var]
1297 1296
1298 1297 def push(self, variables, interactive=True):
1299 1298 """Inject a group of variables into the IPython user namespace.
1300 1299
1301 1300 Parameters
1302 1301 ----------
1303 1302 variables : dict, str or list/tuple of str
1304 1303 The variables to inject into the user's namespace. If a dict, a
1305 1304 simple update is done. If a str, the string is assumed to have
1306 1305 variable names separated by spaces. A list/tuple of str can also
1307 1306 be used to give the variable names. If just the variable names are
1308 1307 give (list/tuple/str) then the variable values looked up in the
1309 1308 callers frame.
1310 1309 interactive : bool
1311 1310 If True (default), the variables will be listed with the ``who``
1312 1311 magic.
1313 1312 """
1314 1313 vdict = None
1315 1314
1316 1315 # We need a dict of name/value pairs to do namespace updates.
1317 1316 if isinstance(variables, dict):
1318 1317 vdict = variables
1319 1318 elif isinstance(variables, string_types+(list, tuple)):
1320 1319 if isinstance(variables, string_types):
1321 1320 vlist = variables.split()
1322 1321 else:
1323 1322 vlist = variables
1324 1323 vdict = {}
1325 1324 cf = sys._getframe(1)
1326 1325 for name in vlist:
1327 1326 try:
1328 1327 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1329 1328 except:
1330 1329 print('Could not get variable %s from %s' %
1331 1330 (name,cf.f_code.co_name))
1332 1331 else:
1333 1332 raise ValueError('variables must be a dict/str/list/tuple')
1334 1333
1335 1334 # Propagate variables to user namespace
1336 1335 self.user_ns.update(vdict)
1337 1336
1338 1337 # And configure interactive visibility
1339 1338 user_ns_hidden = self.user_ns_hidden
1340 1339 if interactive:
1341 1340 for name in vdict:
1342 1341 user_ns_hidden.pop(name, None)
1343 1342 else:
1344 1343 user_ns_hidden.update(vdict)
1345 1344
1346 1345 def drop_by_id(self, variables):
1347 1346 """Remove a dict of variables from the user namespace, if they are the
1348 1347 same as the values in the dictionary.
1349 1348
1350 1349 This is intended for use by extensions: variables that they've added can
1351 1350 be taken back out if they are unloaded, without removing any that the
1352 1351 user has overwritten.
1353 1352
1354 1353 Parameters
1355 1354 ----------
1356 1355 variables : dict
1357 1356 A dictionary mapping object names (as strings) to the objects.
1358 1357 """
1359 1358 for name, obj in iteritems(variables):
1360 1359 if name in self.user_ns and self.user_ns[name] is obj:
1361 1360 del self.user_ns[name]
1362 1361 self.user_ns_hidden.pop(name, None)
1363 1362
1364 1363 #-------------------------------------------------------------------------
1365 1364 # Things related to object introspection
1366 1365 #-------------------------------------------------------------------------
1367 1366
1368 1367 def _ofind(self, oname, namespaces=None):
1369 1368 """Find an object in the available namespaces.
1370 1369
1371 1370 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1372 1371
1373 1372 Has special code to detect magic functions.
1374 1373 """
1375 1374 oname = oname.strip()
1376 1375 #print '1- oname: <%r>' % oname # dbg
1377 1376 if not oname.startswith(ESC_MAGIC) and \
1378 1377 not oname.startswith(ESC_MAGIC2) and \
1379 1378 not py3compat.isidentifier(oname, dotted=True):
1380 1379 return dict(found=False)
1381 1380
1382 1381 alias_ns = None
1383 1382 if namespaces is None:
1384 1383 # Namespaces to search in:
1385 1384 # Put them in a list. The order is important so that we
1386 1385 # find things in the same order that Python finds them.
1387 1386 namespaces = [ ('Interactive', self.user_ns),
1388 1387 ('Interactive (global)', self.user_global_ns),
1389 1388 ('Python builtin', builtin_mod.__dict__),
1390 1389 ]
1391 1390
1392 1391 # initialize results to 'null'
1393 1392 found = False; obj = None; ospace = None; ds = None;
1394 1393 ismagic = False; isalias = False; parent = None
1395 1394
1396 1395 # We need to special-case 'print', which as of python2.6 registers as a
1397 1396 # function but should only be treated as one if print_function was
1398 1397 # loaded with a future import. In this case, just bail.
1399 1398 if (oname == 'print' and not py3compat.PY3 and not \
1400 1399 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1401 1400 return {'found':found, 'obj':obj, 'namespace':ospace,
1402 1401 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1403 1402
1404 1403 # Look for the given name by splitting it in parts. If the head is
1405 1404 # found, then we look for all the remaining parts as members, and only
1406 1405 # declare success if we can find them all.
1407 1406 oname_parts = oname.split('.')
1408 1407 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1409 1408 for nsname,ns in namespaces:
1410 1409 try:
1411 1410 obj = ns[oname_head]
1412 1411 except KeyError:
1413 1412 continue
1414 1413 else:
1415 1414 #print 'oname_rest:', oname_rest # dbg
1416 1415 for part in oname_rest:
1417 1416 try:
1418 1417 parent = obj
1419 1418 obj = getattr(obj,part)
1420 1419 except:
1421 1420 # Blanket except b/c some badly implemented objects
1422 1421 # allow __getattr__ to raise exceptions other than
1423 1422 # AttributeError, which then crashes IPython.
1424 1423 break
1425 1424 else:
1426 1425 # If we finish the for loop (no break), we got all members
1427 1426 found = True
1428 1427 ospace = nsname
1429 1428 break # namespace loop
1430 1429
1431 1430 # Try to see if it's magic
1432 1431 if not found:
1433 1432 obj = None
1434 1433 if oname.startswith(ESC_MAGIC2):
1435 1434 oname = oname.lstrip(ESC_MAGIC2)
1436 1435 obj = self.find_cell_magic(oname)
1437 1436 elif oname.startswith(ESC_MAGIC):
1438 1437 oname = oname.lstrip(ESC_MAGIC)
1439 1438 obj = self.find_line_magic(oname)
1440 1439 else:
1441 1440 # search without prefix, so run? will find %run?
1442 1441 obj = self.find_line_magic(oname)
1443 1442 if obj is None:
1444 1443 obj = self.find_cell_magic(oname)
1445 1444 if obj is not None:
1446 1445 found = True
1447 1446 ospace = 'IPython internal'
1448 1447 ismagic = True
1449 1448
1450 1449 # Last try: special-case some literals like '', [], {}, etc:
1451 1450 if not found and oname_head in ["''",'""','[]','{}','()']:
1452 1451 obj = eval(oname_head)
1453 1452 found = True
1454 1453 ospace = 'Interactive'
1455 1454
1456 1455 return {'found':found, 'obj':obj, 'namespace':ospace,
1457 1456 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1458 1457
1459 1458 def _ofind_property(self, oname, info):
1460 1459 """Second part of object finding, to look for property details."""
1461 1460 if info.found:
1462 1461 # Get the docstring of the class property if it exists.
1463 1462 path = oname.split('.')
1464 1463 root = '.'.join(path[:-1])
1465 1464 if info.parent is not None:
1466 1465 try:
1467 1466 target = getattr(info.parent, '__class__')
1468 1467 # The object belongs to a class instance.
1469 1468 try:
1470 1469 target = getattr(target, path[-1])
1471 1470 # The class defines the object.
1472 1471 if isinstance(target, property):
1473 1472 oname = root + '.__class__.' + path[-1]
1474 1473 info = Struct(self._ofind(oname))
1475 1474 except AttributeError: pass
1476 1475 except AttributeError: pass
1477 1476
1478 1477 # We return either the new info or the unmodified input if the object
1479 1478 # hadn't been found
1480 1479 return info
1481 1480
1482 1481 def _object_find(self, oname, namespaces=None):
1483 1482 """Find an object and return a struct with info about it."""
1484 1483 inf = Struct(self._ofind(oname, namespaces))
1485 1484 return Struct(self._ofind_property(oname, inf))
1486 1485
1487 1486 def _inspect(self, meth, oname, namespaces=None, **kw):
1488 1487 """Generic interface to the inspector system.
1489 1488
1490 1489 This function is meant to be called by pdef, pdoc & friends."""
1491 1490 info = self._object_find(oname, namespaces)
1492 1491 if info.found:
1493 1492 pmethod = getattr(self.inspector, meth)
1494 1493 formatter = format_screen if info.ismagic else None
1495 1494 if meth == 'pdoc':
1496 1495 pmethod(info.obj, oname, formatter)
1497 1496 elif meth == 'pinfo':
1498 1497 pmethod(info.obj, oname, formatter, info, **kw)
1499 1498 else:
1500 1499 pmethod(info.obj, oname)
1501 1500 else:
1502 1501 print('Object `%s` not found.' % oname)
1503 1502 return 'not found' # so callers can take other action
1504 1503
1505 1504 def object_inspect(self, oname, detail_level=0):
1506 1505 with self.builtin_trap:
1507 1506 info = self._object_find(oname)
1508 1507 if info.found:
1509 1508 return self.inspector.info(info.obj, oname, info=info,
1510 1509 detail_level=detail_level
1511 1510 )
1512 1511 else:
1513 1512 return oinspect.object_info(name=oname, found=False)
1514 1513
1515 1514 #-------------------------------------------------------------------------
1516 1515 # Things related to history management
1517 1516 #-------------------------------------------------------------------------
1518 1517
1519 1518 def init_history(self):
1520 1519 """Sets up the command history, and starts regular autosaves."""
1521 1520 self.history_manager = HistoryManager(shell=self, parent=self)
1522 1521 self.configurables.append(self.history_manager)
1523 1522
1524 1523 #-------------------------------------------------------------------------
1525 1524 # Things related to exception handling and tracebacks (not debugging)
1526 1525 #-------------------------------------------------------------------------
1527 1526
1528 1527 def init_traceback_handlers(self, custom_exceptions):
1529 1528 # Syntax error handler.
1530 1529 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1531 1530
1532 1531 # The interactive one is initialized with an offset, meaning we always
1533 1532 # want to remove the topmost item in the traceback, which is our own
1534 1533 # internal code. Valid modes: ['Plain','Context','Verbose']
1535 1534 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1536 1535 color_scheme='NoColor',
1537 1536 tb_offset = 1,
1538 1537 check_cache=check_linecache_ipython)
1539 1538
1540 1539 # The instance will store a pointer to the system-wide exception hook,
1541 1540 # so that runtime code (such as magics) can access it. This is because
1542 1541 # during the read-eval loop, it may get temporarily overwritten.
1543 1542 self.sys_excepthook = sys.excepthook
1544 1543
1545 1544 # and add any custom exception handlers the user may have specified
1546 1545 self.set_custom_exc(*custom_exceptions)
1547 1546
1548 1547 # Set the exception mode
1549 1548 self.InteractiveTB.set_mode(mode=self.xmode)
1550 1549
1551 1550 def set_custom_exc(self, exc_tuple, handler):
1552 1551 """set_custom_exc(exc_tuple,handler)
1553 1552
1554 1553 Set a custom exception handler, which will be called if any of the
1555 1554 exceptions in exc_tuple occur in the mainloop (specifically, in the
1556 1555 run_code() method).
1557 1556
1558 1557 Parameters
1559 1558 ----------
1560 1559
1561 1560 exc_tuple : tuple of exception classes
1562 1561 A *tuple* of exception classes, for which to call the defined
1563 1562 handler. It is very important that you use a tuple, and NOT A
1564 1563 LIST here, because of the way Python's except statement works. If
1565 1564 you only want to trap a single exception, use a singleton tuple::
1566 1565
1567 1566 exc_tuple == (MyCustomException,)
1568 1567
1569 1568 handler : callable
1570 1569 handler must have the following signature::
1571 1570
1572 1571 def my_handler(self, etype, value, tb, tb_offset=None):
1573 1572 ...
1574 1573 return structured_traceback
1575 1574
1576 1575 Your handler must return a structured traceback (a list of strings),
1577 1576 or None.
1578 1577
1579 1578 This will be made into an instance method (via types.MethodType)
1580 1579 of IPython itself, and it will be called if any of the exceptions
1581 1580 listed in the exc_tuple are caught. If the handler is None, an
1582 1581 internal basic one is used, which just prints basic info.
1583 1582
1584 1583 To protect IPython from crashes, if your handler ever raises an
1585 1584 exception or returns an invalid result, it will be immediately
1586 1585 disabled.
1587 1586
1588 1587 WARNING: by putting in your own exception handler into IPython's main
1589 1588 execution loop, you run a very good chance of nasty crashes. This
1590 1589 facility should only be used if you really know what you are doing."""
1591 1590
1592 1591 assert type(exc_tuple)==type(()) , \
1593 1592 "The custom exceptions must be given AS A TUPLE."
1594 1593
1595 1594 def dummy_handler(self,etype,value,tb,tb_offset=None):
1596 1595 print('*** Simple custom exception handler ***')
1597 1596 print('Exception type :',etype)
1598 1597 print('Exception value:',value)
1599 1598 print('Traceback :',tb)
1600 1599 #print 'Source code :','\n'.join(self.buffer)
1601 1600
1602 1601 def validate_stb(stb):
1603 1602 """validate structured traceback return type
1604 1603
1605 1604 return type of CustomTB *should* be a list of strings, but allow
1606 1605 single strings or None, which are harmless.
1607 1606
1608 1607 This function will *always* return a list of strings,
1609 1608 and will raise a TypeError if stb is inappropriate.
1610 1609 """
1611 1610 msg = "CustomTB must return list of strings, not %r" % stb
1612 1611 if stb is None:
1613 1612 return []
1614 1613 elif isinstance(stb, string_types):
1615 1614 return [stb]
1616 1615 elif not isinstance(stb, list):
1617 1616 raise TypeError(msg)
1618 1617 # it's a list
1619 1618 for line in stb:
1620 1619 # check every element
1621 1620 if not isinstance(line, string_types):
1622 1621 raise TypeError(msg)
1623 1622 return stb
1624 1623
1625 1624 if handler is None:
1626 1625 wrapped = dummy_handler
1627 1626 else:
1628 1627 def wrapped(self,etype,value,tb,tb_offset=None):
1629 1628 """wrap CustomTB handler, to protect IPython from user code
1630 1629
1631 1630 This makes it harder (but not impossible) for custom exception
1632 1631 handlers to crash IPython.
1633 1632 """
1634 1633 try:
1635 1634 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1636 1635 return validate_stb(stb)
1637 1636 except:
1638 1637 # clear custom handler immediately
1639 1638 self.set_custom_exc((), None)
1640 1639 print("Custom TB Handler failed, unregistering", file=io.stderr)
1641 1640 # show the exception in handler first
1642 1641 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1643 1642 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1644 1643 print("The original exception:", file=io.stdout)
1645 1644 stb = self.InteractiveTB.structured_traceback(
1646 1645 (etype,value,tb), tb_offset=tb_offset
1647 1646 )
1648 1647 return stb
1649 1648
1650 1649 self.CustomTB = types.MethodType(wrapped,self)
1651 1650 self.custom_exceptions = exc_tuple
1652 1651
1653 1652 def excepthook(self, etype, value, tb):
1654 1653 """One more defense for GUI apps that call sys.excepthook.
1655 1654
1656 1655 GUI frameworks like wxPython trap exceptions and call
1657 1656 sys.excepthook themselves. I guess this is a feature that
1658 1657 enables them to keep running after exceptions that would
1659 1658 otherwise kill their mainloop. This is a bother for IPython
1660 1659 which excepts to catch all of the program exceptions with a try:
1661 1660 except: statement.
1662 1661
1663 1662 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1664 1663 any app directly invokes sys.excepthook, it will look to the user like
1665 1664 IPython crashed. In order to work around this, we can disable the
1666 1665 CrashHandler and replace it with this excepthook instead, which prints a
1667 1666 regular traceback using our InteractiveTB. In this fashion, apps which
1668 1667 call sys.excepthook will generate a regular-looking exception from
1669 1668 IPython, and the CrashHandler will only be triggered by real IPython
1670 1669 crashes.
1671 1670
1672 1671 This hook should be used sparingly, only in places which are not likely
1673 1672 to be true IPython errors.
1674 1673 """
1675 1674 self.showtraceback((etype,value,tb),tb_offset=0)
1676 1675
1677 1676 def _get_exc_info(self, exc_tuple=None):
1678 1677 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1679 1678
1680 1679 Ensures sys.last_type,value,traceback hold the exc_info we found,
1681 1680 from whichever source.
1682 1681
1683 1682 raises ValueError if none of these contain any information
1684 1683 """
1685 1684 if exc_tuple is None:
1686 1685 etype, value, tb = sys.exc_info()
1687 1686 else:
1688 1687 etype, value, tb = exc_tuple
1689 1688
1690 1689 if etype is None:
1691 1690 if hasattr(sys, 'last_type'):
1692 1691 etype, value, tb = sys.last_type, sys.last_value, \
1693 1692 sys.last_traceback
1694 1693
1695 1694 if etype is None:
1696 1695 raise ValueError("No exception to find")
1697 1696
1698 1697 # Now store the exception info in sys.last_type etc.
1699 1698 # WARNING: these variables are somewhat deprecated and not
1700 1699 # necessarily safe to use in a threaded environment, but tools
1701 1700 # like pdb depend on their existence, so let's set them. If we
1702 1701 # find problems in the field, we'll need to revisit their use.
1703 1702 sys.last_type = etype
1704 1703 sys.last_value = value
1705 1704 sys.last_traceback = tb
1706 1705
1707 1706 return etype, value, tb
1708 1707
1709 1708 def show_usage_error(self, exc):
1710 1709 """Show a short message for UsageErrors
1711 1710
1712 1711 These are special exceptions that shouldn't show a traceback.
1713 1712 """
1714 1713 self.write_err("UsageError: %s" % exc)
1715 1714
1716 1715 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1717 1716 exception_only=False):
1718 1717 """Display the exception that just occurred.
1719 1718
1720 1719 If nothing is known about the exception, this is the method which
1721 1720 should be used throughout the code for presenting user tracebacks,
1722 1721 rather than directly invoking the InteractiveTB object.
1723 1722
1724 1723 A specific showsyntaxerror() also exists, but this method can take
1725 1724 care of calling it if needed, so unless you are explicitly catching a
1726 1725 SyntaxError exception, don't try to analyze the stack manually and
1727 1726 simply call this method."""
1728 1727
1729 1728 try:
1730 1729 try:
1731 1730 etype, value, tb = self._get_exc_info(exc_tuple)
1732 1731 except ValueError:
1733 1732 self.write_err('No traceback available to show.\n')
1734 1733 return
1735 1734
1736 1735 if issubclass(etype, SyntaxError):
1737 1736 # Though this won't be called by syntax errors in the input
1738 1737 # line, there may be SyntaxError cases with imported code.
1739 1738 self.showsyntaxerror(filename)
1740 1739 elif etype is UsageError:
1741 1740 self.show_usage_error(value)
1742 1741 else:
1743 1742 if exception_only:
1744 1743 stb = ['An exception has occurred, use %tb to see '
1745 1744 'the full traceback.\n']
1746 1745 stb.extend(self.InteractiveTB.get_exception_only(etype,
1747 1746 value))
1748 1747 else:
1749 1748 try:
1750 1749 # Exception classes can customise their traceback - we
1751 1750 # use this in IPython.parallel for exceptions occurring
1752 1751 # in the engines. This should return a list of strings.
1753 1752 stb = value._render_traceback_()
1754 1753 except Exception:
1755 1754 stb = self.InteractiveTB.structured_traceback(etype,
1756 1755 value, tb, tb_offset=tb_offset)
1757 1756
1758 1757 self._showtraceback(etype, value, stb)
1759 1758 if self.call_pdb:
1760 1759 # drop into debugger
1761 1760 self.debugger(force=True)
1762 1761 return
1763 1762
1764 1763 # Actually show the traceback
1765 1764 self._showtraceback(etype, value, stb)
1766 1765
1767 1766 except KeyboardInterrupt:
1768 1767 self.write_err("\nKeyboardInterrupt\n")
1769 1768
1770 1769 def _showtraceback(self, etype, evalue, stb):
1771 1770 """Actually show a traceback.
1772 1771
1773 1772 Subclasses may override this method to put the traceback on a different
1774 1773 place, like a side channel.
1775 1774 """
1776 1775 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1777 1776
1778 1777 def showsyntaxerror(self, filename=None):
1779 1778 """Display the syntax error that just occurred.
1780 1779
1781 1780 This doesn't display a stack trace because there isn't one.
1782 1781
1783 1782 If a filename is given, it is stuffed in the exception instead
1784 1783 of what was there before (because Python's parser always uses
1785 1784 "<string>" when reading from a string).
1786 1785 """
1787 1786 etype, value, last_traceback = self._get_exc_info()
1788 1787
1789 1788 if filename and issubclass(etype, SyntaxError):
1790 1789 try:
1791 1790 value.filename = filename
1792 1791 except:
1793 1792 # Not the format we expect; leave it alone
1794 1793 pass
1795 1794
1796 1795 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1797 1796 self._showtraceback(etype, value, stb)
1798 1797
1799 1798 # This is overridden in TerminalInteractiveShell to show a message about
1800 1799 # the %paste magic.
1801 1800 def showindentationerror(self):
1802 1801 """Called by run_cell when there's an IndentationError in code entered
1803 1802 at the prompt.
1804 1803
1805 1804 This is overridden in TerminalInteractiveShell to show a message about
1806 1805 the %paste magic."""
1807 1806 self.showsyntaxerror()
1808 1807
1809 1808 #-------------------------------------------------------------------------
1810 1809 # Things related to readline
1811 1810 #-------------------------------------------------------------------------
1812 1811
1813 1812 def init_readline(self):
1814 1813 """Command history completion/saving/reloading."""
1815 1814
1816 1815 if self.readline_use:
1817 1816 import IPython.utils.rlineimpl as readline
1818 1817
1819 1818 self.rl_next_input = None
1820 1819 self.rl_do_indent = False
1821 1820
1822 1821 if not self.readline_use or not readline.have_readline:
1823 1822 self.has_readline = False
1824 1823 self.readline = None
1825 1824 # Set a number of methods that depend on readline to be no-op
1826 1825 self.readline_no_record = no_op_context
1827 1826 self.set_readline_completer = no_op
1828 1827 self.set_custom_completer = no_op
1829 1828 if self.readline_use:
1830 1829 warn('Readline services not available or not loaded.')
1831 1830 else:
1832 1831 self.has_readline = True
1833 1832 self.readline = readline
1834 1833 sys.modules['readline'] = readline
1835 1834
1836 1835 # Platform-specific configuration
1837 1836 if os.name == 'nt':
1838 1837 # FIXME - check with Frederick to see if we can harmonize
1839 1838 # naming conventions with pyreadline to avoid this
1840 1839 # platform-dependent check
1841 1840 self.readline_startup_hook = readline.set_pre_input_hook
1842 1841 else:
1843 1842 self.readline_startup_hook = readline.set_startup_hook
1844 1843
1845 1844 # Load user's initrc file (readline config)
1846 1845 # Or if libedit is used, load editrc.
1847 1846 inputrc_name = os.environ.get('INPUTRC')
1848 1847 if inputrc_name is None:
1849 1848 inputrc_name = '.inputrc'
1850 1849 if readline.uses_libedit:
1851 1850 inputrc_name = '.editrc'
1852 1851 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1853 1852 if os.path.isfile(inputrc_name):
1854 1853 try:
1855 1854 readline.read_init_file(inputrc_name)
1856 1855 except:
1857 1856 warn('Problems reading readline initialization file <%s>'
1858 1857 % inputrc_name)
1859 1858
1860 1859 # Configure readline according to user's prefs
1861 1860 # This is only done if GNU readline is being used. If libedit
1862 1861 # is being used (as on Leopard) the readline config is
1863 1862 # not run as the syntax for libedit is different.
1864 1863 if not readline.uses_libedit:
1865 1864 for rlcommand in self.readline_parse_and_bind:
1866 1865 #print "loading rl:",rlcommand # dbg
1867 1866 readline.parse_and_bind(rlcommand)
1868 1867
1869 1868 # Remove some chars from the delimiters list. If we encounter
1870 1869 # unicode chars, discard them.
1871 1870 delims = readline.get_completer_delims()
1872 1871 if not py3compat.PY3:
1873 1872 delims = delims.encode("ascii", "ignore")
1874 1873 for d in self.readline_remove_delims:
1875 1874 delims = delims.replace(d, "")
1876 1875 delims = delims.replace(ESC_MAGIC, '')
1877 1876 readline.set_completer_delims(delims)
1878 1877 # Store these so we can restore them if something like rpy2 modifies
1879 1878 # them.
1880 1879 self.readline_delims = delims
1881 1880 # otherwise we end up with a monster history after a while:
1882 1881 readline.set_history_length(self.history_length)
1883 1882
1884 1883 self.refill_readline_hist()
1885 1884 self.readline_no_record = ReadlineNoRecord(self)
1886 1885
1887 1886 # Configure auto-indent for all platforms
1888 1887 self.set_autoindent(self.autoindent)
1889 1888
1890 1889 def refill_readline_hist(self):
1891 1890 # Load the last 1000 lines from history
1892 1891 self.readline.clear_history()
1893 1892 stdin_encoding = sys.stdin.encoding or "utf-8"
1894 1893 last_cell = u""
1895 1894 for _, _, cell in self.history_manager.get_tail(1000,
1896 1895 include_latest=True):
1897 1896 # Ignore blank lines and consecutive duplicates
1898 1897 cell = cell.rstrip()
1899 1898 if cell and (cell != last_cell):
1900 1899 try:
1901 1900 if self.multiline_history:
1902 1901 self.readline.add_history(py3compat.unicode_to_str(cell,
1903 1902 stdin_encoding))
1904 1903 else:
1905 1904 for line in cell.splitlines():
1906 1905 self.readline.add_history(py3compat.unicode_to_str(line,
1907 1906 stdin_encoding))
1908 1907 last_cell = cell
1909 1908
1910 1909 except TypeError:
1911 1910 # The history DB can get corrupted so it returns strings
1912 1911 # containing null bytes, which readline objects to.
1913 1912 continue
1914 1913
1915 1914 @skip_doctest
1916 1915 def set_next_input(self, s):
1917 1916 """ Sets the 'default' input string for the next command line.
1918 1917
1919 1918 Requires readline.
1920 1919
1921 1920 Example::
1922 1921
1923 1922 In [1]: _ip.set_next_input("Hello Word")
1924 1923 In [2]: Hello Word_ # cursor is here
1925 1924 """
1926 1925 self.rl_next_input = py3compat.cast_bytes_py2(s)
1927 1926
1928 1927 # Maybe move this to the terminal subclass?
1929 1928 def pre_readline(self):
1930 1929 """readline hook to be used at the start of each line.
1931 1930
1932 1931 Currently it handles auto-indent only."""
1933 1932
1934 1933 if self.rl_do_indent:
1935 1934 self.readline.insert_text(self._indent_current_str())
1936 1935 if self.rl_next_input is not None:
1937 1936 self.readline.insert_text(self.rl_next_input)
1938 1937 self.rl_next_input = None
1939 1938
1940 1939 def _indent_current_str(self):
1941 1940 """return the current level of indentation as a string"""
1942 1941 return self.input_splitter.indent_spaces * ' '
1943 1942
1944 1943 #-------------------------------------------------------------------------
1945 1944 # Things related to text completion
1946 1945 #-------------------------------------------------------------------------
1947 1946
1948 1947 def init_completer(self):
1949 1948 """Initialize the completion machinery.
1950 1949
1951 1950 This creates completion machinery that can be used by client code,
1952 1951 either interactively in-process (typically triggered by the readline
1953 1952 library), programatically (such as in test suites) or out-of-prcess
1954 1953 (typically over the network by remote frontends).
1955 1954 """
1956 1955 from IPython.core.completer import IPCompleter
1957 1956 from IPython.core.completerlib import (module_completer,
1958 1957 magic_run_completer, cd_completer, reset_completer)
1959 1958
1960 1959 self.Completer = IPCompleter(shell=self,
1961 1960 namespace=self.user_ns,
1962 1961 global_namespace=self.user_global_ns,
1963 1962 use_readline=self.has_readline,
1964 1963 parent=self,
1965 1964 )
1966 1965 self.configurables.append(self.Completer)
1967 1966
1968 1967 # Add custom completers to the basic ones built into IPCompleter
1969 1968 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1970 1969 self.strdispatchers['complete_command'] = sdisp
1971 1970 self.Completer.custom_completers = sdisp
1972 1971
1973 1972 self.set_hook('complete_command', module_completer, str_key = 'import')
1974 1973 self.set_hook('complete_command', module_completer, str_key = 'from')
1975 1974 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
1976 1975 self.set_hook('complete_command', cd_completer, str_key = '%cd')
1977 1976 self.set_hook('complete_command', reset_completer, str_key = '%reset')
1978 1977
1979 1978 # Only configure readline if we truly are using readline. IPython can
1980 1979 # do tab-completion over the network, in GUIs, etc, where readline
1981 1980 # itself may be absent
1982 1981 if self.has_readline:
1983 1982 self.set_readline_completer()
1984 1983
1985 1984 def complete(self, text, line=None, cursor_pos=None):
1986 1985 """Return the completed text and a list of completions.
1987 1986
1988 1987 Parameters
1989 1988 ----------
1990 1989
1991 1990 text : string
1992 1991 A string of text to be completed on. It can be given as empty and
1993 1992 instead a line/position pair are given. In this case, the
1994 1993 completer itself will split the line like readline does.
1995 1994
1996 1995 line : string, optional
1997 1996 The complete line that text is part of.
1998 1997
1999 1998 cursor_pos : int, optional
2000 1999 The position of the cursor on the input line.
2001 2000
2002 2001 Returns
2003 2002 -------
2004 2003 text : string
2005 2004 The actual text that was completed.
2006 2005
2007 2006 matches : list
2008 2007 A sorted list with all possible completions.
2009 2008
2010 2009 The optional arguments allow the completion to take more context into
2011 2010 account, and are part of the low-level completion API.
2012 2011
2013 2012 This is a wrapper around the completion mechanism, similar to what
2014 2013 readline does at the command line when the TAB key is hit. By
2015 2014 exposing it as a method, it can be used by other non-readline
2016 2015 environments (such as GUIs) for text completion.
2017 2016
2018 2017 Simple usage example:
2019 2018
2020 2019 In [1]: x = 'hello'
2021 2020
2022 2021 In [2]: _ip.complete('x.l')
2023 2022 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2024 2023 """
2025 2024
2026 2025 # Inject names into __builtin__ so we can complete on the added names.
2027 2026 with self.builtin_trap:
2028 2027 return self.Completer.complete(text, line, cursor_pos)
2029 2028
2030 2029 def set_custom_completer(self, completer, pos=0):
2031 2030 """Adds a new custom completer function.
2032 2031
2033 2032 The position argument (defaults to 0) is the index in the completers
2034 2033 list where you want the completer to be inserted."""
2035 2034
2036 2035 newcomp = types.MethodType(completer,self.Completer)
2037 2036 self.Completer.matchers.insert(pos,newcomp)
2038 2037
2039 2038 def set_readline_completer(self):
2040 2039 """Reset readline's completer to be our own."""
2041 2040 self.readline.set_completer(self.Completer.rlcomplete)
2042 2041
2043 2042 def set_completer_frame(self, frame=None):
2044 2043 """Set the frame of the completer."""
2045 2044 if frame:
2046 2045 self.Completer.namespace = frame.f_locals
2047 2046 self.Completer.global_namespace = frame.f_globals
2048 2047 else:
2049 2048 self.Completer.namespace = self.user_ns
2050 2049 self.Completer.global_namespace = self.user_global_ns
2051 2050
2052 2051 #-------------------------------------------------------------------------
2053 2052 # Things related to magics
2054 2053 #-------------------------------------------------------------------------
2055 2054
2056 2055 def init_magics(self):
2057 2056 from IPython.core import magics as m
2058 2057 self.magics_manager = magic.MagicsManager(shell=self,
2059 2058 parent=self,
2060 2059 user_magics=m.UserMagics(self))
2061 2060 self.configurables.append(self.magics_manager)
2062 2061
2063 2062 # Expose as public API from the magics manager
2064 2063 self.register_magics = self.magics_manager.register
2065 2064 self.define_magic = self.magics_manager.define_magic
2066 2065
2067 2066 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2068 2067 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2069 2068 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2070 2069 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2071 2070 )
2072 2071
2073 2072 # Register Magic Aliases
2074 2073 mman = self.magics_manager
2075 2074 # FIXME: magic aliases should be defined by the Magics classes
2076 2075 # or in MagicsManager, not here
2077 2076 mman.register_alias('ed', 'edit')
2078 2077 mman.register_alias('hist', 'history')
2079 2078 mman.register_alias('rep', 'recall')
2080 2079 mman.register_alias('SVG', 'svg', 'cell')
2081 2080 mman.register_alias('HTML', 'html', 'cell')
2082 2081 mman.register_alias('file', 'writefile', 'cell')
2083 2082
2084 2083 # FIXME: Move the color initialization to the DisplayHook, which
2085 2084 # should be split into a prompt manager and displayhook. We probably
2086 2085 # even need a centralize colors management object.
2087 2086 self.magic('colors %s' % self.colors)
2088 2087
2089 2088 # Defined here so that it's included in the documentation
2090 2089 @functools.wraps(magic.MagicsManager.register_function)
2091 2090 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2092 2091 self.magics_manager.register_function(func,
2093 2092 magic_kind=magic_kind, magic_name=magic_name)
2094 2093
2095 2094 def run_line_magic(self, magic_name, line):
2096 2095 """Execute the given line magic.
2097 2096
2098 2097 Parameters
2099 2098 ----------
2100 2099 magic_name : str
2101 2100 Name of the desired magic function, without '%' prefix.
2102 2101
2103 2102 line : str
2104 2103 The rest of the input line as a single string.
2105 2104 """
2106 2105 fn = self.find_line_magic(magic_name)
2107 2106 if fn is None:
2108 2107 cm = self.find_cell_magic(magic_name)
2109 2108 etpl = "Line magic function `%%%s` not found%s."
2110 2109 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2111 2110 'did you mean that instead?)' % magic_name )
2112 2111 error(etpl % (magic_name, extra))
2113 2112 else:
2114 2113 # Note: this is the distance in the stack to the user's frame.
2115 2114 # This will need to be updated if the internal calling logic gets
2116 2115 # refactored, or else we'll be expanding the wrong variables.
2117 2116 stack_depth = 2
2118 2117 magic_arg_s = self.var_expand(line, stack_depth)
2119 2118 # Put magic args in a list so we can call with f(*a) syntax
2120 2119 args = [magic_arg_s]
2121 2120 kwargs = {}
2122 2121 # Grab local namespace if we need it:
2123 2122 if getattr(fn, "needs_local_scope", False):
2124 2123 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2125 2124 with self.builtin_trap:
2126 2125 result = fn(*args,**kwargs)
2127 2126 return result
2128 2127
2129 2128 def run_cell_magic(self, magic_name, line, cell):
2130 2129 """Execute the given cell magic.
2131 2130
2132 2131 Parameters
2133 2132 ----------
2134 2133 magic_name : str
2135 2134 Name of the desired magic function, without '%' prefix.
2136 2135
2137 2136 line : str
2138 2137 The rest of the first input line as a single string.
2139 2138
2140 2139 cell : str
2141 2140 The body of the cell as a (possibly multiline) string.
2142 2141 """
2143 2142 fn = self.find_cell_magic(magic_name)
2144 2143 if fn is None:
2145 2144 lm = self.find_line_magic(magic_name)
2146 2145 etpl = "Cell magic `%%{0}` not found{1}."
2147 2146 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2148 2147 'did you mean that instead?)'.format(magic_name))
2149 2148 error(etpl.format(magic_name, extra))
2150 2149 elif cell == '':
2151 2150 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2152 2151 if self.find_line_magic(magic_name) is not None:
2153 2152 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2154 2153 raise UsageError(message)
2155 2154 else:
2156 2155 # Note: this is the distance in the stack to the user's frame.
2157 2156 # This will need to be updated if the internal calling logic gets
2158 2157 # refactored, or else we'll be expanding the wrong variables.
2159 2158 stack_depth = 2
2160 2159 magic_arg_s = self.var_expand(line, stack_depth)
2161 2160 with self.builtin_trap:
2162 2161 result = fn(magic_arg_s, cell)
2163 2162 return result
2164 2163
2165 2164 def find_line_magic(self, magic_name):
2166 2165 """Find and return a line magic by name.
2167 2166
2168 2167 Returns None if the magic isn't found."""
2169 2168 return self.magics_manager.magics['line'].get(magic_name)
2170 2169
2171 2170 def find_cell_magic(self, magic_name):
2172 2171 """Find and return a cell magic by name.
2173 2172
2174 2173 Returns None if the magic isn't found."""
2175 2174 return self.magics_manager.magics['cell'].get(magic_name)
2176 2175
2177 2176 def find_magic(self, magic_name, magic_kind='line'):
2178 2177 """Find and return a magic of the given type by name.
2179 2178
2180 2179 Returns None if the magic isn't found."""
2181 2180 return self.magics_manager.magics[magic_kind].get(magic_name)
2182 2181
2183 2182 def magic(self, arg_s):
2184 2183 """DEPRECATED. Use run_line_magic() instead.
2185 2184
2186 2185 Call a magic function by name.
2187 2186
2188 2187 Input: a string containing the name of the magic function to call and
2189 2188 any additional arguments to be passed to the magic.
2190 2189
2191 2190 magic('name -opt foo bar') is equivalent to typing at the ipython
2192 2191 prompt:
2193 2192
2194 2193 In[1]: %name -opt foo bar
2195 2194
2196 2195 To call a magic without arguments, simply use magic('name').
2197 2196
2198 2197 This provides a proper Python function to call IPython's magics in any
2199 2198 valid Python code you can type at the interpreter, including loops and
2200 2199 compound statements.
2201 2200 """
2202 2201 # TODO: should we issue a loud deprecation warning here?
2203 2202 magic_name, _, magic_arg_s = arg_s.partition(' ')
2204 2203 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2205 2204 return self.run_line_magic(magic_name, magic_arg_s)
2206 2205
2207 2206 #-------------------------------------------------------------------------
2208 2207 # Things related to macros
2209 2208 #-------------------------------------------------------------------------
2210 2209
2211 2210 def define_macro(self, name, themacro):
2212 2211 """Define a new macro
2213 2212
2214 2213 Parameters
2215 2214 ----------
2216 2215 name : str
2217 2216 The name of the macro.
2218 2217 themacro : str or Macro
2219 2218 The action to do upon invoking the macro. If a string, a new
2220 2219 Macro object is created by passing the string to it.
2221 2220 """
2222 2221
2223 2222 from IPython.core import macro
2224 2223
2225 2224 if isinstance(themacro, string_types):
2226 2225 themacro = macro.Macro(themacro)
2227 2226 if not isinstance(themacro, macro.Macro):
2228 2227 raise ValueError('A macro must be a string or a Macro instance.')
2229 2228 self.user_ns[name] = themacro
2230 2229
2231 2230 #-------------------------------------------------------------------------
2232 2231 # Things related to the running of system commands
2233 2232 #-------------------------------------------------------------------------
2234 2233
2235 2234 def system_piped(self, cmd):
2236 2235 """Call the given cmd in a subprocess, piping stdout/err
2237 2236
2238 2237 Parameters
2239 2238 ----------
2240 2239 cmd : str
2241 2240 Command to execute (can not end in '&', as background processes are
2242 2241 not supported. Should not be a command that expects input
2243 2242 other than simple text.
2244 2243 """
2245 2244 if cmd.rstrip().endswith('&'):
2246 2245 # this is *far* from a rigorous test
2247 2246 # We do not support backgrounding processes because we either use
2248 2247 # pexpect or pipes to read from. Users can always just call
2249 2248 # os.system() or use ip.system=ip.system_raw
2250 2249 # if they really want a background process.
2251 2250 raise OSError("Background processes not supported.")
2252 2251
2253 2252 # we explicitly do NOT return the subprocess status code, because
2254 2253 # a non-None value would trigger :func:`sys.displayhook` calls.
2255 2254 # Instead, we store the exit_code in user_ns.
2256 2255 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2257 2256
2258 2257 def system_raw(self, cmd):
2259 2258 """Call the given cmd in a subprocess using os.system on Windows or
2260 2259 subprocess.call using the system shell on other platforms.
2261 2260
2262 2261 Parameters
2263 2262 ----------
2264 2263 cmd : str
2265 2264 Command to execute.
2266 2265 """
2267 2266 cmd = self.var_expand(cmd, depth=1)
2268 2267 # protect os.system from UNC paths on Windows, which it can't handle:
2269 2268 if sys.platform == 'win32':
2270 2269 from IPython.utils._process_win32 import AvoidUNCPath
2271 2270 with AvoidUNCPath() as path:
2272 2271 if path is not None:
2273 2272 cmd = '"pushd %s &&"%s' % (path, cmd)
2274 2273 cmd = py3compat.unicode_to_str(cmd)
2275 2274 ec = os.system(cmd)
2276 2275 else:
2277 2276 cmd = py3compat.unicode_to_str(cmd)
2278 2277 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2279 2278 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2280 2279 # exit code is positive for program failure, or negative for
2281 2280 # terminating signal number.
2282 2281
2283 2282 # We explicitly do NOT return the subprocess status code, because
2284 2283 # a non-None value would trigger :func:`sys.displayhook` calls.
2285 2284 # Instead, we store the exit_code in user_ns.
2286 2285 self.user_ns['_exit_code'] = ec
2287 2286
2288 2287 # use piped system by default, because it is better behaved
2289 2288 system = system_piped
2290 2289
2291 2290 def getoutput(self, cmd, split=True, depth=0):
2292 2291 """Get output (possibly including stderr) from a subprocess.
2293 2292
2294 2293 Parameters
2295 2294 ----------
2296 2295 cmd : str
2297 2296 Command to execute (can not end in '&', as background processes are
2298 2297 not supported.
2299 2298 split : bool, optional
2300 2299 If True, split the output into an IPython SList. Otherwise, an
2301 2300 IPython LSString is returned. These are objects similar to normal
2302 2301 lists and strings, with a few convenience attributes for easier
2303 2302 manipulation of line-based output. You can use '?' on them for
2304 2303 details.
2305 2304 depth : int, optional
2306 2305 How many frames above the caller are the local variables which should
2307 2306 be expanded in the command string? The default (0) assumes that the
2308 2307 expansion variables are in the stack frame calling this function.
2309 2308 """
2310 2309 if cmd.rstrip().endswith('&'):
2311 2310 # this is *far* from a rigorous test
2312 2311 raise OSError("Background processes not supported.")
2313 2312 out = getoutput(self.var_expand(cmd, depth=depth+1))
2314 2313 if split:
2315 2314 out = SList(out.splitlines())
2316 2315 else:
2317 2316 out = LSString(out)
2318 2317 return out
2319 2318
2320 2319 #-------------------------------------------------------------------------
2321 2320 # Things related to aliases
2322 2321 #-------------------------------------------------------------------------
2323 2322
2324 2323 def init_alias(self):
2325 2324 self.alias_manager = AliasManager(shell=self, parent=self)
2326 2325 self.configurables.append(self.alias_manager)
2327 2326
2328 2327 #-------------------------------------------------------------------------
2329 2328 # Things related to extensions
2330 2329 #-------------------------------------------------------------------------
2331 2330
2332 2331 def init_extension_manager(self):
2333 2332 self.extension_manager = ExtensionManager(shell=self, parent=self)
2334 2333 self.configurables.append(self.extension_manager)
2335 2334
2336 2335 #-------------------------------------------------------------------------
2337 2336 # Things related to payloads
2338 2337 #-------------------------------------------------------------------------
2339 2338
2340 2339 def init_payload(self):
2341 2340 self.payload_manager = PayloadManager(parent=self)
2342 2341 self.configurables.append(self.payload_manager)
2343 2342
2344 2343 #-------------------------------------------------------------------------
2345 2344 # Things related to widgets
2346 2345 #-------------------------------------------------------------------------
2347 2346
2348 2347 def init_comms(self):
2349 2348 # not implemented in the base class
2350 2349 pass
2351 2350
2352 2351 #-------------------------------------------------------------------------
2353 2352 # Things related to the prefilter
2354 2353 #-------------------------------------------------------------------------
2355 2354
2356 2355 def init_prefilter(self):
2357 2356 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2358 2357 self.configurables.append(self.prefilter_manager)
2359 2358 # Ultimately this will be refactored in the new interpreter code, but
2360 2359 # for now, we should expose the main prefilter method (there's legacy
2361 2360 # code out there that may rely on this).
2362 2361 self.prefilter = self.prefilter_manager.prefilter_lines
2363 2362
2364 2363 def auto_rewrite_input(self, cmd):
2365 2364 """Print to the screen the rewritten form of the user's command.
2366 2365
2367 2366 This shows visual feedback by rewriting input lines that cause
2368 2367 automatic calling to kick in, like::
2369 2368
2370 2369 /f x
2371 2370
2372 2371 into::
2373 2372
2374 2373 ------> f(x)
2375 2374
2376 2375 after the user's input prompt. This helps the user understand that the
2377 2376 input line was transformed automatically by IPython.
2378 2377 """
2379 2378 if not self.show_rewritten_input:
2380 2379 return
2381 2380
2382 2381 rw = self.prompt_manager.render('rewrite') + cmd
2383 2382
2384 2383 try:
2385 2384 # plain ascii works better w/ pyreadline, on some machines, so
2386 2385 # we use it and only print uncolored rewrite if we have unicode
2387 2386 rw = str(rw)
2388 2387 print(rw, file=io.stdout)
2389 2388 except UnicodeEncodeError:
2390 2389 print("------> " + cmd)
2391 2390
2392 2391 #-------------------------------------------------------------------------
2393 2392 # Things related to extracting values/expressions from kernel and user_ns
2394 2393 #-------------------------------------------------------------------------
2395 2394
2396 2395 def _user_obj_error(self):
2397 2396 """return simple exception dict
2398 2397
2399 2398 for use in user_variables / expressions
2400 2399 """
2401 2400
2402 2401 etype, evalue, tb = self._get_exc_info()
2403 2402 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2404 2403
2405 2404 exc_info = {
2406 2405 u'status' : 'error',
2407 2406 u'traceback' : stb,
2408 2407 u'ename' : unicode_type(etype.__name__),
2409 2408 u'evalue' : py3compat.safe_unicode(evalue),
2410 2409 }
2411 2410
2412 2411 return exc_info
2413 2412
2414 2413 def _format_user_obj(self, obj):
2415 2414 """format a user object to display dict
2416 2415
2417 2416 for use in user_expressions / variables
2418 2417 """
2419 2418
2420 2419 data, md = self.display_formatter.format(obj)
2421 2420 value = {
2422 2421 'status' : 'ok',
2423 2422 'data' : data,
2424 2423 'metadata' : md,
2425 2424 }
2426 2425 return value
2427 2426
2428 2427 def user_variables(self, names):
2429 2428 """Get a list of variable names from the user's namespace.
2430 2429
2431 2430 Parameters
2432 2431 ----------
2433 2432 names : list of strings
2434 2433 A list of names of variables to be read from the user namespace.
2435 2434
2436 2435 Returns
2437 2436 -------
2438 2437 A dict, keyed by the input names and with the rich mime-type repr(s) of each value.
2439 2438 Each element will be a sub-dict of the same form as a display_data message.
2440 2439 """
2441 2440 out = {}
2442 2441 user_ns = self.user_ns
2443 2442
2444 2443 for varname in names:
2445 2444 try:
2446 2445 value = self._format_user_obj(user_ns[varname])
2447 2446 except:
2448 2447 value = self._user_obj_error()
2449 2448 out[varname] = value
2450 2449 return out
2451 2450
2452 2451 def user_expressions(self, expressions):
2453 2452 """Evaluate a dict of expressions in the user's namespace.
2454 2453
2455 2454 Parameters
2456 2455 ----------
2457 2456 expressions : dict
2458 2457 A dict with string keys and string values. The expression values
2459 2458 should be valid Python expressions, each of which will be evaluated
2460 2459 in the user namespace.
2461 2460
2462 2461 Returns
2463 2462 -------
2464 2463 A dict, keyed like the input expressions dict, with the rich mime-typed
2465 2464 display_data of each value.
2466 2465 """
2467 2466 out = {}
2468 2467 user_ns = self.user_ns
2469 2468 global_ns = self.user_global_ns
2470 2469
2471 2470 for key, expr in iteritems(expressions):
2472 2471 try:
2473 2472 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2474 2473 except:
2475 2474 value = self._user_obj_error()
2476 2475 out[key] = value
2477 2476 return out
2478 2477
2479 2478 #-------------------------------------------------------------------------
2480 2479 # Things related to the running of code
2481 2480 #-------------------------------------------------------------------------
2482 2481
2483 2482 def ex(self, cmd):
2484 2483 """Execute a normal python statement in user namespace."""
2485 2484 with self.builtin_trap:
2486 2485 exec(cmd, self.user_global_ns, self.user_ns)
2487 2486
2488 2487 def ev(self, expr):
2489 2488 """Evaluate python expression expr in user namespace.
2490 2489
2491 2490 Returns the result of evaluation
2492 2491 """
2493 2492 with self.builtin_trap:
2494 2493 return eval(expr, self.user_global_ns, self.user_ns)
2495 2494
2496 2495 def safe_execfile(self, fname, *where, **kw):
2497 2496 """A safe version of the builtin execfile().
2498 2497
2499 2498 This version will never throw an exception, but instead print
2500 2499 helpful error messages to the screen. This only works on pure
2501 2500 Python files with the .py extension.
2502 2501
2503 2502 Parameters
2504 2503 ----------
2505 2504 fname : string
2506 2505 The name of the file to be executed.
2507 2506 where : tuple
2508 2507 One or two namespaces, passed to execfile() as (globals,locals).
2509 2508 If only one is given, it is passed as both.
2510 2509 exit_ignore : bool (False)
2511 2510 If True, then silence SystemExit for non-zero status (it is always
2512 2511 silenced for zero status, as it is so common).
2513 2512 raise_exceptions : bool (False)
2514 2513 If True raise exceptions everywhere. Meant for testing.
2515 2514
2516 2515 """
2517 2516 kw.setdefault('exit_ignore', False)
2518 2517 kw.setdefault('raise_exceptions', False)
2519 2518
2520 2519 fname = os.path.abspath(os.path.expanduser(fname))
2521 2520
2522 2521 # Make sure we can open the file
2523 2522 try:
2524 2523 with open(fname) as thefile:
2525 2524 pass
2526 2525 except:
2527 2526 warn('Could not open file <%s> for safe execution.' % fname)
2528 2527 return
2529 2528
2530 2529 # Find things also in current directory. This is needed to mimic the
2531 2530 # behavior of running a script from the system command line, where
2532 2531 # Python inserts the script's directory into sys.path
2533 2532 dname = os.path.dirname(fname)
2534 2533
2535 2534 with prepended_to_syspath(dname):
2536 2535 try:
2537 2536 py3compat.execfile(fname,*where)
2538 2537 except SystemExit as status:
2539 2538 # If the call was made with 0 or None exit status (sys.exit(0)
2540 2539 # or sys.exit() ), don't bother showing a traceback, as both of
2541 2540 # these are considered normal by the OS:
2542 2541 # > python -c'import sys;sys.exit(0)'; echo $?
2543 2542 # 0
2544 2543 # > python -c'import sys;sys.exit()'; echo $?
2545 2544 # 0
2546 2545 # For other exit status, we show the exception unless
2547 2546 # explicitly silenced, but only in short form.
2548 2547 if kw['raise_exceptions']:
2549 2548 raise
2550 2549 if status.code and not kw['exit_ignore']:
2551 2550 self.showtraceback(exception_only=True)
2552 2551 except:
2553 2552 if kw['raise_exceptions']:
2554 2553 raise
2555 2554 # tb offset is 2 because we wrap execfile
2556 2555 self.showtraceback(tb_offset=2)
2557 2556
2558 2557 def safe_execfile_ipy(self, fname):
2559 2558 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2560 2559
2561 2560 Parameters
2562 2561 ----------
2563 2562 fname : str
2564 2563 The name of the file to execute. The filename must have a
2565 2564 .ipy or .ipynb extension.
2566 2565 """
2567 2566 fname = os.path.abspath(os.path.expanduser(fname))
2568 2567
2569 2568 # Make sure we can open the file
2570 2569 try:
2571 2570 with open(fname) as thefile:
2572 2571 pass
2573 2572 except:
2574 2573 warn('Could not open file <%s> for safe execution.' % fname)
2575 2574 return
2576 2575
2577 2576 # Find things also in current directory. This is needed to mimic the
2578 2577 # behavior of running a script from the system command line, where
2579 2578 # Python inserts the script's directory into sys.path
2580 2579 dname = os.path.dirname(fname)
2581 2580
2582 2581 def get_cells():
2583 2582 """generator for sequence of code blocks to run"""
2584 2583 if fname.endswith('.ipynb'):
2585 2584 from IPython.nbformat import current
2586 2585 with open(fname) as f:
2587 2586 nb = current.read(f, 'json')
2588 2587 if not nb.worksheets:
2589 2588 return
2590 2589 for cell in nb.worksheets[0].cells:
2591 2590 if cell.cell_type == 'code':
2592 2591 yield cell.input
2593 2592 else:
2594 2593 with open(fname) as f:
2595 2594 yield f.read()
2596 2595
2597 2596 with prepended_to_syspath(dname):
2598 2597 try:
2599 2598 for cell in get_cells():
2600 2599 # self.run_cell currently captures all exceptions
2601 2600 # raised in user code. It would be nice if there were
2602 2601 # versions of run_cell that did raise, so
2603 2602 # we could catch the errors.
2604 2603 self.run_cell(cell, store_history=False, shell_futures=False)
2605 2604 except:
2606 2605 self.showtraceback()
2607 2606 warn('Unknown failure executing file: <%s>' % fname)
2608 2607
2609 2608 def safe_run_module(self, mod_name, where):
2610 2609 """A safe version of runpy.run_module().
2611 2610
2612 2611 This version will never throw an exception, but instead print
2613 2612 helpful error messages to the screen.
2614 2613
2615 2614 `SystemExit` exceptions with status code 0 or None are ignored.
2616 2615
2617 2616 Parameters
2618 2617 ----------
2619 2618 mod_name : string
2620 2619 The name of the module to be executed.
2621 2620 where : dict
2622 2621 The globals namespace.
2623 2622 """
2624 2623 try:
2625 2624 try:
2626 2625 where.update(
2627 2626 runpy.run_module(str(mod_name), run_name="__main__",
2628 2627 alter_sys=True)
2629 2628 )
2630 2629 except SystemExit as status:
2631 2630 if status.code:
2632 2631 raise
2633 2632 except:
2634 2633 self.showtraceback()
2635 2634 warn('Unknown failure executing module: <%s>' % mod_name)
2636 2635
2637 2636 def _run_cached_cell_magic(self, magic_name, line):
2638 2637 """Special method to call a cell magic with the data stored in self.
2639 2638 """
2640 2639 cell = self._current_cell_magic_body
2641 2640 self._current_cell_magic_body = None
2642 2641 return self.run_cell_magic(magic_name, line, cell)
2643 2642
2644 2643 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2645 2644 """Run a complete IPython cell.
2646 2645
2647 2646 Parameters
2648 2647 ----------
2649 2648 raw_cell : str
2650 2649 The code (including IPython code such as %magic functions) to run.
2651 2650 store_history : bool
2652 2651 If True, the raw and translated cell will be stored in IPython's
2653 2652 history. For user code calling back into IPython's machinery, this
2654 2653 should be set to False.
2655 2654 silent : bool
2656 2655 If True, avoid side-effects, such as implicit displayhooks and
2657 2656 and logging. silent=True forces store_history=False.
2658 2657 shell_futures : bool
2659 2658 If True, the code will share future statements with the interactive
2660 2659 shell. It will both be affected by previous __future__ imports, and
2661 2660 any __future__ imports in the code will affect the shell. If False,
2662 2661 __future__ imports are not shared in either direction.
2663 2662 """
2664 2663 if (not raw_cell) or raw_cell.isspace():
2665 2664 return
2666 2665
2667 2666 if silent:
2668 2667 store_history = False
2669 2668
2670 2669 self.events.trigger('pre_execute')
2671 2670 if not silent:
2672 2671 self.events.trigger('pre_run_cell')
2673 2672
2674 2673 # If any of our input transformation (input_transformer_manager or
2675 2674 # prefilter_manager) raises an exception, we store it in this variable
2676 2675 # so that we can display the error after logging the input and storing
2677 2676 # it in the history.
2678 2677 preprocessing_exc_tuple = None
2679 2678 try:
2680 2679 # Static input transformations
2681 2680 cell = self.input_transformer_manager.transform_cell(raw_cell)
2682 2681 except SyntaxError:
2683 2682 preprocessing_exc_tuple = sys.exc_info()
2684 2683 cell = raw_cell # cell has to exist so it can be stored/logged
2685 2684 else:
2686 2685 if len(cell.splitlines()) == 1:
2687 2686 # Dynamic transformations - only applied for single line commands
2688 2687 with self.builtin_trap:
2689 2688 try:
2690 2689 # use prefilter_lines to handle trailing newlines
2691 2690 # restore trailing newline for ast.parse
2692 2691 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2693 2692 except Exception:
2694 2693 # don't allow prefilter errors to crash IPython
2695 2694 preprocessing_exc_tuple = sys.exc_info()
2696 2695
2697 2696 # Store raw and processed history
2698 2697 if store_history:
2699 2698 self.history_manager.store_inputs(self.execution_count,
2700 2699 cell, raw_cell)
2701 2700 if not silent:
2702 2701 self.logger.log(cell, raw_cell)
2703 2702
2704 2703 # Display the exception if input processing failed.
2705 2704 if preprocessing_exc_tuple is not None:
2706 2705 self.showtraceback(preprocessing_exc_tuple)
2707 2706 if store_history:
2708 2707 self.execution_count += 1
2709 2708 return
2710 2709
2711 2710 # Our own compiler remembers the __future__ environment. If we want to
2712 2711 # run code with a separate __future__ environment, use the default
2713 2712 # compiler
2714 2713 compiler = self.compile if shell_futures else CachingCompiler()
2715 2714
2716 2715 with self.builtin_trap:
2717 2716 cell_name = self.compile.cache(cell, self.execution_count)
2718 2717
2719 2718 with self.display_trap:
2720 2719 # Compile to bytecode
2721 2720 try:
2722 2721 code_ast = compiler.ast_parse(cell, filename=cell_name)
2723 2722 except IndentationError:
2724 2723 self.showindentationerror()
2725 2724 if store_history:
2726 2725 self.execution_count += 1
2727 2726 return None
2728 2727 except (OverflowError, SyntaxError, ValueError, TypeError,
2729 2728 MemoryError):
2730 2729 self.showsyntaxerror()
2731 2730 if store_history:
2732 2731 self.execution_count += 1
2733 2732 return None
2734 2733
2735 2734 # Apply AST transformations
2736 2735 code_ast = self.transform_ast(code_ast)
2737 2736
2738 2737 # Execute the user code
2739 2738 interactivity = "none" if silent else self.ast_node_interactivity
2740 2739 self.run_ast_nodes(code_ast.body, cell_name,
2741 2740 interactivity=interactivity, compiler=compiler)
2742 2741
2743 2742 self.events.trigger('post_execute')
2744 2743 if not silent:
2745 2744 self.events.trigger('post_run_cell')
2746 2745
2747 2746 if store_history:
2748 2747 # Write output to the database. Does nothing unless
2749 2748 # history output logging is enabled.
2750 2749 self.history_manager.store_output(self.execution_count)
2751 2750 # Each cell is a *single* input, regardless of how many lines it has
2752 2751 self.execution_count += 1
2753 2752
2754 2753 def transform_ast(self, node):
2755 2754 """Apply the AST transformations from self.ast_transformers
2756 2755
2757 2756 Parameters
2758 2757 ----------
2759 2758 node : ast.Node
2760 2759 The root node to be transformed. Typically called with the ast.Module
2761 2760 produced by parsing user input.
2762 2761
2763 2762 Returns
2764 2763 -------
2765 2764 An ast.Node corresponding to the node it was called with. Note that it
2766 2765 may also modify the passed object, so don't rely on references to the
2767 2766 original AST.
2768 2767 """
2769 2768 for transformer in self.ast_transformers:
2770 2769 try:
2771 2770 node = transformer.visit(node)
2772 2771 except Exception:
2773 2772 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2774 2773 self.ast_transformers.remove(transformer)
2775 2774
2776 2775 if self.ast_transformers:
2777 2776 ast.fix_missing_locations(node)
2778 2777 return node
2779 2778
2780 2779
2781 2780 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2782 2781 compiler=compile):
2783 2782 """Run a sequence of AST nodes. The execution mode depends on the
2784 2783 interactivity parameter.
2785 2784
2786 2785 Parameters
2787 2786 ----------
2788 2787 nodelist : list
2789 2788 A sequence of AST nodes to run.
2790 2789 cell_name : str
2791 2790 Will be passed to the compiler as the filename of the cell. Typically
2792 2791 the value returned by ip.compile.cache(cell).
2793 2792 interactivity : str
2794 2793 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2795 2794 run interactively (displaying output from expressions). 'last_expr'
2796 2795 will run the last node interactively only if it is an expression (i.e.
2797 2796 expressions in loops or other blocks are not displayed. Other values
2798 2797 for this parameter will raise a ValueError.
2799 2798 compiler : callable
2800 2799 A function with the same interface as the built-in compile(), to turn
2801 2800 the AST nodes into code objects. Default is the built-in compile().
2802 2801 """
2803 2802 if not nodelist:
2804 2803 return
2805 2804
2806 2805 if interactivity == 'last_expr':
2807 2806 if isinstance(nodelist[-1], ast.Expr):
2808 2807 interactivity = "last"
2809 2808 else:
2810 2809 interactivity = "none"
2811 2810
2812 2811 if interactivity == 'none':
2813 2812 to_run_exec, to_run_interactive = nodelist, []
2814 2813 elif interactivity == 'last':
2815 2814 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2816 2815 elif interactivity == 'all':
2817 2816 to_run_exec, to_run_interactive = [], nodelist
2818 2817 else:
2819 2818 raise ValueError("Interactivity was %r" % interactivity)
2820 2819
2821 2820 exec_count = self.execution_count
2822 2821
2823 2822 try:
2824 2823 for i, node in enumerate(to_run_exec):
2825 2824 mod = ast.Module([node])
2826 2825 code = compiler(mod, cell_name, "exec")
2827 2826 if self.run_code(code):
2828 2827 return True
2829 2828
2830 2829 for i, node in enumerate(to_run_interactive):
2831 2830 mod = ast.Interactive([node])
2832 2831 code = compiler(mod, cell_name, "single")
2833 2832 if self.run_code(code):
2834 2833 return True
2835 2834
2836 2835 # Flush softspace
2837 2836 if softspace(sys.stdout, 0):
2838 2837 print()
2839 2838
2840 2839 except:
2841 2840 # It's possible to have exceptions raised here, typically by
2842 2841 # compilation of odd code (such as a naked 'return' outside a
2843 2842 # function) that did parse but isn't valid. Typically the exception
2844 2843 # is a SyntaxError, but it's safest just to catch anything and show
2845 2844 # the user a traceback.
2846 2845
2847 2846 # We do only one try/except outside the loop to minimize the impact
2848 2847 # on runtime, and also because if any node in the node list is
2849 2848 # broken, we should stop execution completely.
2850 2849 self.showtraceback()
2851 2850
2852 2851 return False
2853 2852
2854 2853 def run_code(self, code_obj):
2855 2854 """Execute a code object.
2856 2855
2857 2856 When an exception occurs, self.showtraceback() is called to display a
2858 2857 traceback.
2859 2858
2860 2859 Parameters
2861 2860 ----------
2862 2861 code_obj : code object
2863 2862 A compiled code object, to be executed
2864 2863
2865 2864 Returns
2866 2865 -------
2867 2866 False : successful execution.
2868 2867 True : an error occurred.
2869 2868 """
2870 2869
2871 2870 # Set our own excepthook in case the user code tries to call it
2872 2871 # directly, so that the IPython crash handler doesn't get triggered
2873 2872 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2874 2873
2875 2874 # we save the original sys.excepthook in the instance, in case config
2876 2875 # code (such as magics) needs access to it.
2877 2876 self.sys_excepthook = old_excepthook
2878 2877 outflag = 1 # happens in more places, so it's easier as default
2879 2878 try:
2880 2879 try:
2881 2880 self.hooks.pre_run_code_hook()
2882 2881 #rprint('Running code', repr(code_obj)) # dbg
2883 2882 exec(code_obj, self.user_global_ns, self.user_ns)
2884 2883 finally:
2885 2884 # Reset our crash handler in place
2886 2885 sys.excepthook = old_excepthook
2887 2886 except SystemExit:
2888 2887 self.showtraceback(exception_only=True)
2889 2888 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2890 2889 except self.custom_exceptions:
2891 2890 etype,value,tb = sys.exc_info()
2892 2891 self.CustomTB(etype,value,tb)
2893 2892 except:
2894 2893 self.showtraceback()
2895 2894 else:
2896 2895 outflag = 0
2897 2896 return outflag
2898 2897
2899 2898 # For backwards compatibility
2900 2899 runcode = run_code
2901 2900
2902 2901 #-------------------------------------------------------------------------
2903 2902 # Things related to GUI support and pylab
2904 2903 #-------------------------------------------------------------------------
2905 2904
2906 2905 def enable_gui(self, gui=None):
2907 2906 raise NotImplementedError('Implement enable_gui in a subclass')
2908 2907
2909 2908 def enable_matplotlib(self, gui=None):
2910 2909 """Enable interactive matplotlib and inline figure support.
2911 2910
2912 2911 This takes the following steps:
2913 2912
2914 2913 1. select the appropriate eventloop and matplotlib backend
2915 2914 2. set up matplotlib for interactive use with that backend
2916 2915 3. configure formatters for inline figure display
2917 2916 4. enable the selected gui eventloop
2918 2917
2919 2918 Parameters
2920 2919 ----------
2921 2920 gui : optional, string
2922 2921 If given, dictates the choice of matplotlib GUI backend to use
2923 2922 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2924 2923 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2925 2924 matplotlib (as dictated by the matplotlib build-time options plus the
2926 2925 user's matplotlibrc configuration file). Note that not all backends
2927 2926 make sense in all contexts, for example a terminal ipython can't
2928 2927 display figures inline.
2929 2928 """
2930 2929 from IPython.core import pylabtools as pt
2931 2930 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
2932 2931
2933 2932 if gui != 'inline':
2934 2933 # If we have our first gui selection, store it
2935 2934 if self.pylab_gui_select is None:
2936 2935 self.pylab_gui_select = gui
2937 2936 # Otherwise if they are different
2938 2937 elif gui != self.pylab_gui_select:
2939 2938 print ('Warning: Cannot change to a different GUI toolkit: %s.'
2940 2939 ' Using %s instead.' % (gui, self.pylab_gui_select))
2941 2940 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
2942 2941
2943 2942 pt.activate_matplotlib(backend)
2944 2943 pt.configure_inline_support(self, backend)
2945 2944
2946 2945 # Now we must activate the gui pylab wants to use, and fix %run to take
2947 2946 # plot updates into account
2948 2947 self.enable_gui(gui)
2949 2948 self.magics_manager.registry['ExecutionMagics'].default_runner = \
2950 2949 pt.mpl_runner(self.safe_execfile)
2951 2950
2952 2951 return gui, backend
2953 2952
2954 2953 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
2955 2954 """Activate pylab support at runtime.
2956 2955
2957 2956 This turns on support for matplotlib, preloads into the interactive
2958 2957 namespace all of numpy and pylab, and configures IPython to correctly
2959 2958 interact with the GUI event loop. The GUI backend to be used can be
2960 2959 optionally selected with the optional ``gui`` argument.
2961 2960
2962 2961 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
2963 2962
2964 2963 Parameters
2965 2964 ----------
2966 2965 gui : optional, string
2967 2966 If given, dictates the choice of matplotlib GUI backend to use
2968 2967 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2969 2968 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2970 2969 matplotlib (as dictated by the matplotlib build-time options plus the
2971 2970 user's matplotlibrc configuration file). Note that not all backends
2972 2971 make sense in all contexts, for example a terminal ipython can't
2973 2972 display figures inline.
2974 2973 import_all : optional, bool, default: True
2975 2974 Whether to do `from numpy import *` and `from pylab import *`
2976 2975 in addition to module imports.
2977 2976 welcome_message : deprecated
2978 2977 This argument is ignored, no welcome message will be displayed.
2979 2978 """
2980 2979 from IPython.core.pylabtools import import_pylab
2981 2980
2982 2981 gui, backend = self.enable_matplotlib(gui)
2983 2982
2984 2983 # We want to prevent the loading of pylab to pollute the user's
2985 2984 # namespace as shown by the %who* magics, so we execute the activation
2986 2985 # code in an empty namespace, and we update *both* user_ns and
2987 2986 # user_ns_hidden with this information.
2988 2987 ns = {}
2989 2988 import_pylab(ns, import_all)
2990 2989 # warn about clobbered names
2991 2990 ignored = set(["__builtins__"])
2992 2991 both = set(ns).intersection(self.user_ns).difference(ignored)
2993 2992 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
2994 2993 self.user_ns.update(ns)
2995 2994 self.user_ns_hidden.update(ns)
2996 2995 return gui, backend, clobbered
2997 2996
2998 2997 #-------------------------------------------------------------------------
2999 2998 # Utilities
3000 2999 #-------------------------------------------------------------------------
3001 3000
3002 3001 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3003 3002 """Expand python variables in a string.
3004 3003
3005 3004 The depth argument indicates how many frames above the caller should
3006 3005 be walked to look for the local namespace where to expand variables.
3007 3006
3008 3007 The global namespace for expansion is always the user's interactive
3009 3008 namespace.
3010 3009 """
3011 3010 ns = self.user_ns.copy()
3012 3011 ns.update(sys._getframe(depth+1).f_locals)
3013 3012 try:
3014 3013 # We have to use .vformat() here, because 'self' is a valid and common
3015 3014 # name, and expanding **ns for .format() would make it collide with
3016 3015 # the 'self' argument of the method.
3017 3016 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3018 3017 except Exception:
3019 3018 # if formatter couldn't format, just let it go untransformed
3020 3019 pass
3021 3020 return cmd
3022 3021
3023 3022 def mktempfile(self, data=None, prefix='ipython_edit_'):
3024 3023 """Make a new tempfile and return its filename.
3025 3024
3026 3025 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3027 3026 but it registers the created filename internally so ipython cleans it up
3028 3027 at exit time.
3029 3028
3030 3029 Optional inputs:
3031 3030
3032 3031 - data(None): if data is given, it gets written out to the temp file
3033 3032 immediately, and the file is closed again."""
3034 3033
3035 3034 dirname = tempfile.mkdtemp(prefix=prefix)
3036 3035 self.tempdirs.append(dirname)
3037 3036
3038 3037 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3039 3038 self.tempfiles.append(filename)
3040 3039
3041 3040 if data:
3042 3041 tmp_file = open(filename,'w')
3043 3042 tmp_file.write(data)
3044 3043 tmp_file.close()
3045 3044 return filename
3046 3045
3047 3046 # TODO: This should be removed when Term is refactored.
3048 3047 def write(self,data):
3049 3048 """Write a string to the default output"""
3050 3049 io.stdout.write(data)
3051 3050
3052 3051 # TODO: This should be removed when Term is refactored.
3053 3052 def write_err(self,data):
3054 3053 """Write a string to the default error output"""
3055 3054 io.stderr.write(data)
3056 3055
3057 3056 def ask_yes_no(self, prompt, default=None):
3058 3057 if self.quiet:
3059 3058 return True
3060 3059 return ask_yes_no(prompt,default)
3061 3060
3062 3061 def show_usage(self):
3063 3062 """Show a usage message"""
3064 3063 page.page(IPython.core.usage.interactive_usage)
3065 3064
3066 3065 def extract_input_lines(self, range_str, raw=False):
3067 3066 """Return as a string a set of input history slices.
3068 3067
3069 3068 Parameters
3070 3069 ----------
3071 3070 range_str : string
3072 3071 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3073 3072 since this function is for use by magic functions which get their
3074 3073 arguments as strings. The number before the / is the session
3075 3074 number: ~n goes n back from the current session.
3076 3075
3077 3076 raw : bool, optional
3078 3077 By default, the processed input is used. If this is true, the raw
3079 3078 input history is used instead.
3080 3079
3081 3080 Notes
3082 3081 -----
3083 3082
3084 3083 Slices can be described with two notations:
3085 3084
3086 3085 * ``N:M`` -> standard python form, means including items N...(M-1).
3087 3086 * ``N-M`` -> include items N..M (closed endpoint).
3088 3087 """
3089 3088 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3090 3089 return "\n".join(x for _, _, x in lines)
3091 3090
3092 3091 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3093 3092 """Get a code string from history, file, url, or a string or macro.
3094 3093
3095 3094 This is mainly used by magic functions.
3096 3095
3097 3096 Parameters
3098 3097 ----------
3099 3098
3100 3099 target : str
3101 3100
3102 3101 A string specifying code to retrieve. This will be tried respectively
3103 3102 as: ranges of input history (see %history for syntax), url,
3104 3103 correspnding .py file, filename, or an expression evaluating to a
3105 3104 string or Macro in the user namespace.
3106 3105
3107 3106 raw : bool
3108 3107 If true (default), retrieve raw history. Has no effect on the other
3109 3108 retrieval mechanisms.
3110 3109
3111 3110 py_only : bool (default False)
3112 3111 Only try to fetch python code, do not try alternative methods to decode file
3113 3112 if unicode fails.
3114 3113
3115 3114 Returns
3116 3115 -------
3117 3116 A string of code.
3118 3117
3119 3118 ValueError is raised if nothing is found, and TypeError if it evaluates
3120 3119 to an object of another type. In each case, .args[0] is a printable
3121 3120 message.
3122 3121 """
3123 3122 code = self.extract_input_lines(target, raw=raw) # Grab history
3124 3123 if code:
3125 3124 return code
3126 3125 utarget = unquote_filename(target)
3127 3126 try:
3128 3127 if utarget.startswith(('http://', 'https://')):
3129 3128 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3130 3129 except UnicodeDecodeError:
3131 3130 if not py_only :
3132 3131 # Deferred import
3133 3132 try:
3134 3133 from urllib.request import urlopen # Py3
3135 3134 except ImportError:
3136 3135 from urllib import urlopen
3137 3136 response = urlopen(target)
3138 3137 return response.read().decode('latin1')
3139 3138 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3140 3139
3141 3140 potential_target = [target]
3142 3141 try :
3143 3142 potential_target.insert(0,get_py_filename(target))
3144 3143 except IOError:
3145 3144 pass
3146 3145
3147 3146 for tgt in potential_target :
3148 3147 if os.path.isfile(tgt): # Read file
3149 3148 try :
3150 3149 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3151 3150 except UnicodeDecodeError :
3152 3151 if not py_only :
3153 3152 with io_open(tgt,'r', encoding='latin1') as f :
3154 3153 return f.read()
3155 3154 raise ValueError(("'%s' seem to be unreadable.") % target)
3156 3155 elif os.path.isdir(os.path.expanduser(tgt)):
3157 3156 raise ValueError("'%s' is a directory, not a regular file." % target)
3158 3157
3159 3158 if search_ns:
3160 3159 # Inspect namespace to load object source
3161 3160 object_info = self.object_inspect(target, detail_level=1)
3162 3161 if object_info['found'] and object_info['source']:
3163 3162 return object_info['source']
3164 3163
3165 3164 try: # User namespace
3166 3165 codeobj = eval(target, self.user_ns)
3167 3166 except Exception:
3168 3167 raise ValueError(("'%s' was not found in history, as a file, url, "
3169 3168 "nor in the user namespace.") % target)
3170 3169
3171 3170 if isinstance(codeobj, string_types):
3172 3171 return codeobj
3173 3172 elif isinstance(codeobj, Macro):
3174 3173 return codeobj.value
3175 3174
3176 3175 raise TypeError("%s is neither a string nor a macro." % target,
3177 3176 codeobj)
3178 3177
3179 3178 #-------------------------------------------------------------------------
3180 3179 # Things related to IPython exiting
3181 3180 #-------------------------------------------------------------------------
3182 3181 def atexit_operations(self):
3183 3182 """This will be executed at the time of exit.
3184 3183
3185 3184 Cleanup operations and saving of persistent data that is done
3186 3185 unconditionally by IPython should be performed here.
3187 3186
3188 3187 For things that may depend on startup flags or platform specifics (such
3189 3188 as having readline or not), register a separate atexit function in the
3190 3189 code that has the appropriate information, rather than trying to
3191 3190 clutter
3192 3191 """
3193 3192 # Close the history session (this stores the end time and line count)
3194 3193 # this must be *before* the tempfile cleanup, in case of temporary
3195 3194 # history db
3196 3195 self.history_manager.end_session()
3197 3196
3198 3197 # Cleanup all tempfiles and folders left around
3199 3198 for tfile in self.tempfiles:
3200 3199 try:
3201 3200 os.unlink(tfile)
3202 3201 except OSError:
3203 3202 pass
3204 3203
3205 3204 for tdir in self.tempdirs:
3206 3205 try:
3207 3206 os.rmdir(tdir)
3208 3207 except OSError:
3209 3208 pass
3210 3209
3211 3210 # Clear all user namespaces to release all references cleanly.
3212 3211 self.reset(new_session=False)
3213 3212
3214 3213 # Run user hooks
3215 3214 self.hooks.shutdown_hook()
3216 3215
3217 3216 def cleanup(self):
3218 3217 self.restore_sys_module_state()
3219 3218
3220 3219
3221 3220 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3222 3221 """An abstract base class for InteractiveShell."""
3223 3222
3224 3223 InteractiveShellABC.register(InteractiveShell)
@@ -1,281 +1,250
1 1 # encoding: utf-8
2 """
3 An object for managing IPython profile directories.
2 """An object for managing IPython profile directories."""
4 3
5 Authors:
6
7 * Brian Granger
8 * Fernando Perez
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 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
23 6
24 7 import os
25 8 import shutil
26 9 import errno
27 10 import time
28 11
29 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 14 from IPython.utils import py3compat
32 15 from IPython.utils.traitlets import Unicode, Bool
33 16
34 17 #-----------------------------------------------------------------------------
35 # Classes and functions
36 #-----------------------------------------------------------------------------
37
38
39 #-----------------------------------------------------------------------------
40 18 # Module errors
41 19 #-----------------------------------------------------------------------------
42 20
43 21 class ProfileDirError(Exception):
44 22 pass
45 23
46 24
47 25 #-----------------------------------------------------------------------------
48 26 # Class for managing profile directories
49 27 #-----------------------------------------------------------------------------
50 28
51 29 class ProfileDir(LoggingConfigurable):
52 30 """An object to manage the profile directory and its resources.
53 31
54 32 The profile directory is used by all IPython applications, to manage
55 33 configuration, logging and security.
56 34
57 35 This object knows how to find, create and manage these directories. This
58 36 should be used by any code that wants to handle profiles.
59 37 """
60 38
61 39 security_dir_name = Unicode('security')
62 40 log_dir_name = Unicode('log')
63 41 startup_dir_name = Unicode('startup')
64 42 pid_dir_name = Unicode('pid')
65 43 static_dir_name = Unicode('static')
66 44 security_dir = Unicode(u'')
67 45 log_dir = Unicode(u'')
68 46 startup_dir = Unicode(u'')
69 47 pid_dir = Unicode(u'')
70 48 static_dir = Unicode(u'')
71 49
72 50 location = Unicode(u'', config=True,
73 51 help="""Set the profile location directly. This overrides the logic used by the
74 52 `profile` option.""",
75 53 )
76 54
77 55 _location_isset = Bool(False) # flag for detecting multiply set location
78 56
79 57 def _location_changed(self, name, old, new):
80 58 if self._location_isset:
81 59 raise RuntimeError("Cannot set profile location more than once.")
82 60 self._location_isset = True
83 num_tries = 0
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)
61 ensure_dir_exists(new)
93 62
94 63 # ensure config files exist:
95 64 self.security_dir = os.path.join(new, self.security_dir_name)
96 65 self.log_dir = os.path.join(new, self.log_dir_name)
97 66 self.startup_dir = os.path.join(new, self.startup_dir_name)
98 67 self.pid_dir = os.path.join(new, self.pid_dir_name)
99 68 self.static_dir = os.path.join(new, self.static_dir_name)
100 69 self.check_dirs()
101 70
102 71 def _log_dir_changed(self, name, old, new):
103 72 self.check_log_dir()
104 73
105 74 def _mkdir(self, path, mode=None):
106 75 """ensure a directory exists at a given path
107 76
108 77 This is a version of os.mkdir, with the following differences:
109 78
110 79 - returns True if it created the directory, False otherwise
111 80 - ignores EEXIST, protecting against race conditions where
112 81 the dir may have been created in between the check and
113 82 the creation
114 83 - sets permissions if requested and the dir already exists
115 84 """
116 85 if os.path.exists(path):
117 86 if mode and os.stat(path).st_mode != mode:
118 87 try:
119 88 os.chmod(path, mode)
120 89 except OSError:
121 90 self.log.warn(
122 91 "Could not set permissions on %s",
123 92 path
124 93 )
125 94 return False
126 95 try:
127 96 if mode:
128 97 os.mkdir(path, mode)
129 98 else:
130 99 os.mkdir(path)
131 100 except OSError as e:
132 101 if e.errno == errno.EEXIST:
133 102 return False
134 103 else:
135 104 raise
136 105
137 106 return True
138 107
139 108 def check_log_dir(self):
140 109 self._mkdir(self.log_dir)
141 110
142 111 def _startup_dir_changed(self, name, old, new):
143 112 self.check_startup_dir()
144 113
145 114 def check_startup_dir(self):
146 115 self._mkdir(self.startup_dir)
147 116
148 117 readme = os.path.join(self.startup_dir, 'README')
149 118 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
150 119
151 120 if not os.path.exists(src):
152 121 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
153 122
154 123 if os.path.exists(src) and not os.path.exists(readme):
155 124 shutil.copy(src, readme)
156 125
157 126 def _security_dir_changed(self, name, old, new):
158 127 self.check_security_dir()
159 128
160 129 def check_security_dir(self):
161 130 self._mkdir(self.security_dir, 0o40700)
162 131
163 132 def _pid_dir_changed(self, name, old, new):
164 133 self.check_pid_dir()
165 134
166 135 def check_pid_dir(self):
167 136 self._mkdir(self.pid_dir, 0o40700)
168 137
169 138 def _static_dir_changed(self, name, old, new):
170 139 self.check_startup_dir()
171 140
172 141 def check_static_dir(self):
173 142 self._mkdir(self.static_dir)
174 143 custom = os.path.join(self.static_dir, 'custom')
175 144 self._mkdir(custom)
176 145 from IPython.html import DEFAULT_STATIC_FILES_PATH
177 146 for fname in ('custom.js', 'custom.css'):
178 147 src = os.path.join(DEFAULT_STATIC_FILES_PATH, 'custom', fname)
179 148 dest = os.path.join(custom, fname)
180 149 if not os.path.exists(src):
181 150 self.log.warn("Could not copy default file to static dir. Source file %s does not exist.", src)
182 151 continue
183 152 if not os.path.exists(dest):
184 153 shutil.copy(src, dest)
185 154
186 155 def check_dirs(self):
187 156 self.check_security_dir()
188 157 self.check_log_dir()
189 158 self.check_pid_dir()
190 159 self.check_startup_dir()
191 160 self.check_static_dir()
192 161
193 162 def copy_config_file(self, config_file, path=None, overwrite=False):
194 163 """Copy a default config file into the active profile directory.
195 164
196 165 Default configuration files are kept in :mod:`IPython.config.default`.
197 166 This function moves these from that location to the working profile
198 167 directory.
199 168 """
200 169 dst = os.path.join(self.location, config_file)
201 170 if os.path.isfile(dst) and not overwrite:
202 171 return False
203 172 if path is None:
204 173 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
205 174 src = os.path.join(path, config_file)
206 175 shutil.copy(src, dst)
207 176 return True
208 177
209 178 @classmethod
210 179 def create_profile_dir(cls, profile_dir, config=None):
211 180 """Create a new profile directory given a full path.
212 181
213 182 Parameters
214 183 ----------
215 184 profile_dir : str
216 185 The full path to the profile directory. If it does exist, it will
217 186 be used. If not, it will be created.
218 187 """
219 188 return cls(location=profile_dir, config=config)
220 189
221 190 @classmethod
222 191 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
223 192 """Create a profile dir by profile name and path.
224 193
225 194 Parameters
226 195 ----------
227 196 path : unicode
228 197 The path (directory) to put the profile directory in.
229 198 name : unicode
230 199 The name of the profile. The name of the profile directory will
231 200 be "profile_<profile>".
232 201 """
233 202 if not os.path.isdir(path):
234 203 raise ProfileDirError('Directory not found: %s' % path)
235 204 profile_dir = os.path.join(path, u'profile_' + name)
236 205 return cls(location=profile_dir, config=config)
237 206
238 207 @classmethod
239 208 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
240 209 """Find an existing profile dir by profile name, return its ProfileDir.
241 210
242 211 This searches through a sequence of paths for a profile dir. If it
243 212 is not found, a :class:`ProfileDirError` exception will be raised.
244 213
245 214 The search path algorithm is:
246 215 1. ``py3compat.getcwd()``
247 216 2. ``ipython_dir``
248 217
249 218 Parameters
250 219 ----------
251 220 ipython_dir : unicode or str
252 221 The IPython directory to use.
253 222 name : unicode or str
254 223 The name of the profile. The name of the profile directory
255 224 will be "profile_<profile>".
256 225 """
257 226 dirname = u'profile_' + name
258 227 paths = [py3compat.getcwd(), ipython_dir]
259 228 for p in paths:
260 229 profile_dir = os.path.join(p, dirname)
261 230 if os.path.isdir(profile_dir):
262 231 return cls(location=profile_dir, config=config)
263 232 else:
264 233 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
265 234
266 235 @classmethod
267 236 def find_profile_dir(cls, profile_dir, config=None):
268 237 """Find/create a profile dir and return its ProfileDir.
269 238
270 239 This will create the profile directory if it doesn't exist.
271 240
272 241 Parameters
273 242 ----------
274 243 profile_dir : unicode or str
275 244 The path of the profile directory. This is expanded using
276 245 :func:`IPython.utils.genutils.expand_path`.
277 246 """
278 247 profile_dir = expand_path(profile_dir)
279 248 if not os.path.isdir(profile_dir):
280 249 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
281 250 return cls(location=profile_dir, config=config)
@@ -1,268 +1,263
1 1 # coding: utf-8
2 2 """Utilities for installing Javascript extensions for the notebook"""
3 3
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2014 The IPython Development Team
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 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
10 6
11 7 from __future__ import print_function
12 8
13 9 import os
14 10 import shutil
15 11 import tarfile
16 12 import zipfile
17 13 from os.path import basename, join as pjoin
18 14
19 15 # Deferred imports
20 16 try:
21 17 from urllib.parse import urlparse # Py3
22 18 from urllib.request import urlretrieve
23 19 except ImportError:
24 20 from urlparse import urlparse
25 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 24 from IPython.utils.py3compat import string_types, cast_unicode_py2
29 25 from IPython.utils.tempdir import TemporaryDirectory
30 26
31 27
32 28 def _should_copy(src, dest, verbose=1):
33 29 """should a file be copied?"""
34 30 if not os.path.exists(dest):
35 31 return True
36 32 if os.stat(dest).st_mtime < os.stat(src).st_mtime:
37 33 if verbose >= 2:
38 34 print("%s is out of date" % dest)
39 35 return True
40 36 if verbose >= 2:
41 37 print("%s is up to date" % dest)
42 38 return False
43 39
44 40
45 41 def _maybe_copy(src, dest, verbose=1):
46 42 """copy a file if it needs updating"""
47 43 if _should_copy(src, dest, verbose):
48 44 if verbose >= 1:
49 45 print("copying %s -> %s" % (src, dest))
50 46 shutil.copy2(src, dest)
51 47
52 48
53 49 def _safe_is_tarfile(path):
54 50 """safe version of is_tarfile, return False on IOError"""
55 51 try:
56 52 return tarfile.is_tarfile(path)
57 53 except IOError:
58 54 return False
59 55
60 56
61 57 def check_nbextension(files, ipython_dir=None):
62 58 """Check whether nbextension files have been installed
63 59
64 60 files should be a list of relative paths within nbextensions.
65 61
66 62 Returns True if all files are found, False if any are missing.
67 63 """
68 64 ipython_dir = ipython_dir or get_ipython_dir()
69 65 nbext = pjoin(ipython_dir, u'nbextensions')
70 66 # make sure nbextensions dir exists
71 67 if not os.path.exists(nbext):
72 68 return False
73 69
74 70 if isinstance(files, string_types):
75 71 # one file given, turn it into a list
76 72 files = [files]
77 73
78 74 return all(os.path.exists(pjoin(nbext, f)) for f in files)
79 75
80 76
81 77 def install_nbextension(files, overwrite=False, symlink=False, ipython_dir=None, verbose=1):
82 78 """Install a Javascript extension for the notebook
83 79
84 80 Stages files and/or directories into IPYTHONDIR/nbextensions.
85 81 By default, this compares modification time, and only stages files that need updating.
86 82 If `overwrite` is specified, matching files are purged before proceeding.
87 83
88 84 Parameters
89 85 ----------
90 86
91 87 files : list(paths or URLs)
92 88 One or more paths or URLs to existing files directories to install.
93 89 These will be installed with their base name, so '/path/to/foo'
94 90 will install to 'nbextensions/foo'.
95 91 Archives (zip or tarballs) will be extracted into the nbextensions directory.
96 92 overwrite : bool [default: False]
97 93 If True, always install the files, regardless of what may already be installed.
98 94 symlink : bool [default: False]
99 95 If True, create a symlink in nbextensions, rather than copying files.
100 96 Not allowed with URLs or archives.
101 97 ipython_dir : str [optional]
102 98 The path to an IPython directory, if the default value is not desired.
103 99 get_ipython_dir() is used by default.
104 100 verbose : int [default: 1]
105 101 Set verbosity level. The default is 1, where file actions are printed.
106 102 set verbose=2 for more output, or verbose=0 for silence.
107 103 """
108 104
109 105 ipython_dir = ipython_dir or get_ipython_dir()
110 106 nbext = pjoin(ipython_dir, u'nbextensions')
111 107 # make sure nbextensions dir exists
112 if not os.path.exists(nbext):
113 os.makedirs(nbext)
108 ensure_dir_exists(nbext)
114 109
115 110 if isinstance(files, string_types):
116 111 # one file given, turn it into a list
117 112 files = [files]
118 113
119 114 for path in map(cast_unicode_py2, files):
120 115
121 116 if path.startswith(('https://', 'http://')):
122 117 if symlink:
123 118 raise ValueError("Cannot symlink from URLs")
124 119 # Given a URL, download it
125 120 with TemporaryDirectory() as td:
126 121 filename = urlparse(path).path.split('/')[-1]
127 122 local_path = os.path.join(td, filename)
128 123 if verbose >= 1:
129 124 print("downloading %s to %s" % (path, local_path))
130 125 urlretrieve(path, local_path)
131 126 # now install from the local copy
132 127 install_nbextension(local_path, overwrite, symlink, ipython_dir, verbose)
133 128 continue
134 129
135 130 # handle archives
136 131 archive = None
137 132 if path.endswith('.zip'):
138 133 archive = zipfile.ZipFile(path)
139 134 elif _safe_is_tarfile(path):
140 135 archive = tarfile.open(path)
141 136
142 137 if archive:
143 138 if symlink:
144 139 raise ValueError("Cannot symlink from archives")
145 140 if verbose >= 1:
146 141 print("extracting %s to %s" % (path, nbext))
147 142 archive.extractall(nbext)
148 143 archive.close()
149 144 continue
150 145
151 146 dest = pjoin(nbext, basename(path))
152 147 if overwrite and os.path.exists(dest):
153 148 if verbose >= 1:
154 149 print("removing %s" % dest)
155 150 if os.path.isdir(dest):
156 151 shutil.rmtree(dest)
157 152 else:
158 153 os.remove(dest)
159 154
160 155 if symlink:
161 156 path = os.path.abspath(path)
162 157 if not os.path.exists(dest):
163 158 if verbose >= 1:
164 159 print("symlink %s -> %s" % (dest, path))
165 160 os.symlink(path, dest)
166 161 continue
167 162
168 163 if os.path.isdir(path):
169 164 strip_prefix_len = len(path) - len(basename(path))
170 165 for parent, dirs, files in os.walk(path):
171 166 dest_dir = pjoin(nbext, parent[strip_prefix_len:])
172 167 if not os.path.exists(dest_dir):
173 168 if verbose >= 2:
174 169 print("making directory %s" % dest_dir)
175 170 os.makedirs(dest_dir)
176 171 for file in files:
177 172 src = pjoin(parent, file)
178 173 # print("%r, %r" % (dest_dir, file))
179 174 dest = pjoin(dest_dir, file)
180 175 _maybe_copy(src, dest, verbose)
181 176 else:
182 177 src = path
183 178 _maybe_copy(src, dest, verbose)
184 179
185 180 #----------------------------------------------------------------------
186 181 # install nbextension app
187 182 #----------------------------------------------------------------------
188 183
189 184 from IPython.utils.traitlets import Bool, Enum
190 185 from IPython.core.application import BaseIPythonApplication
191 186
192 187 flags = {
193 188 "overwrite" : ({
194 189 "NBExtensionApp" : {
195 190 "overwrite" : True,
196 191 }}, "Force overwrite of existing files"
197 192 ),
198 193 "debug" : ({
199 194 "NBExtensionApp" : {
200 195 "verbose" : 2,
201 196 }}, "Extra output"
202 197 ),
203 198 "quiet" : ({
204 199 "NBExtensionApp" : {
205 200 "verbose" : 0,
206 201 }}, "Minimal output"
207 202 ),
208 203 "symlink" : ({
209 204 "NBExtensionApp" : {
210 205 "symlink" : True,
211 206 }}, "Create symlinks instead of copying files"
212 207 ),
213 208 }
214 209 flags['s'] = flags['symlink']
215 210
216 211 aliases = {
217 212 "ipython-dir" : "NBExtensionApp.ipython_dir"
218 213 }
219 214
220 215 class NBExtensionApp(BaseIPythonApplication):
221 216 """Entry point for installing notebook extensions"""
222 217
223 218 description = """Install IPython notebook extensions
224 219
225 220 Usage
226 221
227 222 ipython install-nbextension file [more files, folders, archives or urls]
228 223
229 224 This copies files and/or folders into the IPython nbextensions directory.
230 225 If a URL is given, it will be downloaded.
231 226 If an archive is given, it will be extracted into nbextensions.
232 227 If the requested files are already up to date, no action is taken
233 228 unless --overwrite is specified.
234 229 """
235 230
236 231 examples = """
237 232 ipython install-nbextension /path/to/d3.js /path/to/myextension
238 233 """
239 234 aliases = aliases
240 235 flags = flags
241 236
242 237 overwrite = Bool(False, config=True, help="Force overwrite of existing files")
243 238 symlink = Bool(False, config=True, help="Create symlinks instead of copying files")
244 239 verbose = Enum((0,1,2), default_value=1, config=True,
245 240 help="Verbosity level"
246 241 )
247 242
248 243 def install_extensions(self):
249 244 install_nbextension(self.extra_args,
250 245 overwrite=self.overwrite,
251 246 symlink=self.symlink,
252 247 verbose=self.verbose,
253 248 ipython_dir=self.ipython_dir,
254 249 )
255 250
256 251 def start(self):
257 252 if not self.extra_args:
258 253 nbext = pjoin(self.ipython_dir, u'nbextensions')
259 254 print("Notebook extensions in %s:" % nbext)
260 255 for ext in os.listdir(nbext):
261 256 print(u" %s" % ext)
262 257 else:
263 258 self.install_extensions()
264 259
265 260
266 261 if __name__ == '__main__':
267 262 NBExtensionApp.launch_instance()
268 263 No newline at end of file
@@ -1,486 +1,470
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:
4
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 #-----------------------------------------------------------------------------
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
19 5
20 6 import io
21 7 import os
22 8 import glob
23 9 import shutil
24 10
25 11 from tornado import web
26 12
27 13 from .nbmanager import NotebookManager
28 14 from IPython.nbformat import current
15 from IPython.utils.path import ensure_dir_exists
29 16 from IPython.utils.traitlets import Unicode, Bool, TraitError
30 17 from IPython.utils.py3compat import getcwd
31 18 from IPython.utils import tz
32 19 from IPython.html.utils import is_hidden, to_os_path
33 20
34 21 def sort_key(item):
35 22 """Case-insensitive sorting."""
36 23 return item['name'].lower()
37 24
38 25 #-----------------------------------------------------------------------------
39 26 # Classes
40 27 #-----------------------------------------------------------------------------
41 28
42 29 class FileNotebookManager(NotebookManager):
43 30
44 31 save_script = Bool(False, config=True,
45 32 help="""Automatically create a Python script when saving the notebook.
46 33
47 34 For easier use of import, %run and %load across notebooks, a
48 35 <notebook-name>.py script will be created next to any
49 36 <notebook-name>.ipynb on each save. This can also be set with the
50 37 short `--script` flag.
51 38 """
52 39 )
53 40 notebook_dir = Unicode(getcwd(), config=True)
54 41
55 42 def _notebook_dir_changed(self, name, old, new):
56 43 """Do a bit of validation of the notebook dir."""
57 44 if not os.path.isabs(new):
58 45 # If we receive a non-absolute path, make it absolute.
59 46 self.notebook_dir = os.path.abspath(new)
60 47 return
61 48 if not os.path.exists(new) or not os.path.isdir(new):
62 49 raise TraitError("notebook dir %r is not a directory" % new)
63 50
64 51 checkpoint_dir = Unicode('.ipynb_checkpoints', config=True,
65 52 help="""The directory name in which to keep notebook checkpoints
66 53
67 54 This is a path relative to the notebook's own directory.
68 55
69 56 By default, it is .ipynb_checkpoints
70 57 """
71 58 )
72 59
73 60 def _copy(self, src, dest):
74 61 """copy src to dest
75 62
76 63 like shutil.copy2, but log errors in copystat
77 64 """
78 65 shutil.copyfile(src, dest)
79 66 try:
80 67 shutil.copystat(src, dest)
81 68 except OSError as e:
82 69 self.log.debug("copystat on %s failed", dest, exc_info=True)
83 70
84 71 def get_notebook_names(self, path=''):
85 72 """List all notebook names in the notebook dir and path."""
86 73 path = path.strip('/')
87 74 if not os.path.isdir(self._get_os_path(path=path)):
88 75 raise web.HTTPError(404, 'Directory not found: ' + path)
89 76 names = glob.glob(self._get_os_path('*'+self.filename_ext, path))
90 77 names = [os.path.basename(name)
91 78 for name in names]
92 79 return names
93 80
94 81 def path_exists(self, path):
95 82 """Does the API-style path (directory) actually exist?
96 83
97 84 Parameters
98 85 ----------
99 86 path : string
100 87 The path to check. This is an API path (`/` separated,
101 88 relative to base notebook-dir).
102 89
103 90 Returns
104 91 -------
105 92 exists : bool
106 93 Whether the path is indeed a directory.
107 94 """
108 95 path = path.strip('/')
109 96 os_path = self._get_os_path(path=path)
110 97 return os.path.isdir(os_path)
111 98
112 99 def is_hidden(self, path):
113 100 """Does the API style path correspond to a hidden directory or file?
114 101
115 102 Parameters
116 103 ----------
117 104 path : string
118 105 The path to check. This is an API path (`/` separated,
119 106 relative to base notebook-dir).
120 107
121 108 Returns
122 109 -------
123 110 exists : bool
124 111 Whether the path is hidden.
125 112
126 113 """
127 114 path = path.strip('/')
128 115 os_path = self._get_os_path(path=path)
129 116 return is_hidden(os_path, self.notebook_dir)
130 117
131 118 def _get_os_path(self, name=None, path=''):
132 119 """Given a notebook name and a URL path, return its file system
133 120 path.
134 121
135 122 Parameters
136 123 ----------
137 124 name : string
138 125 The name of a notebook file with the .ipynb extension
139 126 path : string
140 127 The relative URL path (with '/' as separator) to the named
141 128 notebook.
142 129
143 130 Returns
144 131 -------
145 132 path : string
146 133 A file system path that combines notebook_dir (location where
147 134 server started), the relative path, and the filename with the
148 135 current operating system's url.
149 136 """
150 137 if name is not None:
151 138 path = path + '/' + name
152 139 return to_os_path(path, self.notebook_dir)
153 140
154 141 def notebook_exists(self, name, path=''):
155 142 """Returns a True if the notebook exists. Else, returns False.
156 143
157 144 Parameters
158 145 ----------
159 146 name : string
160 147 The name of the notebook you are checking.
161 148 path : string
162 149 The relative path to the notebook (with '/' as separator)
163 150
164 151 Returns
165 152 -------
166 153 bool
167 154 """
168 155 path = path.strip('/')
169 156 nbpath = self._get_os_path(name, path=path)
170 157 return os.path.isfile(nbpath)
171 158
172 159 # TODO: Remove this after we create the contents web service and directories are
173 160 # no longer listed by the notebook web service.
174 161 def list_dirs(self, path):
175 162 """List the directories for a given API style path."""
176 163 path = path.strip('/')
177 164 os_path = self._get_os_path('', path)
178 165 if not os.path.isdir(os_path):
179 166 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
180 167 elif is_hidden(os_path, self.notebook_dir):
181 168 self.log.info("Refusing to serve hidden directory, via 404 Error")
182 169 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
183 170 dir_names = os.listdir(os_path)
184 171 dirs = []
185 172 for name in dir_names:
186 173 os_path = self._get_os_path(name, path)
187 174 if os.path.isdir(os_path) and not is_hidden(os_path, self.notebook_dir)\
188 175 and self.should_list(name):
189 176 try:
190 177 model = self.get_dir_model(name, path)
191 178 except IOError:
192 179 pass
193 180 dirs.append(model)
194 181 dirs = sorted(dirs, key=sort_key)
195 182 return dirs
196 183
197 184 # TODO: Remove this after we create the contents web service and directories are
198 185 # no longer listed by the notebook web service.
199 186 def get_dir_model(self, name, path=''):
200 187 """Get the directory model given a directory name and its API style path"""
201 188 path = path.strip('/')
202 189 os_path = self._get_os_path(name, path)
203 190 if not os.path.isdir(os_path):
204 191 raise IOError('directory does not exist: %r' % os_path)
205 192 info = os.stat(os_path)
206 193 last_modified = tz.utcfromtimestamp(info.st_mtime)
207 194 created = tz.utcfromtimestamp(info.st_ctime)
208 195 # Create the notebook model.
209 196 model ={}
210 197 model['name'] = name
211 198 model['path'] = path
212 199 model['last_modified'] = last_modified
213 200 model['created'] = created
214 201 model['type'] = 'directory'
215 202 return model
216 203
217 204 def list_notebooks(self, path):
218 205 """Returns a list of dictionaries that are the standard model
219 206 for all notebooks in the relative 'path'.
220 207
221 208 Parameters
222 209 ----------
223 210 path : str
224 211 the URL path that describes the relative path for the
225 212 listed notebooks
226 213
227 214 Returns
228 215 -------
229 216 notebooks : list of dicts
230 217 a list of the notebook models without 'content'
231 218 """
232 219 path = path.strip('/')
233 220 notebook_names = self.get_notebook_names(path)
234 221 notebooks = [self.get_notebook(name, path, content=False)
235 222 for name in notebook_names if self.should_list(name)]
236 223 notebooks = sorted(notebooks, key=sort_key)
237 224 return notebooks
238 225
239 226 def get_notebook(self, name, path='', content=True):
240 227 """ Takes a path and name for a notebook and returns its model
241 228
242 229 Parameters
243 230 ----------
244 231 name : str
245 232 the name of the notebook
246 233 path : str
247 234 the URL path that describes the relative path for
248 235 the notebook
249 236
250 237 Returns
251 238 -------
252 239 model : dict
253 240 the notebook model. If contents=True, returns the 'contents'
254 241 dict in the model as well.
255 242 """
256 243 path = path.strip('/')
257 244 if not self.notebook_exists(name=name, path=path):
258 245 raise web.HTTPError(404, u'Notebook does not exist: %s' % name)
259 246 os_path = self._get_os_path(name, path)
260 247 info = os.stat(os_path)
261 248 last_modified = tz.utcfromtimestamp(info.st_mtime)
262 249 created = tz.utcfromtimestamp(info.st_ctime)
263 250 # Create the notebook model.
264 251 model ={}
265 252 model['name'] = name
266 253 model['path'] = path
267 254 model['last_modified'] = last_modified
268 255 model['created'] = created
269 256 model['type'] = 'notebook'
270 257 if content:
271 258 with io.open(os_path, 'r', encoding='utf-8') as f:
272 259 try:
273 260 nb = current.read(f, u'json')
274 261 except Exception as e:
275 262 raise web.HTTPError(400, u"Unreadable Notebook: %s %s" % (os_path, e))
276 263 self.mark_trusted_cells(nb, name, path)
277 264 model['content'] = nb
278 265 return model
279 266
280 267 def save_notebook(self, model, name='', path=''):
281 268 """Save the notebook model and return the model with no content."""
282 269 path = path.strip('/')
283 270
284 271 if 'content' not in model:
285 272 raise web.HTTPError(400, u'No notebook JSON data provided')
286 273
287 274 # One checkpoint should always exist
288 275 if self.notebook_exists(name, path) and not self.list_checkpoints(name, path):
289 276 self.create_checkpoint(name, path)
290 277
291 278 new_path = model.get('path', path).strip('/')
292 279 new_name = model.get('name', name)
293 280
294 281 if path != new_path or name != new_name:
295 282 self.rename_notebook(name, path, new_name, new_path)
296 283
297 284 # Save the notebook file
298 285 os_path = self._get_os_path(new_name, new_path)
299 286 nb = current.to_notebook_json(model['content'])
300 287
301 288 self.check_and_sign(nb, new_name, new_path)
302 289
303 290 if 'name' in nb['metadata']:
304 291 nb['metadata']['name'] = u''
305 292 try:
306 293 self.log.debug("Autosaving notebook %s", os_path)
307 294 with io.open(os_path, 'w', encoding='utf-8') as f:
308 295 current.write(nb, f, u'json')
309 296 except Exception as e:
310 297 raise web.HTTPError(400, u'Unexpected error while autosaving notebook: %s %s' % (os_path, e))
311 298
312 299 # Save .py script as well
313 300 if self.save_script:
314 301 py_path = os.path.splitext(os_path)[0] + '.py'
315 302 self.log.debug("Writing script %s", py_path)
316 303 try:
317 304 with io.open(py_path, 'w', encoding='utf-8') as f:
318 305 current.write(nb, f, u'py')
319 306 except Exception as e:
320 307 raise web.HTTPError(400, u'Unexpected error while saving notebook as script: %s %s' % (py_path, e))
321 308
322 309 model = self.get_notebook(new_name, new_path, content=False)
323 310 return model
324 311
325 312 def update_notebook(self, model, name, path=''):
326 313 """Update the notebook's path and/or name"""
327 314 path = path.strip('/')
328 315 new_name = model.get('name', name)
329 316 new_path = model.get('path', path).strip('/')
330 317 if path != new_path or name != new_name:
331 318 self.rename_notebook(name, path, new_name, new_path)
332 319 model = self.get_notebook(new_name, new_path, content=False)
333 320 return model
334 321
335 322 def delete_notebook(self, name, path=''):
336 323 """Delete notebook by name and path."""
337 324 path = path.strip('/')
338 325 os_path = self._get_os_path(name, path)
339 326 if not os.path.isfile(os_path):
340 327 raise web.HTTPError(404, u'Notebook does not exist: %s' % os_path)
341 328
342 329 # clear checkpoints
343 330 for checkpoint in self.list_checkpoints(name, path):
344 331 checkpoint_id = checkpoint['id']
345 332 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
346 333 if os.path.isfile(cp_path):
347 334 self.log.debug("Unlinking checkpoint %s", cp_path)
348 335 os.unlink(cp_path)
349 336
350 337 self.log.debug("Unlinking notebook %s", os_path)
351 338 os.unlink(os_path)
352 339
353 340 def rename_notebook(self, old_name, old_path, new_name, new_path):
354 341 """Rename a notebook."""
355 342 old_path = old_path.strip('/')
356 343 new_path = new_path.strip('/')
357 344 if new_name == old_name and new_path == old_path:
358 345 return
359 346
360 347 new_os_path = self._get_os_path(new_name, new_path)
361 348 old_os_path = self._get_os_path(old_name, old_path)
362 349
363 350 # Should we proceed with the move?
364 351 if os.path.isfile(new_os_path):
365 352 raise web.HTTPError(409, u'Notebook with name already exists: %s' % new_os_path)
366 353 if self.save_script:
367 354 old_py_path = os.path.splitext(old_os_path)[0] + '.py'
368 355 new_py_path = os.path.splitext(new_os_path)[0] + '.py'
369 356 if os.path.isfile(new_py_path):
370 357 raise web.HTTPError(409, u'Python script with name already exists: %s' % new_py_path)
371 358
372 359 # Move the notebook file
373 360 try:
374 361 shutil.move(old_os_path, new_os_path)
375 362 except Exception as e:
376 363 raise web.HTTPError(500, u'Unknown error renaming notebook: %s %s' % (old_os_path, e))
377 364
378 365 # Move the checkpoints
379 366 old_checkpoints = self.list_checkpoints(old_name, old_path)
380 367 for cp in old_checkpoints:
381 368 checkpoint_id = cp['id']
382 369 old_cp_path = self.get_checkpoint_path(checkpoint_id, old_name, old_path)
383 370 new_cp_path = self.get_checkpoint_path(checkpoint_id, new_name, new_path)
384 371 if os.path.isfile(old_cp_path):
385 372 self.log.debug("Renaming checkpoint %s -> %s", old_cp_path, new_cp_path)
386 373 shutil.move(old_cp_path, new_cp_path)
387 374
388 375 # Move the .py script
389 376 if self.save_script:
390 377 shutil.move(old_py_path, new_py_path)
391 378
392 379 # Checkpoint-related utilities
393 380
394 381 def get_checkpoint_path(self, checkpoint_id, name, path=''):
395 382 """find the path to a checkpoint"""
396 383 path = path.strip('/')
397 384 basename, _ = os.path.splitext(name)
398 385 filename = u"{name}-{checkpoint_id}{ext}".format(
399 386 name=basename,
400 387 checkpoint_id=checkpoint_id,
401 388 ext=self.filename_ext,
402 389 )
403 390 os_path = self._get_os_path(path=path)
404 391 cp_dir = os.path.join(os_path, self.checkpoint_dir)
405 if not os.path.exists(cp_dir):
406 os.mkdir(cp_dir)
392 ensure_dir_exists(cp_dir)
407 393 cp_path = os.path.join(cp_dir, filename)
408 394 return cp_path
409 395
410 396 def get_checkpoint_model(self, checkpoint_id, name, path=''):
411 397 """construct the info dict for a given checkpoint"""
412 398 path = path.strip('/')
413 399 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
414 400 stats = os.stat(cp_path)
415 401 last_modified = tz.utcfromtimestamp(stats.st_mtime)
416 402 info = dict(
417 403 id = checkpoint_id,
418 404 last_modified = last_modified,
419 405 )
420 406 return info
421 407
422 408 # public checkpoint API
423 409
424 410 def create_checkpoint(self, name, path=''):
425 411 """Create a checkpoint from the current state of a notebook"""
426 412 path = path.strip('/')
427 413 nb_path = self._get_os_path(name, path)
428 414 # only the one checkpoint ID:
429 415 checkpoint_id = u"checkpoint"
430 416 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
431 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 418 self._copy(nb_path, cp_path)
435 419
436 420 # return the checkpoint info
437 421 return self.get_checkpoint_model(checkpoint_id, name, path)
438 422
439 423 def list_checkpoints(self, name, path=''):
440 424 """list the checkpoints for a given notebook
441 425
442 426 This notebook manager currently only supports one checkpoint per notebook.
443 427 """
444 428 path = path.strip('/')
445 429 checkpoint_id = "checkpoint"
446 430 os_path = self.get_checkpoint_path(checkpoint_id, name, path)
447 431 if not os.path.exists(os_path):
448 432 return []
449 433 else:
450 434 return [self.get_checkpoint_model(checkpoint_id, name, path)]
451 435
452 436
453 437 def restore_checkpoint(self, checkpoint_id, name, path=''):
454 438 """restore a notebook to a checkpointed state"""
455 439 path = path.strip('/')
456 440 self.log.info("restoring Notebook %s from checkpoint %s", name, checkpoint_id)
457 441 nb_path = self._get_os_path(name, path)
458 442 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
459 443 if not os.path.isfile(cp_path):
460 444 self.log.debug("checkpoint file does not exist: %s", cp_path)
461 445 raise web.HTTPError(404,
462 446 u'Notebook checkpoint does not exist: %s-%s' % (name, checkpoint_id)
463 447 )
464 448 # ensure notebook is readable (never restore from an unreadable notebook)
465 449 with io.open(cp_path, 'r', encoding='utf-8') as f:
466 450 current.read(f, u'json')
467 451 self._copy(cp_path, nb_path)
468 452 self.log.debug("copying %s -> %s", cp_path, nb_path)
469 453
470 454 def delete_checkpoint(self, checkpoint_id, name, path=''):
471 455 """delete a notebook's checkpoint"""
472 456 path = path.strip('/')
473 457 cp_path = self.get_checkpoint_path(checkpoint_id, name, path)
474 458 if not os.path.isfile(cp_path):
475 459 raise web.HTTPError(404,
476 460 u'Notebook checkpoint does not exist: %s%s-%s' % (path, name, checkpoint_id)
477 461 )
478 462 self.log.debug("unlinking %s", cp_path)
479 463 os.unlink(cp_path)
480 464
481 465 def info_string(self):
482 466 return "Serving notebooks from local directory: %s" % self.notebook_dir
483 467
484 468 def get_kernel_path(self, name, path='', model=None):
485 469 """ Return the path to start kernel in """
486 470 return os.path.join(self.notebook_dir, path)
@@ -1,111 +1,111
1 1 """Contains writer for writing nbconvert output to filesystem."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import io
7 7 import os
8 8 import glob
9 9
10 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 12 from IPython.utils.py3compat import unicode_type
13 13
14 14 from .base import WriterBase
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Classes
18 18 #-----------------------------------------------------------------------------
19 19
20 20 class FilesWriter(WriterBase):
21 21 """Consumes nbconvert output and produces files."""
22 22
23 23
24 24 build_directory = Unicode("", config=True,
25 25 help="""Directory to write output to. Leave blank
26 26 to output to the current directory""")
27 27
28 28
29 29 # Make sure that the output directory exists.
30 30 def _build_directory_changed(self, name, old, new):
31 if new and not os.path.isdir(new):
32 os.makedirs(new)
31 if new:
32 ensure_dir_exists(new)
33 33
34 34
35 35 def __init__(self, **kw):
36 36 super(FilesWriter, self).__init__(**kw)
37 37 self._build_directory_changed('build_directory', self.build_directory,
38 38 self.build_directory)
39 39
40 40 def _makedir(self, path):
41 41 """Make a directory if it doesn't already exist"""
42 if path and not os.path.isdir(path):
42 if path:
43 43 self.log.info("Making directory %s", path)
44 os.makedirs(path)
44 ensure_dir_exists(path)
45 45
46 46 def write(self, output, resources, notebook_name=None, **kw):
47 47 """
48 48 Consume and write Jinja output to the file system. Output directory
49 49 is set via the 'build_directory' variable of this instance (a
50 50 configurable).
51 51
52 52 See base for more...
53 53 """
54 54
55 55 # Verify that a notebook name is provided.
56 56 if notebook_name is None:
57 57 raise TypeError('notebook_name')
58 58
59 59 # Pull the extension and subdir from the resources dict.
60 60 output_extension = resources.get('output_extension', None)
61 61
62 62 # Write all of the extracted resources to the destination directory.
63 63 # NOTE: WE WRITE EVERYTHING AS-IF IT'S BINARY. THE EXTRACT FIG
64 64 # PREPROCESSOR SHOULD HANDLE UNIX/WINDOWS LINE ENDINGS...
65 65 for filename, data in resources.get('outputs', {}).items():
66 66
67 67 # Determine where to write the file to
68 68 dest = os.path.join(self.build_directory, filename)
69 69 path = os.path.dirname(dest)
70 70 self._makedir(path)
71 71
72 72 # Write file
73 73 self.log.debug("Writing %i bytes to support file %s", len(data), dest)
74 74 with io.open(dest, 'wb') as f:
75 75 f.write(data)
76 76
77 77 # Copy referenced files to output directory
78 78 if self.build_directory:
79 79 for filename in self.files:
80 80
81 81 # Copy files that match search pattern
82 82 for matching_filename in glob.glob(filename):
83 83
84 84 # Make sure folder exists.
85 85 dest = os.path.join(self.build_directory, filename)
86 86 path = os.path.dirname(dest)
87 87 self._makedir(path)
88 88
89 89 # Copy if destination is different.
90 90 if not os.path.normpath(dest) == os.path.normpath(matching_filename):
91 91 self.log.info("Linking %s -> %s", matching_filename, dest)
92 92 link_or_copy(matching_filename, dest)
93 93
94 94 # Determine where to write conversion results.
95 95 if output_extension is not None:
96 96 dest = notebook_name + '.' + output_extension
97 97 else:
98 98 dest = notebook_name
99 99 if self.build_directory:
100 100 dest = os.path.join(self.build_directory, dest)
101 101
102 102 # Write conversion results.
103 103 self.log.info("Writing %i bytes to %s", len(output), dest)
104 104 if isinstance(output, unicode_type):
105 105 with io.open(dest, 'w', encoding='utf-8') as f:
106 106 f.write(output)
107 107 else:
108 108 with io.open(dest, 'wb') as f:
109 109 f.write(output)
110 110
111 111 return dest
@@ -1,1463 +1,1447
1 1 # encoding: utf-8
2 """
3 Facilities for launching IPython processes asynchronously.
2 """Facilities for launching IPython processes asynchronously."""
4 3
5 Authors:
6
7 * Brian Granger
8 * MinRK
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 #-----------------------------------------------------------------------------
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
21 6
22 7 import copy
23 8 import logging
24 9 import os
25 10 import pipes
26 11 import stat
27 12 import sys
28 13 import time
29 14
30 15 # signal imports, handling various platforms, versions
31 16
32 17 from signal import SIGINT, SIGTERM
33 18 try:
34 19 from signal import SIGKILL
35 20 except ImportError:
36 21 # Windows
37 22 SIGKILL=SIGTERM
38 23
39 24 try:
40 25 # Windows >= 2.7, 3.2
41 26 from signal import CTRL_C_EVENT as SIGINT
42 27 except ImportError:
43 28 pass
44 29
45 30 from subprocess import Popen, PIPE, STDOUT
46 31 try:
47 32 from subprocess import check_output
48 33 except ImportError:
49 34 # pre-2.7, define check_output with Popen
50 35 def check_output(*args, **kwargs):
51 36 kwargs.update(dict(stdout=PIPE))
52 37 p = Popen(*args, **kwargs)
53 38 out,err = p.communicate()
54 39 return out
55 40
56 41 from zmq.eventloop import ioloop
57 42
58 43 from IPython.config.application import Application
59 44 from IPython.config.configurable import LoggingConfigurable
60 45 from IPython.utils.text import EvalFormatter
61 46 from IPython.utils.traitlets import (
62 47 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
63 48 )
64 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 51 from IPython.utils.process import find_cmd, FindCmdError
67 52 from IPython.utils.py3compat import iteritems, itervalues
68 53
69 54 from .win32support import forward_read_events
70 55
71 56 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
72 57
73 58 WINDOWS = os.name == 'nt'
74 59
75 60 #-----------------------------------------------------------------------------
76 61 # Paths to the kernel apps
77 62 #-----------------------------------------------------------------------------
78 63
79 64 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
80 65
81 66 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
82 67
83 68 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
84 69
85 70 if WINDOWS and sys.version_info < (3,):
86 71 # `python -m package` doesn't work on Windows Python 2,
87 72 # but `python -m module` does.
88 73 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
89 74 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
90 75
91 76 #-----------------------------------------------------------------------------
92 77 # Base launchers and errors
93 78 #-----------------------------------------------------------------------------
94 79
95 80 class LauncherError(Exception):
96 81 pass
97 82
98 83
99 84 class ProcessStateError(LauncherError):
100 85 pass
101 86
102 87
103 88 class UnknownStatus(LauncherError):
104 89 pass
105 90
106 91
107 92 class BaseLauncher(LoggingConfigurable):
108 93 """An asbtraction for starting, stopping and signaling a process."""
109 94
110 95 # In all of the launchers, the work_dir is where child processes will be
111 96 # run. This will usually be the profile_dir, but may not be. any work_dir
112 97 # passed into the __init__ method will override the config value.
113 98 # This should not be used to set the work_dir for the actual engine
114 99 # and controller. Instead, use their own config files or the
115 100 # controller_args, engine_args attributes of the launchers to add
116 101 # the work_dir option.
117 102 work_dir = Unicode(u'.')
118 103 loop = Instance('zmq.eventloop.ioloop.IOLoop')
119 104
120 105 start_data = Any()
121 106 stop_data = Any()
122 107
123 108 def _loop_default(self):
124 109 return ioloop.IOLoop.instance()
125 110
126 111 def __init__(self, work_dir=u'.', config=None, **kwargs):
127 112 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
128 113 self.state = 'before' # can be before, running, after
129 114 self.stop_callbacks = []
130 115 self.start_data = None
131 116 self.stop_data = None
132 117
133 118 @property
134 119 def args(self):
135 120 """A list of cmd and args that will be used to start the process.
136 121
137 122 This is what is passed to :func:`spawnProcess` and the first element
138 123 will be the process name.
139 124 """
140 125 return self.find_args()
141 126
142 127 def find_args(self):
143 128 """The ``.args`` property calls this to find the args list.
144 129
145 130 Subcommand should implement this to construct the cmd and args.
146 131 """
147 132 raise NotImplementedError('find_args must be implemented in a subclass')
148 133
149 134 @property
150 135 def arg_str(self):
151 136 """The string form of the program arguments."""
152 137 return ' '.join(self.args)
153 138
154 139 @property
155 140 def running(self):
156 141 """Am I running."""
157 142 if self.state == 'running':
158 143 return True
159 144 else:
160 145 return False
161 146
162 147 def start(self):
163 148 """Start the process."""
164 149 raise NotImplementedError('start must be implemented in a subclass')
165 150
166 151 def stop(self):
167 152 """Stop the process and notify observers of stopping.
168 153
169 154 This method will return None immediately.
170 155 To observe the actual process stopping, see :meth:`on_stop`.
171 156 """
172 157 raise NotImplementedError('stop must be implemented in a subclass')
173 158
174 159 def on_stop(self, f):
175 160 """Register a callback to be called with this Launcher's stop_data
176 161 when the process actually finishes.
177 162 """
178 163 if self.state=='after':
179 164 return f(self.stop_data)
180 165 else:
181 166 self.stop_callbacks.append(f)
182 167
183 168 def notify_start(self, data):
184 169 """Call this to trigger startup actions.
185 170
186 171 This logs the process startup and sets the state to 'running'. It is
187 172 a pass-through so it can be used as a callback.
188 173 """
189 174
190 175 self.log.debug('Process %r started: %r', self.args[0], data)
191 176 self.start_data = data
192 177 self.state = 'running'
193 178 return data
194 179
195 180 def notify_stop(self, data):
196 181 """Call this to trigger process stop actions.
197 182
198 183 This logs the process stopping and sets the state to 'after'. Call
199 184 this to trigger callbacks registered via :meth:`on_stop`."""
200 185
201 186 self.log.debug('Process %r stopped: %r', self.args[0], data)
202 187 self.stop_data = data
203 188 self.state = 'after'
204 189 for i in range(len(self.stop_callbacks)):
205 190 d = self.stop_callbacks.pop()
206 191 d(data)
207 192 return data
208 193
209 194 def signal(self, sig):
210 195 """Signal the process.
211 196
212 197 Parameters
213 198 ----------
214 199 sig : str or int
215 200 'KILL', 'INT', etc., or any signal number
216 201 """
217 202 raise NotImplementedError('signal must be implemented in a subclass')
218 203
219 204 class ClusterAppMixin(HasTraits):
220 205 """MixIn for cluster args as traits"""
221 206 profile_dir=Unicode('')
222 207 cluster_id=Unicode('')
223 208
224 209 @property
225 210 def cluster_args(self):
226 211 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
227 212
228 213 class ControllerMixin(ClusterAppMixin):
229 214 controller_cmd = List(ipcontroller_cmd_argv, config=True,
230 215 help="""Popen command to launch ipcontroller.""")
231 216 # Command line arguments to ipcontroller.
232 217 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
233 218 help="""command-line args to pass to ipcontroller""")
234 219
235 220 class EngineMixin(ClusterAppMixin):
236 221 engine_cmd = List(ipengine_cmd_argv, config=True,
237 222 help="""command to launch the Engine.""")
238 223 # Command line arguments for ipengine.
239 224 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
240 225 help="command-line arguments to pass to ipengine"
241 226 )
242 227
243 228
244 229 #-----------------------------------------------------------------------------
245 230 # Local process launchers
246 231 #-----------------------------------------------------------------------------
247 232
248 233
249 234 class LocalProcessLauncher(BaseLauncher):
250 235 """Start and stop an external process in an asynchronous manner.
251 236
252 237 This will launch the external process with a working directory of
253 238 ``self.work_dir``.
254 239 """
255 240
256 241 # This is used to to construct self.args, which is passed to
257 242 # spawnProcess.
258 243 cmd_and_args = List([])
259 244 poll_frequency = Integer(100) # in ms
260 245
261 246 def __init__(self, work_dir=u'.', config=None, **kwargs):
262 247 super(LocalProcessLauncher, self).__init__(
263 248 work_dir=work_dir, config=config, **kwargs
264 249 )
265 250 self.process = None
266 251 self.poller = None
267 252
268 253 def find_args(self):
269 254 return self.cmd_and_args
270 255
271 256 def start(self):
272 257 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
273 258 if self.state == 'before':
274 259 self.process = Popen(self.args,
275 260 stdout=PIPE,stderr=PIPE,stdin=PIPE,
276 261 env=os.environ,
277 262 cwd=self.work_dir
278 263 )
279 264 if WINDOWS:
280 265 self.stdout = forward_read_events(self.process.stdout)
281 266 self.stderr = forward_read_events(self.process.stderr)
282 267 else:
283 268 self.stdout = self.process.stdout.fileno()
284 269 self.stderr = self.process.stderr.fileno()
285 270 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
286 271 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
287 272 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
288 273 self.poller.start()
289 274 self.notify_start(self.process.pid)
290 275 else:
291 276 s = 'The process was already started and has state: %r' % self.state
292 277 raise ProcessStateError(s)
293 278
294 279 def stop(self):
295 280 return self.interrupt_then_kill()
296 281
297 282 def signal(self, sig):
298 283 if self.state == 'running':
299 284 if WINDOWS and sig != SIGINT:
300 285 # use Windows tree-kill for better child cleanup
301 286 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
302 287 else:
303 288 self.process.send_signal(sig)
304 289
305 290 def interrupt_then_kill(self, delay=2.0):
306 291 """Send INT, wait a delay and then send KILL."""
307 292 try:
308 293 self.signal(SIGINT)
309 294 except Exception:
310 295 self.log.debug("interrupt failed")
311 296 pass
312 297 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
313 298 self.killer.start()
314 299
315 300 # callbacks, etc:
316 301
317 302 def handle_stdout(self, fd, events):
318 303 if WINDOWS:
319 304 line = self.stdout.recv()
320 305 else:
321 306 line = self.process.stdout.readline()
322 307 # a stopped process will be readable but return empty strings
323 308 if line:
324 309 self.log.debug(line[:-1])
325 310 else:
326 311 self.poll()
327 312
328 313 def handle_stderr(self, fd, events):
329 314 if WINDOWS:
330 315 line = self.stderr.recv()
331 316 else:
332 317 line = self.process.stderr.readline()
333 318 # a stopped process will be readable but return empty strings
334 319 if line:
335 320 self.log.debug(line[:-1])
336 321 else:
337 322 self.poll()
338 323
339 324 def poll(self):
340 325 status = self.process.poll()
341 326 if status is not None:
342 327 self.poller.stop()
343 328 self.loop.remove_handler(self.stdout)
344 329 self.loop.remove_handler(self.stderr)
345 330 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
346 331 return status
347 332
348 333 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
349 334 """Launch a controller as a regular external process."""
350 335
351 336 def find_args(self):
352 337 return self.controller_cmd + self.cluster_args + self.controller_args
353 338
354 339 def start(self):
355 340 """Start the controller by profile_dir."""
356 341 return super(LocalControllerLauncher, self).start()
357 342
358 343
359 344 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
360 345 """Launch a single engine as a regular externall process."""
361 346
362 347 def find_args(self):
363 348 return self.engine_cmd + self.cluster_args + self.engine_args
364 349
365 350
366 351 class LocalEngineSetLauncher(LocalEngineLauncher):
367 352 """Launch a set of engines as regular external processes."""
368 353
369 354 delay = CFloat(0.1, config=True,
370 355 help="""delay (in seconds) between starting each engine after the first.
371 356 This can help force the engines to get their ids in order, or limit
372 357 process flood when starting many engines."""
373 358 )
374 359
375 360 # launcher class
376 361 launcher_class = LocalEngineLauncher
377 362
378 363 launchers = Dict()
379 364 stop_data = Dict()
380 365
381 366 def __init__(self, work_dir=u'.', config=None, **kwargs):
382 367 super(LocalEngineSetLauncher, self).__init__(
383 368 work_dir=work_dir, config=config, **kwargs
384 369 )
385 370 self.stop_data = {}
386 371
387 372 def start(self, n):
388 373 """Start n engines by profile or profile_dir."""
389 374 dlist = []
390 375 for i in range(n):
391 376 if i > 0:
392 377 time.sleep(self.delay)
393 378 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
394 379 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
395 380 )
396 381
397 382 # Copy the engine args over to each engine launcher.
398 383 el.engine_cmd = copy.deepcopy(self.engine_cmd)
399 384 el.engine_args = copy.deepcopy(self.engine_args)
400 385 el.on_stop(self._notice_engine_stopped)
401 386 d = el.start()
402 387 self.launchers[i] = el
403 388 dlist.append(d)
404 389 self.notify_start(dlist)
405 390 return dlist
406 391
407 392 def find_args(self):
408 393 return ['engine set']
409 394
410 395 def signal(self, sig):
411 396 dlist = []
412 397 for el in itervalues(self.launchers):
413 398 d = el.signal(sig)
414 399 dlist.append(d)
415 400 return dlist
416 401
417 402 def interrupt_then_kill(self, delay=1.0):
418 403 dlist = []
419 404 for el in itervalues(self.launchers):
420 405 d = el.interrupt_then_kill(delay)
421 406 dlist.append(d)
422 407 return dlist
423 408
424 409 def stop(self):
425 410 return self.interrupt_then_kill()
426 411
427 412 def _notice_engine_stopped(self, data):
428 413 pid = data['pid']
429 414 for idx,el in iteritems(self.launchers):
430 415 if el.process.pid == pid:
431 416 break
432 417 self.launchers.pop(idx)
433 418 self.stop_data[idx] = data
434 419 if not self.launchers:
435 420 self.notify_stop(self.stop_data)
436 421
437 422
438 423 #-----------------------------------------------------------------------------
439 424 # MPI launchers
440 425 #-----------------------------------------------------------------------------
441 426
442 427
443 428 class MPILauncher(LocalProcessLauncher):
444 429 """Launch an external process using mpiexec."""
445 430
446 431 mpi_cmd = List(['mpiexec'], config=True,
447 432 help="The mpiexec command to use in starting the process."
448 433 )
449 434 mpi_args = List([], config=True,
450 435 help="The command line arguments to pass to mpiexec."
451 436 )
452 437 program = List(['date'],
453 438 help="The program to start via mpiexec.")
454 439 program_args = List([],
455 440 help="The command line argument to the program."
456 441 )
457 442 n = Integer(1)
458 443
459 444 def __init__(self, *args, **kwargs):
460 445 # deprecation for old MPIExec names:
461 446 config = kwargs.get('config', {})
462 447 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
463 448 deprecated = config.get(oldname)
464 449 if deprecated:
465 450 newname = oldname.replace('MPIExec', 'MPI')
466 451 config[newname].update(deprecated)
467 452 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
468 453
469 454 super(MPILauncher, self).__init__(*args, **kwargs)
470 455
471 456 def find_args(self):
472 457 """Build self.args using all the fields."""
473 458 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
474 459 self.program + self.program_args
475 460
476 461 def start(self, n):
477 462 """Start n instances of the program using mpiexec."""
478 463 self.n = n
479 464 return super(MPILauncher, self).start()
480 465
481 466
482 467 class MPIControllerLauncher(MPILauncher, ControllerMixin):
483 468 """Launch a controller using mpiexec."""
484 469
485 470 # alias back to *non-configurable* program[_args] for use in find_args()
486 471 # this way all Controller/EngineSetLaunchers have the same form, rather
487 472 # than *some* having `program_args` and others `controller_args`
488 473 @property
489 474 def program(self):
490 475 return self.controller_cmd
491 476
492 477 @property
493 478 def program_args(self):
494 479 return self.cluster_args + self.controller_args
495 480
496 481 def start(self):
497 482 """Start the controller by profile_dir."""
498 483 return super(MPIControllerLauncher, self).start(1)
499 484
500 485
501 486 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
502 487 """Launch engines using mpiexec"""
503 488
504 489 # alias back to *non-configurable* program[_args] for use in find_args()
505 490 # this way all Controller/EngineSetLaunchers have the same form, rather
506 491 # than *some* having `program_args` and others `controller_args`
507 492 @property
508 493 def program(self):
509 494 return self.engine_cmd
510 495
511 496 @property
512 497 def program_args(self):
513 498 return self.cluster_args + self.engine_args
514 499
515 500 def start(self, n):
516 501 """Start n engines by profile or profile_dir."""
517 502 self.n = n
518 503 return super(MPIEngineSetLauncher, self).start(n)
519 504
520 505 # deprecated MPIExec names
521 506 class DeprecatedMPILauncher(object):
522 507 def warn(self):
523 508 oldname = self.__class__.__name__
524 509 newname = oldname.replace('MPIExec', 'MPI')
525 510 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
526 511
527 512 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
528 513 """Deprecated, use MPILauncher"""
529 514 def __init__(self, *args, **kwargs):
530 515 super(MPIExecLauncher, self).__init__(*args, **kwargs)
531 516 self.warn()
532 517
533 518 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
534 519 """Deprecated, use MPIControllerLauncher"""
535 520 def __init__(self, *args, **kwargs):
536 521 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
537 522 self.warn()
538 523
539 524 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
540 525 """Deprecated, use MPIEngineSetLauncher"""
541 526 def __init__(self, *args, **kwargs):
542 527 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
543 528 self.warn()
544 529
545 530
546 531 #-----------------------------------------------------------------------------
547 532 # SSH launchers
548 533 #-----------------------------------------------------------------------------
549 534
550 535 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
551 536
552 537 class SSHLauncher(LocalProcessLauncher):
553 538 """A minimal launcher for ssh.
554 539
555 540 To be useful this will probably have to be extended to use the ``sshx``
556 541 idea for environment variables. There could be other things this needs
557 542 as well.
558 543 """
559 544
560 545 ssh_cmd = List(['ssh'], config=True,
561 546 help="command for starting ssh")
562 547 ssh_args = List(['-tt'], config=True,
563 548 help="args to pass to ssh")
564 549 scp_cmd = List(['scp'], config=True,
565 550 help="command for sending files")
566 551 program = List(['date'],
567 552 help="Program to launch via ssh")
568 553 program_args = List([],
569 554 help="args to pass to remote program")
570 555 hostname = Unicode('', config=True,
571 556 help="hostname on which to launch the program")
572 557 user = Unicode('', config=True,
573 558 help="username for ssh")
574 559 location = Unicode('', config=True,
575 560 help="user@hostname location for ssh in one setting")
576 561 to_fetch = List([], config=True,
577 562 help="List of (remote, local) files to fetch after starting")
578 563 to_send = List([], config=True,
579 564 help="List of (local, remote) files to send before starting")
580 565
581 566 def _hostname_changed(self, name, old, new):
582 567 if self.user:
583 568 self.location = u'%s@%s' % (self.user, new)
584 569 else:
585 570 self.location = new
586 571
587 572 def _user_changed(self, name, old, new):
588 573 self.location = u'%s@%s' % (new, self.hostname)
589 574
590 575 def find_args(self):
591 576 return self.ssh_cmd + self.ssh_args + [self.location] + \
592 577 list(map(pipes.quote, self.program + self.program_args))
593 578
594 579 def _send_file(self, local, remote):
595 580 """send a single file"""
596 581 full_remote = "%s:%s" % (self.location, remote)
597 582 for i in range(10):
598 583 if not os.path.exists(local):
599 584 self.log.debug("waiting for %s" % local)
600 585 time.sleep(1)
601 586 else:
602 587 break
603 588 remote_dir = os.path.dirname(remote)
604 589 self.log.info("ensuring remote %s:%s/ exists", self.location, remote_dir)
605 590 check_output(self.ssh_cmd + self.ssh_args + \
606 591 [self.location, 'mkdir', '-p', '--', remote_dir]
607 592 )
608 593 self.log.info("sending %s to %s", local, full_remote)
609 594 check_output(self.scp_cmd + [local, full_remote])
610 595
611 596 def send_files(self):
612 597 """send our files (called before start)"""
613 598 if not self.to_send:
614 599 return
615 600 for local_file, remote_file in self.to_send:
616 601 self._send_file(local_file, remote_file)
617 602
618 603 def _fetch_file(self, remote, local):
619 604 """fetch a single file"""
620 605 full_remote = "%s:%s" % (self.location, remote)
621 606 self.log.info("fetching %s from %s", local, full_remote)
622 607 for i in range(10):
623 608 # wait up to 10s for remote file to exist
624 609 check = check_output(self.ssh_cmd + self.ssh_args + \
625 610 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
626 611 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
627 612 if check == u'no':
628 613 time.sleep(1)
629 614 elif check == u'yes':
630 615 break
631 616 local_dir = os.path.dirname(local)
632 if not os.path.exists(local_dir):
633 os.makedirs(local_dir, 775)
617 ensure_dir_exists(local_dir, 775)
634 618 check_output(self.scp_cmd + [full_remote, local])
635 619
636 620 def fetch_files(self):
637 621 """fetch remote files (called after start)"""
638 622 if not self.to_fetch:
639 623 return
640 624 for remote_file, local_file in self.to_fetch:
641 625 self._fetch_file(remote_file, local_file)
642 626
643 627 def start(self, hostname=None, user=None):
644 628 if hostname is not None:
645 629 self.hostname = hostname
646 630 if user is not None:
647 631 self.user = user
648 632
649 633 self.send_files()
650 634 super(SSHLauncher, self).start()
651 635 self.fetch_files()
652 636
653 637 def signal(self, sig):
654 638 if self.state == 'running':
655 639 # send escaped ssh connection-closer
656 640 self.process.stdin.write('~.')
657 641 self.process.stdin.flush()
658 642
659 643 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
660 644
661 645 remote_profile_dir = Unicode('', config=True,
662 646 help="""The remote profile_dir to use.
663 647
664 648 If not specified, use calling profile, stripping out possible leading homedir.
665 649 """)
666 650
667 651 def _profile_dir_changed(self, name, old, new):
668 652 if not self.remote_profile_dir:
669 653 # trigger remote_profile_dir_default logic again,
670 654 # in case it was already triggered before profile_dir was set
671 655 self.remote_profile_dir = self._strip_home(new)
672 656
673 657 @staticmethod
674 658 def _strip_home(path):
675 659 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
676 660 home = get_home_dir()
677 661 if not home.endswith('/'):
678 662 home = home+'/'
679 663
680 664 if path.startswith(home):
681 665 return path[len(home):]
682 666 else:
683 667 return path
684 668
685 669 def _remote_profile_dir_default(self):
686 670 return self._strip_home(self.profile_dir)
687 671
688 672 def _cluster_id_changed(self, name, old, new):
689 673 if new:
690 674 raise ValueError("cluster id not supported by SSH launchers")
691 675
692 676 @property
693 677 def cluster_args(self):
694 678 return ['--profile-dir', self.remote_profile_dir]
695 679
696 680 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
697 681
698 682 # alias back to *non-configurable* program[_args] for use in find_args()
699 683 # this way all Controller/EngineSetLaunchers have the same form, rather
700 684 # than *some* having `program_args` and others `controller_args`
701 685
702 686 def _controller_cmd_default(self):
703 687 return ['ipcontroller']
704 688
705 689 @property
706 690 def program(self):
707 691 return self.controller_cmd
708 692
709 693 @property
710 694 def program_args(self):
711 695 return self.cluster_args + self.controller_args
712 696
713 697 def _to_fetch_default(self):
714 698 return [
715 699 (os.path.join(self.remote_profile_dir, 'security', cf),
716 700 os.path.join(self.profile_dir, 'security', cf),)
717 701 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
718 702 ]
719 703
720 704 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
721 705
722 706 # alias back to *non-configurable* program[_args] for use in find_args()
723 707 # this way all Controller/EngineSetLaunchers have the same form, rather
724 708 # than *some* having `program_args` and others `controller_args`
725 709
726 710 def _engine_cmd_default(self):
727 711 return ['ipengine']
728 712
729 713 @property
730 714 def program(self):
731 715 return self.engine_cmd
732 716
733 717 @property
734 718 def program_args(self):
735 719 return self.cluster_args + self.engine_args
736 720
737 721 def _to_send_default(self):
738 722 return [
739 723 (os.path.join(self.profile_dir, 'security', cf),
740 724 os.path.join(self.remote_profile_dir, 'security', cf))
741 725 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
742 726 ]
743 727
744 728
745 729 class SSHEngineSetLauncher(LocalEngineSetLauncher):
746 730 launcher_class = SSHEngineLauncher
747 731 engines = Dict(config=True,
748 732 help="""dict of engines to launch. This is a dict by hostname of ints,
749 733 corresponding to the number of engines to start on that host.""")
750 734
751 735 def _engine_cmd_default(self):
752 736 return ['ipengine']
753 737
754 738 @property
755 739 def engine_count(self):
756 740 """determine engine count from `engines` dict"""
757 741 count = 0
758 742 for n in itervalues(self.engines):
759 743 if isinstance(n, (tuple,list)):
760 744 n,args = n
761 745 count += n
762 746 return count
763 747
764 748 def start(self, n):
765 749 """Start engines by profile or profile_dir.
766 750 `n` is ignored, and the `engines` config property is used instead.
767 751 """
768 752
769 753 dlist = []
770 754 for host, n in iteritems(self.engines):
771 755 if isinstance(n, (tuple, list)):
772 756 n, args = n
773 757 else:
774 758 args = copy.deepcopy(self.engine_args)
775 759
776 760 if '@' in host:
777 761 user,host = host.split('@',1)
778 762 else:
779 763 user=None
780 764 for i in range(n):
781 765 if i > 0:
782 766 time.sleep(self.delay)
783 767 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
784 768 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
785 769 )
786 770 if i > 0:
787 771 # only send files for the first engine on each host
788 772 el.to_send = []
789 773
790 774 # Copy the engine args over to each engine launcher.
791 775 el.engine_cmd = self.engine_cmd
792 776 el.engine_args = args
793 777 el.on_stop(self._notice_engine_stopped)
794 778 d = el.start(user=user, hostname=host)
795 779 self.launchers[ "%s/%i" % (host,i) ] = el
796 780 dlist.append(d)
797 781 self.notify_start(dlist)
798 782 return dlist
799 783
800 784
801 785 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
802 786 """Launcher for calling
803 787 `ipcluster engines` on a remote machine.
804 788
805 789 Requires that remote profile is already configured.
806 790 """
807 791
808 792 n = Integer()
809 793 ipcluster_cmd = List(['ipcluster'], config=True)
810 794
811 795 @property
812 796 def program(self):
813 797 return self.ipcluster_cmd + ['engines']
814 798
815 799 @property
816 800 def program_args(self):
817 801 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
818 802
819 803 def _to_send_default(self):
820 804 return [
821 805 (os.path.join(self.profile_dir, 'security', cf),
822 806 os.path.join(self.remote_profile_dir, 'security', cf))
823 807 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
824 808 ]
825 809
826 810 def start(self, n):
827 811 self.n = n
828 812 super(SSHProxyEngineSetLauncher, self).start()
829 813
830 814
831 815 #-----------------------------------------------------------------------------
832 816 # Windows HPC Server 2008 scheduler launchers
833 817 #-----------------------------------------------------------------------------
834 818
835 819
836 820 # This is only used on Windows.
837 821 def find_job_cmd():
838 822 if WINDOWS:
839 823 try:
840 824 return find_cmd('job')
841 825 except (FindCmdError, ImportError):
842 826 # ImportError will be raised if win32api is not installed
843 827 return 'job'
844 828 else:
845 829 return 'job'
846 830
847 831
848 832 class WindowsHPCLauncher(BaseLauncher):
849 833
850 834 job_id_regexp = CRegExp(r'\d+', config=True,
851 835 help="""A regular expression used to get the job id from the output of the
852 836 submit_command. """
853 837 )
854 838 job_file_name = Unicode(u'ipython_job.xml', config=True,
855 839 help="The filename of the instantiated job script.")
856 840 # The full path to the instantiated job script. This gets made dynamically
857 841 # by combining the work_dir with the job_file_name.
858 842 job_file = Unicode(u'')
859 843 scheduler = Unicode('', config=True,
860 844 help="The hostname of the scheduler to submit the job to.")
861 845 job_cmd = Unicode(find_job_cmd(), config=True,
862 846 help="The command for submitting jobs.")
863 847
864 848 def __init__(self, work_dir=u'.', config=None, **kwargs):
865 849 super(WindowsHPCLauncher, self).__init__(
866 850 work_dir=work_dir, config=config, **kwargs
867 851 )
868 852
869 853 @property
870 854 def job_file(self):
871 855 return os.path.join(self.work_dir, self.job_file_name)
872 856
873 857 def write_job_file(self, n):
874 858 raise NotImplementedError("Implement write_job_file in a subclass.")
875 859
876 860 def find_args(self):
877 861 return [u'job.exe']
878 862
879 863 def parse_job_id(self, output):
880 864 """Take the output of the submit command and return the job id."""
881 865 m = self.job_id_regexp.search(output)
882 866 if m is not None:
883 867 job_id = m.group()
884 868 else:
885 869 raise LauncherError("Job id couldn't be determined: %s" % output)
886 870 self.job_id = job_id
887 871 self.log.info('Job started with id: %r', job_id)
888 872 return job_id
889 873
890 874 def start(self, n):
891 875 """Start n copies of the process using the Win HPC job scheduler."""
892 876 self.write_job_file(n)
893 877 args = [
894 878 'submit',
895 879 '/jobfile:%s' % self.job_file,
896 880 '/scheduler:%s' % self.scheduler
897 881 ]
898 882 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
899 883
900 884 output = check_output([self.job_cmd]+args,
901 885 env=os.environ,
902 886 cwd=self.work_dir,
903 887 stderr=STDOUT
904 888 )
905 889 output = output.decode(DEFAULT_ENCODING, 'replace')
906 890 job_id = self.parse_job_id(output)
907 891 self.notify_start(job_id)
908 892 return job_id
909 893
910 894 def stop(self):
911 895 args = [
912 896 'cancel',
913 897 self.job_id,
914 898 '/scheduler:%s' % self.scheduler
915 899 ]
916 900 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
917 901 try:
918 902 output = check_output([self.job_cmd]+args,
919 903 env=os.environ,
920 904 cwd=self.work_dir,
921 905 stderr=STDOUT
922 906 )
923 907 output = output.decode(DEFAULT_ENCODING, 'replace')
924 908 except:
925 909 output = u'The job already appears to be stopped: %r' % self.job_id
926 910 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
927 911 return output
928 912
929 913
930 914 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
931 915
932 916 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
933 917 help="WinHPC xml job file.")
934 918 controller_args = List([], config=False,
935 919 help="extra args to pass to ipcontroller")
936 920
937 921 def write_job_file(self, n):
938 922 job = IPControllerJob(parent=self)
939 923
940 924 t = IPControllerTask(parent=self)
941 925 # The tasks work directory is *not* the actual work directory of
942 926 # the controller. It is used as the base path for the stdout/stderr
943 927 # files that the scheduler redirects to.
944 928 t.work_directory = self.profile_dir
945 929 # Add the profile_dir and from self.start().
946 930 t.controller_args.extend(self.cluster_args)
947 931 t.controller_args.extend(self.controller_args)
948 932 job.add_task(t)
949 933
950 934 self.log.debug("Writing job description file: %s", self.job_file)
951 935 job.write(self.job_file)
952 936
953 937 @property
954 938 def job_file(self):
955 939 return os.path.join(self.profile_dir, self.job_file_name)
956 940
957 941 def start(self):
958 942 """Start the controller by profile_dir."""
959 943 return super(WindowsHPCControllerLauncher, self).start(1)
960 944
961 945
962 946 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
963 947
964 948 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
965 949 help="jobfile for ipengines job")
966 950 engine_args = List([], config=False,
967 951 help="extra args to pas to ipengine")
968 952
969 953 def write_job_file(self, n):
970 954 job = IPEngineSetJob(parent=self)
971 955
972 956 for i in range(n):
973 957 t = IPEngineTask(parent=self)
974 958 # The tasks work directory is *not* the actual work directory of
975 959 # the engine. It is used as the base path for the stdout/stderr
976 960 # files that the scheduler redirects to.
977 961 t.work_directory = self.profile_dir
978 962 # Add the profile_dir and from self.start().
979 963 t.engine_args.extend(self.cluster_args)
980 964 t.engine_args.extend(self.engine_args)
981 965 job.add_task(t)
982 966
983 967 self.log.debug("Writing job description file: %s", self.job_file)
984 968 job.write(self.job_file)
985 969
986 970 @property
987 971 def job_file(self):
988 972 return os.path.join(self.profile_dir, self.job_file_name)
989 973
990 974 def start(self, n):
991 975 """Start the controller by profile_dir."""
992 976 return super(WindowsHPCEngineSetLauncher, self).start(n)
993 977
994 978
995 979 #-----------------------------------------------------------------------------
996 980 # Batch (PBS) system launchers
997 981 #-----------------------------------------------------------------------------
998 982
999 983 class BatchClusterAppMixin(ClusterAppMixin):
1000 984 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
1001 985 def _profile_dir_changed(self, name, old, new):
1002 986 self.context[name] = new
1003 987 _cluster_id_changed = _profile_dir_changed
1004 988
1005 989 def _profile_dir_default(self):
1006 990 self.context['profile_dir'] = ''
1007 991 return ''
1008 992 def _cluster_id_default(self):
1009 993 self.context['cluster_id'] = ''
1010 994 return ''
1011 995
1012 996
1013 997 class BatchSystemLauncher(BaseLauncher):
1014 998 """Launch an external process using a batch system.
1015 999
1016 1000 This class is designed to work with UNIX batch systems like PBS, LSF,
1017 1001 GridEngine, etc. The overall model is that there are different commands
1018 1002 like qsub, qdel, etc. that handle the starting and stopping of the process.
1019 1003
1020 1004 This class also has the notion of a batch script. The ``batch_template``
1021 1005 attribute can be set to a string that is a template for the batch script.
1022 1006 This template is instantiated using string formatting. Thus the template can
1023 1007 use {n} fot the number of instances. Subclasses can add additional variables
1024 1008 to the template dict.
1025 1009 """
1026 1010
1027 1011 # Subclasses must fill these in. See PBSEngineSet
1028 1012 submit_command = List([''], config=True,
1029 1013 help="The name of the command line program used to submit jobs.")
1030 1014 delete_command = List([''], config=True,
1031 1015 help="The name of the command line program used to delete jobs.")
1032 1016 job_id_regexp = CRegExp('', config=True,
1033 1017 help="""A regular expression used to get the job id from the output of the
1034 1018 submit_command.""")
1035 1019 job_id_regexp_group = Integer(0, config=True,
1036 1020 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1037 1021 batch_template = Unicode('', config=True,
1038 1022 help="The string that is the batch script template itself.")
1039 1023 batch_template_file = Unicode(u'', config=True,
1040 1024 help="The file that contains the batch template.")
1041 1025 batch_file_name = Unicode(u'batch_script', config=True,
1042 1026 help="The filename of the instantiated batch script.")
1043 1027 queue = Unicode(u'', config=True,
1044 1028 help="The PBS Queue.")
1045 1029
1046 1030 def _queue_changed(self, name, old, new):
1047 1031 self.context[name] = new
1048 1032
1049 1033 n = Integer(1)
1050 1034 _n_changed = _queue_changed
1051 1035
1052 1036 # not configurable, override in subclasses
1053 1037 # PBS Job Array regex
1054 1038 job_array_regexp = CRegExp('')
1055 1039 job_array_template = Unicode('')
1056 1040 # PBS Queue regex
1057 1041 queue_regexp = CRegExp('')
1058 1042 queue_template = Unicode('')
1059 1043 # The default batch template, override in subclasses
1060 1044 default_template = Unicode('')
1061 1045 # The full path to the instantiated batch script.
1062 1046 batch_file = Unicode(u'')
1063 1047 # the format dict used with batch_template:
1064 1048 context = Dict()
1065 1049
1066 1050 def _context_default(self):
1067 1051 """load the default context with the default values for the basic keys
1068 1052
1069 1053 because the _trait_changed methods only load the context if they
1070 1054 are set to something other than the default value.
1071 1055 """
1072 1056 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1073 1057
1074 1058 # the Formatter instance for rendering the templates:
1075 1059 formatter = Instance(EvalFormatter, (), {})
1076 1060
1077 1061 def find_args(self):
1078 1062 return self.submit_command + [self.batch_file]
1079 1063
1080 1064 def __init__(self, work_dir=u'.', config=None, **kwargs):
1081 1065 super(BatchSystemLauncher, self).__init__(
1082 1066 work_dir=work_dir, config=config, **kwargs
1083 1067 )
1084 1068 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1085 1069
1086 1070 def parse_job_id(self, output):
1087 1071 """Take the output of the submit command and return the job id."""
1088 1072 m = self.job_id_regexp.search(output)
1089 1073 if m is not None:
1090 1074 job_id = m.group(self.job_id_regexp_group)
1091 1075 else:
1092 1076 raise LauncherError("Job id couldn't be determined: %s" % output)
1093 1077 self.job_id = job_id
1094 1078 self.log.info('Job submitted with job id: %r', job_id)
1095 1079 return job_id
1096 1080
1097 1081 def write_batch_script(self, n):
1098 1082 """Instantiate and write the batch script to the work_dir."""
1099 1083 self.n = n
1100 1084 # first priority is batch_template if set
1101 1085 if self.batch_template_file and not self.batch_template:
1102 1086 # second priority is batch_template_file
1103 1087 with open(self.batch_template_file) as f:
1104 1088 self.batch_template = f.read()
1105 1089 if not self.batch_template:
1106 1090 # third (last) priority is default_template
1107 1091 self.batch_template = self.default_template
1108 1092 # add jobarray or queue lines to user-specified template
1109 1093 # note that this is *only* when user did not specify a template.
1110 1094 self._insert_queue_in_script()
1111 1095 self._insert_job_array_in_script()
1112 1096 script_as_string = self.formatter.format(self.batch_template, **self.context)
1113 1097 self.log.debug('Writing batch script: %s', self.batch_file)
1114 1098 with open(self.batch_file, 'w') as f:
1115 1099 f.write(script_as_string)
1116 1100 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1117 1101
1118 1102 def _insert_queue_in_script(self):
1119 1103 """Inserts a queue if required into the batch script.
1120 1104 """
1121 1105 if self.queue and not self.queue_regexp.search(self.batch_template):
1122 1106 self.log.debug("adding PBS queue settings to batch script")
1123 1107 firstline, rest = self.batch_template.split('\n',1)
1124 1108 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1125 1109
1126 1110 def _insert_job_array_in_script(self):
1127 1111 """Inserts a job array if required into the batch script.
1128 1112 """
1129 1113 if not self.job_array_regexp.search(self.batch_template):
1130 1114 self.log.debug("adding job array settings to batch script")
1131 1115 firstline, rest = self.batch_template.split('\n',1)
1132 1116 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1133 1117
1134 1118 def start(self, n):
1135 1119 """Start n copies of the process using a batch system."""
1136 1120 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1137 1121 # Here we save profile_dir in the context so they
1138 1122 # can be used in the batch script template as {profile_dir}
1139 1123 self.write_batch_script(n)
1140 1124 output = check_output(self.args, env=os.environ)
1141 1125 output = output.decode(DEFAULT_ENCODING, 'replace')
1142 1126
1143 1127 job_id = self.parse_job_id(output)
1144 1128 self.notify_start(job_id)
1145 1129 return job_id
1146 1130
1147 1131 def stop(self):
1148 1132 try:
1149 1133 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1150 1134 stdout=PIPE, stderr=PIPE)
1151 1135 out, err = p.communicate()
1152 1136 output = out + err
1153 1137 except:
1154 1138 self.log.exception("Problem stopping cluster with command: %s" %
1155 1139 (self.delete_command + [self.job_id]))
1156 1140 output = ""
1157 1141 output = output.decode(DEFAULT_ENCODING, 'replace')
1158 1142 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1159 1143 return output
1160 1144
1161 1145
1162 1146 class PBSLauncher(BatchSystemLauncher):
1163 1147 """A BatchSystemLauncher subclass for PBS."""
1164 1148
1165 1149 submit_command = List(['qsub'], config=True,
1166 1150 help="The PBS submit command ['qsub']")
1167 1151 delete_command = List(['qdel'], config=True,
1168 1152 help="The PBS delete command ['qsub']")
1169 1153 job_id_regexp = CRegExp(r'\d+', config=True,
1170 1154 help="Regular expresion for identifying the job ID [r'\d+']")
1171 1155
1172 1156 batch_file = Unicode(u'')
1173 1157 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1174 1158 job_array_template = Unicode('#PBS -t 1-{n}')
1175 1159 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1176 1160 queue_template = Unicode('#PBS -q {queue}')
1177 1161
1178 1162
1179 1163 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1180 1164 """Launch a controller using PBS."""
1181 1165
1182 1166 batch_file_name = Unicode(u'pbs_controller', config=True,
1183 1167 help="batch file name for the controller job.")
1184 1168 default_template= Unicode("""#!/bin/sh
1185 1169 #PBS -V
1186 1170 #PBS -N ipcontroller
1187 1171 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1188 1172 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1189 1173
1190 1174 def start(self):
1191 1175 """Start the controller by profile or profile_dir."""
1192 1176 return super(PBSControllerLauncher, self).start(1)
1193 1177
1194 1178
1195 1179 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1196 1180 """Launch Engines using PBS"""
1197 1181 batch_file_name = Unicode(u'pbs_engines', config=True,
1198 1182 help="batch file name for the engine(s) job.")
1199 1183 default_template= Unicode(u"""#!/bin/sh
1200 1184 #PBS -V
1201 1185 #PBS -N ipengine
1202 1186 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1203 1187 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1204 1188
1205 1189
1206 1190 #SGE is very similar to PBS
1207 1191
1208 1192 class SGELauncher(PBSLauncher):
1209 1193 """Sun GridEngine is a PBS clone with slightly different syntax"""
1210 1194 job_array_regexp = CRegExp('#\$\W+\-t')
1211 1195 job_array_template = Unicode('#$ -t 1-{n}')
1212 1196 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1213 1197 queue_template = Unicode('#$ -q {queue}')
1214 1198
1215 1199
1216 1200 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1217 1201 """Launch a controller using SGE."""
1218 1202
1219 1203 batch_file_name = Unicode(u'sge_controller', config=True,
1220 1204 help="batch file name for the ipontroller job.")
1221 1205 default_template= Unicode(u"""#$ -V
1222 1206 #$ -S /bin/sh
1223 1207 #$ -N ipcontroller
1224 1208 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1225 1209 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1226 1210
1227 1211 def start(self):
1228 1212 """Start the controller by profile or profile_dir."""
1229 1213 return super(SGEControllerLauncher, self).start(1)
1230 1214
1231 1215
1232 1216 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1233 1217 """Launch Engines with SGE"""
1234 1218 batch_file_name = Unicode(u'sge_engines', config=True,
1235 1219 help="batch file name for the engine(s) job.")
1236 1220 default_template = Unicode("""#$ -V
1237 1221 #$ -S /bin/sh
1238 1222 #$ -N ipengine
1239 1223 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1240 1224 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1241 1225
1242 1226
1243 1227 # LSF launchers
1244 1228
1245 1229 class LSFLauncher(BatchSystemLauncher):
1246 1230 """A BatchSystemLauncher subclass for LSF."""
1247 1231
1248 1232 submit_command = List(['bsub'], config=True,
1249 1233 help="The PBS submit command ['bsub']")
1250 1234 delete_command = List(['bkill'], config=True,
1251 1235 help="The PBS delete command ['bkill']")
1252 1236 job_id_regexp = CRegExp(r'\d+', config=True,
1253 1237 help="Regular expresion for identifying the job ID [r'\d+']")
1254 1238
1255 1239 batch_file = Unicode(u'')
1256 1240 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1257 1241 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1258 1242 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1259 1243 queue_template = Unicode('#BSUB -q {queue}')
1260 1244
1261 1245 def start(self, n):
1262 1246 """Start n copies of the process using LSF batch system.
1263 1247 This cant inherit from the base class because bsub expects
1264 1248 to be piped a shell script in order to honor the #BSUB directives :
1265 1249 bsub < script
1266 1250 """
1267 1251 # Here we save profile_dir in the context so they
1268 1252 # can be used in the batch script template as {profile_dir}
1269 1253 self.write_batch_script(n)
1270 1254 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1271 1255 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1272 1256 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1273 1257 output,err = p.communicate()
1274 1258 output = output.decode(DEFAULT_ENCODING, 'replace')
1275 1259 job_id = self.parse_job_id(output)
1276 1260 self.notify_start(job_id)
1277 1261 return job_id
1278 1262
1279 1263
1280 1264 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1281 1265 """Launch a controller using LSF."""
1282 1266
1283 1267 batch_file_name = Unicode(u'lsf_controller', config=True,
1284 1268 help="batch file name for the controller job.")
1285 1269 default_template= Unicode("""#!/bin/sh
1286 1270 #BSUB -J ipcontroller
1287 1271 #BSUB -oo ipcontroller.o.%%J
1288 1272 #BSUB -eo ipcontroller.e.%%J
1289 1273 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1290 1274 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1291 1275
1292 1276 def start(self):
1293 1277 """Start the controller by profile or profile_dir."""
1294 1278 return super(LSFControllerLauncher, self).start(1)
1295 1279
1296 1280
1297 1281 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1298 1282 """Launch Engines using LSF"""
1299 1283 batch_file_name = Unicode(u'lsf_engines', config=True,
1300 1284 help="batch file name for the engine(s) job.")
1301 1285 default_template= Unicode(u"""#!/bin/sh
1302 1286 #BSUB -oo ipengine.o.%%J
1303 1287 #BSUB -eo ipengine.e.%%J
1304 1288 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1305 1289 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1306 1290
1307 1291
1308 1292
1309 1293 class HTCondorLauncher(BatchSystemLauncher):
1310 1294 """A BatchSystemLauncher subclass for HTCondor.
1311 1295
1312 1296 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1313 1297 that the python instance but otherwise is very similar to PBS. This is because
1314 1298 HTCondor destroys sys.executable when launching remote processes - a launched
1315 1299 python process depends on sys.executable to effectively evaluate its
1316 1300 module search paths. Without it, regardless of which python interpreter you launch
1317 1301 you will get the to built in module search paths.
1318 1302
1319 1303 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1320 1304 this - the mechanism of shebanged scripts means that the python binary will be
1321 1305 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1322 1306 scripts on the remote node*. This means you need to take care that:
1323 1307
1324 1308 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1325 1309 of the python environment you wish to execute code in having top precedence.
1326 1310 b. This functionality is untested on Windows.
1327 1311
1328 1312 If you need different behavior, consider making you own template.
1329 1313 """
1330 1314
1331 1315 submit_command = List(['condor_submit'], config=True,
1332 1316 help="The HTCondor submit command ['condor_submit']")
1333 1317 delete_command = List(['condor_rm'], config=True,
1334 1318 help="The HTCondor delete command ['condor_rm']")
1335 1319 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1336 1320 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1337 1321 job_id_regexp_group = Integer(1, config=True,
1338 1322 help="""The group we wish to match in job_id_regexp [1]""")
1339 1323
1340 1324 job_array_regexp = CRegExp('queue\W+\$')
1341 1325 job_array_template = Unicode('queue {n}')
1342 1326
1343 1327
1344 1328 def _insert_job_array_in_script(self):
1345 1329 """Inserts a job array if required into the batch script.
1346 1330 """
1347 1331 if not self.job_array_regexp.search(self.batch_template):
1348 1332 self.log.debug("adding job array settings to batch script")
1349 1333 #HTCondor requires that the job array goes at the bottom of the script
1350 1334 self.batch_template = '\n'.join([self.batch_template,
1351 1335 self.job_array_template])
1352 1336
1353 1337 def _insert_queue_in_script(self):
1354 1338 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1355 1339 specified in the script.
1356 1340 """
1357 1341 pass
1358 1342
1359 1343
1360 1344 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1361 1345 """Launch a controller using HTCondor."""
1362 1346
1363 1347 batch_file_name = Unicode(u'htcondor_controller', config=True,
1364 1348 help="batch file name for the controller job.")
1365 1349 default_template = Unicode(r"""
1366 1350 universe = vanilla
1367 1351 executable = ipcontroller
1368 1352 # by default we expect a shared file system
1369 1353 transfer_executable = False
1370 1354 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1371 1355 """)
1372 1356
1373 1357 def start(self):
1374 1358 """Start the controller by profile or profile_dir."""
1375 1359 return super(HTCondorControllerLauncher, self).start(1)
1376 1360
1377 1361
1378 1362 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1379 1363 """Launch Engines using HTCondor"""
1380 1364 batch_file_name = Unicode(u'htcondor_engines', config=True,
1381 1365 help="batch file name for the engine(s) job.")
1382 1366 default_template = Unicode("""
1383 1367 universe = vanilla
1384 1368 executable = ipengine
1385 1369 # by default we expect a shared file system
1386 1370 transfer_executable = False
1387 1371 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1388 1372 """)
1389 1373
1390 1374
1391 1375 #-----------------------------------------------------------------------------
1392 1376 # A launcher for ipcluster itself!
1393 1377 #-----------------------------------------------------------------------------
1394 1378
1395 1379
1396 1380 class IPClusterLauncher(LocalProcessLauncher):
1397 1381 """Launch the ipcluster program in an external process."""
1398 1382
1399 1383 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1400 1384 help="Popen command for ipcluster")
1401 1385 ipcluster_args = List(
1402 1386 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1403 1387 help="Command line arguments to pass to ipcluster.")
1404 1388 ipcluster_subcommand = Unicode('start')
1405 1389 profile = Unicode('default')
1406 1390 n = Integer(2)
1407 1391
1408 1392 def find_args(self):
1409 1393 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1410 1394 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1411 1395 self.ipcluster_args
1412 1396
1413 1397 def start(self):
1414 1398 return super(IPClusterLauncher, self).start()
1415 1399
1416 1400 #-----------------------------------------------------------------------------
1417 1401 # Collections of launchers
1418 1402 #-----------------------------------------------------------------------------
1419 1403
1420 1404 local_launchers = [
1421 1405 LocalControllerLauncher,
1422 1406 LocalEngineLauncher,
1423 1407 LocalEngineSetLauncher,
1424 1408 ]
1425 1409 mpi_launchers = [
1426 1410 MPILauncher,
1427 1411 MPIControllerLauncher,
1428 1412 MPIEngineSetLauncher,
1429 1413 ]
1430 1414 ssh_launchers = [
1431 1415 SSHLauncher,
1432 1416 SSHControllerLauncher,
1433 1417 SSHEngineLauncher,
1434 1418 SSHEngineSetLauncher,
1435 1419 SSHProxyEngineSetLauncher,
1436 1420 ]
1437 1421 winhpc_launchers = [
1438 1422 WindowsHPCLauncher,
1439 1423 WindowsHPCControllerLauncher,
1440 1424 WindowsHPCEngineSetLauncher,
1441 1425 ]
1442 1426 pbs_launchers = [
1443 1427 PBSLauncher,
1444 1428 PBSControllerLauncher,
1445 1429 PBSEngineSetLauncher,
1446 1430 ]
1447 1431 sge_launchers = [
1448 1432 SGELauncher,
1449 1433 SGEControllerLauncher,
1450 1434 SGEEngineSetLauncher,
1451 1435 ]
1452 1436 lsf_launchers = [
1453 1437 LSFLauncher,
1454 1438 LSFControllerLauncher,
1455 1439 LSFEngineSetLauncher,
1456 1440 ]
1457 1441 htcondor_launchers = [
1458 1442 HTCondorLauncher,
1459 1443 HTCondorControllerLauncher,
1460 1444 HTCondorEngineSetLauncher,
1461 1445 ]
1462 1446 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1463 1447 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
@@ -1,343 +1,335
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2010, IPython Development Team.
3 #
1 # Copyright (c) IPython Development Team.
4 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 4 from base64 import decodestring
11 5 import os
12 6 import re
13 7
14 # System libary imports.
15 8 from IPython.external.qt import QtCore, QtGui
16 9
17 # Local imports
10 from IPython.utils.path import ensure_dir_exists
18 11 from IPython.utils.traitlets import Bool
19 12 from IPython.qt.svg import save_svg, svg_to_clipboard, svg_to_image
20 13 from .ipython_widget import IPythonWidget
21 14
22 15
23 16 class RichIPythonWidget(IPythonWidget):
24 17 """ An IPythonWidget that supports rich text, including lists, images, and
25 18 tables. Note that raw performance will be reduced compared to the plain
26 19 text version.
27 20 """
28 21
29 22 # RichIPythonWidget protected class variables.
30 23 _payload_source_plot = 'IPython.kernel.zmq.pylab.backend_payload.add_plot_payload'
31 24 _jpg_supported = Bool(False)
32 25
33 26 # Used to determine whether a given html export attempt has already
34 27 # displayed a warning about being unable to convert a png to svg.
35 28 _svg_warning_displayed = False
36 29
37 30 #---------------------------------------------------------------------------
38 31 # 'object' interface
39 32 #---------------------------------------------------------------------------
40 33
41 34 def __init__(self, *args, **kw):
42 35 """ Create a RichIPythonWidget.
43 36 """
44 37 kw['kind'] = 'rich'
45 38 super(RichIPythonWidget, self).__init__(*args, **kw)
46 39
47 40 # Configure the ConsoleWidget HTML exporter for our formats.
48 41 self._html_exporter.image_tag = self._get_image_tag
49 42
50 43 # Dictionary for resolving document resource names to SVG data.
51 44 self._name_to_svg_map = {}
52 45
53 46 # Do we support jpg ?
54 47 # it seems that sometime jpg support is a plugin of QT, so try to assume
55 48 # it is not always supported.
56 49 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
57 50 self._jpg_supported = 'jpeg' in _supported_format
58 51
59 52
60 53 #---------------------------------------------------------------------------
61 54 # 'ConsoleWidget' public interface overides
62 55 #---------------------------------------------------------------------------
63 56
64 57 def export_html(self):
65 58 """ Shows a dialog to export HTML/XML in various formats.
66 59
67 60 Overridden in order to reset the _svg_warning_displayed flag prior
68 61 to the export running.
69 62 """
70 63 self._svg_warning_displayed = False
71 64 super(RichIPythonWidget, self).export_html()
72 65
73 66
74 67 #---------------------------------------------------------------------------
75 68 # 'ConsoleWidget' protected interface
76 69 #---------------------------------------------------------------------------
77 70
78 71 def _context_menu_make(self, pos):
79 72 """ Reimplemented to return a custom context menu for images.
80 73 """
81 74 format = self._control.cursorForPosition(pos).charFormat()
82 75 name = format.stringProperty(QtGui.QTextFormat.ImageName)
83 76 if name:
84 77 menu = QtGui.QMenu()
85 78
86 79 menu.addAction('Copy Image', lambda: self._copy_image(name))
87 80 menu.addAction('Save Image As...', lambda: self._save_image(name))
88 81 menu.addSeparator()
89 82
90 83 svg = self._name_to_svg_map.get(name, None)
91 84 if svg is not None:
92 85 menu.addSeparator()
93 86 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
94 87 menu.addAction('Save SVG As...',
95 88 lambda: save_svg(svg, self._control))
96 89 else:
97 90 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
98 91 return menu
99 92
100 93 #---------------------------------------------------------------------------
101 94 # 'BaseFrontendMixin' abstract interface
102 95 #---------------------------------------------------------------------------
103 96 def _pre_image_append(self, msg, prompt_number):
104 97 """ Append the Out[] prompt and make the output nicer
105 98
106 99 Shared code for some the following if statement
107 100 """
108 101 self.log.debug("pyout: %s", msg.get('content', ''))
109 102 self._append_plain_text(self.output_sep, True)
110 103 self._append_html(self._make_out_prompt(prompt_number), True)
111 104 self._append_plain_text('\n', True)
112 105
113 106 def _handle_pyout(self, msg):
114 107 """ Overridden to handle rich data types, like SVG.
115 108 """
116 109 if not self._hidden and self._is_from_this_session(msg):
117 110 self.flush_clearoutput()
118 111 content = msg['content']
119 112 prompt_number = content.get('execution_count', 0)
120 113 data = content['data']
121 114 metadata = msg['content']['metadata']
122 115 if 'image/svg+xml' in data:
123 116 self._pre_image_append(msg, prompt_number)
124 117 self._append_svg(data['image/svg+xml'], True)
125 118 self._append_html(self.output_sep2, True)
126 119 elif 'image/png' in data:
127 120 self._pre_image_append(msg, prompt_number)
128 121 png = decodestring(data['image/png'].encode('ascii'))
129 122 self._append_png(png, True, metadata=metadata.get('image/png', None))
130 123 self._append_html(self.output_sep2, True)
131 124 elif 'image/jpeg' in data and self._jpg_supported:
132 125 self._pre_image_append(msg, prompt_number)
133 126 jpg = decodestring(data['image/jpeg'].encode('ascii'))
134 127 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
135 128 self._append_html(self.output_sep2, True)
136 129 else:
137 130 # Default back to the plain text representation.
138 131 return super(RichIPythonWidget, self)._handle_pyout(msg)
139 132
140 133 def _handle_display_data(self, msg):
141 134 """ Overridden to handle rich data types, like SVG.
142 135 """
143 136 if not self._hidden and self._is_from_this_session(msg):
144 137 self.flush_clearoutput()
145 138 source = msg['content']['source']
146 139 data = msg['content']['data']
147 140 metadata = msg['content']['metadata']
148 141 # Try to use the svg or html representations.
149 142 # FIXME: Is this the right ordering of things to try?
150 143 if 'image/svg+xml' in data:
151 144 self.log.debug("display: %s", msg.get('content', ''))
152 145 svg = data['image/svg+xml']
153 146 self._append_svg(svg, True)
154 147 elif 'image/png' in data:
155 148 self.log.debug("display: %s", msg.get('content', ''))
156 149 # PNG data is base64 encoded as it passes over the network
157 150 # in a JSON structure so we decode it.
158 151 png = decodestring(data['image/png'].encode('ascii'))
159 152 self._append_png(png, True, metadata=metadata.get('image/png', None))
160 153 elif 'image/jpeg' in data and self._jpg_supported:
161 154 self.log.debug("display: %s", msg.get('content', ''))
162 155 jpg = decodestring(data['image/jpeg'].encode('ascii'))
163 156 self._append_jpg(jpg, True, metadata=metadata.get('image/jpeg', None))
164 157 else:
165 158 # Default back to the plain text representation.
166 159 return super(RichIPythonWidget, self)._handle_display_data(msg)
167 160
168 161 #---------------------------------------------------------------------------
169 162 # 'RichIPythonWidget' protected interface
170 163 #---------------------------------------------------------------------------
171 164
172 165 def _append_jpg(self, jpg, before_prompt=False, metadata=None):
173 166 """ Append raw JPG data to the widget."""
174 167 self._append_custom(self._insert_jpg, jpg, before_prompt, metadata=metadata)
175 168
176 169 def _append_png(self, png, before_prompt=False, metadata=None):
177 170 """ Append raw PNG data to the widget.
178 171 """
179 172 self._append_custom(self._insert_png, png, before_prompt, metadata=metadata)
180 173
181 174 def _append_svg(self, svg, before_prompt=False):
182 175 """ Append raw SVG data to the widget.
183 176 """
184 177 self._append_custom(self._insert_svg, svg, before_prompt)
185 178
186 179 def _add_image(self, image):
187 180 """ Adds the specified QImage to the document and returns a
188 181 QTextImageFormat that references it.
189 182 """
190 183 document = self._control.document()
191 184 name = str(image.cacheKey())
192 185 document.addResource(QtGui.QTextDocument.ImageResource,
193 186 QtCore.QUrl(name), image)
194 187 format = QtGui.QTextImageFormat()
195 188 format.setName(name)
196 189 return format
197 190
198 191 def _copy_image(self, name):
199 192 """ Copies the ImageResource with 'name' to the clipboard.
200 193 """
201 194 image = self._get_image(name)
202 195 QtGui.QApplication.clipboard().setImage(image)
203 196
204 197 def _get_image(self, name):
205 198 """ Returns the QImage stored as the ImageResource with 'name'.
206 199 """
207 200 document = self._control.document()
208 201 image = document.resource(QtGui.QTextDocument.ImageResource,
209 202 QtCore.QUrl(name))
210 203 return image
211 204
212 205 def _get_image_tag(self, match, path = None, format = "png"):
213 206 """ Return (X)HTML mark-up for the image-tag given by match.
214 207
215 208 Parameters
216 209 ----------
217 210 match : re.SRE_Match
218 211 A match to an HTML image tag as exported by Qt, with
219 212 match.group("Name") containing the matched image ID.
220 213
221 214 path : string|None, optional [default None]
222 215 If not None, specifies a path to which supporting files may be
223 216 written (e.g., for linked images). If None, all images are to be
224 217 included inline.
225 218
226 219 format : "png"|"svg"|"jpg", optional [default "png"]
227 220 Format for returned or referenced images.
228 221 """
229 222 if format in ("png","jpg"):
230 223 try:
231 224 image = self._get_image(match.group("name"))
232 225 except KeyError:
233 226 return "<b>Couldn't find image %s</b>" % match.group("name")
234 227
235 228 if path is not None:
236 if not os.path.exists(path):
237 os.mkdir(path)
229 ensure_dir_exists(path)
238 230 relpath = os.path.basename(path)
239 231 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
240 232 "PNG"):
241 233 return '<img src="%s/qt_img%s.%s">' % (relpath,
242 234 match.group("name"),format)
243 235 else:
244 236 return "<b>Couldn't save image!</b>"
245 237 else:
246 238 ba = QtCore.QByteArray()
247 239 buffer_ = QtCore.QBuffer(ba)
248 240 buffer_.open(QtCore.QIODevice.WriteOnly)
249 241 image.save(buffer_, format.upper())
250 242 buffer_.close()
251 243 return '<img src="data:image/%s;base64,\n%s\n" />' % (
252 244 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
253 245
254 246 elif format == "svg":
255 247 try:
256 248 svg = str(self._name_to_svg_map[match.group("name")])
257 249 except KeyError:
258 250 if not self._svg_warning_displayed:
259 251 QtGui.QMessageBox.warning(self, 'Error converting PNG to SVG.',
260 252 'Cannot convert PNG images to SVG, export with PNG figures instead. '
261 253 'If you want to export matplotlib figures as SVG, add '
262 254 'to your ipython config:\n\n'
263 255 '\tc.InlineBackend.figure_format = \'svg\'\n\n'
264 256 'And regenerate the figures.',
265 257 QtGui.QMessageBox.Ok)
266 258 self._svg_warning_displayed = True
267 259 return ("<b>Cannot convert PNG images to SVG.</b> "
268 260 "You must export this session with PNG images. "
269 261 "If you want to export matplotlib figures as SVG, add to your config "
270 262 "<span>c.InlineBackend.figure_format = 'svg'</span> "
271 263 "and regenerate the figures.")
272 264
273 265 # Not currently checking path, because it's tricky to find a
274 266 # cross-browser way to embed external SVG images (e.g., via
275 267 # object or embed tags).
276 268
277 269 # Chop stand-alone header from matplotlib SVG
278 270 offset = svg.find("<svg")
279 271 assert(offset > -1)
280 272
281 273 return svg[offset:]
282 274
283 275 else:
284 276 return '<b>Unrecognized image format</b>'
285 277
286 278 def _insert_jpg(self, cursor, jpg, metadata=None):
287 279 """ Insert raw PNG data into the widget."""
288 280 self._insert_img(cursor, jpg, 'jpg', metadata=metadata)
289 281
290 282 def _insert_png(self, cursor, png, metadata=None):
291 283 """ Insert raw PNG data into the widget.
292 284 """
293 285 self._insert_img(cursor, png, 'png', metadata=metadata)
294 286
295 287 def _insert_img(self, cursor, img, fmt, metadata=None):
296 288 """ insert a raw image, jpg or png """
297 289 if metadata:
298 290 width = metadata.get('width', None)
299 291 height = metadata.get('height', None)
300 292 else:
301 293 width = height = None
302 294 try:
303 295 image = QtGui.QImage()
304 296 image.loadFromData(img, fmt.upper())
305 297 if width and height:
306 298 image = image.scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
307 299 elif width and not height:
308 300 image = image.scaledToWidth(width, transformMode=QtCore.Qt.SmoothTransformation)
309 301 elif height and not width:
310 302 image = image.scaledToHeight(height, transformMode=QtCore.Qt.SmoothTransformation)
311 303 except ValueError:
312 304 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
313 305 else:
314 306 format = self._add_image(image)
315 307 cursor.insertBlock()
316 308 cursor.insertImage(format)
317 309 cursor.insertBlock()
318 310
319 311 def _insert_svg(self, cursor, svg):
320 312 """ Insert raw SVG data into the widet.
321 313 """
322 314 try:
323 315 image = svg_to_image(svg)
324 316 except ValueError:
325 317 self._insert_plain_text(cursor, 'Received invalid SVG data.')
326 318 else:
327 319 format = self._add_image(image)
328 320 self._name_to_svg_map[format.name()] = svg
329 321 cursor.insertBlock()
330 322 cursor.insertImage(format)
331 323 cursor.insertBlock()
332 324
333 325 def _save_image(self, name, format='PNG'):
334 326 """ Shows a save dialog for the ImageResource with 'name'.
335 327 """
336 328 dialog = QtGui.QFileDialog(self._control, 'Save Image')
337 329 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
338 330 dialog.setDefaultSuffix(format.lower())
339 331 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
340 332 if dialog.exec_():
341 333 filename = dialog.selectedFiles()[0]
342 334 image = self._get_image(name)
343 335 image.save(filename, format)
@@ -1,574 +1,580
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for path handling.
4 4 """
5 5
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
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 #-----------------------------------------------------------------------------
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
16 8
17 9 import os
18 10 import sys
19 11 import errno
20 12 import shutil
21 13 import random
22 14 import tempfile
23 15 import warnings
24 16 from hashlib import md5
25 17 import glob
26 18
27 19 import IPython
28 20 from IPython.testing.skipdoctest import skip_doctest
29 21 from IPython.utils.process import system
30 22 from IPython.utils.importstring import import_item
31 23 from IPython.utils import py3compat
32 24 #-----------------------------------------------------------------------------
33 25 # Code
34 26 #-----------------------------------------------------------------------------
35 27
36 28 fs_encoding = sys.getfilesystemencoding()
37 29
38 30 def _get_long_path_name(path):
39 31 """Dummy no-op."""
40 32 return path
41 33
42 34 def _writable_dir(path):
43 35 """Whether `path` is a directory, to which the user has write access."""
44 36 return os.path.isdir(path) and os.access(path, os.W_OK)
45 37
46 38 if sys.platform == 'win32':
47 39 @skip_doctest
48 40 def _get_long_path_name(path):
49 41 """Get a long path name (expand ~) on Windows using ctypes.
50 42
51 43 Examples
52 44 --------
53 45
54 46 >>> get_long_path_name('c:\\docume~1')
55 47 u'c:\\\\Documents and Settings'
56 48
57 49 """
58 50 try:
59 51 import ctypes
60 52 except ImportError:
61 53 raise ImportError('you need to have ctypes installed for this to work')
62 54 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
63 55 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
64 56 ctypes.c_uint ]
65 57
66 58 buf = ctypes.create_unicode_buffer(260)
67 59 rv = _GetLongPathName(path, buf, 260)
68 60 if rv == 0 or rv > 260:
69 61 return path
70 62 else:
71 63 return buf.value
72 64
73 65
74 66 def get_long_path_name(path):
75 67 """Expand a path into its long form.
76 68
77 69 On Windows this expands any ~ in the paths. On other platforms, it is
78 70 a null operation.
79 71 """
80 72 return _get_long_path_name(path)
81 73
82 74
83 75 def unquote_filename(name, win32=(sys.platform=='win32')):
84 76 """ On Windows, remove leading and trailing quotes from filenames.
85 77 """
86 78 if win32:
87 79 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
88 80 name = name[1:-1]
89 81 return name
90 82
91 83 def compress_user(path):
92 84 """Reverse of :func:`os.path.expanduser`
93 85 """
94 86 home = os.path.expanduser('~')
95 87 if path.startswith(home):
96 88 path = "~" + path[len(home):]
97 89 return path
98 90
99 91 def get_py_filename(name, force_win32=None):
100 92 """Return a valid python filename in the current directory.
101 93
102 94 If the given name is not a file, it adds '.py' and searches again.
103 95 Raises IOError with an informative message if the file isn't found.
104 96
105 97 On Windows, apply Windows semantics to the filename. In particular, remove
106 98 any quoting that has been applied to it. This option can be forced for
107 99 testing purposes.
108 100 """
109 101
110 102 name = os.path.expanduser(name)
111 103 if force_win32 is None:
112 104 win32 = (sys.platform == 'win32')
113 105 else:
114 106 win32 = force_win32
115 107 name = unquote_filename(name, win32=win32)
116 108 if not os.path.isfile(name) and not name.endswith('.py'):
117 109 name += '.py'
118 110 if os.path.isfile(name):
119 111 return name
120 112 else:
121 113 raise IOError('File `%r` not found.' % name)
122 114
123 115
124 116 def filefind(filename, path_dirs=None):
125 117 """Find a file by looking through a sequence of paths.
126 118
127 119 This iterates through a sequence of paths looking for a file and returns
128 120 the full, absolute path of the first occurence of the file. If no set of
129 121 path dirs is given, the filename is tested as is, after running through
130 122 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
131 123
132 124 filefind('myfile.txt')
133 125
134 126 will find the file in the current working dir, but::
135 127
136 128 filefind('~/myfile.txt')
137 129
138 130 Will find the file in the users home directory. This function does not
139 131 automatically try any paths, such as the cwd or the user's home directory.
140 132
141 133 Parameters
142 134 ----------
143 135 filename : str
144 136 The filename to look for.
145 137 path_dirs : str, None or sequence of str
146 138 The sequence of paths to look for the file in. If None, the filename
147 139 need to be absolute or be in the cwd. If a string, the string is
148 140 put into a sequence and the searched. If a sequence, walk through
149 141 each element and join with ``filename``, calling :func:`expandvars`
150 142 and :func:`expanduser` before testing for existence.
151 143
152 144 Returns
153 145 -------
154 146 Raises :exc:`IOError` or returns absolute path to file.
155 147 """
156 148
157 149 # If paths are quoted, abspath gets confused, strip them...
158 150 filename = filename.strip('"').strip("'")
159 151 # If the input is an absolute path, just check it exists
160 152 if os.path.isabs(filename) and os.path.isfile(filename):
161 153 return filename
162 154
163 155 if path_dirs is None:
164 156 path_dirs = ("",)
165 157 elif isinstance(path_dirs, py3compat.string_types):
166 158 path_dirs = (path_dirs,)
167 159
168 160 for path in path_dirs:
169 161 if path == '.': path = py3compat.getcwd()
170 162 testname = expand_path(os.path.join(path, filename))
171 163 if os.path.isfile(testname):
172 164 return os.path.abspath(testname)
173 165
174 166 raise IOError("File %r does not exist in any of the search paths: %r" %
175 167 (filename, path_dirs) )
176 168
177 169
178 170 class HomeDirError(Exception):
179 171 pass
180 172
181 173
182 174 def get_home_dir(require_writable=False):
183 175 """Return the 'home' directory, as a unicode string.
184 176
185 177 Uses os.path.expanduser('~'), and checks for writability.
186 178
187 179 See stdlib docs for how this is determined.
188 180 $HOME is first priority on *ALL* platforms.
189 181
190 182 Parameters
191 183 ----------
192 184
193 185 require_writable : bool [default: False]
194 186 if True:
195 187 guarantees the return value is a writable directory, otherwise
196 188 raises HomeDirError
197 189 if False:
198 190 The path is resolved, but it is not guaranteed to exist or be writable.
199 191 """
200 192
201 193 homedir = os.path.expanduser('~')
202 194 # Next line will make things work even when /home/ is a symlink to
203 195 # /usr/home as it is on FreeBSD, for example
204 196 homedir = os.path.realpath(homedir)
205 197
206 198 if not _writable_dir(homedir) and os.name == 'nt':
207 199 # expanduser failed, use the registry to get the 'My Documents' folder.
208 200 try:
209 201 try:
210 202 import winreg as wreg # Py 3
211 203 except ImportError:
212 204 import _winreg as wreg # Py 2
213 205 key = wreg.OpenKey(
214 206 wreg.HKEY_CURRENT_USER,
215 207 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
216 208 )
217 209 homedir = wreg.QueryValueEx(key,'Personal')[0]
218 210 key.Close()
219 211 except:
220 212 pass
221 213
222 214 if (not require_writable) or _writable_dir(homedir):
223 215 return py3compat.cast_unicode(homedir, fs_encoding)
224 216 else:
225 217 raise HomeDirError('%s is not a writable dir, '
226 218 'set $HOME environment variable to override' % homedir)
227 219
228 220 def get_xdg_dir():
229 221 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
230 222
231 223 This is only for non-OS X posix (Linux,Unix,etc.) systems.
232 224 """
233 225
234 226 env = os.environ
235 227
236 228 if os.name == 'posix' and sys.platform != 'darwin':
237 229 # Linux, Unix, AIX, etc.
238 230 # use ~/.config if empty OR not set
239 231 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
240 232 if xdg and _writable_dir(xdg):
241 233 return py3compat.cast_unicode(xdg, fs_encoding)
242 234
243 235 return None
244 236
245 237
246 238 def get_xdg_cache_dir():
247 239 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
248 240
249 241 This is only for non-OS X posix (Linux,Unix,etc.) systems.
250 242 """
251 243
252 244 env = os.environ
253 245
254 246 if os.name == 'posix' and sys.platform != 'darwin':
255 247 # Linux, Unix, AIX, etc.
256 248 # use ~/.cache if empty OR not set
257 249 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
258 250 if xdg and _writable_dir(xdg):
259 251 return py3compat.cast_unicode(xdg, fs_encoding)
260 252
261 253 return None
262 254
263 255
264 256 def get_ipython_dir():
265 257 """Get the IPython directory for this platform and user.
266 258
267 259 This uses the logic in `get_home_dir` to find the home directory
268 260 and then adds .ipython to the end of the path.
269 261 """
270 262
271 263 env = os.environ
272 264 pjoin = os.path.join
273 265
274 266
275 267 ipdir_def = '.ipython'
276 268
277 269 home_dir = get_home_dir()
278 270 xdg_dir = get_xdg_dir()
279 271
280 272 # import pdb; pdb.set_trace() # dbg
281 273 if 'IPYTHON_DIR' in env:
282 274 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
283 275 'Please use IPYTHONDIR instead.')
284 276 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
285 277 if ipdir is None:
286 278 # not set explicitly, use ~/.ipython
287 279 ipdir = pjoin(home_dir, ipdir_def)
288 280 if xdg_dir:
289 281 # Several IPython versions (up to 1.x) defaulted to .config/ipython
290 282 # on Linux. We have decided to go back to using .ipython everywhere
291 283 xdg_ipdir = pjoin(xdg_dir, 'ipython')
292 284
293 285 if _writable_dir(xdg_ipdir):
294 286 cu = compress_user
295 287 if os.path.exists(ipdir):
296 288 warnings.warn(('Ignoring {0} in favour of {1}. Remove {0} '
297 289 'to get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
298 290 else:
299 291 warnings.warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
300 292 os.rename(xdg_ipdir, ipdir)
301 293
302 294 ipdir = os.path.normpath(os.path.expanduser(ipdir))
303 295
304 296 if os.path.exists(ipdir) and not _writable_dir(ipdir):
305 297 # ipdir exists, but is not writable
306 298 warnings.warn("IPython dir '%s' is not a writable location,"
307 299 " using a temp directory."%ipdir)
308 300 ipdir = tempfile.mkdtemp()
309 301 elif not os.path.exists(ipdir):
310 302 parent = os.path.dirname(ipdir)
311 303 if not _writable_dir(parent):
312 304 # ipdir does not exist and parent isn't writable
313 305 warnings.warn("IPython parent '%s' is not a writable location,"
314 306 " using a temp directory."%parent)
315 307 ipdir = tempfile.mkdtemp()
316 308
317 309 return py3compat.cast_unicode(ipdir, fs_encoding)
318 310
319 311
320 312 def get_ipython_cache_dir():
321 313 """Get the cache directory it is created if it does not exist."""
322 314 xdgdir = get_xdg_cache_dir()
323 315 if xdgdir is None:
324 316 return get_ipython_dir()
325 317 ipdir = os.path.join(xdgdir, "ipython")
326 318 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
327 os.makedirs(ipdir)
319 ensure_dir_exists(ipdir)
328 320 elif not _writable_dir(xdgdir):
329 321 return get_ipython_dir()
330 322
331 323 return py3compat.cast_unicode(ipdir, fs_encoding)
332 324
333 325
334 326 def get_ipython_package_dir():
335 327 """Get the base directory where IPython itself is installed."""
336 328 ipdir = os.path.dirname(IPython.__file__)
337 329 return py3compat.cast_unicode(ipdir, fs_encoding)
338 330
339 331
340 332 def get_ipython_module_path(module_str):
341 333 """Find the path to an IPython module in this version of IPython.
342 334
343 335 This will always find the version of the module that is in this importable
344 336 IPython package. This will always return the path to the ``.py``
345 337 version of the module.
346 338 """
347 339 if module_str == 'IPython':
348 340 return os.path.join(get_ipython_package_dir(), '__init__.py')
349 341 mod = import_item(module_str)
350 342 the_path = mod.__file__.replace('.pyc', '.py')
351 343 the_path = the_path.replace('.pyo', '.py')
352 344 return py3compat.cast_unicode(the_path, fs_encoding)
353 345
354 346 def locate_profile(profile='default'):
355 347 """Find the path to the folder associated with a given profile.
356 348
357 349 I.e. find $IPYTHONDIR/profile_whatever.
358 350 """
359 351 from IPython.core.profiledir import ProfileDir, ProfileDirError
360 352 try:
361 353 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
362 354 except ProfileDirError:
363 355 # IOError makes more sense when people are expecting a path
364 356 raise IOError("Couldn't find profile %r" % profile)
365 357 return pd.location
366 358
367 359 def expand_path(s):
368 360 """Expand $VARS and ~names in a string, like a shell
369 361
370 362 :Examples:
371 363
372 364 In [2]: os.environ['FOO']='test'
373 365
374 366 In [3]: expand_path('variable FOO is $FOO')
375 367 Out[3]: 'variable FOO is test'
376 368 """
377 369 # This is a pretty subtle hack. When expand user is given a UNC path
378 370 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
379 371 # the $ to get (\\server\share\%username%). I think it considered $
380 372 # alone an empty var. But, we need the $ to remains there (it indicates
381 373 # a hidden share).
382 374 if os.name=='nt':
383 375 s = s.replace('$\\', 'IPYTHON_TEMP')
384 376 s = os.path.expandvars(os.path.expanduser(s))
385 377 if os.name=='nt':
386 378 s = s.replace('IPYTHON_TEMP', '$\\')
387 379 return s
388 380
389 381
390 382 def unescape_glob(string):
391 383 """Unescape glob pattern in `string`."""
392 384 def unescape(s):
393 385 for pattern in '*[]!?':
394 386 s = s.replace(r'\{0}'.format(pattern), pattern)
395 387 return s
396 388 return '\\'.join(map(unescape, string.split('\\\\')))
397 389
398 390
399 391 def shellglob(args):
400 392 """
401 393 Do glob expansion for each element in `args` and return a flattened list.
402 394
403 395 Unmatched glob pattern will remain as-is in the returned list.
404 396
405 397 """
406 398 expanded = []
407 399 # Do not unescape backslash in Windows as it is interpreted as
408 400 # path separator:
409 401 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
410 402 for a in args:
411 403 expanded.extend(glob.glob(a) or [unescape(a)])
412 404 return expanded
413 405
414 406
415 407 def target_outdated(target,deps):
416 408 """Determine whether a target is out of date.
417 409
418 410 target_outdated(target,deps) -> 1/0
419 411
420 412 deps: list of filenames which MUST exist.
421 413 target: single filename which may or may not exist.
422 414
423 415 If target doesn't exist or is older than any file listed in deps, return
424 416 true, otherwise return false.
425 417 """
426 418 try:
427 419 target_time = os.path.getmtime(target)
428 420 except os.error:
429 421 return 1
430 422 for dep in deps:
431 423 dep_time = os.path.getmtime(dep)
432 424 if dep_time > target_time:
433 425 #print "For target",target,"Dep failed:",dep # dbg
434 426 #print "times (dep,tar):",dep_time,target_time # dbg
435 427 return 1
436 428 return 0
437 429
438 430
439 431 def target_update(target,deps,cmd):
440 432 """Update a target with a given command given a list of dependencies.
441 433
442 434 target_update(target,deps,cmd) -> runs cmd if target is outdated.
443 435
444 436 This is just a wrapper around target_outdated() which calls the given
445 437 command if target is outdated."""
446 438
447 439 if target_outdated(target,deps):
448 440 system(cmd)
449 441
450 442 def filehash(path):
451 443 """Make an MD5 hash of a file, ignoring any differences in line
452 444 ending characters."""
453 445 with open(path, "rU") as f:
454 446 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
455 447
456 448 # If the config is unmodified from the default, we'll just delete it.
457 449 # These are consistent for 0.10.x, thankfully. We're not going to worry about
458 450 # older versions.
459 451 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
460 452 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
461 453
462 454 def check_for_old_config(ipython_dir=None):
463 455 """Check for old config files, and present a warning if they exist.
464 456
465 457 A link to the docs of the new config is included in the message.
466 458
467 459 This should mitigate confusion with the transition to the new
468 460 config system in 0.11.
469 461 """
470 462 if ipython_dir is None:
471 463 ipython_dir = get_ipython_dir()
472 464
473 465 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
474 466 warned = False
475 467 for cfg in old_configs:
476 468 f = os.path.join(ipython_dir, cfg)
477 469 if os.path.exists(f):
478 470 if filehash(f) == old_config_md5.get(cfg, ''):
479 471 os.unlink(f)
480 472 else:
481 473 warnings.warn("Found old IPython config file %r (modified by user)"%f)
482 474 warned = True
483 475
484 476 if warned:
485 477 warnings.warn("""
486 478 The IPython configuration system has changed as of 0.11, and these files will
487 479 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
488 480 of the new config system.
489 481 To start configuring IPython, do `ipython profile create`, and edit
490 482 `ipython_config.py` in <ipython_dir>/profile_default.
491 483 If you need to leave the old config files in place for an older version of
492 484 IPython and want to suppress this warning message, set
493 485 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
494 486
495 487 def get_security_file(filename, profile='default'):
496 488 """Return the absolute path of a security file given by filename and profile
497 489
498 490 This allows users and developers to find security files without
499 491 knowledge of the IPython directory structure. The search path
500 492 will be ['.', profile.security_dir]
501 493
502 494 Parameters
503 495 ----------
504 496
505 497 filename : str
506 498 The file to be found. If it is passed as an absolute path, it will
507 499 simply be returned.
508 500 profile : str [default: 'default']
509 501 The name of the profile to search. Leaving this unspecified
510 502 The file to be found. If it is passed as an absolute path, fname will
511 503 simply be returned.
512 504
513 505 Returns
514 506 -------
515 507 Raises :exc:`IOError` if file not found or returns absolute path to file.
516 508 """
517 509 # import here, because profiledir also imports from utils.path
518 510 from IPython.core.profiledir import ProfileDir
519 511 try:
520 512 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
521 513 except Exception:
522 514 # will raise ProfileDirError if no such profile
523 515 raise IOError("Profile %r not found")
524 516 return filefind(filename, ['.', pd.security_dir])
525 517
526 518
527 519 ENOLINK = 1998
528 520
529 521 def link(src, dst):
530 522 """Hard links ``src`` to ``dst``, returning 0 or errno.
531 523
532 524 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
533 525 supported by the operating system.
534 526 """
535 527
536 528 if not hasattr(os, "link"):
537 529 return ENOLINK
538 530 link_errno = 0
539 531 try:
540 532 os.link(src, dst)
541 533 except OSError as e:
542 534 link_errno = e.errno
543 535 return link_errno
544 536
545 537
546 538 def link_or_copy(src, dst):
547 539 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
548 540
549 541 Attempts to maintain the semantics of ``shutil.copy``.
550 542
551 543 Because ``os.link`` does not overwrite files, a unique temporary file
552 544 will be used if the target already exists, then that file will be moved
553 545 into place.
554 546 """
555 547
556 548 if os.path.isdir(dst):
557 549 dst = os.path.join(dst, os.path.basename(src))
558 550
559 551 link_errno = link(src, dst)
560 552 if link_errno == errno.EEXIST:
561 553 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
562 554 try:
563 555 link_or_copy(src, new_dst)
564 556 except:
565 557 try:
566 558 os.remove(new_dst)
567 559 except OSError:
568 560 pass
569 561 raise
570 562 os.rename(new_dst, dst)
571 563 elif link_errno != 0:
572 564 # Either link isn't supported, or the filesystem doesn't support
573 565 # linking, or 'src' and 'dst' are on different filesystems.
574 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