##// END OF EJS Templates
Merge pull request #11831 from minho42/Fix-typos...
Matthias Bussonnier -
r25149:29f2a6d6 merge
parent child Browse files
Show More
@@ -1,462 +1,462 b''
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
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 import atexit
16 16 from copy import deepcopy
17 17 import glob
18 18 import logging
19 19 import os
20 20 import shutil
21 21 import sys
22 22
23 23 from traitlets.config.application import Application, catch_config_error
24 24 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
25 25 from IPython.core import release, crashhandler
26 26 from IPython.core.profiledir import ProfileDir, ProfileDirError
27 27 from IPython.paths import get_ipython_dir, get_ipython_package_dir
28 28 from IPython.utils.path import ensure_dir_exists
29 29 from traitlets import (
30 30 List, Unicode, Type, Bool, Set, Instance, Undefined,
31 31 default, observe,
32 32 )
33 33
34 34 if os.name == 'nt':
35 35 programdata = os.environ.get('PROGRAMDATA', None)
36 36 if programdata:
37 37 SYSTEM_CONFIG_DIRS = [os.path.join(programdata, 'ipython')]
38 38 else: # PROGRAMDATA is not defined by default on XP.
39 39 SYSTEM_CONFIG_DIRS = []
40 40 else:
41 41 SYSTEM_CONFIG_DIRS = [
42 42 "/usr/local/etc/ipython",
43 43 "/etc/ipython",
44 44 ]
45 45
46 46
47 47 ENV_CONFIG_DIRS = []
48 48 _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
49 49 if _env_config_dir not in SYSTEM_CONFIG_DIRS:
50 50 # only add ENV_CONFIG if sys.prefix is not already included
51 51 ENV_CONFIG_DIRS.append(_env_config_dir)
52 52
53 53
54 54 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
55 55 if _envvar in {None, ''}:
56 56 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
57 57 else:
58 58 if _envvar.lower() in {'1','true'}:
59 59 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
60 60 elif _envvar.lower() in {'0','false'} :
61 61 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
62 62 else:
63 63 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
64 64
65 65 # aliases and flags
66 66
67 67 base_aliases = {
68 68 'profile-dir' : 'ProfileDir.location',
69 69 'profile' : 'BaseIPythonApplication.profile',
70 70 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
71 71 'log-level' : 'Application.log_level',
72 72 'config' : 'BaseIPythonApplication.extra_config_file',
73 73 }
74 74
75 75 base_flags = dict(
76 76 debug = ({'Application' : {'log_level' : logging.DEBUG}},
77 77 "set log level to logging.DEBUG (maximize logging output)"),
78 78 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
79 79 "set log level to logging.CRITICAL (minimize logging output)"),
80 80 init = ({'BaseIPythonApplication' : {
81 81 'copy_config_files' : True,
82 82 'auto_create' : True}
83 83 }, """Initialize profile with default config files. This is equivalent
84 84 to running `ipython profile create <profile>` prior to startup.
85 85 """)
86 86 )
87 87
88 88 class ProfileAwareConfigLoader(PyFileConfigLoader):
89 89 """A Python file config loader that is aware of IPython profiles."""
90 90 def load_subconfig(self, fname, path=None, profile=None):
91 91 if profile is not None:
92 92 try:
93 93 profile_dir = ProfileDir.find_profile_dir_by_name(
94 94 get_ipython_dir(),
95 95 profile,
96 96 )
97 97 except ProfileDirError:
98 98 return
99 99 path = profile_dir.location
100 100 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
101 101
102 102 class BaseIPythonApplication(Application):
103 103
104 104 name = u'ipython'
105 105 description = Unicode(u'IPython: an enhanced interactive Python shell.')
106 106 version = Unicode(release.version)
107 107
108 108 aliases = base_aliases
109 109 flags = base_flags
110 110 classes = List([ProfileDir])
111 111
112 112 # enable `load_subconfig('cfg.py', profile='name')`
113 113 python_config_loader_class = ProfileAwareConfigLoader
114 114
115 115 # Track whether the config_file has changed,
116 116 # because some logic happens only if we aren't using the default.
117 117 config_file_specified = Set()
118 118
119 119 config_file_name = Unicode()
120 120 @default('config_file_name')
121 121 def _config_file_name_default(self):
122 122 return self.name.replace('-','_') + u'_config.py'
123 123 @observe('config_file_name')
124 124 def _config_file_name_changed(self, change):
125 125 if change['new'] != change['old']:
126 126 self.config_file_specified.add(change['new'])
127 127
128 128 # The directory that contains IPython's builtin profiles.
129 129 builtin_profile_dir = Unicode(
130 130 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
131 131 )
132 132
133 133 config_file_paths = List(Unicode())
134 134 @default('config_file_paths')
135 135 def _config_file_paths_default(self):
136 136 return [os.getcwd()]
137 137
138 138 extra_config_file = Unicode(
139 139 help="""Path to an extra config file to load.
140 140
141 141 If specified, load this config file in addition to any other IPython config.
142 142 """).tag(config=True)
143 143 @observe('extra_config_file')
144 144 def _extra_config_file_changed(self, change):
145 145 old = change['old']
146 146 new = change['new']
147 147 try:
148 148 self.config_files.remove(old)
149 149 except ValueError:
150 150 pass
151 151 self.config_file_specified.add(new)
152 152 self.config_files.append(new)
153 153
154 154 profile = Unicode(u'default',
155 155 help="""The IPython profile to use."""
156 156 ).tag(config=True)
157 157
158 158 @observe('profile')
159 159 def _profile_changed(self, change):
160 160 self.builtin_profile_dir = os.path.join(
161 161 get_ipython_package_dir(), u'config', u'profile', change['new']
162 162 )
163 163
164 164 ipython_dir = Unicode(
165 165 help="""
166 166 The name of the IPython directory. This directory is used for logging
167 167 configuration (through profiles), history storage, etc. The default
168 168 is usually $HOME/.ipython. This option can also be specified through
169 169 the environment variable IPYTHONDIR.
170 170 """
171 171 ).tag(config=True)
172 172 @default('ipython_dir')
173 173 def _ipython_dir_default(self):
174 174 d = get_ipython_dir()
175 175 self._ipython_dir_changed({
176 176 'name': 'ipython_dir',
177 177 'old': d,
178 178 'new': d,
179 179 })
180 180 return d
181 181
182 182 _in_init_profile_dir = False
183 183 profile_dir = Instance(ProfileDir, allow_none=True)
184 184 @default('profile_dir')
185 185 def _profile_dir_default(self):
186 186 # avoid recursion
187 187 if self._in_init_profile_dir:
188 188 return
189 189 # profile_dir requested early, force initialization
190 190 self.init_profile_dir()
191 191 return self.profile_dir
192 192
193 193 overwrite = Bool(False,
194 194 help="""Whether to overwrite existing config files when copying"""
195 195 ).tag(config=True)
196 196 auto_create = Bool(False,
197 197 help="""Whether to create profile dir if it doesn't exist"""
198 198 ).tag(config=True)
199 199
200 200 config_files = List(Unicode())
201 201 @default('config_files')
202 202 def _config_files_default(self):
203 203 return [self.config_file_name]
204 204
205 205 copy_config_files = Bool(False,
206 206 help="""Whether to install the default config files into the profile dir.
207 207 If a new profile is being created, and IPython contains config files for that
208 208 profile, then they will be staged into the new directory. Otherwise,
209 209 default config files will be automatically generated.
210 210 """).tag(config=True)
211 211
212 212 verbose_crash = Bool(False,
213 213 help="""Create a massive crash report when IPython encounters what may be an
214 214 internal error. The default is to append a short message to the
215 215 usual traceback""").tag(config=True)
216 216
217 217 # The class to use as the crash handler.
218 218 crash_handler_class = Type(crashhandler.CrashHandler)
219 219
220 220 @catch_config_error
221 221 def __init__(self, **kwargs):
222 222 super(BaseIPythonApplication, self).__init__(**kwargs)
223 223 # ensure current working directory exists
224 224 try:
225 225 os.getcwd()
226 226 except:
227 227 # exit if cwd doesn't exist
228 228 self.log.error("Current working directory doesn't exist.")
229 229 self.exit(1)
230 230
231 231 #-------------------------------------------------------------------------
232 232 # Various stages of Application creation
233 233 #-------------------------------------------------------------------------
234 234
235 235 deprecated_subcommands = {}
236 236
237 237 def initialize_subcommand(self, subc, argv=None):
238 238 if subc in self.deprecated_subcommands:
239 239 self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed "
240 240 "in future versions.".format(sub=subc))
241 241 self.log.warning("You likely want to use `jupyter {sub}` in the "
242 242 "future".format(sub=subc))
243 243 return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv)
244 244
245 245 def init_crash_handler(self):
246 246 """Create a crash handler, typically setting sys.excepthook to it."""
247 247 self.crash_handler = self.crash_handler_class(self)
248 248 sys.excepthook = self.excepthook
249 249 def unset_crashhandler():
250 250 sys.excepthook = sys.__excepthook__
251 251 atexit.register(unset_crashhandler)
252 252
253 253 def excepthook(self, etype, evalue, tb):
254 254 """this is sys.excepthook after init_crashhandler
255 255
256 256 set self.verbose_crash=True to use our full crashhandler, instead of
257 257 a regular traceback with a short message (crash_handler_lite)
258 258 """
259 259
260 260 if self.verbose_crash:
261 261 return self.crash_handler(etype, evalue, tb)
262 262 else:
263 263 return crashhandler.crash_handler_lite(etype, evalue, tb)
264 264
265 265 @observe('ipython_dir')
266 266 def _ipython_dir_changed(self, change):
267 267 old = change['old']
268 268 new = change['new']
269 269 if old is not Undefined:
270 270 str_old = os.path.abspath(old)
271 271 if str_old in sys.path:
272 272 sys.path.remove(str_old)
273 273 str_path = os.path.abspath(new)
274 274 sys.path.append(str_path)
275 275 ensure_dir_exists(new)
276 276 readme = os.path.join(new, 'README')
277 277 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
278 278 if not os.path.exists(readme) and os.path.exists(readme_src):
279 279 shutil.copy(readme_src, readme)
280 280 for d in ('extensions', 'nbextensions'):
281 281 path = os.path.join(new, d)
282 282 try:
283 283 ensure_dir_exists(path)
284 284 except OSError as e:
285 285 # this will not be EEXIST
286 286 self.log.error("couldn't create path %s: %s", path, e)
287 287 self.log.debug("IPYTHONDIR set to: %s" % new)
288 288
289 289 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
290 290 """Load the config file.
291 291
292 292 By default, errors in loading config are handled, and a warning
293 293 printed on screen. For testing, the suppress_errors option is set
294 294 to False, so errors will make tests fail.
295 295
296 `supress_errors` default value is to be `None` in which case the
296 `suppress_errors` default value is to be `None` in which case the
297 297 behavior default to the one of `traitlets.Application`.
298 298
299 299 The default value can be set :
300 300 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
301 301 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
302 302 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
303 303
304 304 Any other value are invalid, and will make IPython exit with a non-zero return code.
305 305 """
306 306
307 307
308 308 self.log.debug("Searching path %s for config files", self.config_file_paths)
309 309 base_config = 'ipython_config.py'
310 310 self.log.debug("Attempting to load config file: %s" %
311 311 base_config)
312 312 try:
313 313 if suppress_errors is not None:
314 314 old_value = Application.raise_config_file_errors
315 315 Application.raise_config_file_errors = not suppress_errors;
316 316 Application.load_config_file(
317 317 self,
318 318 base_config,
319 319 path=self.config_file_paths
320 320 )
321 321 except ConfigFileNotFound:
322 322 # ignore errors loading parent
323 323 self.log.debug("Config file %s not found", base_config)
324 324 pass
325 325 if suppress_errors is not None:
326 326 Application.raise_config_file_errors = old_value
327 327
328 328 for config_file_name in self.config_files:
329 329 if not config_file_name or config_file_name == base_config:
330 330 continue
331 331 self.log.debug("Attempting to load config file: %s" %
332 332 self.config_file_name)
333 333 try:
334 334 Application.load_config_file(
335 335 self,
336 336 config_file_name,
337 337 path=self.config_file_paths
338 338 )
339 339 except ConfigFileNotFound:
340 340 # Only warn if the default config file was NOT being used.
341 341 if config_file_name in self.config_file_specified:
342 342 msg = self.log.warning
343 343 else:
344 344 msg = self.log.debug
345 345 msg("Config file not found, skipping: %s", config_file_name)
346 346 except Exception:
347 347 # For testing purposes.
348 348 if not suppress_errors:
349 349 raise
350 350 self.log.warning("Error loading config file: %s" %
351 351 self.config_file_name, exc_info=True)
352 352
353 353 def init_profile_dir(self):
354 354 """initialize the profile dir"""
355 355 self._in_init_profile_dir = True
356 356 if self.profile_dir is not None:
357 357 # already ran
358 358 return
359 359 if 'ProfileDir.location' not in self.config:
360 360 # location not specified, find by profile name
361 361 try:
362 362 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
363 363 except ProfileDirError:
364 364 # not found, maybe create it (always create default profile)
365 365 if self.auto_create or self.profile == 'default':
366 366 try:
367 367 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
368 368 except ProfileDirError:
369 369 self.log.fatal("Could not create profile: %r"%self.profile)
370 370 self.exit(1)
371 371 else:
372 372 self.log.info("Created profile dir: %r"%p.location)
373 373 else:
374 374 self.log.fatal("Profile %r not found."%self.profile)
375 375 self.exit(1)
376 376 else:
377 377 self.log.debug("Using existing profile dir: %r"%p.location)
378 378 else:
379 379 location = self.config.ProfileDir.location
380 380 # location is fully specified
381 381 try:
382 382 p = ProfileDir.find_profile_dir(location, self.config)
383 383 except ProfileDirError:
384 384 # not found, maybe create it
385 385 if self.auto_create:
386 386 try:
387 387 p = ProfileDir.create_profile_dir(location, self.config)
388 388 except ProfileDirError:
389 389 self.log.fatal("Could not create profile directory: %r"%location)
390 390 self.exit(1)
391 391 else:
392 392 self.log.debug("Creating new profile dir: %r"%location)
393 393 else:
394 394 self.log.fatal("Profile directory %r not found."%location)
395 395 self.exit(1)
396 396 else:
397 397 self.log.info("Using existing profile dir: %r"%location)
398 398 # if profile_dir is specified explicitly, set profile name
399 399 dir_name = os.path.basename(p.location)
400 400 if dir_name.startswith('profile_'):
401 401 self.profile = dir_name[8:]
402 402
403 403 self.profile_dir = p
404 404 self.config_file_paths.append(p.location)
405 405 self._in_init_profile_dir = False
406 406
407 407 def init_config_files(self):
408 408 """[optionally] copy default config files into profile dir."""
409 409 self.config_file_paths.extend(ENV_CONFIG_DIRS)
410 410 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
411 411 # copy config files
412 412 path = self.builtin_profile_dir
413 413 if self.copy_config_files:
414 414 src = self.profile
415 415
416 416 cfg = self.config_file_name
417 417 if path and os.path.exists(os.path.join(path, cfg)):
418 418 self.log.warning("Staging %r from %s into %r [overwrite=%s]"%(
419 419 cfg, src, self.profile_dir.location, self.overwrite)
420 420 )
421 421 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
422 422 else:
423 423 self.stage_default_config_file()
424 424 else:
425 425 # Still stage *bundled* config files, but not generated ones
426 426 # This is necessary for `ipython profile=sympy` to load the profile
427 427 # on the first go
428 428 files = glob.glob(os.path.join(path, '*.py'))
429 429 for fullpath in files:
430 430 cfg = os.path.basename(fullpath)
431 431 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
432 432 # file was copied
433 433 self.log.warning("Staging bundled %s from %s into %r"%(
434 434 cfg, self.profile, self.profile_dir.location)
435 435 )
436 436
437 437
438 438 def stage_default_config_file(self):
439 439 """auto generate default config file, and stage it into the profile."""
440 440 s = self.generate_config_file()
441 441 fname = os.path.join(self.profile_dir.location, self.config_file_name)
442 442 if self.overwrite or not os.path.exists(fname):
443 443 self.log.warning("Generating default config file: %r"%(fname))
444 444 with open(fname, 'w') as f:
445 445 f.write(s)
446 446
447 447 @catch_config_error
448 448 def initialize(self, argv=None):
449 449 # don't hook up crash handler before parsing command-line
450 450 self.parse_command_line(argv)
451 451 self.init_crash_handler()
452 452 if self.subapp is not None:
453 453 # stop here if subapp is taking over
454 454 return
455 455 # save a copy of CLI config to re-load after config files
456 456 # so that it has highest priority
457 457 cl_config = deepcopy(self.config)
458 458 self.init_profile_dir()
459 459 self.init_config_files()
460 460 self.load_config_file()
461 461 # enforce cl-opts override configfile opts:
462 462 self.update_config(cl_config)
1 NO CONTENT: modified file
1 NO CONTENT: modified file
@@ -1,1473 +1,1473 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencryted
44 potentially leak sensitive information like access keys, or unencrypted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 - Neutral: a neutral color scheme that should be readable on both light and
71 71 dark background
72 72
73 73 You can implement other color schemes easily, the syntax is fairly
74 74 self-explanatory. Please send back new schemes you develop to the author for
75 75 possible inclusion in future releases.
76 76
77 77 Inheritance diagram:
78 78
79 79 .. inheritance-diagram:: IPython.core.ultratb
80 80 :parts: 3
81 81 """
82 82
83 83 #*****************************************************************************
84 84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 86 #
87 87 # Distributed under the terms of the BSD License. The full license is in
88 88 # the file COPYING, distributed as part of this software.
89 89 #*****************************************************************************
90 90
91 91
92 92 import dis
93 93 import inspect
94 94 import keyword
95 95 import linecache
96 96 import os
97 97 import pydoc
98 98 import re
99 99 import sys
100 100 import time
101 101 import tokenize
102 102 import traceback
103 103
104 104 try: # Python 2
105 105 generate_tokens = tokenize.generate_tokens
106 106 except AttributeError: # Python 3
107 107 generate_tokens = tokenize.tokenize
108 108
109 109 # For purposes of monkeypatching inspect to fix a bug in it.
110 110 from inspect import getsourcefile, getfile, getmodule, \
111 111 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
112 112
113 113 # IPython's own modules
114 114 from IPython import get_ipython
115 115 from IPython.core import debugger
116 116 from IPython.core.display_trap import DisplayTrap
117 117 from IPython.core.excolors import exception_colors
118 118 from IPython.utils import PyColorize
119 119 from IPython.utils import path as util_path
120 120 from IPython.utils import py3compat
121 121 from IPython.utils.data import uniq_stable
122 122 from IPython.utils.terminal import get_terminal_size
123 123
124 124 from logging import info, error, debug
125 125
126 126 from importlib.util import source_from_cache
127 127
128 128 import IPython.utils.colorable as colorable
129 129
130 130 # Globals
131 131 # amount of space to put line numbers before verbose tracebacks
132 132 INDENT_SIZE = 8
133 133
134 134 # Default color scheme. This is used, for example, by the traceback
135 135 # formatter. When running in an actual IPython instance, the user's rc.colors
136 136 # value is used, but having a module global makes this functionality available
137 137 # to users of ultratb who are NOT running inside ipython.
138 138 DEFAULT_SCHEME = 'NoColor'
139 139
140 140
141 141 # Number of frame above which we are likely to have a recursion and will
142 142 # **attempt** to detect it. Made modifiable mostly to speedup test suite
143 143 # as detecting recursion is one of our slowest test
144 144 _FRAME_RECURSION_LIMIT = 500
145 145
146 146 # ---------------------------------------------------------------------------
147 147 # Code begins
148 148
149 149 # Utility functions
150 150 def inspect_error():
151 151 """Print a message about internal inspect errors.
152 152
153 153 These are unfortunately quite common."""
154 154
155 155 error('Internal Python error in the inspect module.\n'
156 156 'Below is the traceback from this internal error.\n')
157 157
158 158
159 159 # This function is a monkeypatch we apply to the Python inspect module. We have
160 160 # now found when it's needed (see discussion on issue gh-1456), and we have a
161 161 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
162 162 # the monkeypatch is not applied. TK, Aug 2012.
163 163 def findsource(object):
164 164 """Return the entire source file and starting line number for an object.
165 165
166 166 The argument may be a module, class, method, function, traceback, frame,
167 167 or code object. The source code is returned as a list of all the lines
168 168 in the file and the line number indexes a line in that list. An IOError
169 169 is raised if the source code cannot be retrieved.
170 170
171 171 FIXED version with which we monkeypatch the stdlib to work around a bug."""
172 172
173 173 file = getsourcefile(object) or getfile(object)
174 174 # If the object is a frame, then trying to get the globals dict from its
175 175 # module won't work. Instead, the frame object itself has the globals
176 176 # dictionary.
177 177 globals_dict = None
178 178 if inspect.isframe(object):
179 179 # XXX: can this ever be false?
180 180 globals_dict = object.f_globals
181 181 else:
182 182 module = getmodule(object, file)
183 183 if module:
184 184 globals_dict = module.__dict__
185 185 lines = linecache.getlines(file, globals_dict)
186 186 if not lines:
187 187 raise IOError('could not get source code')
188 188
189 189 if ismodule(object):
190 190 return lines, 0
191 191
192 192 if isclass(object):
193 193 name = object.__name__
194 194 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
195 195 # make some effort to find the best matching class definition:
196 196 # use the one with the least indentation, which is the one
197 197 # that's most probably not inside a function definition.
198 198 candidates = []
199 199 for i, line in enumerate(lines):
200 200 match = pat.match(line)
201 201 if match:
202 202 # if it's at toplevel, it's already the best one
203 203 if line[0] == 'c':
204 204 return lines, i
205 205 # else add whitespace to candidate list
206 206 candidates.append((match.group(1), i))
207 207 if candidates:
208 208 # this will sort by whitespace, and by line number,
209 209 # less whitespace first
210 210 candidates.sort()
211 211 return lines, candidates[0][1]
212 212 else:
213 213 raise IOError('could not find class definition')
214 214
215 215 if ismethod(object):
216 216 object = object.__func__
217 217 if isfunction(object):
218 218 object = object.__code__
219 219 if istraceback(object):
220 220 object = object.tb_frame
221 221 if isframe(object):
222 222 object = object.f_code
223 223 if iscode(object):
224 224 if not hasattr(object, 'co_firstlineno'):
225 225 raise IOError('could not find function definition')
226 226 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
227 227 pmatch = pat.match
228 228 # fperez - fix: sometimes, co_firstlineno can give a number larger than
229 229 # the length of lines, which causes an error. Safeguard against that.
230 230 lnum = min(object.co_firstlineno, len(lines)) - 1
231 231 while lnum > 0:
232 232 if pmatch(lines[lnum]):
233 233 break
234 234 lnum -= 1
235 235
236 236 return lines, lnum
237 237 raise IOError('could not find code object')
238 238
239 239
240 240 # This is a patched version of inspect.getargs that applies the (unmerged)
241 241 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
242 242 # https://github.com/ipython/ipython/issues/8205 and
243 243 # https://github.com/ipython/ipython/issues/8293
244 244 def getargs(co):
245 245 """Get information about the arguments accepted by a code object.
246 246
247 247 Three things are returned: (args, varargs, varkw), where 'args' is
248 248 a list of argument names (possibly containing nested lists), and
249 249 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
250 250 if not iscode(co):
251 251 raise TypeError('{!r} is not a code object'.format(co))
252 252
253 253 nargs = co.co_argcount
254 254 names = co.co_varnames
255 255 args = list(names[:nargs])
256 256 step = 0
257 257
258 258 # The following acrobatics are for anonymous (tuple) arguments.
259 259 for i in range(nargs):
260 260 if args[i][:1] in ('', '.'):
261 261 stack, remain, count = [], [], []
262 262 while step < len(co.co_code):
263 263 op = ord(co.co_code[step])
264 264 step = step + 1
265 265 if op >= dis.HAVE_ARGUMENT:
266 266 opname = dis.opname[op]
267 267 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
268 268 step = step + 2
269 269 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
270 270 remain.append(value)
271 271 count.append(value)
272 272 elif opname in ('STORE_FAST', 'STORE_DEREF'):
273 273 if op in dis.haslocal:
274 274 stack.append(co.co_varnames[value])
275 275 elif op in dis.hasfree:
276 276 stack.append((co.co_cellvars + co.co_freevars)[value])
277 277 # Special case for sublists of length 1: def foo((bar))
278 278 # doesn't generate the UNPACK_TUPLE bytecode, so if
279 279 # `remain` is empty here, we have such a sublist.
280 280 if not remain:
281 281 stack[0] = [stack[0]]
282 282 break
283 283 else:
284 284 remain[-1] = remain[-1] - 1
285 285 while remain[-1] == 0:
286 286 remain.pop()
287 287 size = count.pop()
288 288 stack[-size:] = [stack[-size:]]
289 289 if not remain:
290 290 break
291 291 remain[-1] = remain[-1] - 1
292 292 if not remain:
293 293 break
294 294 args[i] = stack[0]
295 295
296 296 varargs = None
297 297 if co.co_flags & inspect.CO_VARARGS:
298 298 varargs = co.co_varnames[nargs]
299 299 nargs = nargs + 1
300 300 varkw = None
301 301 if co.co_flags & inspect.CO_VARKEYWORDS:
302 302 varkw = co.co_varnames[nargs]
303 303 return inspect.Arguments(args, varargs, varkw)
304 304
305 305
306 306 # Monkeypatch inspect to apply our bugfix.
307 307 def with_patch_inspect(f):
308 308 """
309 309 Deprecated since IPython 6.0
310 310 decorator for monkeypatching inspect.findsource
311 311 """
312 312
313 313 def wrapped(*args, **kwargs):
314 314 save_findsource = inspect.findsource
315 315 save_getargs = inspect.getargs
316 316 inspect.findsource = findsource
317 317 inspect.getargs = getargs
318 318 try:
319 319 return f(*args, **kwargs)
320 320 finally:
321 321 inspect.findsource = save_findsource
322 322 inspect.getargs = save_getargs
323 323
324 324 return wrapped
325 325
326 326
327 327 def fix_frame_records_filenames(records):
328 328 """Try to fix the filenames in each record from inspect.getinnerframes().
329 329
330 330 Particularly, modules loaded from within zip files have useless filenames
331 331 attached to their code object, and inspect.getinnerframes() just uses it.
332 332 """
333 333 fixed_records = []
334 334 for frame, filename, line_no, func_name, lines, index in records:
335 335 # Look inside the frame's globals dictionary for __file__,
336 336 # which should be better. However, keep Cython filenames since
337 337 # we prefer the source filenames over the compiled .so file.
338 338 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
339 339 better_fn = frame.f_globals.get('__file__', None)
340 340 if isinstance(better_fn, str):
341 341 # Check the type just in case someone did something weird with
342 342 # __file__. It might also be None if the error occurred during
343 343 # import.
344 344 filename = better_fn
345 345 fixed_records.append((frame, filename, line_no, func_name, lines, index))
346 346 return fixed_records
347 347
348 348
349 349 @with_patch_inspect
350 350 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
351 351 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
352 352
353 353 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
354 354 # If the error is at the console, don't build any context, since it would
355 355 # otherwise produce 5 blank lines printed out (there is no file at the
356 356 # console)
357 357 rec_check = records[tb_offset:]
358 358 try:
359 359 rname = rec_check[0][1]
360 360 if rname == '<ipython console>' or rname.endswith('<string>'):
361 361 return rec_check
362 362 except IndexError:
363 363 pass
364 364
365 365 aux = traceback.extract_tb(etb)
366 366 assert len(records) == len(aux)
367 367 for i, (file, lnum, _, _) in enumerate(aux):
368 368 maybeStart = lnum - 1 - context // 2
369 369 start = max(maybeStart, 0)
370 370 end = start + context
371 371 lines = linecache.getlines(file)[start:end]
372 372 buf = list(records[i])
373 373 buf[LNUM_POS] = lnum
374 374 buf[INDEX_POS] = lnum - 1 - start
375 375 buf[LINES_POS] = lines
376 376 records[i] = tuple(buf)
377 377 return records[tb_offset:]
378 378
379 379 # Helper function -- largely belongs to VerboseTB, but we need the same
380 380 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
381 381 # can be recognized properly by ipython.el's py-traceback-line-re
382 382 # (SyntaxErrors have to be treated specially because they have no traceback)
383 383
384 384
385 385 def _format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
386 386 """
387 387 Format tracebacks lines with pointing arrow, leading numbers...
388 388
389 389 Parameters
390 390 ==========
391 391
392 392 lnum: int
393 393 index: int
394 394 lines: list[string]
395 395 Colors:
396 396 ColorScheme used.
397 397 lvals: bytes
398 398 Values of local variables, already colored, to inject just after the error line.
399 399 _line_format: f (str) -> (str, bool)
400 400 return (colorized version of str, failure to do so)
401 401 """
402 402 numbers_width = INDENT_SIZE - 1
403 403 res = []
404 404
405 405 for i,line in enumerate(lines, lnum-index):
406 406 line = py3compat.cast_unicode(line)
407 407
408 408 new_line, err = _line_format(line, 'str')
409 409 if not err:
410 410 line = new_line
411 411
412 412 if i == lnum:
413 413 # This is the line with the error
414 414 pad = numbers_width - len(str(i))
415 415 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
416 416 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
417 417 Colors.line, line, Colors.Normal)
418 418 else:
419 419 num = '%*s' % (numbers_width, i)
420 420 line = '%s%s%s %s' % (Colors.lineno, num,
421 421 Colors.Normal, line)
422 422
423 423 res.append(line)
424 424 if lvals and i == lnum:
425 425 res.append(lvals + '\n')
426 426 return res
427 427
428 428 def is_recursion_error(etype, value, records):
429 429 try:
430 430 # RecursionError is new in Python 3.5
431 431 recursion_error_type = RecursionError
432 432 except NameError:
433 433 recursion_error_type = RuntimeError
434 434
435 435 # The default recursion limit is 1000, but some of that will be taken up
436 436 # by stack frames in IPython itself. >500 frames probably indicates
437 437 # a recursion error.
438 438 return (etype is recursion_error_type) \
439 439 and "recursion" in str(value).lower() \
440 440 and len(records) > _FRAME_RECURSION_LIMIT
441 441
442 442 def find_recursion(etype, value, records):
443 443 """Identify the repeating stack frames from a RecursionError traceback
444 444
445 445 'records' is a list as returned by VerboseTB.get_records()
446 446
447 447 Returns (last_unique, repeat_length)
448 448 """
449 449 # This involves a bit of guesswork - we want to show enough of the traceback
450 450 # to indicate where the recursion is occurring. We guess that the innermost
451 451 # quarter of the traceback (250 frames by default) is repeats, and find the
452 452 # first frame (from in to out) that looks different.
453 453 if not is_recursion_error(etype, value, records):
454 454 return len(records), 0
455 455
456 456 # Select filename, lineno, func_name to track frames with
457 457 records = [r[1:4] for r in records]
458 458 inner_frames = records[-(len(records)//4):]
459 459 frames_repeated = set(inner_frames)
460 460
461 461 last_seen_at = {}
462 462 longest_repeat = 0
463 463 i = len(records)
464 464 for frame in reversed(records):
465 465 i -= 1
466 466 if frame not in frames_repeated:
467 467 last_unique = i
468 468 break
469 469
470 470 if frame in last_seen_at:
471 471 distance = last_seen_at[frame] - i
472 472 longest_repeat = max(longest_repeat, distance)
473 473
474 474 last_seen_at[frame] = i
475 475 else:
476 476 last_unique = 0 # The whole traceback was recursion
477 477
478 478 return last_unique, longest_repeat
479 479
480 480 #---------------------------------------------------------------------------
481 481 # Module classes
482 482 class TBTools(colorable.Colorable):
483 483 """Basic tools used by all traceback printer classes."""
484 484
485 485 # Number of frames to skip when reporting tracebacks
486 486 tb_offset = 0
487 487
488 488 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
489 489 # Whether to call the interactive pdb debugger after printing
490 490 # tracebacks or not
491 491 super(TBTools, self).__init__(parent=parent, config=config)
492 492 self.call_pdb = call_pdb
493 493
494 494 # Output stream to write to. Note that we store the original value in
495 495 # a private attribute and then make the public ostream a property, so
496 496 # that we can delay accessing sys.stdout until runtime. The way
497 497 # things are written now, the sys.stdout object is dynamically managed
498 498 # so a reference to it should NEVER be stored statically. This
499 499 # property approach confines this detail to a single location, and all
500 500 # subclasses can simply access self.ostream for writing.
501 501 self._ostream = ostream
502 502
503 503 # Create color table
504 504 self.color_scheme_table = exception_colors()
505 505
506 506 self.set_colors(color_scheme)
507 507 self.old_scheme = color_scheme # save initial value for toggles
508 508
509 509 if call_pdb:
510 510 self.pdb = debugger.Pdb()
511 511 else:
512 512 self.pdb = None
513 513
514 514 def _get_ostream(self):
515 515 """Output stream that exceptions are written to.
516 516
517 517 Valid values are:
518 518
519 519 - None: the default, which means that IPython will dynamically resolve
520 520 to sys.stdout. This ensures compatibility with most tools, including
521 521 Windows (where plain stdout doesn't recognize ANSI escapes).
522 522
523 523 - Any object with 'write' and 'flush' attributes.
524 524 """
525 525 return sys.stdout if self._ostream is None else self._ostream
526 526
527 527 def _set_ostream(self, val):
528 528 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
529 529 self._ostream = val
530 530
531 531 ostream = property(_get_ostream, _set_ostream)
532 532
533 533 def set_colors(self, *args, **kw):
534 534 """Shorthand access to the color table scheme selector method."""
535 535
536 536 # Set own color table
537 537 self.color_scheme_table.set_active_scheme(*args, **kw)
538 538 # for convenience, set Colors to the active scheme
539 539 self.Colors = self.color_scheme_table.active_colors
540 540 # Also set colors of debugger
541 541 if hasattr(self, 'pdb') and self.pdb is not None:
542 542 self.pdb.set_colors(*args, **kw)
543 543
544 544 def color_toggle(self):
545 545 """Toggle between the currently active color scheme and NoColor."""
546 546
547 547 if self.color_scheme_table.active_scheme_name == 'NoColor':
548 548 self.color_scheme_table.set_active_scheme(self.old_scheme)
549 549 self.Colors = self.color_scheme_table.active_colors
550 550 else:
551 551 self.old_scheme = self.color_scheme_table.active_scheme_name
552 552 self.color_scheme_table.set_active_scheme('NoColor')
553 553 self.Colors = self.color_scheme_table.active_colors
554 554
555 555 def stb2text(self, stb):
556 556 """Convert a structured traceback (a list) to a string."""
557 557 return '\n'.join(stb)
558 558
559 559 def text(self, etype, value, tb, tb_offset=None, context=5):
560 560 """Return formatted traceback.
561 561
562 562 Subclasses may override this if they add extra arguments.
563 563 """
564 564 tb_list = self.structured_traceback(etype, value, tb,
565 565 tb_offset, context)
566 566 return self.stb2text(tb_list)
567 567
568 568 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
569 569 context=5, mode=None):
570 570 """Return a list of traceback frames.
571 571
572 572 Must be implemented by each class.
573 573 """
574 574 raise NotImplementedError()
575 575
576 576
577 577 #---------------------------------------------------------------------------
578 578 class ListTB(TBTools):
579 579 """Print traceback information from a traceback list, with optional color.
580 580
581 581 Calling requires 3 arguments: (etype, evalue, elist)
582 582 as would be obtained by::
583 583
584 584 etype, evalue, tb = sys.exc_info()
585 585 if tb:
586 586 elist = traceback.extract_tb(tb)
587 587 else:
588 588 elist = None
589 589
590 590 It can thus be used by programs which need to process the traceback before
591 591 printing (such as console replacements based on the code module from the
592 592 standard library).
593 593
594 594 Because they are meant to be called without a full traceback (only a
595 595 list), instances of this class can't call the interactive pdb debugger."""
596 596
597 597 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
598 598 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
599 599 ostream=ostream, parent=parent,config=config)
600 600
601 601 def __call__(self, etype, value, elist):
602 602 self.ostream.flush()
603 603 self.ostream.write(self.text(etype, value, elist))
604 604 self.ostream.write('\n')
605 605
606 606 def structured_traceback(self, etype, value, elist, tb_offset=None,
607 607 context=5):
608 608 """Return a color formatted string with the traceback info.
609 609
610 610 Parameters
611 611 ----------
612 612 etype : exception type
613 613 Type of the exception raised.
614 614
615 615 value : object
616 616 Data stored in the exception
617 617
618 618 elist : list
619 619 List of frames, see class docstring for details.
620 620
621 621 tb_offset : int, optional
622 622 Number of frames in the traceback to skip. If not given, the
623 623 instance value is used (set in constructor).
624 624
625 625 context : int, optional
626 626 Number of lines of context information to print.
627 627
628 628 Returns
629 629 -------
630 630 String with formatted exception.
631 631 """
632 632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
633 633 Colors = self.Colors
634 634 out_list = []
635 635 if elist:
636 636
637 637 if tb_offset and len(elist) > tb_offset:
638 638 elist = elist[tb_offset:]
639 639
640 640 out_list.append('Traceback %s(most recent call last)%s:' %
641 641 (Colors.normalEm, Colors.Normal) + '\n')
642 642 out_list.extend(self._format_list(elist))
643 643 # The exception info should be a single entry in the list.
644 644 lines = ''.join(self._format_exception_only(etype, value))
645 645 out_list.append(lines)
646 646
647 647 return out_list
648 648
649 649 def _format_list(self, extracted_list):
650 650 """Format a list of traceback entry tuples for printing.
651 651
652 652 Given a list of tuples as returned by extract_tb() or
653 653 extract_stack(), return a list of strings ready for printing.
654 654 Each string in the resulting list corresponds to the item with the
655 655 same index in the argument list. Each string ends in a newline;
656 656 the strings may contain internal newlines as well, for those items
657 657 whose source text line is not None.
658 658
659 659 Lifted almost verbatim from traceback.py
660 660 """
661 661
662 662 Colors = self.Colors
663 663 list = []
664 664 for filename, lineno, name, line in extracted_list[:-1]:
665 665 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
666 666 (Colors.filename, filename, Colors.Normal,
667 667 Colors.lineno, lineno, Colors.Normal,
668 668 Colors.name, name, Colors.Normal)
669 669 if line:
670 670 item += ' %s\n' % line.strip()
671 671 list.append(item)
672 672 # Emphasize the last entry
673 673 filename, lineno, name, line = extracted_list[-1]
674 674 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
675 675 (Colors.normalEm,
676 676 Colors.filenameEm, filename, Colors.normalEm,
677 677 Colors.linenoEm, lineno, Colors.normalEm,
678 678 Colors.nameEm, name, Colors.normalEm,
679 679 Colors.Normal)
680 680 if line:
681 681 item += '%s %s%s\n' % (Colors.line, line.strip(),
682 682 Colors.Normal)
683 683 list.append(item)
684 684 return list
685 685
686 686 def _format_exception_only(self, etype, value):
687 687 """Format the exception part of a traceback.
688 688
689 689 The arguments are the exception type and value such as given by
690 690 sys.exc_info()[:2]. The return value is a list of strings, each ending
691 691 in a newline. Normally, the list contains a single string; however,
692 692 for SyntaxError exceptions, it contains several lines that (when
693 693 printed) display detailed information about where the syntax error
694 694 occurred. The message indicating which exception occurred is the
695 695 always last string in the list.
696 696
697 697 Also lifted nearly verbatim from traceback.py
698 698 """
699 699 have_filedata = False
700 700 Colors = self.Colors
701 701 list = []
702 702 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
703 703 if value is None:
704 704 # Not sure if this can still happen in Python 2.6 and above
705 705 list.append(stype + '\n')
706 706 else:
707 707 if issubclass(etype, SyntaxError):
708 708 have_filedata = True
709 709 if not value.filename: value.filename = "<string>"
710 710 if value.lineno:
711 711 lineno = value.lineno
712 712 textline = linecache.getline(value.filename, value.lineno)
713 713 else:
714 714 lineno = 'unknown'
715 715 textline = ''
716 716 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
717 717 (Colors.normalEm,
718 718 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
719 719 Colors.linenoEm, lineno, Colors.Normal ))
720 720 if textline == '':
721 721 textline = py3compat.cast_unicode(value.text, "utf-8")
722 722
723 723 if textline is not None:
724 724 i = 0
725 725 while i < len(textline) and textline[i].isspace():
726 726 i += 1
727 727 list.append('%s %s%s\n' % (Colors.line,
728 728 textline.strip(),
729 729 Colors.Normal))
730 730 if value.offset is not None:
731 731 s = ' '
732 732 for c in textline[i:value.offset - 1]:
733 733 if c.isspace():
734 734 s += c
735 735 else:
736 736 s += ' '
737 737 list.append('%s%s^%s\n' % (Colors.caret, s,
738 738 Colors.Normal))
739 739
740 740 try:
741 741 s = value.msg
742 742 except Exception:
743 743 s = self._some_str(value)
744 744 if s:
745 745 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
746 746 Colors.Normal, s))
747 747 else:
748 748 list.append('%s\n' % stype)
749 749
750 750 # sync with user hooks
751 751 if have_filedata:
752 752 ipinst = get_ipython()
753 753 if ipinst is not None:
754 754 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
755 755
756 756 return list
757 757
758 758 def get_exception_only(self, etype, value):
759 759 """Only print the exception type and message, without a traceback.
760 760
761 761 Parameters
762 762 ----------
763 763 etype : exception type
764 764 value : exception value
765 765 """
766 766 return ListTB.structured_traceback(self, etype, value, [])
767 767
768 768 def show_exception_only(self, etype, evalue):
769 769 """Only print the exception type and message, without a traceback.
770 770
771 771 Parameters
772 772 ----------
773 773 etype : exception type
774 774 value : exception value
775 775 """
776 776 # This method needs to use __call__ from *this* class, not the one from
777 777 # a subclass whose signature or behavior may be different
778 778 ostream = self.ostream
779 779 ostream.flush()
780 780 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
781 781 ostream.flush()
782 782
783 783 def _some_str(self, value):
784 784 # Lifted from traceback.py
785 785 try:
786 786 return py3compat.cast_unicode(str(value))
787 787 except:
788 788 return u'<unprintable %s object>' % type(value).__name__
789 789
790 790
791 791 #----------------------------------------------------------------------------
792 792 class VerboseTB(TBTools):
793 793 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
794 794 of HTML. Requires inspect and pydoc. Crazy, man.
795 795
796 796 Modified version which optionally strips the topmost entries from the
797 797 traceback, to be used with alternate interpreters (because their own code
798 798 would appear in the traceback)."""
799 799
800 800 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
801 801 tb_offset=0, long_header=False, include_vars=True,
802 802 check_cache=None, debugger_cls = None,
803 803 parent=None, config=None):
804 804 """Specify traceback offset, headers and color scheme.
805 805
806 806 Define how many frames to drop from the tracebacks. Calling it with
807 807 tb_offset=1 allows use of this handler in interpreters which will have
808 808 their own code at the top of the traceback (VerboseTB will first
809 809 remove that frame before printing the traceback info)."""
810 810 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
811 811 ostream=ostream, parent=parent, config=config)
812 812 self.tb_offset = tb_offset
813 813 self.long_header = long_header
814 814 self.include_vars = include_vars
815 815 # By default we use linecache.checkcache, but the user can provide a
816 816 # different check_cache implementation. This is used by the IPython
817 817 # kernel to provide tracebacks for interactive code that is cached,
818 818 # by a compiler instance that flushes the linecache but preserves its
819 819 # own code cache.
820 820 if check_cache is None:
821 821 check_cache = linecache.checkcache
822 822 self.check_cache = check_cache
823 823
824 824 self.debugger_cls = debugger_cls or debugger.Pdb
825 825
826 826 def format_records(self, records, last_unique, recursion_repeat):
827 827 """Format the stack frames of the traceback"""
828 828 frames = []
829 829 for r in records[:last_unique+recursion_repeat+1]:
830 830 #print '*** record:',file,lnum,func,lines,index # dbg
831 831 frames.append(self.format_record(*r))
832 832
833 833 if recursion_repeat:
834 834 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
835 835 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
836 836
837 837 return frames
838 838
839 839 def format_record(self, frame, file, lnum, func, lines, index):
840 840 """Format a single stack frame"""
841 841 Colors = self.Colors # just a shorthand + quicker name lookup
842 842 ColorsNormal = Colors.Normal # used a lot
843 843 col_scheme = self.color_scheme_table.active_scheme_name
844 844 indent = ' ' * INDENT_SIZE
845 845 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
846 846 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
847 847 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
848 848 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
849 849 ColorsNormal)
850 850 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
851 851 (Colors.vName, Colors.valEm, ColorsNormal)
852 852 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
853 853 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
854 854 Colors.vName, ColorsNormal)
855 855 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
856 856
857 857 if not file:
858 858 file = '?'
859 859 elif file.startswith(str("<")) and file.endswith(str(">")):
860 860 # Not a real filename, no problem...
861 861 pass
862 862 elif not os.path.isabs(file):
863 863 # Try to make the filename absolute by trying all
864 864 # sys.path entries (which is also what linecache does)
865 865 for dirname in sys.path:
866 866 try:
867 867 fullname = os.path.join(dirname, file)
868 868 if os.path.isfile(fullname):
869 869 file = os.path.abspath(fullname)
870 870 break
871 871 except Exception:
872 872 # Just in case that sys.path contains very
873 873 # strange entries...
874 874 pass
875 875
876 876 file = py3compat.cast_unicode(file, util_path.fs_encoding)
877 877 link = tpl_link % util_path.compress_user(file)
878 878 args, varargs, varkw, locals_ = inspect.getargvalues(frame)
879 879
880 880 if func == '?':
881 881 call = ''
882 882 elif func == '<module>':
883 883 call = tpl_call % (func, '')
884 884 else:
885 885 # Decide whether to include variable details or not
886 886 var_repr = eqrepr if self.include_vars else nullrepr
887 887 try:
888 888 call = tpl_call % (func, inspect.formatargvalues(args,
889 889 varargs, varkw,
890 890 locals_, formatvalue=var_repr))
891 891 except KeyError:
892 892 # This happens in situations like errors inside generator
893 893 # expressions, where local variables are listed in the
894 894 # line, but can't be extracted from the frame. I'm not
895 895 # 100% sure this isn't actually a bug in inspect itself,
896 896 # but since there's no info for us to compute with, the
897 897 # best we can do is report the failure and move on. Here
898 898 # we must *not* call any traceback construction again,
899 899 # because that would mess up use of %debug later on. So we
900 900 # simply report the failure and move on. The only
901 901 # limitation will be that this frame won't have locals
902 902 # listed in the call signature. Quite subtle problem...
903 903 # I can't think of a good way to validate this in a unit
904 904 # test, but running a script consisting of:
905 905 # dict( (k,v.strip()) for (k,v) in range(10) )
906 906 # will illustrate the error, if this exception catch is
907 907 # disabled.
908 908 call = tpl_call_fail % func
909 909
910 910 # Don't attempt to tokenize binary files.
911 911 if file.endswith(('.so', '.pyd', '.dll')):
912 912 return '%s %s\n' % (link, call)
913 913
914 914 elif file.endswith(('.pyc', '.pyo')):
915 915 # Look up the corresponding source file.
916 916 try:
917 917 file = source_from_cache(file)
918 918 except ValueError:
919 919 # Failed to get the source file for some reason
920 920 # E.g. https://github.com/ipython/ipython/issues/9486
921 921 return '%s %s\n' % (link, call)
922 922
923 923 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
924 924 line = getline(file, lnum[0])
925 925 lnum[0] += 1
926 926 return line
927 927
928 928 # Build the list of names on this line of code where the exception
929 929 # occurred.
930 930 try:
931 931 names = []
932 932 name_cont = False
933 933
934 934 for token_type, token, start, end, line in generate_tokens(linereader):
935 935 # build composite names
936 936 if token_type == tokenize.NAME and token not in keyword.kwlist:
937 937 if name_cont:
938 938 # Continuation of a dotted name
939 939 try:
940 940 names[-1].append(token)
941 941 except IndexError:
942 942 names.append([token])
943 943 name_cont = False
944 944 else:
945 945 # Regular new names. We append everything, the caller
946 946 # will be responsible for pruning the list later. It's
947 947 # very tricky to try to prune as we go, b/c composite
948 948 # names can fool us. The pruning at the end is easy
949 949 # to do (or the caller can print a list with repeated
950 950 # names if so desired.
951 951 names.append([token])
952 952 elif token == '.':
953 953 name_cont = True
954 954 elif token_type == tokenize.NEWLINE:
955 955 break
956 956
957 957 except (IndexError, UnicodeDecodeError, SyntaxError):
958 958 # signals exit of tokenizer
959 959 # SyntaxError can occur if the file is not actually Python
960 960 # - see gh-6300
961 961 pass
962 962 except tokenize.TokenError as msg:
963 963 # Tokenizing may fail for various reasons, many of which are
964 964 # harmless. (A good example is when the line in question is the
965 965 # close of a triple-quoted string, cf gh-6864). We don't want to
966 966 # show this to users, but want make it available for debugging
967 967 # purposes.
968 968 _m = ("An unexpected error occurred while tokenizing input\n"
969 969 "The following traceback may be corrupted or invalid\n"
970 970 "The error message is: %s\n" % msg)
971 971 debug(_m)
972 972
973 973 # Join composite names (e.g. "dict.fromkeys")
974 974 names = ['.'.join(n) for n in names]
975 975 # prune names list of duplicates, but keep the right order
976 976 unique_names = uniq_stable(names)
977 977
978 978 # Start loop over vars
979 979 lvals = ''
980 980 lvals_list = []
981 981 if self.include_vars:
982 982 for name_full in unique_names:
983 983 name_base = name_full.split('.', 1)[0]
984 984 if name_base in frame.f_code.co_varnames:
985 985 if name_base in locals_:
986 986 try:
987 987 value = repr(eval(name_full, locals_))
988 988 except:
989 989 value = undefined
990 990 else:
991 991 value = undefined
992 992 name = tpl_local_var % name_full
993 993 else:
994 994 if name_base in frame.f_globals:
995 995 try:
996 996 value = repr(eval(name_full, frame.f_globals))
997 997 except:
998 998 value = undefined
999 999 else:
1000 1000 value = undefined
1001 1001 name = tpl_global_var % name_full
1002 1002 lvals_list.append(tpl_name_val % (name, value))
1003 1003 if lvals_list:
1004 1004 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
1005 1005
1006 1006 level = '%s %s\n' % (link, call)
1007 1007
1008 1008 if index is None:
1009 1009 return level
1010 1010 else:
1011 1011 _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2
1012 1012 return '%s%s' % (level, ''.join(
1013 1013 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1014 1014 _line_format)))
1015 1015
1016 1016 def prepare_chained_exception_message(self, cause):
1017 1017 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1018 1018 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1019 1019
1020 1020 if cause:
1021 1021 message = [[direct_cause]]
1022 1022 else:
1023 1023 message = [[exception_during_handling]]
1024 1024 return message
1025 1025
1026 1026 def prepare_header(self, etype, long_version=False):
1027 1027 colors = self.Colors # just a shorthand + quicker name lookup
1028 1028 colorsnormal = colors.Normal # used a lot
1029 1029 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1030 1030 width = min(75, get_terminal_size()[0])
1031 1031 if long_version:
1032 1032 # Header with the exception type, python version, and date
1033 1033 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1034 1034 date = time.ctime(time.time())
1035 1035
1036 1036 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1037 1037 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1038 1038 pyver, date.rjust(width) )
1039 1039 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1040 1040 "\ncalls leading up to the error, with the most recent (innermost) call last."
1041 1041 else:
1042 1042 # Simplified header
1043 1043 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1044 1044 rjust(width - len(str(etype))) )
1045 1045
1046 1046 return head
1047 1047
1048 1048 def format_exception(self, etype, evalue):
1049 1049 colors = self.Colors # just a shorthand + quicker name lookup
1050 1050 colorsnormal = colors.Normal # used a lot
1051 1051 # Get (safely) a string form of the exception info
1052 1052 try:
1053 1053 etype_str, evalue_str = map(str, (etype, evalue))
1054 1054 except:
1055 1055 # User exception is improperly defined.
1056 1056 etype, evalue = str, sys.exc_info()[:2]
1057 1057 etype_str, evalue_str = map(str, (etype, evalue))
1058 1058 # ... and format it
1059 1059 return ['%s%s%s: %s' % (colors.excName, etype_str,
1060 1060 colorsnormal, py3compat.cast_unicode(evalue_str))]
1061 1061
1062 1062 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1063 1063 """Formats the header, traceback and exception message for a single exception.
1064 1064
1065 1065 This may be called multiple times by Python 3 exception chaining
1066 1066 (PEP 3134).
1067 1067 """
1068 1068 # some locals
1069 1069 orig_etype = etype
1070 1070 try:
1071 1071 etype = etype.__name__
1072 1072 except AttributeError:
1073 1073 pass
1074 1074
1075 1075 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1076 1076 head = self.prepare_header(etype, self.long_header)
1077 1077 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1078 1078
1079 1079 if records is None:
1080 1080 return ""
1081 1081
1082 1082 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1083 1083
1084 1084 frames = self.format_records(records, last_unique, recursion_repeat)
1085 1085
1086 1086 formatted_exception = self.format_exception(etype, evalue)
1087 1087 if records:
1088 1088 filepath, lnum = records[-1][1:3]
1089 1089 filepath = os.path.abspath(filepath)
1090 1090 ipinst = get_ipython()
1091 1091 if ipinst is not None:
1092 1092 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1093 1093
1094 1094 return [[head] + frames + [''.join(formatted_exception[0])]]
1095 1095
1096 1096 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1097 1097 try:
1098 1098 # Try the default getinnerframes and Alex's: Alex's fixes some
1099 1099 # problems, but it generates empty tracebacks for console errors
1100 1100 # (5 blanks lines) where none should be returned.
1101 1101 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1102 1102 except UnicodeDecodeError:
1103 1103 # This can occur if a file's encoding magic comment is wrong.
1104 1104 # I can't see a way to recover without duplicating a bunch of code
1105 1105 # from the stdlib traceback module. --TK
1106 1106 error('\nUnicodeDecodeError while processing traceback.\n')
1107 1107 return None
1108 1108 except:
1109 1109 # FIXME: I've been getting many crash reports from python 2.3
1110 1110 # users, traceable to inspect.py. If I can find a small test-case
1111 1111 # to reproduce this, I should either write a better workaround or
1112 1112 # file a bug report against inspect (if that's the real problem).
1113 1113 # So far, I haven't been able to find an isolated example to
1114 1114 # reproduce the problem.
1115 1115 inspect_error()
1116 1116 traceback.print_exc(file=self.ostream)
1117 1117 info('\nUnfortunately, your original traceback can not be constructed.\n')
1118 1118 return None
1119 1119
1120 1120 def get_parts_of_chained_exception(self, evalue):
1121 1121 def get_chained_exception(exception_value):
1122 1122 cause = getattr(exception_value, '__cause__', None)
1123 1123 if cause:
1124 1124 return cause
1125 1125 if getattr(exception_value, '__suppress_context__', False):
1126 1126 return None
1127 1127 return getattr(exception_value, '__context__', None)
1128 1128
1129 1129 chained_evalue = get_chained_exception(evalue)
1130 1130
1131 1131 if chained_evalue:
1132 1132 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1133 1133
1134 1134 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1135 1135 number_of_lines_of_context=5):
1136 1136 """Return a nice text document describing the traceback."""
1137 1137
1138 1138 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1139 1139 tb_offset)
1140 1140
1141 1141 colors = self.Colors # just a shorthand + quicker name lookup
1142 1142 colorsnormal = colors.Normal # used a lot
1143 1143 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1144 1144 structured_traceback_parts = [head]
1145 1145 chained_exceptions_tb_offset = 0
1146 1146 lines_of_context = 3
1147 1147 formatted_exceptions = formatted_exception
1148 1148 exception = self.get_parts_of_chained_exception(evalue)
1149 1149 if exception:
1150 1150 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1151 1151 etype, evalue, etb = exception
1152 1152 else:
1153 1153 evalue = None
1154 1154 chained_exc_ids = set()
1155 1155 while evalue:
1156 1156 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1157 1157 chained_exceptions_tb_offset)
1158 1158 exception = self.get_parts_of_chained_exception(evalue)
1159 1159
1160 1160 if exception and not id(exception[1]) in chained_exc_ids:
1161 1161 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1162 1162 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1163 1163 etype, evalue, etb = exception
1164 1164 else:
1165 1165 evalue = None
1166 1166
1167 1167 # we want to see exceptions in a reversed order:
1168 1168 # the first exception should be on top
1169 1169 for formatted_exception in reversed(formatted_exceptions):
1170 1170 structured_traceback_parts += formatted_exception
1171 1171
1172 1172 return structured_traceback_parts
1173 1173
1174 1174 def debugger(self, force=False):
1175 1175 """Call up the pdb debugger if desired, always clean up the tb
1176 1176 reference.
1177 1177
1178 1178 Keywords:
1179 1179
1180 1180 - force(False): by default, this routine checks the instance call_pdb
1181 1181 flag and does not actually invoke the debugger if the flag is false.
1182 1182 The 'force' option forces the debugger to activate even if the flag
1183 1183 is false.
1184 1184
1185 1185 If the call_pdb flag is set, the pdb interactive debugger is
1186 1186 invoked. In all cases, the self.tb reference to the current traceback
1187 1187 is deleted to prevent lingering references which hamper memory
1188 1188 management.
1189 1189
1190 1190 Note that each call to pdb() does an 'import readline', so if your app
1191 1191 requires a special setup for the readline completers, you'll have to
1192 1192 fix that by hand after invoking the exception handler."""
1193 1193
1194 1194 if force or self.call_pdb:
1195 1195 if self.pdb is None:
1196 1196 self.pdb = self.debugger_cls()
1197 1197 # the system displayhook may have changed, restore the original
1198 1198 # for pdb
1199 1199 display_trap = DisplayTrap(hook=sys.__displayhook__)
1200 1200 with display_trap:
1201 1201 self.pdb.reset()
1202 1202 # Find the right frame so we don't pop up inside ipython itself
1203 1203 if hasattr(self, 'tb') and self.tb is not None:
1204 1204 etb = self.tb
1205 1205 else:
1206 1206 etb = self.tb = sys.last_traceback
1207 1207 while self.tb is not None and self.tb.tb_next is not None:
1208 1208 self.tb = self.tb.tb_next
1209 1209 if etb and etb.tb_next:
1210 1210 etb = etb.tb_next
1211 1211 self.pdb.botframe = etb.tb_frame
1212 1212 self.pdb.interaction(None, etb)
1213 1213
1214 1214 if hasattr(self, 'tb'):
1215 1215 del self.tb
1216 1216
1217 1217 def handler(self, info=None):
1218 1218 (etype, evalue, etb) = info or sys.exc_info()
1219 1219 self.tb = etb
1220 1220 ostream = self.ostream
1221 1221 ostream.flush()
1222 1222 ostream.write(self.text(etype, evalue, etb))
1223 1223 ostream.write('\n')
1224 1224 ostream.flush()
1225 1225
1226 1226 # Changed so an instance can just be called as VerboseTB_inst() and print
1227 1227 # out the right info on its own.
1228 1228 def __call__(self, etype=None, evalue=None, etb=None):
1229 1229 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1230 1230 if etb is None:
1231 1231 self.handler()
1232 1232 else:
1233 1233 self.handler((etype, evalue, etb))
1234 1234 try:
1235 1235 self.debugger()
1236 1236 except KeyboardInterrupt:
1237 1237 print("\nKeyboardInterrupt")
1238 1238
1239 1239
1240 1240 #----------------------------------------------------------------------------
1241 1241 class FormattedTB(VerboseTB, ListTB):
1242 1242 """Subclass ListTB but allow calling with a traceback.
1243 1243
1244 1244 It can thus be used as a sys.excepthook for Python > 2.1.
1245 1245
1246 1246 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1247 1247
1248 1248 Allows a tb_offset to be specified. This is useful for situations where
1249 1249 one needs to remove a number of topmost frames from the traceback (such as
1250 1250 occurs with python programs that themselves execute other python code,
1251 1251 like Python shells). """
1252 1252
1253 1253 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1254 1254 ostream=None,
1255 1255 tb_offset=0, long_header=False, include_vars=False,
1256 1256 check_cache=None, debugger_cls=None,
1257 1257 parent=None, config=None):
1258 1258
1259 1259 # NEVER change the order of this list. Put new modes at the end:
1260 1260 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1261 1261 self.verbose_modes = self.valid_modes[1:3]
1262 1262
1263 1263 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1264 1264 ostream=ostream, tb_offset=tb_offset,
1265 1265 long_header=long_header, include_vars=include_vars,
1266 1266 check_cache=check_cache, debugger_cls=debugger_cls,
1267 1267 parent=parent, config=config)
1268 1268
1269 1269 # Different types of tracebacks are joined with different separators to
1270 1270 # form a single string. They are taken from this dict
1271 1271 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1272 1272 Minimal='')
1273 1273 # set_mode also sets the tb_join_char attribute
1274 1274 self.set_mode(mode)
1275 1275
1276 1276 def _extract_tb(self, tb):
1277 1277 if tb:
1278 1278 return traceback.extract_tb(tb)
1279 1279 else:
1280 1280 return None
1281 1281
1282 1282 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1283 1283 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1284 1284 mode = self.mode
1285 1285 if mode in self.verbose_modes:
1286 1286 # Verbose modes need a full traceback
1287 1287 return VerboseTB.structured_traceback(
1288 1288 self, etype, value, tb, tb_offset, number_of_lines_of_context
1289 1289 )
1290 1290 elif mode == 'Minimal':
1291 1291 return ListTB.get_exception_only(self, etype, value)
1292 1292 else:
1293 1293 # We must check the source cache because otherwise we can print
1294 1294 # out-of-date source code.
1295 1295 self.check_cache()
1296 1296 # Now we can extract and format the exception
1297 1297 elist = self._extract_tb(tb)
1298 1298 return ListTB.structured_traceback(
1299 1299 self, etype, value, elist, tb_offset, number_of_lines_of_context
1300 1300 )
1301 1301
1302 1302 def stb2text(self, stb):
1303 1303 """Convert a structured traceback (a list) to a string."""
1304 1304 return self.tb_join_char.join(stb)
1305 1305
1306 1306
1307 1307 def set_mode(self, mode=None):
1308 1308 """Switch to the desired mode.
1309 1309
1310 1310 If mode is not specified, cycles through the available modes."""
1311 1311
1312 1312 if not mode:
1313 1313 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1314 1314 len(self.valid_modes)
1315 1315 self.mode = self.valid_modes[new_idx]
1316 1316 elif mode not in self.valid_modes:
1317 1317 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1318 1318 'Valid modes: ' + str(self.valid_modes))
1319 1319 else:
1320 1320 self.mode = mode
1321 1321 # include variable details only in 'Verbose' mode
1322 1322 self.include_vars = (self.mode == self.valid_modes[2])
1323 1323 # Set the join character for generating text tracebacks
1324 1324 self.tb_join_char = self._join_chars[self.mode]
1325 1325
1326 1326 # some convenient shortcuts
1327 1327 def plain(self):
1328 1328 self.set_mode(self.valid_modes[0])
1329 1329
1330 1330 def context(self):
1331 1331 self.set_mode(self.valid_modes[1])
1332 1332
1333 1333 def verbose(self):
1334 1334 self.set_mode(self.valid_modes[2])
1335 1335
1336 1336 def minimal(self):
1337 1337 self.set_mode(self.valid_modes[3])
1338 1338
1339 1339
1340 1340 #----------------------------------------------------------------------------
1341 1341 class AutoFormattedTB(FormattedTB):
1342 1342 """A traceback printer which can be called on the fly.
1343 1343
1344 1344 It will find out about exceptions by itself.
1345 1345
1346 1346 A brief example::
1347 1347
1348 1348 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1349 1349 try:
1350 1350 ...
1351 1351 except:
1352 1352 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1353 1353 """
1354 1354
1355 1355 def __call__(self, etype=None, evalue=None, etb=None,
1356 1356 out=None, tb_offset=None):
1357 1357 """Print out a formatted exception traceback.
1358 1358
1359 1359 Optional arguments:
1360 1360 - out: an open file-like object to direct output to.
1361 1361
1362 1362 - tb_offset: the number of frames to skip over in the stack, on a
1363 1363 per-call basis (this overrides temporarily the instance's tb_offset
1364 1364 given at initialization time. """
1365 1365
1366 1366 if out is None:
1367 1367 out = self.ostream
1368 1368 out.flush()
1369 1369 out.write(self.text(etype, evalue, etb, tb_offset))
1370 1370 out.write('\n')
1371 1371 out.flush()
1372 1372 # FIXME: we should remove the auto pdb behavior from here and leave
1373 1373 # that to the clients.
1374 1374 try:
1375 1375 self.debugger()
1376 1376 except KeyboardInterrupt:
1377 1377 print("\nKeyboardInterrupt")
1378 1378
1379 1379 def structured_traceback(self, etype=None, value=None, tb=None,
1380 1380 tb_offset=None, number_of_lines_of_context=5):
1381 1381 if etype is None:
1382 1382 etype, value, tb = sys.exc_info()
1383 1383 self.tb = tb
1384 1384 return FormattedTB.structured_traceback(
1385 1385 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1386 1386
1387 1387
1388 1388 #---------------------------------------------------------------------------
1389 1389
1390 1390 # A simple class to preserve Nathan's original functionality.
1391 1391 class ColorTB(FormattedTB):
1392 1392 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1393 1393
1394 1394 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1395 1395 FormattedTB.__init__(self, color_scheme=color_scheme,
1396 1396 call_pdb=call_pdb, **kwargs)
1397 1397
1398 1398
1399 1399 class SyntaxTB(ListTB):
1400 1400 """Extension which holds some state: the last exception value"""
1401 1401
1402 1402 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1403 1403 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1404 1404 self.last_syntax_error = None
1405 1405
1406 1406 def __call__(self, etype, value, elist):
1407 1407 self.last_syntax_error = value
1408 1408
1409 1409 ListTB.__call__(self, etype, value, elist)
1410 1410
1411 1411 def structured_traceback(self, etype, value, elist, tb_offset=None,
1412 1412 context=5):
1413 1413 # If the source file has been edited, the line in the syntax error can
1414 1414 # be wrong (retrieved from an outdated cache). This replaces it with
1415 1415 # the current value.
1416 1416 if isinstance(value, SyntaxError) \
1417 1417 and isinstance(value.filename, str) \
1418 1418 and isinstance(value.lineno, int):
1419 1419 linecache.checkcache(value.filename)
1420 1420 newtext = linecache.getline(value.filename, value.lineno)
1421 1421 if newtext:
1422 1422 value.text = newtext
1423 1423 self.last_syntax_error = value
1424 1424 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1425 1425 tb_offset=tb_offset, context=context)
1426 1426
1427 1427 def clear_err_state(self):
1428 1428 """Return the current error state and clear it"""
1429 1429 e = self.last_syntax_error
1430 1430 self.last_syntax_error = None
1431 1431 return e
1432 1432
1433 1433 def stb2text(self, stb):
1434 1434 """Convert a structured traceback (a list) to a string."""
1435 1435 return ''.join(stb)
1436 1436
1437 1437
1438 1438 # some internal-use functions
1439 1439 def text_repr(value):
1440 1440 """Hopefully pretty robust repr equivalent."""
1441 1441 # this is pretty horrible but should always return *something*
1442 1442 try:
1443 1443 return pydoc.text.repr(value)
1444 1444 except KeyboardInterrupt:
1445 1445 raise
1446 1446 except:
1447 1447 try:
1448 1448 return repr(value)
1449 1449 except KeyboardInterrupt:
1450 1450 raise
1451 1451 except:
1452 1452 try:
1453 1453 # all still in an except block so we catch
1454 1454 # getattr raising
1455 1455 name = getattr(value, '__name__', None)
1456 1456 if name:
1457 1457 # ick, recursion
1458 1458 return text_repr(name)
1459 1459 klass = getattr(value, '__class__', None)
1460 1460 if klass:
1461 1461 return '%s instance' % text_repr(klass)
1462 1462 except KeyboardInterrupt:
1463 1463 raise
1464 1464 except:
1465 1465 return 'UNRECOVERABLE REPR FAILURE'
1466 1466
1467 1467
1468 1468 def eqrepr(value, repr=text_repr):
1469 1469 return '=%s' % repr(value)
1470 1470
1471 1471
1472 1472 def nullrepr(value, repr=text_repr):
1473 1473 return ''
@@ -1,32 +1,32 b''
1 1 """
2 2 **DEPRECATED**
3 3
4 4 A print function that pretty prints sympy Basic objects.
5 5
6 6 :moduleauthor: Brian Granger
7 7
8 8 Usage
9 9 =====
10 10
11 11 Once the extension is loaded, Sympy Basic objects are automatically
12 12 pretty-printed.
13 13
14 14 As of SymPy 0.7.2, maintenance of this extension has moved to SymPy under
15 15 sympy.interactive.ipythonprinting, any modifications to account for changes to
16 16 SymPy should be submitted to SymPy rather than changed here. This module is
17 maintained here for backwards compatablitiy with old SymPy versions.
17 maintained here for backwards compatibility with old SymPy versions.
18 18
19 19 """
20 20 #-----------------------------------------------------------------------------
21 21 # Copyright (C) 2008 The IPython Development Team
22 22 #-----------------------------------------------------------------------------
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Imports
26 26 #-----------------------------------------------------------------------------
27 27
28 28 import warnings
29 29
30 30 def load_ipython_extension(ip):
31 31 warnings.warn("The sympyprinting extension has moved to `sympy`, "
32 32 "use `from sympy import init_printing; init_printing()`")
@@ -1,761 +1,761 b''
1 1 """Nose Plugin that supports IPython doctests.
2 2
3 3 Limitations:
4 4
5 5 - When generating examples for use as doctests, make sure that you have
6 6 pretty-printing OFF. This can be done either by setting the
7 7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 8 by interactively disabling it with %Pprint. This is required so that IPython
9 9 output matches that of normal Python, which is used by doctest for internal
10 10 execution.
11 11
12 12 - Do not rely on specific prompt numbers for results (such as using
13 13 '_34==True', for example). For IPython tests run via an external process the
14 14 prompt numbers may be different, and IPython tests run as normal python code
15 15 won't even have these special _NN variables set at all.
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Module imports
20 20
21 21 # From the standard library
22 22 import builtins as builtin_mod
23 23 import doctest
24 24 import inspect
25 25 import logging
26 26 import os
27 27 import re
28 28 import sys
29 29 from importlib import import_module
30 30 from io import StringIO
31 31
32 32 from testpath import modified_env
33 33
34 34 from inspect import getmodule
35 35
36 36 # We are overriding the default doctest runner, so we need to import a few
37 37 # things from doctest directly
38 38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 39 _unittest_reportflags, DocTestRunner,
40 40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 41 _exception_traceback,
42 42 linecache)
43 43
44 44 # Third-party modules
45 45
46 46 from nose.plugins import doctests, Plugin
47 47 from nose.util import anyp, tolist
48 48
49 49 #-----------------------------------------------------------------------------
50 50 # Module globals and other constants
51 51 #-----------------------------------------------------------------------------
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Classes and functions
58 58 #-----------------------------------------------------------------------------
59 59
60 60 def is_extension_module(filename):
61 61 """Return whether the given filename is an extension module.
62 62
63 63 This simply checks that the extension is either .so or .pyd.
64 64 """
65 65 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
66 66
67 67
68 68 class DocTestSkip(object):
69 69 """Object wrapper for doctests to be skipped."""
70 70
71 71 ds_skip = """Doctest to skip.
72 72 >>> 1 #doctest: +SKIP
73 73 """
74 74
75 75 def __init__(self,obj):
76 76 self.obj = obj
77 77
78 78 def __getattribute__(self,key):
79 79 if key == '__doc__':
80 80 return DocTestSkip.ds_skip
81 81 else:
82 82 return getattr(object.__getattribute__(self,'obj'),key)
83 83
84 84 # Modified version of the one in the stdlib, that fixes a python bug (doctests
85 85 # not found in extension modules, http://bugs.python.org/issue3158)
86 86 class DocTestFinder(doctest.DocTestFinder):
87 87
88 88 def _from_module(self, module, object):
89 89 """
90 90 Return true if the given object is defined in the given
91 91 module.
92 92 """
93 93 if module is None:
94 94 return True
95 95 elif inspect.isfunction(object):
96 96 return module.__dict__ is object.__globals__
97 97 elif inspect.isbuiltin(object):
98 98 return module.__name__ == object.__module__
99 99 elif inspect.isclass(object):
100 100 return module.__name__ == object.__module__
101 101 elif inspect.ismethod(object):
102 102 # This one may be a bug in cython that fails to correctly set the
103 103 # __module__ attribute of methods, but since the same error is easy
104 104 # to make by extension code writers, having this safety in place
105 105 # isn't such a bad idea
106 106 return module.__name__ == object.__self__.__class__.__module__
107 107 elif inspect.getmodule(object) is not None:
108 108 return module is inspect.getmodule(object)
109 109 elif hasattr(object, '__module__'):
110 110 return module.__name__ == object.__module__
111 111 elif isinstance(object, property):
112 112 return True # [XX] no way not be sure.
113 113 elif inspect.ismethoddescriptor(object):
114 114 # Unbound PyQt signals reach this point in Python 3.4b3, and we want
115 115 # to avoid throwing an error. See also http://bugs.python.org/issue3158
116 116 return False
117 117 else:
118 118 raise ValueError("object must be a class or function, got %r" % object)
119 119
120 120 def _find(self, tests, obj, name, module, source_lines, globs, seen):
121 121 """
122 122 Find tests for the given object and any contained objects, and
123 123 add them to `tests`.
124 124 """
125 125 print('_find for:', obj, name, module) # dbg
126 126 if hasattr(obj,"skip_doctest"):
127 127 #print 'SKIPPING DOCTEST FOR:',obj # dbg
128 128 obj = DocTestSkip(obj)
129 129
130 130 doctest.DocTestFinder._find(self,tests, obj, name, module,
131 131 source_lines, globs, seen)
132 132
133 133 # Below we re-run pieces of the above method with manual modifications,
134 134 # because the original code is buggy and fails to correctly identify
135 135 # doctests in extension modules.
136 136
137 137 # Local shorthands
138 138 from inspect import isroutine, isclass
139 139
140 140 # Look for tests in a module's contained objects.
141 141 if inspect.ismodule(obj) and self._recurse:
142 142 for valname, val in obj.__dict__.items():
143 143 valname1 = '%s.%s' % (name, valname)
144 144 if ( (isroutine(val) or isclass(val))
145 145 and self._from_module(module, val) ):
146 146
147 147 self._find(tests, val, valname1, module, source_lines,
148 148 globs, seen)
149 149
150 150 # Look for tests in a class's contained objects.
151 151 if inspect.isclass(obj) and self._recurse:
152 152 #print 'RECURSE into class:',obj # dbg
153 153 for valname, val in obj.__dict__.items():
154 154 # Special handling for staticmethod/classmethod.
155 155 if isinstance(val, staticmethod):
156 156 val = getattr(obj, valname)
157 157 if isinstance(val, classmethod):
158 158 val = getattr(obj, valname).__func__
159 159
160 160 # Recurse to methods, properties, and nested classes.
161 161 if ((inspect.isfunction(val) or inspect.isclass(val) or
162 162 inspect.ismethod(val) or
163 163 isinstance(val, property)) and
164 164 self._from_module(module, val)):
165 165 valname = '%s.%s' % (name, valname)
166 166 self._find(tests, val, valname, module, source_lines,
167 167 globs, seen)
168 168
169 169
170 170 class IPDoctestOutputChecker(doctest.OutputChecker):
171 171 """Second-chance checker with support for random tests.
172 172
173 173 If the default comparison doesn't pass, this checker looks in the expected
174 174 output string for flags that tell us to ignore the output.
175 175 """
176 176
177 177 random_re = re.compile(r'#\s*random\s+')
178 178
179 179 def check_output(self, want, got, optionflags):
180 180 """Check output, accepting special markers embedded in the output.
181 181
182 182 If the output didn't pass the default validation but the special string
183 183 '#random' is included, we accept it."""
184 184
185 185 # Let the original tester verify first, in case people have valid tests
186 186 # that happen to have a comment saying '#random' embedded in.
187 187 ret = doctest.OutputChecker.check_output(self, want, got,
188 188 optionflags)
189 189 if not ret and self.random_re.search(want):
190 190 #print >> sys.stderr, 'RANDOM OK:',want # dbg
191 191 return True
192 192
193 193 return ret
194 194
195 195
196 196 class DocTestCase(doctests.DocTestCase):
197 197 """Proxy for DocTestCase: provides an address() method that
198 198 returns the correct address for the doctest case. Otherwise
199 199 acts as a proxy to the test case. To provide hints for address(),
200 200 an obj may also be passed -- this will be used as the test object
201 201 for purposes of determining the test address, if it is provided.
202 202 """
203 203
204 204 # Note: this method was taken from numpy's nosetester module.
205 205
206 206 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
207 207 # its constructor that blocks non-default arguments from being passed
208 208 # down into doctest.DocTestCase
209 209
210 210 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
211 211 checker=None, obj=None, result_var='_'):
212 212 self._result_var = result_var
213 213 doctests.DocTestCase.__init__(self, test,
214 214 optionflags=optionflags,
215 215 setUp=setUp, tearDown=tearDown,
216 216 checker=checker)
217 217 # Now we must actually copy the original constructor from the stdlib
218 218 # doctest class, because we can't call it directly and a bug in nose
219 219 # means it never gets passed the right arguments.
220 220
221 221 self._dt_optionflags = optionflags
222 222 self._dt_checker = checker
223 223 self._dt_test = test
224 224 self._dt_test_globs_ori = test.globs
225 225 self._dt_setUp = setUp
226 226 self._dt_tearDown = tearDown
227 227
228 228 # XXX - store this runner once in the object!
229 229 runner = IPDocTestRunner(optionflags=optionflags,
230 230 checker=checker, verbose=False)
231 231 self._dt_runner = runner
232 232
233 233
234 234 # Each doctest should remember the directory it was loaded from, so
235 235 # things like %run work without too many contortions
236 236 self._ori_dir = os.path.dirname(test.filename)
237 237
238 238 # Modified runTest from the default stdlib
239 239 def runTest(self):
240 240 test = self._dt_test
241 241 runner = self._dt_runner
242 242
243 243 old = sys.stdout
244 244 new = StringIO()
245 245 optionflags = self._dt_optionflags
246 246
247 247 if not (optionflags & REPORTING_FLAGS):
248 248 # The option flags don't include any reporting flags,
249 249 # so add the default reporting flags
250 250 optionflags |= _unittest_reportflags
251 251
252 252 try:
253 253 # Save our current directory and switch out to the one where the
254 254 # test was originally created, in case another doctest did a
255 255 # directory change. We'll restore this in the finally clause.
256 256 curdir = os.getcwd()
257 257 #print 'runTest in dir:', self._ori_dir # dbg
258 258 os.chdir(self._ori_dir)
259 259
260 260 runner.DIVIDER = "-"*70
261 261 failures, tries = runner.run(test,out=new.write,
262 262 clear_globs=False)
263 263 finally:
264 264 sys.stdout = old
265 265 os.chdir(curdir)
266 266
267 267 if failures:
268 268 raise self.failureException(self.format_failure(new.getvalue()))
269 269
270 270 def setUp(self):
271 271 """Modified test setup that syncs with ipython namespace"""
272 272 #print "setUp test", self._dt_test.examples # dbg
273 273 if isinstance(self._dt_test.examples[0], IPExample):
274 274 # for IPython examples *only*, we swap the globals with the ipython
275 275 # namespace, after updating it with the globals (which doctest
276 276 # fills with the necessary info from the module being tested).
277 277 self.user_ns_orig = {}
278 278 self.user_ns_orig.update(_ip.user_ns)
279 279 _ip.user_ns.update(self._dt_test.globs)
280 280 # We must remove the _ key in the namespace, so that Python's
281 281 # doctest code sets it naturally
282 282 _ip.user_ns.pop('_', None)
283 283 _ip.user_ns['__builtins__'] = builtin_mod
284 284 self._dt_test.globs = _ip.user_ns
285 285
286 286 super(DocTestCase, self).setUp()
287 287
288 288 def tearDown(self):
289 289
290 290 # Undo the test.globs reassignment we made, so that the parent class
291 291 # teardown doesn't destroy the ipython namespace
292 292 if isinstance(self._dt_test.examples[0], IPExample):
293 293 self._dt_test.globs = self._dt_test_globs_ori
294 294 _ip.user_ns.clear()
295 295 _ip.user_ns.update(self.user_ns_orig)
296 296
297 297 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
298 298 # it does look like one to me: its tearDown method tries to run
299 299 #
300 300 # delattr(builtin_mod, self._result_var)
301 301 #
302 302 # without checking that the attribute really is there; it implicitly
303 303 # assumes it should have been set via displayhook. But if the
304 304 # displayhook was never called, this doesn't necessarily happen. I
305 305 # haven't been able to find a little self-contained example outside of
306 306 # ipython that would show the problem so I can report it to the nose
307 307 # team, but it does happen a lot in our code.
308 308 #
309 309 # So here, we just protect as narrowly as possible by trapping an
310 310 # attribute error whose message would be the name of self._result_var,
311 311 # and letting any other error propagate.
312 312 try:
313 313 super(DocTestCase, self).tearDown()
314 314 except AttributeError as exc:
315 315 if exc.args[0] != self._result_var:
316 316 raise
317 317
318 318
319 319 # A simple subclassing of the original with a different class name, so we can
320 320 # distinguish and treat differently IPython examples from pure python ones.
321 321 class IPExample(doctest.Example): pass
322 322
323 323
324 324 class IPExternalExample(doctest.Example):
325 325 """Doctest examples to be run in an external process."""
326 326
327 327 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
328 328 options=None):
329 329 # Parent constructor
330 330 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
331 331
332 332 # An EXTRA newline is needed to prevent pexpect hangs
333 333 self.source += '\n'
334 334
335 335
336 336 class IPDocTestParser(doctest.DocTestParser):
337 337 """
338 338 A class used to parse strings containing doctest examples.
339 339
340 340 Note: This is a version modified to properly recognize IPython input and
341 341 convert any IPython examples into valid Python ones.
342 342 """
343 343 # This regular expression is used to find doctest examples in a
344 344 # string. It defines three groups: `source` is the source code
345 345 # (including leading indentation and prompts); `indent` is the
346 346 # indentation of the first (PS1) line of the source code; and
347 347 # `want` is the expected output (including leading indentation).
348 348
349 349 # Classic Python prompts or default IPython ones
350 350 _PS1_PY = r'>>>'
351 351 _PS2_PY = r'\.\.\.'
352 352
353 353 _PS1_IP = r'In\ \[\d+\]:'
354 354 _PS2_IP = r'\ \ \ \.\.\.+:'
355 355
356 356 _RE_TPL = r'''
357 357 # Source consists of a PS1 line followed by zero or more PS2 lines.
358 358 (?P<source>
359 359 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
360 360 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
361 361 \n? # a newline
362 362 # Want consists of any non-blank lines that do not start with PS1.
363 363 (?P<want> (?:(?![ ]*$) # Not a blank line
364 364 (?![ ]*%s) # Not a line starting with PS1
365 365 (?![ ]*%s) # Not a line starting with PS2
366 366 .*$\n? # But any other line
367 367 )*)
368 368 '''
369 369
370 370 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
371 371 re.MULTILINE | re.VERBOSE)
372 372
373 373 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
374 374 re.MULTILINE | re.VERBOSE)
375 375
376 376 # Mark a test as being fully random. In this case, we simply append the
377 377 # random marker ('#random') to each individual example's output. This way
378 378 # we don't need to modify any other code.
379 379 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
380 380
381 381 # Mark tests to be executed in an external process - currently unsupported.
382 382 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
383 383
384 384 def ip2py(self,source):
385 385 """Convert input IPython source into valid Python."""
386 386 block = _ip.input_transformer_manager.transform_cell(source)
387 387 if len(block.splitlines()) == 1:
388 388 return _ip.prefilter(block)
389 389 else:
390 390 return block
391 391
392 392 def parse(self, string, name='<string>'):
393 393 """
394 394 Divide the given string into examples and intervening text,
395 395 and return them as a list of alternating Examples and strings.
396 396 Line numbers for the Examples are 0-based. The optional
397 397 argument `name` is a name identifying this string, and is only
398 398 used for error messages.
399 399 """
400 400
401 401 #print 'Parse string:\n',string # dbg
402 402
403 403 string = string.expandtabs()
404 404 # If all lines begin with the same indentation, then strip it.
405 405 min_indent = self._min_indent(string)
406 406 if min_indent > 0:
407 407 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
408 408
409 409 output = []
410 410 charno, lineno = 0, 0
411 411
412 412 # We make 'all random' tests by adding the '# random' mark to every
413 413 # block of output in the test.
414 414 if self._RANDOM_TEST.search(string):
415 415 random_marker = '\n# random'
416 416 else:
417 417 random_marker = ''
418 418
419 419 # Whether to convert the input from ipython to python syntax
420 420 ip2py = False
421 421 # Find all doctest examples in the string. First, try them as Python
422 422 # examples, then as IPython ones
423 423 terms = list(self._EXAMPLE_RE_PY.finditer(string))
424 424 if terms:
425 425 # Normal Python example
426 426 #print '-'*70 # dbg
427 427 #print 'PyExample, Source:\n',string # dbg
428 428 #print '-'*70 # dbg
429 429 Example = doctest.Example
430 430 else:
431 431 # It's an ipython example. Note that IPExamples are run
432 432 # in-process, so their syntax must be turned into valid python.
433 433 # IPExternalExamples are run out-of-process (via pexpect) so they
434 434 # don't need any filtering (a real ipython will be executing them).
435 435 terms = list(self._EXAMPLE_RE_IP.finditer(string))
436 436 if self._EXTERNAL_IP.search(string):
437 437 #print '-'*70 # dbg
438 438 #print 'IPExternalExample, Source:\n',string # dbg
439 439 #print '-'*70 # dbg
440 440 Example = IPExternalExample
441 441 else:
442 442 #print '-'*70 # dbg
443 443 #print 'IPExample, Source:\n',string # dbg
444 444 #print '-'*70 # dbg
445 445 Example = IPExample
446 446 ip2py = True
447 447
448 448 for m in terms:
449 449 # Add the pre-example text to `output`.
450 450 output.append(string[charno:m.start()])
451 451 # Update lineno (lines before this example)
452 452 lineno += string.count('\n', charno, m.start())
453 453 # Extract info from the regexp match.
454 454 (source, options, want, exc_msg) = \
455 455 self._parse_example(m, name, lineno,ip2py)
456 456
457 457 # Append the random-output marker (it defaults to empty in most
458 458 # cases, it's only non-empty for 'all-random' tests):
459 459 want += random_marker
460 460
461 461 if Example is IPExternalExample:
462 462 options[doctest.NORMALIZE_WHITESPACE] = True
463 463 want += '\n'
464 464
465 465 # Create an Example, and add it to the list.
466 466 if not self._IS_BLANK_OR_COMMENT(source):
467 467 output.append(Example(source, want, exc_msg,
468 468 lineno=lineno,
469 469 indent=min_indent+len(m.group('indent')),
470 470 options=options))
471 471 # Update lineno (lines inside this example)
472 472 lineno += string.count('\n', m.start(), m.end())
473 473 # Update charno.
474 474 charno = m.end()
475 475 # Add any remaining post-example text to `output`.
476 476 output.append(string[charno:])
477 477 return output
478 478
479 479 def _parse_example(self, m, name, lineno,ip2py=False):
480 480 """
481 481 Given a regular expression match from `_EXAMPLE_RE` (`m`),
482 482 return a pair `(source, want)`, where `source` is the matched
483 483 example's source code (with prompts and indentation stripped);
484 484 and `want` is the example's expected output (with indentation
485 485 stripped).
486 486
487 487 `name` is the string's name, and `lineno` is the line number
488 488 where the example starts; both are used for error messages.
489 489
490 490 Optional:
491 491 `ip2py`: if true, filter the input via IPython to convert the syntax
492 492 into valid python.
493 493 """
494 494
495 495 # Get the example's indentation level.
496 496 indent = len(m.group('indent'))
497 497
498 498 # Divide source into lines; check that they're properly
499 499 # indented; and then strip their indentation & prompts.
500 500 source_lines = m.group('source').split('\n')
501 501
502 502 # We're using variable-length input prompts
503 503 ps1 = m.group('ps1')
504 504 ps2 = m.group('ps2')
505 505 ps1_len = len(ps1)
506 506
507 507 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
508 508 if ps2:
509 509 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
510 510
511 511 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
512 512
513 513 if ip2py:
514 514 # Convert source input from IPython into valid Python syntax
515 515 source = self.ip2py(source)
516 516
517 517 # Divide want into lines; check that it's properly indented; and
518 518 # then strip the indentation. Spaces before the last newline should
519 519 # be preserved, so plain rstrip() isn't good enough.
520 520 want = m.group('want')
521 521 want_lines = want.split('\n')
522 522 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
523 523 del want_lines[-1] # forget final newline & spaces after it
524 524 self._check_prefix(want_lines, ' '*indent, name,
525 525 lineno + len(source_lines))
526 526
527 527 # Remove ipython output prompt that might be present in the first line
528 528 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
529 529
530 530 want = '\n'.join([wl[indent:] for wl in want_lines])
531 531
532 532 # If `want` contains a traceback message, then extract it.
533 533 m = self._EXCEPTION_RE.match(want)
534 534 if m:
535 535 exc_msg = m.group('msg')
536 536 else:
537 537 exc_msg = None
538 538
539 539 # Extract options from the source.
540 540 options = self._find_options(source, name, lineno)
541 541
542 542 return source, options, want, exc_msg
543 543
544 544 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
545 545 """
546 546 Given the lines of a source string (including prompts and
547 547 leading indentation), check to make sure that every prompt is
548 548 followed by a space character. If any line is not followed by
549 549 a space character, then raise ValueError.
550 550
551 551 Note: IPython-modified version which takes the input prompt length as a
552 552 parameter, so that prompts of variable length can be dealt with.
553 553 """
554 554 space_idx = indent+ps1_len
555 555 min_len = space_idx+1
556 556 for i, line in enumerate(lines):
557 557 if len(line) >= min_len and line[space_idx] != ' ':
558 558 raise ValueError('line %r of the docstring for %s '
559 559 'lacks blank after %s: %r' %
560 560 (lineno+i+1, name,
561 561 line[indent:space_idx], line))
562 562
563 563
564 564 SKIP = doctest.register_optionflag('SKIP')
565 565
566 566
567 567 class IPDocTestRunner(doctest.DocTestRunner,object):
568 568 """Test runner that synchronizes the IPython namespace with test globals.
569 569 """
570 570
571 571 def run(self, test, compileflags=None, out=None, clear_globs=True):
572 572
573 573 # Hack: ipython needs access to the execution context of the example,
574 574 # so that it can propagate user variables loaded by %run into
575 575 # test.globs. We put them here into our modified %run as a function
576 576 # attribute. Our new %run will then only make the namespace update
577 # when called (rather than unconconditionally updating test.globs here
577 # when called (rather than unconditionally updating test.globs here
578 578 # for all examples, most of which won't be calling %run anyway).
579 579 #_ip._ipdoctest_test_globs = test.globs
580 580 #_ip._ipdoctest_test_filename = test.filename
581 581
582 582 test.globs.update(_ip.user_ns)
583 583
584 584 # Override terminal size to standardise traceback format
585 585 with modified_env({'COLUMNS': '80', 'LINES': '24'}):
586 586 return super(IPDocTestRunner,self).run(test,
587 587 compileflags,out,clear_globs)
588 588
589 589
590 590 class DocFileCase(doctest.DocFileCase):
591 591 """Overrides to provide filename
592 592 """
593 593 def address(self):
594 594 return (self._dt_test.filename, None, None)
595 595
596 596
597 597 class ExtensionDoctest(doctests.Doctest):
598 598 """Nose Plugin that supports doctests in extension modules.
599 599 """
600 600 name = 'extdoctest' # call nosetests with --with-extdoctest
601 601 enabled = True
602 602
603 603 def options(self, parser, env=os.environ):
604 604 Plugin.options(self, parser, env)
605 605 parser.add_option('--doctest-tests', action='store_true',
606 606 dest='doctest_tests',
607 607 default=env.get('NOSE_DOCTEST_TESTS',True),
608 608 help="Also look for doctests in test modules. "
609 609 "Note that classes, methods and functions should "
610 610 "have either doctests or non-doctest tests, "
611 611 "not both. [NOSE_DOCTEST_TESTS]")
612 612 parser.add_option('--doctest-extension', action="append",
613 613 dest="doctestExtension",
614 614 help="Also look for doctests in files with "
615 615 "this extension [NOSE_DOCTEST_EXTENSION]")
616 616 # Set the default as a list, if given in env; otherwise
617 617 # an additional value set on the command line will cause
618 618 # an error.
619 619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
620 620 if env_setting is not None:
621 621 parser.set_defaults(doctestExtension=tolist(env_setting))
622 622
623 623
624 624 def configure(self, options, config):
625 625 Plugin.configure(self, options, config)
626 626 # Pull standard doctest plugin out of config; we will do doctesting
627 627 config.plugins.plugins = [p for p in config.plugins.plugins
628 628 if p.name != 'doctest']
629 629 self.doctest_tests = options.doctest_tests
630 630 self.extension = tolist(options.doctestExtension)
631 631
632 632 self.parser = doctest.DocTestParser()
633 633 self.finder = DocTestFinder()
634 634 self.checker = IPDoctestOutputChecker()
635 635 self.globs = None
636 636 self.extraglobs = None
637 637
638 638
639 639 def loadTestsFromExtensionModule(self,filename):
640 640 bpath,mod = os.path.split(filename)
641 641 modname = os.path.splitext(mod)[0]
642 642 try:
643 643 sys.path.append(bpath)
644 644 module = import_module(modname)
645 645 tests = list(self.loadTestsFromModule(module))
646 646 finally:
647 647 sys.path.pop()
648 648 return tests
649 649
650 650 # NOTE: the method below is almost a copy of the original one in nose, with
651 651 # a few modifications to control output checking.
652 652
653 653 def loadTestsFromModule(self, module):
654 654 #print '*** ipdoctest - lTM',module # dbg
655 655
656 656 if not self.matches(module.__name__):
657 657 log.debug("Doctest doesn't want module %s", module)
658 658 return
659 659
660 660 tests = self.finder.find(module,globs=self.globs,
661 661 extraglobs=self.extraglobs)
662 662 if not tests:
663 663 return
664 664
665 665 # always use whitespace and ellipsis options
666 666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
667 667
668 668 tests.sort()
669 669 module_file = module.__file__
670 670 if module_file[-4:] in ('.pyc', '.pyo'):
671 671 module_file = module_file[:-1]
672 672 for test in tests:
673 673 if not test.examples:
674 674 continue
675 675 if not test.filename:
676 676 test.filename = module_file
677 677
678 678 yield DocTestCase(test,
679 679 optionflags=optionflags,
680 680 checker=self.checker)
681 681
682 682
683 683 def loadTestsFromFile(self, filename):
684 684 #print "ipdoctest - from file", filename # dbg
685 685 if is_extension_module(filename):
686 686 for t in self.loadTestsFromExtensionModule(filename):
687 687 yield t
688 688 else:
689 689 if self.extension and anyp(filename.endswith, self.extension):
690 690 name = os.path.basename(filename)
691 691 with open(filename) as dh:
692 692 doc = dh.read()
693 693 test = self.parser.get_doctest(
694 694 doc, globs={'__file__': filename}, name=name,
695 695 filename=filename, lineno=0)
696 696 if test.examples:
697 697 #print 'FileCase:',test.examples # dbg
698 698 yield DocFileCase(test)
699 699 else:
700 700 yield False # no tests to load
701 701
702 702
703 703 class IPythonDoctest(ExtensionDoctest):
704 704 """Nose Plugin that supports doctests in extension modules.
705 705 """
706 706 name = 'ipdoctest' # call nosetests with --with-ipdoctest
707 707 enabled = True
708 708
709 709 def makeTest(self, obj, parent):
710 710 """Look for doctests in the given object, which will be a
711 711 function, method or class.
712 712 """
713 713 #print 'Plugin analyzing:', obj, parent # dbg
714 714 # always use whitespace and ellipsis options
715 715 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
716 716
717 717 doctests = self.finder.find(obj, module=getmodule(parent))
718 718 if doctests:
719 719 for test in doctests:
720 720 if len(test.examples) == 0:
721 721 continue
722 722
723 723 yield DocTestCase(test, obj=obj,
724 724 optionflags=optionflags,
725 725 checker=self.checker)
726 726
727 727 def options(self, parser, env=os.environ):
728 728 #print "Options for nose plugin:", self.name # dbg
729 729 Plugin.options(self, parser, env)
730 730 parser.add_option('--ipdoctest-tests', action='store_true',
731 731 dest='ipdoctest_tests',
732 732 default=env.get('NOSE_IPDOCTEST_TESTS',True),
733 733 help="Also look for doctests in test modules. "
734 734 "Note that classes, methods and functions should "
735 735 "have either doctests or non-doctest tests, "
736 736 "not both. [NOSE_IPDOCTEST_TESTS]")
737 737 parser.add_option('--ipdoctest-extension', action="append",
738 738 dest="ipdoctest_extension",
739 739 help="Also look for doctests in files with "
740 740 "this extension [NOSE_IPDOCTEST_EXTENSION]")
741 741 # Set the default as a list, if given in env; otherwise
742 742 # an additional value set on the command line will cause
743 743 # an error.
744 744 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
745 745 if env_setting is not None:
746 746 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
747 747
748 748 def configure(self, options, config):
749 749 #print "Configuring nose plugin:", self.name # dbg
750 750 Plugin.configure(self, options, config)
751 751 # Pull standard doctest plugin out of config; we will do doctesting
752 752 config.plugins.plugins = [p for p in config.plugins.plugins
753 753 if p.name != 'doctest']
754 754 self.doctest_tests = options.ipdoctest_tests
755 755 self.extension = tolist(options.ipdoctest_extension)
756 756
757 757 self.parser = IPDocTestParser()
758 758 self.finder = DocTestFinder(parser=self.parser)
759 759 self.checker = IPDoctestOutputChecker()
760 760 self.globs = None
761 761 self.extraglobs = None
@@ -1,765 +1,765 b''
1 1 =============
2 2 0.11 Series
3 3 =============
4 4
5 5 Release 0.11
6 6 ============
7 7
8 8 IPython 0.11 is a *major* overhaul of IPython, two years in the making. Most
9 9 of the code base has been rewritten or at least reorganized, breaking backward
10 10 compatibility with several APIs in previous versions. It is the first major
11 11 release in two years, and probably the most significant change to IPython since
12 12 its inception. We plan to have a relatively quick succession of releases, as
13 13 people discover new bugs and regressions. Once we iron out any significant
14 14 bugs in this process and settle down the new APIs, this series will become
15 15 IPython 1.0. We encourage feedback now on the core APIs, which we hope to
16 16 maintain stable during the 1.0 series.
17 17
18 18 Since the internal APIs have changed so much, projects using IPython as a
19 19 library (as opposed to end-users of the application) are the most likely to
20 20 encounter regressions or changes that break their existing use patterns. We
21 21 will make every effort to provide updated versions of the APIs to facilitate
22 22 the transition, and we encourage you to contact us on the `development mailing
23 23 list`__ with questions and feedback.
24 24
25 25 .. __: http://mail.scipy.org/mailman/listinfo/ipython-dev
26 26
27 27 Chris Fonnesbeck recently wrote an `excellent post`__ that highlights some of
28 28 our major new features, with examples and screenshots. We encourage you to
29 29 read it as it provides an illustrated, high-level overview complementing the
30 30 detailed feature breakdown in this document.
31 31
32 32 .. __: http://stronginference.com/post/innovations-in-ipython
33 33
34 34 A quick summary of the major changes (see below for details):
35 35
36 36 * **Standalone Qt console**: a new rich console has been added to IPython,
37 37 started with `ipython qtconsole`. In this application we have tried to
38 38 retain the feel of a terminal for fast and efficient workflows, while adding
39 39 many features that a line-oriented terminal simply can not support, such as
40 40 inline figures, full multiline editing with syntax highlighting, graphical
41 41 tooltips for function calls and much more. This development was sponsored by
42 42 `Enthought Inc.`__. See :ref:`below <qtconsole_011>` for details.
43 43
44 44 .. __: http://enthought.com
45 45
46 46 * **High-level parallel computing with ZeroMQ**. Using the same architecture
47 47 that our Qt console is based on, we have completely rewritten our high-level
48 48 parallel computing machinery that in prior versions used the Twisted
49 49 networking framework. While this change will require users to update their
50 50 codes, the improvements in performance, memory control and internal
51 51 consistency across our codebase convinced us it was a price worth paying. We
52 52 have tried to explain how to best proceed with this update, and will be happy
53 53 to answer questions that may arise. A full tutorial describing these
54 54 features `was presented at SciPy'11`__, more details :ref:`below
55 55 <parallel_011>`.
56 56
57 57 .. __: http://minrk.github.com/scipy-tutorial-2011
58 58
59 59 * **New model for GUI/plotting support in the terminal**. Now instead of the
60 60 various `-Xthread` flags we had before, GUI support is provided without the
61 61 use of any threads, by directly integrating GUI event loops with Python's
62 62 `PyOS_InputHook` API. A new command-line flag `--gui` controls GUI support,
63 63 and it can also be enabled after IPython startup via the new `%gui` magic.
64 64 This requires some changes if you want to execute GUI-using scripts inside
65 65 IPython, see :ref:`the GUI support section <gui_support>` for more details.
66 66
67 67 * **A two-process architecture.** The Qt console is the first use of a new
68 68 model that splits IPython between a kernel process where code is executed and
69 69 a client that handles user interaction. We plan on also providing terminal
70 70 and web-browser based clients using this infrastructure in future releases.
71 71 This model allows multiple clients to interact with an IPython process
72 72 through a :ref:`well-documented messaging protocol <messaging>` using the
73 73 ZeroMQ networking library.
74 74
75 75 * **Refactoring.** the entire codebase has been refactored, in order to make it
76 76 more modular and easier to contribute to. IPython has traditionally been a
77 77 hard project to participate because the old codebase was very monolithic. We
78 78 hope this (ongoing) restructuring will make it easier for new developers to
79 79 join us.
80 80
81 81 * **Vim integration**. Vim can be configured to seamlessly control an IPython
82 82 kernel, see the files in :file:`docs/examples/vim` for the full details.
83 83 This work was done by Paul Ivanov, who prepared a nice `video
84 84 demonstration`__ of the features it provides.
85 85
86 86 .. __: http://pirsquared.org/blog/2011/07/28/vim-ipython/
87 87
88 88 * **Integration into Microsoft Visual Studio**. Thanks to the work of the
89 89 Microsoft `Python Tools for Visual Studio`__ team, this version of IPython
90 90 has been integrated into Microsoft Visual Studio's Python tools open source
91 91 plug-in. `Details below`_
92 92
93 93 .. __: http://pytools.codeplex.com
94 94 .. _details below: ms_visual_studio_011_
95 95
96 96 * **Improved unicode support**. We closed many bugs related to unicode input.
97 97
98 98 * **Python 3**. IPython now runs on Python 3.x. See :ref:`python3_011` for
99 99 details.
100 100
101 101 * **New profile model**. Profiles are now directories that contain all relevant
102 102 information for that session, and thus better isolate IPython use-cases.
103 103
104 104 * **SQLite storage for history**. All history is now stored in a SQLite
105 105 database, providing support for multiple simultaneous sessions that won't
106 106 clobber each other as well as the ability to perform queries on all stored
107 107 data.
108 108
109 109 * **New configuration system**. All parts of IPython are now configured via a
110 110 mechanism inspired by the Enthought Traits library. Any configurable element
111 111 can have its attributes set either via files that now use real Python syntax
112 112 or from the command-line.
113 113
114 114 * **Pasting of code with prompts**. IPython now intelligently strips out input
115 115 prompts , be they plain Python ones (``>>>`` and ``...``) or IPython ones
116 116 (``In [N]:`` and ``...:``). More details :ref:`here <pasting_with_prompts>`.
117 117
118 118
119 119 Authors and support
120 120 -------------------
121 121
122 122 Over 60 separate authors have contributed to this release, see :ref:`below
123 123 <credits_011>` for a full list. In particular, we want to highlight the
124 124 extremely active participation of two new core team members: Evan Patterson
125 125 implemented the Qt console, and Thomas Kluyver started with our Python 3 port
126 126 and by now has made major contributions to just about every area of IPython.
127 127
128 128 We are also grateful for the support we have received during this development
129 129 cycle from several institutions:
130 130
131 131 - `Enthought Inc`__ funded the development of our new Qt console, an effort that
132 132 required developing major pieces of underlying infrastructure, which now
133 133 power not only the Qt console but also our new parallel machinery. We'd like
134 134 to thank Eric Jones and Travis Oliphant for their support, as well as Ilan
135 135 Schnell for his tireless work integrating and testing IPython in the
136 136 `Enthought Python Distribution`_.
137 137
138 138 .. __: http://enthought.com
139 139 .. _Enthought Python Distribution: http://www.enthought.com/products/epd.php
140 140
141 141 - Nipy/NIH: funding via the `NiPy project`__ (NIH grant 5R01MH081909-02) helped
142 142 us jumpstart the development of this series by restructuring the entire
143 143 codebase two years ago in a way that would make modular development and
144 144 testing more approachable. Without this initial groundwork, all the new
145 145 features we have added would have been impossible to develop.
146 146
147 147 .. __: http://nipy.org
148 148
149 149 - Sage/NSF: funding via the grant `Sage: Unifying Mathematical Software for
150 150 Scientists, Engineers, and Mathematicians`__ (NSF grant DMS-1015114)
151 151 supported a meeting in spring 2011 of several of the core IPython developers
152 152 where major progress was made integrating the last key pieces leading to this
153 153 release.
154 154
155 155 .. __: http://modular.math.washington.edu/grants/compmath09
156 156
157 157 - Microsoft's team working on `Python Tools for Visual Studio`__ developed the
158 158 integraton of IPython into the Python plugin for Visual Studio 2010.
159 159
160 160 .. __: http://pytools.codeplex.com
161 161
162 162 - Google Summer of Code: in 2010, we had two students developing prototypes of
163 163 the new machinery that is now maturing in this release: `Omar Zapata`_ and
164 164 `Gerardo Gutiérrez`_.
165 165
166 166 .. _Omar Zapata: http://ipythonzmq.blogspot.com/2010/08/ipython-zmq-status.html
167 167 .. _Gerardo Gutiérrez: http://ipythonqt.blogspot.com/2010/04/ipython-qt-interface-gsoc-2010-proposal.html>
168 168
169 169
170 170 Development summary: moving to Git and Github
171 171 ---------------------------------------------
172 172
173 173 In April 2010, after `one breakage too many with bzr`__, we decided to move our
174 174 entire development process to Git and Github.com. This has proven to be one of
175 175 the best decisions in the project's history, as the combination of git and
176 176 github have made us far, far more productive than we could be with our previous
177 177 tools. We first converted our bzr repo to a git one without losing history,
178 178 and a few weeks later ported all open Launchpad bugs to github issues with
179 179 their comments mostly intact (modulo some formatting changes). This ensured a
180 180 smooth transition where no development history or submitted bugs were lost.
181 181 Feel free to use our little Launchpad to Github issues `porting script`_ if you
182 182 need to make a similar transition.
183 183
184 184 .. __: http://mail.scipy.org/pipermail/ipython-dev/2010-April/005944.html
185 185 .. _porting script: https://gist.github.com/835577
186 186
187 187 These simple statistics show how much work has been done on the new release, by
188 188 comparing the current code to the last point it had in common with the 0.10
189 189 series. A huge diff and ~2200 commits make up this cycle::
190 190
191 191 git diff $(git merge-base 0.10.2 HEAD) | wc -l
192 192 288019
193 193
194 194 git log $(git merge-base 0.10.2 HEAD)..HEAD --oneline | wc -l
195 195 2200
196 196
197 197 Since our move to github, 511 issues were closed, 226 of which were pull
198 198 requests and 285 regular issues (:ref:`a full list with links
199 199 <issues_list_011>` is available for those interested in the details). Github's
200 200 pull requests are a fantastic mechanism for reviewing code and building a
201 201 shared ownership of the project, and we are making enthusiastic use of it.
202 202
203 203 .. Note::
204 204
205 205 This undercounts the number of issues closed in this development cycle,
206 206 since we only moved to github for issue tracking in May 2010, but we have no
207 207 way of collecting statistics on the number of issues closed in the old
208 208 Launchpad bug tracker prior to that.
209 209
210 210
211 211 .. _qtconsole_011:
212 212
213 213 Qt Console
214 214 ----------
215 215
216 216 IPython now ships with a Qt application that feels very much like a terminal,
217 217 but is in fact a rich GUI that runs an IPython client but supports inline
218 218 figures, saving sessions to PDF and HTML, multiline editing with syntax
219 219 highlighting, graphical calltips and much more:
220 220
221 221 .. figure:: ../_images/qtconsole.png
222 222 :width: 400px
223 223 :alt: IPython Qt console with embedded plots
224 224 :align: center
225 225 :target: ../_images/qtconsole.png
226 226
227 227 The Qt console for IPython, using inline matplotlib plots.
228 228
229 229 We hope that many projects will embed this widget, which we've kept
230 230 deliberately very lightweight, into their own environments. In the future we
231 231 may also offer a slightly more featureful application (with menus and other GUI
232 232 elements), but we remain committed to always shipping this easy to embed
233 233 widget.
234 234
235 235 See the `Jupyter Qt Console site <https://jupyter.org/qtconsole>`_ for a detailed
236 236 description of the console's features and use.
237 237
238 238
239 239 .. _parallel_011:
240 240
241 241 High-level parallel computing with ZeroMQ
242 242 -----------------------------------------
243 243
244 244 We have completely rewritten the Twisted-based code for high-level parallel
245 245 computing to work atop our new ZeroMQ architecture. While we realize this will
246 246 break compatibility for a number of users, we hope to make the transition as
247 247 easy as possible with our docs, and we are convinced the change is worth it.
248 248 ZeroMQ provides us with much tighter control over memory, higher performance,
249 249 and its communications are impervious to the Python Global Interpreter Lock
250 250 because they take place in a system-level C++ thread. The impact of the GIL in
251 251 our previous code was something we could simply not work around, given that
252 252 Twisted is itself a Python library. So while Twisted is a very capable
253 253 framework, we think ZeroMQ fits our needs much better and we hope you will find
254 254 the change to be a significant improvement in the long run.
255 255
256 256 Our manual contains a full description of how to use IPython for parallel
257 257 computing, and the `tutorial`__ presented by Min
258 258 Ragan-Kelley at the SciPy 2011 conference provides a hands-on complement to the
259 259 reference docs.
260 260
261 261 .. __: http://minrk.github.com/scipy-tutorial-2011
262 262
263 263
264 264 Refactoring
265 265 -----------
266 266
267 As of this release, a signifiant portion of IPython has been refactored. This
267 As of this release, a significant portion of IPython has been refactored. This
268 268 refactoring is founded on a number of new abstractions. The main new classes
269 269 that implement these abstractions are:
270 270
271 271 * :class:`traitlets.HasTraits`.
272 272 * :class:`traitlets.config.configurable.Configurable`.
273 273 * :class:`traitlets.config.application.Application`.
274 274 * :class:`traitlets.config.loader.ConfigLoader`.
275 275 * :class:`traitlets.config.loader.Config`
276 276
277 277 We are still in the process of writing developer focused documentation about
278 278 these classes, but for now our :ref:`configuration documentation
279 279 <config_overview>` contains a high level overview of the concepts that these
280 280 classes express.
281 281
282 282 The biggest user-visible change is likely the move to using the config system
283 283 to determine the command-line arguments for IPython applications. The benefit
284 284 of this is that *all* configurable values in IPython are exposed on the
285 285 command-line, but the syntax for specifying values has changed. The gist is
286 286 that assigning values is pure Python assignment. Simple flags exist for
287 287 commonly used options, these are always prefixed with '--'.
288 288
289 289 The IPython command-line help has the details of all the options (via
290 290 ``ipython --help``), but a simple example should clarify things; the ``pylab``
291 291 flag can be used to start in pylab mode with the qt4 backend::
292 292
293 293 ipython --pylab=qt
294 294
295 295 which is equivalent to using the fully qualified form::
296 296
297 297 ipython --TerminalIPythonApp.pylab=qt
298 298
299 299 The long-form options can be listed via ``ipython --help-all``.
300 300
301 301
302 302 ZeroMQ architecture
303 303 -------------------
304 304
305 305 There is a new GUI framework for IPython, based on a client-server model in
306 306 which multiple clients can communicate with one IPython kernel, using the
307 307 ZeroMQ messaging framework. There is already a Qt console client, which can
308 308 be started by calling ``ipython qtconsole``. The protocol is :ref:`documented
309 309 <messaging>`.
310 310
311 311 The parallel computing framework has also been rewritten using ZMQ. The
312 312 protocol is described :ref:`here <parallel_messages>`, and the code is in the
313 313 new :mod:`IPython.parallel` module.
314 314
315 315 .. _python3_011:
316 316
317 317 Python 3 support
318 318 ----------------
319 319
320 320 A Python 3 version of IPython has been prepared. For the time being, this is
321 321 maintained separately and updated from the main codebase. Its code can be found
322 322 `here <https://github.com/ipython/ipython-py3k>`_. The parallel computing
323 323 components are not perfect on Python3, but most functionality appears to be
324 324 working. As this work is evolving quickly, the best place to find updated
325 325 information about it is our `Python 3 wiki page`__.
326 326
327 327 .. __: http://wiki.ipython.org/index.php?title=Python_3
328 328
329 329
330 330 Unicode
331 331 -------
332 332
333 333 Entering non-ascii characters in unicode literals (``u"€ø"``) now works
334 334 properly on all platforms. However, entering these in byte/string literals
335 335 (``"€ø"``) will not work as expected on Windows (or any platform where the
336 336 terminal encoding is not UTF-8, as it typically is for Linux & Mac OS X). You
337 337 can use escape sequences (``"\xe9\x82"``) to get bytes above 128, or use
338 338 unicode literals and encode them. This is a limitation of Python 2 which we
339 339 cannot easily work around.
340 340
341 341 .. _ms_visual_studio_011:
342 342
343 343 Integration with Microsoft Visual Studio
344 344 ----------------------------------------
345 345
346 346 IPython can be used as the interactive shell in the `Python plugin for
347 347 Microsoft Visual Studio`__, as seen here:
348 348
349 349 .. figure:: ../_images/ms_visual_studio.png
350 350 :width: 500px
351 351 :alt: IPython console embedded in Microsoft Visual Studio.
352 352 :align: center
353 353 :target: ../_images/ms_visual_studio.png
354 354
355 355 IPython console embedded in Microsoft Visual Studio.
356 356
357 357 The Microsoft team developing this currently has a release candidate out using
358 358 IPython 0.11. We will continue to collaborate with them to ensure that as they
359 359 approach their final release date, the integration with IPython remains smooth.
360 360 We'd like to thank Dino Viehland and Shahrokh Mortazavi for the work they have
361 361 done towards this feature, as well as Wenming Ye for his support of our WinHPC
362 362 capabilities.
363 363
364 364 .. __: http://pytools.codeplex.com
365 365
366 366
367 367 Additional new features
368 368 -----------------------
369 369
370 370 * Added ``Bytes`` traitlet, removing ``Str``. All 'string' traitlets should
371 371 either be ``Unicode`` if a real string, or ``Bytes`` if a C-string. This
372 372 removes ambiguity and helps the Python 3 transition.
373 373
374 374 * New magic ``%loadpy`` loads a python file from disk or web URL into
375 375 the current input buffer.
376 376
377 377 * New magic ``%pastebin`` for sharing code via the 'Lodge it' pastebin.
378 378
379 379 * New magic ``%precision`` for controlling float and numpy pretty printing.
380 380
381 381 * IPython applications initiate logging, so any object can gain access to
382 382 a the logger of the currently running Application with:
383 383
384 384 .. sourcecode:: python
385 385
386 386 from traitlets.config.application import Application
387 387 logger = Application.instance().log
388 388
389 389 * You can now get help on an object halfway through typing a command. For
390 390 instance, typing ``a = zip?`` shows the details of :func:`zip`. It also
391 391 leaves the command at the next prompt so you can carry on with it.
392 392
393 393 * The input history is now written to an SQLite database. The API for
394 394 retrieving items from the history has also been redesigned.
395 395
396 396 * The :mod:`IPython.extensions.pretty` extension has been moved out of
397 397 quarantine and fully updated to the new extension API.
398 398
399 399 * New magics for loading/unloading/reloading extensions have been added:
400 400 ``%load_ext``, ``%unload_ext`` and ``%reload_ext``.
401 401
402 402 * The configuration system and configuration files are brand new. See the
403 403 configuration system :ref:`documentation <config_index>` for more details.
404 404
405 405 * The :class:`~IPython.core.interactiveshell.InteractiveShell` class is now a
406 406 :class:`~traitlets.config.configurable.Configurable` subclass and has traitlets
407 407 that determine the defaults and runtime environment. The ``__init__`` method
408 408 has also been refactored so this class can be instantiated and run without
409 409 the old :mod:`ipmaker` module.
410 410
411 411 * The methods of :class:`~IPython.core.interactiveshell.InteractiveShell` have
412 412 been organized into sections to make it easier to turn more sections
413 413 of functionality into components.
414 414
415 415 * The embedded shell has been refactored into a truly standalone subclass of
416 416 :class:`InteractiveShell` called :class:`InteractiveShellEmbed`. All
417 417 embedding logic has been taken out of the base class and put into the
418 418 embedded subclass.
419 419
420 420 * Added methods of :class:`~IPython.core.interactiveshell.InteractiveShell` to
421 421 help it cleanup after itself. The :meth:`cleanup` method controls this. We
422 422 couldn't do this in :meth:`__del__` because we have cycles in our object
423 423 graph that prevent it from being called.
424 424
425 425 * Created a new module :mod:`IPython.utils.importstring` for resolving
426 426 strings like ``foo.bar.Bar`` to the actual class.
427 427
428 428 * Completely refactored the :mod:`IPython.core.prefilter` module into
429 429 :class:`~traitlets.config.configurable.Configurable` subclasses. Added a new
430 430 layer into the prefilter system, called "transformations" that all new
431 431 prefilter logic should use (rather than the older "checker/handler"
432 432 approach).
433 433
434 434 * Aliases are now components (:mod:`IPython.core.alias`).
435 435
436 436 * New top level :func:`~IPython.frontend.terminal.embed.embed` function that can
437 437 be called to embed IPython at any place in user's code. On the first call it
438 438 will create an :class:`~IPython.frontend.terminal.embed.InteractiveShellEmbed`
439 439 instance and call it. In later calls, it just calls the previously created
440 440 :class:`~IPython.frontend.terminal.embed.InteractiveShellEmbed`.
441 441
442 442 * Created a configuration system (:mod:`traitlets.config.configurable`) that is
443 443 based on :mod:`traitlets`. Configurables are arranged into a
444 444 runtime containment tree (not inheritance) that i) automatically propagates
445 445 configuration information and ii) allows singletons to discover each other in
446 446 a loosely coupled manner. In the future all parts of IPython will be
447 447 subclasses of :class:`~traitlets.config.configurable.Configurable`. All IPython
448 448 developers should become familiar with the config system.
449 449
450 450 * Created a new :class:`~traitlets.config.loader.Config` for holding
451 451 configuration information. This is a dict like class with a few extras: i)
452 452 it supports attribute style access, ii) it has a merge function that merges
453 453 two :class:`~traitlets.config.loader.Config` instances recursively and iii) it
454 454 will automatically create sub-:class:`~traitlets.config.loader.Config`
455 455 instances for attributes that start with an uppercase character.
456 456
457 457 * Created new configuration loaders in :mod:`traitlets.config.loader`. These
458 458 loaders provide a unified loading interface for all configuration
459 459 information including command line arguments and configuration files. We
460 460 have two default implementations based on :mod:`argparse` and plain python
461 461 files. These are used to implement the new configuration system.
462 462
463 463 * Created a top-level :class:`Application` class in
464 464 :mod:`IPython.core.application` that is designed to encapsulate the starting
465 465 of any basic Python program. An application loads and merges all the
466 466 configuration objects, constructs the main application, configures and
467 467 initiates logging, and creates and configures any :class:`Configurable`
468 468 instances and then starts the application running. An extended
469 469 :class:`BaseIPythonApplication` class adds logic for handling the
470 470 IPython directory as well as profiles, and all IPython entry points
471 471 extend it.
472 472
473 473 * The :class:`Type` and :class:`Instance` traitlets now handle classes given
474 474 as strings, like ``foo.bar.Bar``. This is needed for forward declarations.
475 475 But, this was implemented in a careful way so that string to class
476 476 resolution is done at a single point, when the parent
477 477 :class:`~traitlets.HasTraitlets` is instantiated.
478 478
479 479 * :mod:`IPython.utils.ipstruct` has been refactored to be a subclass of
480 480 dict. It also now has full docstrings and doctests.
481 481
482 482 * Created a Traits like implementation in :mod:`traitlets`. This
483 483 is a pure Python, lightweight version of a library that is similar to
484 484 Enthought's Traits project, but has no dependencies on Enthought's code. We
485 485 are using this for validation, defaults and notification in our new component
486 486 system. Although it is not 100% API compatible with Enthought's Traits, we
487 487 plan on moving in this direction so that eventually our implementation could
488 488 be replaced by a (yet to exist) pure Python version of Enthought Traits.
489 489
490 490 * Added a new module :mod:`IPython.lib.inputhook` to manage the integration
491 491 with GUI event loops using `PyOS_InputHook`. See the docstrings in this
492 492 module or the main IPython docs for details.
493 493
494 494 * For users, GUI event loop integration is now handled through the new
495 495 :command:`%gui` magic command. Type ``%gui?`` at an IPython prompt for
496 496 documentation.
497 497
498 498 * For developers :mod:`IPython.lib.inputhook` provides a simple interface
499 499 for managing the event loops in their interactive GUI applications.
500 500 Examples can be found in our :file:`examples/lib` directory.
501 501
502 502 Backwards incompatible changes
503 503 ------------------------------
504 504
505 505 * The Twisted-based :mod:`IPython.kernel` has been removed, and completely
506 506 rewritten as :mod:`IPython.parallel`, using ZeroMQ.
507 507
508 508 * Profiles are now directories. Instead of a profile being a single config file,
509 509 profiles are now self-contained directories. By default, profiles get their
510 510 own IPython history, log files, and everything. To create a new profile, do
511 511 ``ipython profile create <name>``.
512 512
513 513 * All IPython applications have been rewritten to use
514 514 :class:`~traitlets.config.loader.KeyValueConfigLoader`. This means that
515 515 command-line options have changed. Now, all configurable values are accessible
516 516 from the command-line with the same syntax as in a configuration file.
517 517
518 518 * The command line options ``-wthread``, ``-qthread`` and
519 519 ``-gthread`` have been removed. Use ``--gui=wx``, ``--gui=qt``, ``--gui=gtk``
520 520 instead.
521 521
522 522 * The extension loading functions have been renamed to
523 523 :func:`load_ipython_extension` and :func:`unload_ipython_extension`.
524 524
525 525 * :class:`~IPython.core.interactiveshell.InteractiveShell` no longer takes an
526 526 ``embedded`` argument. Instead just use the
527 527 :class:`~IPython.core.interactiveshell.InteractiveShellEmbed` class.
528 528
529 529 * ``__IPYTHON__`` is no longer injected into ``__builtin__``.
530 530
531 531 * :meth:`Struct.__init__` no longer takes `None` as its first argument. It
532 532 must be a :class:`dict` or :class:`Struct`.
533 533
534 534 * :meth:`~IPython.core.interactiveshell.InteractiveShell.ipmagic` has been
535 535 renamed :meth:`~IPython.core.interactiveshell.InteractiveShell.magic.`
536 536
537 537 * The functions :func:`ipmagic` and :func:`ipalias` have been removed from
538 538 :mod:`__builtins__`.
539 539
540 540 * The references to the global
541 541 :class:`~IPython.core.interactivehell.InteractiveShell` instance (``_ip``, and
542 542 ``__IP``) have been removed from the user's namespace. They are replaced by a
543 543 new function called :func:`get_ipython` that returns the current
544 544 :class:`~IPython.core.interactiveshell.InteractiveShell` instance. This
545 545 function is injected into the user's namespace and is now the main way of
546 546 accessing the running IPython.
547 547
548 548 * Old style configuration files :file:`ipythonrc` and :file:`ipy_user_conf.py`
549 549 are no longer supported. Users should migrate there configuration files to
550 550 the new format described :doc:`here </config/intro>` and
551 551 :ref:`here <config_overview>`.
552 552
553 553 * The old IPython extension API that relied on :func:`ipapi` has been
554 554 completely removed. The new extension API is described :ref:`here
555 555 <extensions_overview>`.
556 556
557 557 * Support for ``qt3`` has been dropped. Users who need this should use
558 558 previous versions of IPython.
559 559
560 560 * Removed :mod:`shellglobals` as it was obsolete.
561 561
562 562 * Removed all the threaded shells in :mod:`IPython.core.shell`. These are no
563 563 longer needed because of the new capabilities in
564 564 :mod:`IPython.lib.inputhook`.
565 565
566 566 * New top-level sub-packages have been created: :mod:`IPython.core`,
567 567 :mod:`IPython.lib`, :mod:`IPython.utils`, :mod:`IPython.deathrow`,
568 568 :mod:`IPython.quarantine`. All existing top-level modules have been
569 569 moved to appropriate sub-packages. All internal import statements
570 570 have been updated and tests have been added. The build system (setup.py
571 571 and friends) have been updated. See :doc:`/api/index` for details of these
572 572 new sub-packages.
573 573
574 574 * :mod:`IPython.ipapi` has been moved to :mod:`IPython.core.ipapi`.
575 575 :mod:`IPython.Shell` and :mod:`IPython.iplib` have been split and removed as
576 576 part of the refactor.
577 577
578 578 * :mod:`Extensions` has been moved to :mod:`extensions` and all existing
579 579 extensions have been moved to either :mod:`IPython.quarantine` or
580 580 :mod:`IPython.deathrow`. :mod:`IPython.quarantine` contains modules that we
581 581 plan on keeping but that need to be updated. :mod:`IPython.deathrow` contains
582 582 modules that are either dead or that should be maintained as third party
583 583 libraries.
584 584
585 585 * Previous IPython GUIs in :mod:`IPython.frontend` and :mod:`IPython.gui` are
586 586 likely broken, and have been removed to :mod:`IPython.deathrow` because of the
587 587 refactoring in the core. With proper updates, these should still work.
588 588
589 589
590 590 Known Regressions
591 591 -----------------
592 592
593 593 We do our best to improve IPython, but there are some known regressions in 0.11
594 594 relative to 0.10.2. First of all, there are features that have yet to be
595 595 ported to the new APIs, and in order to ensure that all of the installed code
596 596 runs for our users, we have moved them to two separate directories in the
597 597 source distribution, `quarantine` and `deathrow`. Finally, we have some other
598 598 miscellaneous regressions that we hope to fix as soon as possible. We now
599 599 describe all of these in more detail.
600 600
601 601 Quarantine
602 602 ~~~~~~~~~~
603 603
604 604 These are tools and extensions that we consider relatively easy to update to
605 605 the new classes and APIs, but that we simply haven't had time for. Any user
606 606 who is interested in one of these is encouraged to help us by porting it and
607 607 submitting a pull request on our `development site`_.
608 608
609 609 .. _development site: http://github.com/ipython/ipython
610 610
611 611 Currently, the quarantine directory contains::
612 612
613 613 clearcmd.py ipy_fsops.py ipy_signals.py
614 614 envpersist.py ipy_gnuglobal.py ipy_synchronize_with.py
615 615 ext_rescapture.py ipy_greedycompleter.py ipy_system_conf.py
616 616 InterpreterExec.py ipy_jot.py ipy_which.py
617 617 ipy_app_completers.py ipy_lookfor.py ipy_winpdb.py
618 618 ipy_autoreload.py ipy_profile_doctest.py ipy_workdir.py
619 619 ipy_completers.py ipy_pydb.py jobctrl.py
620 620 ipy_editors.py ipy_rehashdir.py ledit.py
621 621 ipy_exportdb.py ipy_render.py pspersistence.py
622 622 ipy_extutil.py ipy_server.py win32clip.py
623 623
624 624 Deathrow
625 625 ~~~~~~~~
626 626
627 627 These packages may be harder to update or make most sense as third-party
628 628 libraries. Some of them are completely obsolete and have been already replaced
629 629 by better functionality (we simply haven't had the time to carefully weed them
630 630 out so they are kept here for now). Others simply require fixes to code that
631 631 the current core team may not be familiar with. If a tool you were used to is
632 632 included here, we encourage you to contact the dev list and we can discuss
633 633 whether it makes sense to keep it in IPython (if it can be maintained).
634 634
635 635 Currently, the deathrow directory contains::
636 636
637 637 astyle.py ipy_defaults.py ipy_vimserver.py
638 638 dtutils.py ipy_kitcfg.py numeric_formats.py
639 639 Gnuplot2.py ipy_legacy.py numutils.py
640 640 GnuplotInteractive.py ipy_p4.py outputtrap.py
641 641 GnuplotRuntime.py ipy_profile_none.py PhysicalQInput.py
642 642 ibrowse.py ipy_profile_numpy.py PhysicalQInteractive.py
643 643 igrid.py ipy_profile_scipy.py quitter.py*
644 644 ipipe.py ipy_profile_sh.py scitedirector.py
645 645 iplib.py ipy_profile_zope.py Shell.py
646 646 ipy_constants.py ipy_traits_completer.py twshell.py
647 647
648 648
649 649 Other regressions
650 650 ~~~~~~~~~~~~~~~~~
651 651
652 652 * The machinery that adds functionality to the 'sh' profile for using IPython
653 653 as your system shell has not been updated to use the new APIs. As a result,
654 654 only the aesthetic (prompt) changes are still implemented. We intend to fix
655 655 this by 0.12. Tracked as issue 547_.
656 656
657 657 .. _547: https://github.com/ipython/ipython/issues/547
658 658
659 659 * The installation of scripts on Windows was broken without setuptools, so we
660 660 now depend on setuptools on Windows. We hope to fix setuptools-less
661 661 installation, and then remove the setuptools dependency. Issue 539_.
662 662
663 663 .. _539: https://github.com/ipython/ipython/issues/539
664 664
665 665 * The directory history `_dh` is not saved between sessions. Issue 634_.
666 666
667 667 .. _634: https://github.com/ipython/ipython/issues/634
668 668
669 669
670 670 Removed Features
671 671 ----------------
672 672
673 673 As part of the updating of IPython, we have removed a few features for the
674 674 purposes of cleaning up the codebase and interfaces. These removals are
675 675 permanent, but for any item listed below, equivalent functionality is
676 676 available.
677 677
678 678 * The magics Exit and Quit have been dropped as ways to exit IPython. Instead,
679 679 the lowercase forms of both work either as a bare name (``exit``) or a
680 680 function call (``exit()``). You can assign these to other names using
681 681 exec_lines in the config file.
682 682
683 683
684 684 .. _credits_011:
685 685
686 686 Credits
687 687 -------
688 688
689 689 Many users and developers contributed code, features, bug reports and ideas to
690 690 this release. Please do not hesitate in contacting us if we've failed to
691 691 acknowledge your contribution here. In particular, for this release we have
692 692 contribution from the following people, a mix of new and regular names (in
693 693 alphabetical order by first name):
694 694
695 695 * Aenugu Sai Kiran Reddy <saikrn08-at-gmail.com>
696 696 * andy wilson <wilson.andrew.j+github-at-gmail.com>
697 697 * Antonio Cuni <antocuni>
698 698 * Barry Wark <barrywark-at-gmail.com>
699 699 * Beetoju Anuradha <anu.beethoju-at-gmail.com>
700 700 * Benjamin Ragan-Kelley <minrk-at-Mercury.local>
701 701 * Brad Reisfeld
702 702 * Brian E. Granger <ellisonbg-at-gmail.com>
703 703 * Christoph Gohlke <cgohlke-at-uci.edu>
704 704 * Cody Precord
705 705 * dan.milstein
706 706 * Darren Dale <dsdale24-at-gmail.com>
707 707 * Dav Clark <davclark-at-berkeley.edu>
708 708 * David Warde-Farley <wardefar-at-iro.umontreal.ca>
709 709 * epatters <ejpatters-at-gmail.com>
710 710 * epatters <epatters-at-caltech.edu>
711 711 * epatters <epatters-at-enthought.com>
712 712 * Eric Firing <efiring-at-hawaii.edu>
713 713 * Erik Tollerud <erik.tollerud-at-gmail.com>
714 714 * Evan Patterson <epatters-at-enthought.com>
715 715 * Fernando Perez <Fernando.Perez-at-berkeley.edu>
716 716 * Gael Varoquaux <gael.varoquaux-at-normalesup.org>
717 717 * Gerardo <muzgash-at-Muzpelheim>
718 718 * Jason Grout <jason.grout-at-drake.edu>
719 719 * John Hunter <jdh2358-at-gmail.com>
720 720 * Jens Hedegaard Nielsen <jenshnielsen-at-gmail.com>
721 721 * Johann Cohen-Tanugi <johann.cohentanugi-at-gmail.com>
722 722 * Jörgen Stenarson <jorgen.stenarson-at-bostream.nu>
723 723 * Justin Riley <justin.t.riley-at-gmail.com>
724 724 * Kiorky
725 725 * Laurent Dufrechou <laurent.dufrechou-at-gmail.com>
726 726 * Luis Pedro Coelho <lpc-at-cmu.edu>
727 727 * Mani chandra <mchandra-at-iitk.ac.in>
728 728 * Mark E. Smith
729 729 * Mark Voorhies <mark.voorhies-at-ucsf.edu>
730 730 * Martin Spacek <git-at-mspacek.mm.st>
731 731 * Michael Droettboom <mdroe-at-stsci.edu>
732 732 * MinRK <benjaminrk-at-gmail.com>
733 733 * muzuiget <muzuiget-at-gmail.com>
734 734 * Nick Tarleton <nick-at-quixey.com>
735 735 * Nicolas Rougier <Nicolas.rougier-at-inria.fr>
736 736 * Omar Andres Zapata Mesa <andresete.chaos-at-gmail.com>
737 737 * Paul Ivanov <pivanov314-at-gmail.com>
738 738 * Pauli Virtanen <pauli.virtanen-at-iki.fi>
739 739 * Prabhu Ramachandran
740 740 * Ramana <sramana9-at-gmail.com>
741 741 * Robert Kern <robert.kern-at-gmail.com>
742 742 * Sathesh Chandra <satheshchandra88-at-gmail.com>
743 743 * Satrajit Ghosh <satra-at-mit.edu>
744 744 * Sebastian Busch
745 745 * Skipper Seabold <jsseabold-at-gmail.com>
746 746 * Stefan van der Walt <bzr-at-mentat.za.net>
747 747 * Stephan Peijnik <debian-at-sp.or.at>
748 748 * Steven Bethard
749 749 * Thomas Kluyver <takowl-at-gmail.com>
750 750 * Thomas Spura <tomspur-at-fedoraproject.org>
751 751 * Tom Fetherston <tfetherston-at-aol.com>
752 752 * Tom MacWright
753 753 * tzanko
754 754 * vankayala sowjanya <hai.sowjanya-at-gmail.com>
755 755 * Vivian De Smedt <vds2212-at-VIVIAN>
756 756 * Ville M. Vainio <vivainio-at-gmail.com>
757 757 * Vishal Vatsa <vishal.vatsa-at-gmail.com>
758 758 * Vishnu S G <sgvishnu777-at-gmail.com>
759 759 * Walter Doerwald <walter-at-livinglogic.de>
760 760
761 761 .. note::
762 762
763 763 This list was generated with the output of
764 764 ``git log dev-0.11 HEAD --format='* %aN <%aE>' | sed 's/@/\-at\-/' | sed 's/<>//' | sort -u``
765 765 after some cleanup. If you should be on this list, please add yourself.
1 NO CONTENT: modified file
General Comments 0
You need to be logged in to leave comments. Login now