##// END OF EJS Templates
some docstring reformatting and fixing
Matthias Bussonnier -
Show More
@@ -1,223 +1,237 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian E. Granger
7 * Brian E. Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import os
22 import os
23 import sys
23 import sys
24 import traceback
24 import traceback
25 from pprint import pformat
25 from pprint import pformat
26 from pathlib import Path
26 from pathlib import Path
27
27
28 from IPython.core import ultratb
28 from IPython.core import ultratb
29 from IPython.core.release import author_email
29 from IPython.core.release import author_email
30 from IPython.utils.sysinfo import sys_info
30 from IPython.utils.sysinfo import sys_info
31 from IPython.utils.py3compat import input
31 from IPython.utils.py3compat import input
32
32
33 from IPython.core.release import __version__ as version
33 from IPython.core.release import __version__ as version
34
34
35 from typing import Optional
36
35 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
36 # Code
38 # Code
37 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
38
40
39 # Template for the user message.
41 # Template for the user message.
40 _default_message_template = """\
42 _default_message_template = """\
41 Oops, {app_name} crashed. We do our best to make it stable, but...
43 Oops, {app_name} crashed. We do our best to make it stable, but...
42
44
43 A crash report was automatically generated with the following information:
45 A crash report was automatically generated with the following information:
44 - A verbatim copy of the crash traceback.
46 - A verbatim copy of the crash traceback.
45 - A copy of your input history during this session.
47 - A copy of your input history during this session.
46 - Data on your current {app_name} configuration.
48 - Data on your current {app_name} configuration.
47
49
48 It was left in the file named:
50 It was left in the file named:
49 \t'{crash_report_fname}'
51 \t'{crash_report_fname}'
50 If you can email this file to the developers, the information in it will help
52 If you can email this file to the developers, the information in it will help
51 them in understanding and correcting the problem.
53 them in understanding and correcting the problem.
52
54
53 You can mail it to: {contact_name} at {contact_email}
55 You can mail it to: {contact_name} at {contact_email}
54 with the subject '{app_name} Crash Report'.
56 with the subject '{app_name} Crash Report'.
55
57
56 If you want to do it now, the following command will work (under Unix):
58 If you want to do it now, the following command will work (under Unix):
57 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
59 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
58
60
59 In your email, please also include information about:
61 In your email, please also include information about:
60 - The operating system under which the crash happened: Linux, macOS, Windows,
62 - The operating system under which the crash happened: Linux, macOS, Windows,
61 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
63 other, and which exact version (for example: Ubuntu 16.04.3, macOS 10.13.2,
62 Windows 10 Pro), and whether it is 32-bit or 64-bit;
64 Windows 10 Pro), and whether it is 32-bit or 64-bit;
63 - How {app_name} was installed: using pip or conda, from GitHub, as part of
65 - How {app_name} was installed: using pip or conda, from GitHub, as part of
64 a Docker container, or other, providing more detail if possible;
66 a Docker container, or other, providing more detail if possible;
65 - How to reproduce the crash: what exact sequence of instructions can one
67 - How to reproduce the crash: what exact sequence of instructions can one
66 input to get the same crash? Ideally, find a minimal yet complete sequence
68 input to get the same crash? Ideally, find a minimal yet complete sequence
67 of instructions that yields the crash.
69 of instructions that yields the crash.
68
70
69 To ensure accurate tracking of this issue, please file a report about it at:
71 To ensure accurate tracking of this issue, please file a report about it at:
70 {bug_tracker}
72 {bug_tracker}
71 """
73 """
72
74
73 _lite_message_template = """
75 _lite_message_template = """
74 If you suspect this is an IPython {version} bug, please report it at:
76 If you suspect this is an IPython {version} bug, please report it at:
75 https://github.com/ipython/ipython/issues
77 https://github.com/ipython/ipython/issues
76 or send an email to the mailing list at {email}
78 or send an email to the mailing list at {email}
77
79
78 You can print a more detailed traceback right now with "%tb", or use "%debug"
80 You can print a more detailed traceback right now with "%tb", or use "%debug"
79 to interactively debug it.
81 to interactively debug it.
80
82
81 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
83 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
82 {config}Application.verbose_crash=True
84 {config}Application.verbose_crash=True
83 """
85 """
84
86
85
87
86 class CrashHandler(object):
88 class CrashHandler(object):
87 """Customizable crash handlers for IPython applications.
89 """Customizable crash handlers for IPython applications.
88
90
89 Instances of this class provide a :meth:`__call__` method which can be
91 Instances of this class provide a :meth:`__call__` method which can be
90 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
92 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
91
93
92 def __call__(self, etype, evalue, etb)
94 def __call__(self, etype, evalue, etb)
93 """
95 """
94
96
95 message_template = _default_message_template
97 message_template = _default_message_template
96 section_sep = '\n\n'+'*'*75+'\n\n'
98 section_sep = '\n\n'+'*'*75+'\n\n'
97
99
98 def __init__(self, app, contact_name=None, contact_email=None,
100 def __init__(
99 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
101 self,
102 app,
103 contact_name: Optional[str] = None,
104 contact_email: Optional[str] = None,
105 bug_tracker: Optional[str] = None,
106 show_crash_traceback: bool = True,
107 call_pdb: bool = False,
108 ):
100 """Create a new crash handler
109 """Create a new crash handler
101
110
102 Parameters
111 Parameters
103 ----------
112 ----------
104 app : Application
113 app : Application
105 A running :class:`Application` instance, which will be queried at
114 A running :class:`Application` instance, which will be queried at
106 crash time for internal information.
115 crash time for internal information.
107 contact_name : str
116 contact_name : str
108 A string with the name of the person to contact.
117 A string with the name of the person to contact.
109 contact_email : str
118 contact_email : str
110 A string with the email address of the contact.
119 A string with the email address of the contact.
111 bug_tracker : str
120 bug_tracker : str
112 A string with the URL for your project's bug tracker.
121 A string with the URL for your project's bug tracker.
113 show_crash_traceback : bool
122 show_crash_traceback : bool
114 If false, don't print the crash traceback on stderr, only generate
123 If false, don't print the crash traceback on stderr, only generate
115 the on-disk report
124 the on-disk report
116 Non-argument instance attributes
125 call_pdb
126 Whether to call pdb on crash
127
128 Attributes
129 ----------
117 These instances contain some non-argument attributes which allow for
130 These instances contain some non-argument attributes which allow for
118 further customization of the crash handler's behavior. Please see the
131 further customization of the crash handler's behavior. Please see the
119 source for further details.
132 source for further details.
133
120 """
134 """
121 self.crash_report_fname = "Crash_report_%s.txt" % app.name
135 self.crash_report_fname = "Crash_report_%s.txt" % app.name
122 self.app = app
136 self.app = app
123 self.call_pdb = call_pdb
137 self.call_pdb = call_pdb
124 #self.call_pdb = True # dbg
138 #self.call_pdb = True # dbg
125 self.show_crash_traceback = show_crash_traceback
139 self.show_crash_traceback = show_crash_traceback
126 self.info = dict(app_name = app.name,
140 self.info = dict(app_name = app.name,
127 contact_name = contact_name,
141 contact_name = contact_name,
128 contact_email = contact_email,
142 contact_email = contact_email,
129 bug_tracker = bug_tracker,
143 bug_tracker = bug_tracker,
130 crash_report_fname = self.crash_report_fname)
144 crash_report_fname = self.crash_report_fname)
131
145
132
146
133 def __call__(self, etype, evalue, etb):
147 def __call__(self, etype, evalue, etb):
134 """Handle an exception, call for compatible with sys.excepthook"""
148 """Handle an exception, call for compatible with sys.excepthook"""
135
149
136 # do not allow the crash handler to be called twice without reinstalling it
150 # do not allow the crash handler to be called twice without reinstalling it
137 # this prevents unlikely errors in the crash handling from entering an
151 # this prevents unlikely errors in the crash handling from entering an
138 # infinite loop.
152 # infinite loop.
139 sys.excepthook = sys.__excepthook__
153 sys.excepthook = sys.__excepthook__
140
154
141 # Report tracebacks shouldn't use color in general (safer for users)
155 # Report tracebacks shouldn't use color in general (safer for users)
142 color_scheme = 'NoColor'
156 color_scheme = 'NoColor'
143
157
144 # Use this ONLY for developer debugging (keep commented out for release)
158 # Use this ONLY for developer debugging (keep commented out for release)
145 #color_scheme = 'Linux' # dbg
159 #color_scheme = 'Linux' # dbg
146 try:
160 try:
147 rptdir = self.app.ipython_dir
161 rptdir = self.app.ipython_dir
148 except:
162 except:
149 rptdir = Path.cwd()
163 rptdir = Path.cwd()
150 if rptdir is None or not Path.is_dir(rptdir):
164 if rptdir is None or not Path.is_dir(rptdir):
151 rptdir = Path.cwd()
165 rptdir = Path.cwd()
152 report_name = rptdir / self.crash_report_fname
166 report_name = rptdir / self.crash_report_fname
153 # write the report filename into the instance dict so it can get
167 # write the report filename into the instance dict so it can get
154 # properly expanded out in the user message template
168 # properly expanded out in the user message template
155 self.crash_report_fname = report_name
169 self.crash_report_fname = report_name
156 self.info['crash_report_fname'] = report_name
170 self.info['crash_report_fname'] = report_name
157 TBhandler = ultratb.VerboseTB(
171 TBhandler = ultratb.VerboseTB(
158 color_scheme=color_scheme,
172 color_scheme=color_scheme,
159 long_header=1,
173 long_header=1,
160 call_pdb=self.call_pdb,
174 call_pdb=self.call_pdb,
161 )
175 )
162 if self.call_pdb:
176 if self.call_pdb:
163 TBhandler(etype,evalue,etb)
177 TBhandler(etype,evalue,etb)
164 return
178 return
165 else:
179 else:
166 traceback = TBhandler.text(etype,evalue,etb,context=31)
180 traceback = TBhandler.text(etype,evalue,etb,context=31)
167
181
168 # print traceback to screen
182 # print traceback to screen
169 if self.show_crash_traceback:
183 if self.show_crash_traceback:
170 print(traceback, file=sys.stderr)
184 print(traceback, file=sys.stderr)
171
185
172 # and generate a complete report on disk
186 # and generate a complete report on disk
173 try:
187 try:
174 report = open(report_name,'w')
188 report = open(report_name,'w')
175 except:
189 except:
176 print('Could not create crash report on disk.', file=sys.stderr)
190 print('Could not create crash report on disk.', file=sys.stderr)
177 return
191 return
178
192
179 with report:
193 with report:
180 # Inform user on stderr of what happened
194 # Inform user on stderr of what happened
181 print('\n'+'*'*70+'\n', file=sys.stderr)
195 print('\n'+'*'*70+'\n', file=sys.stderr)
182 print(self.message_template.format(**self.info), file=sys.stderr)
196 print(self.message_template.format(**self.info), file=sys.stderr)
183
197
184 # Construct report on disk
198 # Construct report on disk
185 report.write(self.make_report(traceback))
199 report.write(self.make_report(traceback))
186
200
187 input("Hit <Enter> to quit (your terminal may close):")
201 input("Hit <Enter> to quit (your terminal may close):")
188
202
189 def make_report(self,traceback):
203 def make_report(self,traceback):
190 """Return a string containing a crash report."""
204 """Return a string containing a crash report."""
191
205
192 sec_sep = self.section_sep
206 sec_sep = self.section_sep
193
207
194 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
208 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
195 rpt_add = report.append
209 rpt_add = report.append
196 rpt_add(sys_info())
210 rpt_add(sys_info())
197
211
198 try:
212 try:
199 config = pformat(self.app.config)
213 config = pformat(self.app.config)
200 rpt_add(sec_sep)
214 rpt_add(sec_sep)
201 rpt_add('Application name: %s\n\n' % self.app_name)
215 rpt_add('Application name: %s\n\n' % self.app_name)
202 rpt_add('Current user configuration structure:\n\n')
216 rpt_add('Current user configuration structure:\n\n')
203 rpt_add(config)
217 rpt_add(config)
204 except:
218 except:
205 pass
219 pass
206 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
220 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
207
221
208 return ''.join(report)
222 return ''.join(report)
209
223
210
224
211 def crash_handler_lite(etype, evalue, tb):
225 def crash_handler_lite(etype, evalue, tb):
212 """a light excepthook, adding a small message to the usual traceback"""
226 """a light excepthook, adding a small message to the usual traceback"""
213 traceback.print_exception(etype, evalue, tb)
227 traceback.print_exception(etype, evalue, tb)
214
228
215 from IPython.core.interactiveshell import InteractiveShell
229 from IPython.core.interactiveshell import InteractiveShell
216 if InteractiveShell.initialized():
230 if InteractiveShell.initialized():
217 # we are in a Shell environment, give %magic example
231 # we are in a Shell environment, give %magic example
218 config = "%config "
232 config = "%config "
219 else:
233 else:
220 # we are not in a shell, show generic config
234 # we are not in a shell, show generic config
221 config = "c."
235 config = "c."
222 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
236 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
223
237
@@ -1,24 +1,24 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Simple function to call to get the current InteractiveShell instance
2 """Simple function to call to get the current InteractiveShell instance
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2013 The IPython Development Team
6 # Copyright (C) 2013 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Classes and functions
13 # Classes and functions
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16
16
17 def get_ipython():
17 def get_ipython():
18 """Get the global InteractiveShell instance.
18 """Get the global InteractiveShell instance.
19
19
20 Returns None if no InteractiveShell instance is registered.
20 Returns None if no InteractiveShell instance is registered.
21 """
21 """
22 from IPython.core.interactiveshell import InteractiveShell
22 from IPython.core.interactiveshell import InteractiveShell
23 if InteractiveShell.initialized():
23 if InteractiveShell.initialized():
24 return InteractiveShell.instance()
24 return InteractiveShell.instance()
@@ -1,712 +1,700 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Magic functions for InteractiveShell.
2 """Magic functions for InteractiveShell.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 The IPython Development Team
9
9
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import os
14 import os
15 import re
15 import re
16 import sys
16 import sys
17 from getopt import getopt, GetoptError
17 from getopt import getopt, GetoptError
18
18
19 from traitlets.config.configurable import Configurable
19 from traitlets.config.configurable import Configurable
20 from . import oinspect
20 from . import oinspect
21 from .error import UsageError
21 from .error import UsageError
22 from .inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
22 from .inputtransformer2 import ESC_MAGIC, ESC_MAGIC2
23 from ..utils.ipstruct import Struct
23 from ..utils.ipstruct import Struct
24 from ..utils.process import arg_split
24 from ..utils.process import arg_split
25 from ..utils.text import dedent
25 from ..utils.text import dedent
26 from traitlets import Bool, Dict, Instance, observe
26 from traitlets import Bool, Dict, Instance, observe
27 from logging import error
27 from logging import error
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Globals
30 # Globals
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # A dict we'll use for each class that has magics, used as temporary storage to
33 # A dict we'll use for each class that has magics, used as temporary storage to
34 # pass information between the @line/cell_magic method decorators and the
34 # pass information between the @line/cell_magic method decorators and the
35 # @magics_class class decorator, because the method decorators have no
35 # @magics_class class decorator, because the method decorators have no
36 # access to the class when they run. See for more details:
36 # access to the class when they run. See for more details:
37 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
37 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
38
38
39 magics = dict(line={}, cell={})
39 magics = dict(line={}, cell={})
40
40
41 magic_kinds = ('line', 'cell')
41 magic_kinds = ('line', 'cell')
42 magic_spec = ('line', 'cell', 'line_cell')
42 magic_spec = ('line', 'cell', 'line_cell')
43 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
43 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Utility classes and functions
46 # Utility classes and functions
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 class Bunch: pass
49 class Bunch: pass
50
50
51
51
52 def on_off(tag):
52 def on_off(tag):
53 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
53 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
54 return ['OFF','ON'][tag]
54 return ['OFF','ON'][tag]
55
55
56
56
57 def compress_dhist(dh):
57 def compress_dhist(dh):
58 """Compress a directory history into a new one with at most 20 entries.
58 """Compress a directory history into a new one with at most 20 entries.
59
59
60 Return a new list made from the first and last 10 elements of dhist after
60 Return a new list made from the first and last 10 elements of dhist after
61 removal of duplicates.
61 removal of duplicates.
62 """
62 """
63 head, tail = dh[:-10], dh[-10:]
63 head, tail = dh[:-10], dh[-10:]
64
64
65 newhead = []
65 newhead = []
66 done = set()
66 done = set()
67 for h in head:
67 for h in head:
68 if h in done:
68 if h in done:
69 continue
69 continue
70 newhead.append(h)
70 newhead.append(h)
71 done.add(h)
71 done.add(h)
72
72
73 return newhead + tail
73 return newhead + tail
74
74
75
75
76 def needs_local_scope(func):
76 def needs_local_scope(func):
77 """Decorator to mark magic functions which need to local scope to run."""
77 """Decorator to mark magic functions which need to local scope to run."""
78 func.needs_local_scope = True
78 func.needs_local_scope = True
79 return func
79 return func
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Class and method decorators for registering magics
82 # Class and method decorators for registering magics
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 def magics_class(cls):
85 def magics_class(cls):
86 """Class decorator for all subclasses of the main Magics class.
86 """Class decorator for all subclasses of the main Magics class.
87
87
88 Any class that subclasses Magics *must* also apply this decorator, to
88 Any class that subclasses Magics *must* also apply this decorator, to
89 ensure that all the methods that have been decorated as line/cell magics
89 ensure that all the methods that have been decorated as line/cell magics
90 get correctly registered in the class instance. This is necessary because
90 get correctly registered in the class instance. This is necessary because
91 when method decorators run, the class does not exist yet, so they
91 when method decorators run, the class does not exist yet, so they
92 temporarily store their information into a module global. Application of
92 temporarily store their information into a module global. Application of
93 this class decorator copies that global data to the class instance and
93 this class decorator copies that global data to the class instance and
94 clears the global.
94 clears the global.
95
95
96 Obviously, this mechanism is not thread-safe, which means that the
96 Obviously, this mechanism is not thread-safe, which means that the
97 *creation* of subclasses of Magic should only be done in a single-thread
97 *creation* of subclasses of Magic should only be done in a single-thread
98 context. Instantiation of the classes has no restrictions. Given that
98 context. Instantiation of the classes has no restrictions. Given that
99 these classes are typically created at IPython startup time and before user
99 these classes are typically created at IPython startup time and before user
100 application code becomes active, in practice this should not pose any
100 application code becomes active, in practice this should not pose any
101 problems.
101 problems.
102 """
102 """
103 cls.registered = True
103 cls.registered = True
104 cls.magics = dict(line = magics['line'],
104 cls.magics = dict(line = magics['line'],
105 cell = magics['cell'])
105 cell = magics['cell'])
106 magics['line'] = {}
106 magics['line'] = {}
107 magics['cell'] = {}
107 magics['cell'] = {}
108 return cls
108 return cls
109
109
110
110
111 def record_magic(dct, magic_kind, magic_name, func):
111 def record_magic(dct, magic_kind, magic_name, func):
112 """Utility function to store a function as a magic of a specific kind.
112 """Utility function to store a function as a magic of a specific kind.
113
113
114 Parameters
114 Parameters
115 ----------
115 ----------
116 dct : dict
116 dct : dict
117 A dictionary with 'line' and 'cell' subdicts.
117 A dictionary with 'line' and 'cell' subdicts.
118
119 magic_kind : str
118 magic_kind : str
120 Kind of magic to be stored.
119 Kind of magic to be stored.
121
122 magic_name : str
120 magic_name : str
123 Key to store the magic as.
121 Key to store the magic as.
124
125 func : function
122 func : function
126 Callable object to store.
123 Callable object to store.
127 """
124 """
128 if magic_kind == 'line_cell':
125 if magic_kind == 'line_cell':
129 dct['line'][magic_name] = dct['cell'][magic_name] = func
126 dct['line'][magic_name] = dct['cell'][magic_name] = func
130 else:
127 else:
131 dct[magic_kind][magic_name] = func
128 dct[magic_kind][magic_name] = func
132
129
133
130
134 def validate_type(magic_kind):
131 def validate_type(magic_kind):
135 """Ensure that the given magic_kind is valid.
132 """Ensure that the given magic_kind is valid.
136
133
137 Check that the given magic_kind is one of the accepted spec types (stored
134 Check that the given magic_kind is one of the accepted spec types (stored
138 in the global `magic_spec`), raise ValueError otherwise.
135 in the global `magic_spec`), raise ValueError otherwise.
139 """
136 """
140 if magic_kind not in magic_spec:
137 if magic_kind not in magic_spec:
141 raise ValueError('magic_kind must be one of %s, %s given' %
138 raise ValueError('magic_kind must be one of %s, %s given' %
142 magic_kinds, magic_kind)
139 magic_kinds, magic_kind)
143
140
144
141
145 # The docstrings for the decorator below will be fairly similar for the two
142 # The docstrings for the decorator below will be fairly similar for the two
146 # types (method and function), so we generate them here once and reuse the
143 # types (method and function), so we generate them here once and reuse the
147 # templates below.
144 # templates below.
148 _docstring_template = \
145 _docstring_template = \
149 """Decorate the given {0} as {1} magic.
146 """Decorate the given {0} as {1} magic.
150
147
151 The decorator can be used with or without arguments, as follows.
148 The decorator can be used with or without arguments, as follows.
152
149
153 i) without arguments: it will create a {1} magic named as the {0} being
150 i) without arguments: it will create a {1} magic named as the {0} being
154 decorated::
151 decorated::
155
152
156 @deco
153 @deco
157 def foo(...)
154 def foo(...)
158
155
159 will create a {1} magic named `foo`.
156 will create a {1} magic named `foo`.
160
157
161 ii) with one string argument: which will be used as the actual name of the
158 ii) with one string argument: which will be used as the actual name of the
162 resulting magic::
159 resulting magic::
163
160
164 @deco('bar')
161 @deco('bar')
165 def foo(...)
162 def foo(...)
166
163
167 will create a {1} magic named `bar`.
164 will create a {1} magic named `bar`.
168
165
169 To register a class magic use ``Interactiveshell.register_magic(class or instance)``.
166 To register a class magic use ``Interactiveshell.register_magic(class or instance)``.
170 """
167 """
171
168
172 # These two are decorator factories. While they are conceptually very similar,
169 # These two are decorator factories. While they are conceptually very similar,
173 # there are enough differences in the details that it's simpler to have them
170 # there are enough differences in the details that it's simpler to have them
174 # written as completely standalone functions rather than trying to share code
171 # written as completely standalone functions rather than trying to share code
175 # and make a single one with convoluted logic.
172 # and make a single one with convoluted logic.
176
173
177 def _method_magic_marker(magic_kind):
174 def _method_magic_marker(magic_kind):
178 """Decorator factory for methods in Magics subclasses.
175 """Decorator factory for methods in Magics subclasses.
179 """
176 """
180
177
181 validate_type(magic_kind)
178 validate_type(magic_kind)
182
179
183 # This is a closure to capture the magic_kind. We could also use a class,
180 # This is a closure to capture the magic_kind. We could also use a class,
184 # but it's overkill for just that one bit of state.
181 # but it's overkill for just that one bit of state.
185 def magic_deco(arg):
182 def magic_deco(arg):
186 if callable(arg):
183 if callable(arg):
187 # "Naked" decorator call (just @foo, no args)
184 # "Naked" decorator call (just @foo, no args)
188 func = arg
185 func = arg
189 name = func.__name__
186 name = func.__name__
190 retval = arg
187 retval = arg
191 record_magic(magics, magic_kind, name, name)
188 record_magic(magics, magic_kind, name, name)
192 elif isinstance(arg, str):
189 elif isinstance(arg, str):
193 # Decorator called with arguments (@foo('bar'))
190 # Decorator called with arguments (@foo('bar'))
194 name = arg
191 name = arg
195 def mark(func, *a, **kw):
192 def mark(func, *a, **kw):
196 record_magic(magics, magic_kind, name, func.__name__)
193 record_magic(magics, magic_kind, name, func.__name__)
197 return func
194 return func
198 retval = mark
195 retval = mark
199 else:
196 else:
200 raise TypeError("Decorator can only be called with "
197 raise TypeError("Decorator can only be called with "
201 "string or function")
198 "string or function")
202 return retval
199 return retval
203
200
204 # Ensure the resulting decorator has a usable docstring
201 # Ensure the resulting decorator has a usable docstring
205 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
202 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
206 return magic_deco
203 return magic_deco
207
204
208
205
209 def _function_magic_marker(magic_kind):
206 def _function_magic_marker(magic_kind):
210 """Decorator factory for standalone functions.
207 """Decorator factory for standalone functions.
211 """
208 """
212 validate_type(magic_kind)
209 validate_type(magic_kind)
213
210
214 # This is a closure to capture the magic_kind. We could also use a class,
211 # This is a closure to capture the magic_kind. We could also use a class,
215 # but it's overkill for just that one bit of state.
212 # but it's overkill for just that one bit of state.
216 def magic_deco(arg):
213 def magic_deco(arg):
217 # Find get_ipython() in the caller's namespace
214 # Find get_ipython() in the caller's namespace
218 caller = sys._getframe(1)
215 caller = sys._getframe(1)
219 for ns in ['f_locals', 'f_globals', 'f_builtins']:
216 for ns in ['f_locals', 'f_globals', 'f_builtins']:
220 get_ipython = getattr(caller, ns).get('get_ipython')
217 get_ipython = getattr(caller, ns).get('get_ipython')
221 if get_ipython is not None:
218 if get_ipython is not None:
222 break
219 break
223 else:
220 else:
224 raise NameError('Decorator can only run in context where '
221 raise NameError('Decorator can only run in context where '
225 '`get_ipython` exists')
222 '`get_ipython` exists')
226
223
227 ip = get_ipython()
224 ip = get_ipython()
228
225
229 if callable(arg):
226 if callable(arg):
230 # "Naked" decorator call (just @foo, no args)
227 # "Naked" decorator call (just @foo, no args)
231 func = arg
228 func = arg
232 name = func.__name__
229 name = func.__name__
233 ip.register_magic_function(func, magic_kind, name)
230 ip.register_magic_function(func, magic_kind, name)
234 retval = arg
231 retval = arg
235 elif isinstance(arg, str):
232 elif isinstance(arg, str):
236 # Decorator called with arguments (@foo('bar'))
233 # Decorator called with arguments (@foo('bar'))
237 name = arg
234 name = arg
238 def mark(func, *a, **kw):
235 def mark(func, *a, **kw):
239 ip.register_magic_function(func, magic_kind, name)
236 ip.register_magic_function(func, magic_kind, name)
240 return func
237 return func
241 retval = mark
238 retval = mark
242 else:
239 else:
243 raise TypeError("Decorator can only be called with "
240 raise TypeError("Decorator can only be called with "
244 "string or function")
241 "string or function")
245 return retval
242 return retval
246
243
247 # Ensure the resulting decorator has a usable docstring
244 # Ensure the resulting decorator has a usable docstring
248 ds = _docstring_template.format('function', magic_kind)
245 ds = _docstring_template.format('function', magic_kind)
249
246
250 ds += dedent("""
247 ds += dedent("""
251 Note: this decorator can only be used in a context where IPython is already
248 Note: this decorator can only be used in a context where IPython is already
252 active, so that the `get_ipython()` call succeeds. You can therefore use
249 active, so that the `get_ipython()` call succeeds. You can therefore use
253 it in your startup files loaded after IPython initializes, but *not* in the
250 it in your startup files loaded after IPython initializes, but *not* in the
254 IPython configuration file itself, which is executed before IPython is
251 IPython configuration file itself, which is executed before IPython is
255 fully up and running. Any file located in the `startup` subdirectory of
252 fully up and running. Any file located in the `startup` subdirectory of
256 your configuration profile will be OK in this sense.
253 your configuration profile will be OK in this sense.
257 """)
254 """)
258
255
259 magic_deco.__doc__ = ds
256 magic_deco.__doc__ = ds
260 return magic_deco
257 return magic_deco
261
258
262
259
263 MAGIC_NO_VAR_EXPAND_ATTR = '_ipython_magic_no_var_expand'
260 MAGIC_NO_VAR_EXPAND_ATTR = '_ipython_magic_no_var_expand'
264
261
265
262
266 def no_var_expand(magic_func):
263 def no_var_expand(magic_func):
267 """Mark a magic function as not needing variable expansion
264 """Mark a magic function as not needing variable expansion
268
265
269 By default, IPython interprets `{a}` or `$a` in the line passed to magics
266 By default, IPython interprets `{a}` or `$a` in the line passed to magics
270 as variables that should be interpolated from the interactive namespace
267 as variables that should be interpolated from the interactive namespace
271 before passing the line to the magic function.
268 before passing the line to the magic function.
272 This is not always desirable, e.g. when the magic executes Python code
269 This is not always desirable, e.g. when the magic executes Python code
273 (%timeit, %time, etc.).
270 (%timeit, %time, etc.).
274 Decorate magics with `@no_var_expand` to opt-out of variable expansion.
271 Decorate magics with `@no_var_expand` to opt-out of variable expansion.
275
272
276 .. versionadded:: 7.3
273 .. versionadded:: 7.3
277 """
274 """
278 setattr(magic_func, MAGIC_NO_VAR_EXPAND_ATTR, True)
275 setattr(magic_func, MAGIC_NO_VAR_EXPAND_ATTR, True)
279 return magic_func
276 return magic_func
280
277
281
278
282 # Create the actual decorators for public use
279 # Create the actual decorators for public use
283
280
284 # These three are used to decorate methods in class definitions
281 # These three are used to decorate methods in class definitions
285 line_magic = _method_magic_marker('line')
282 line_magic = _method_magic_marker('line')
286 cell_magic = _method_magic_marker('cell')
283 cell_magic = _method_magic_marker('cell')
287 line_cell_magic = _method_magic_marker('line_cell')
284 line_cell_magic = _method_magic_marker('line_cell')
288
285
289 # These three decorate standalone functions and perform the decoration
286 # These three decorate standalone functions and perform the decoration
290 # immediately. They can only run where get_ipython() works
287 # immediately. They can only run where get_ipython() works
291 register_line_magic = _function_magic_marker('line')
288 register_line_magic = _function_magic_marker('line')
292 register_cell_magic = _function_magic_marker('cell')
289 register_cell_magic = _function_magic_marker('cell')
293 register_line_cell_magic = _function_magic_marker('line_cell')
290 register_line_cell_magic = _function_magic_marker('line_cell')
294
291
295 #-----------------------------------------------------------------------------
292 #-----------------------------------------------------------------------------
296 # Core Magic classes
293 # Core Magic classes
297 #-----------------------------------------------------------------------------
294 #-----------------------------------------------------------------------------
298
295
299 class MagicsManager(Configurable):
296 class MagicsManager(Configurable):
300 """Object that handles all magic-related functionality for IPython.
297 """Object that handles all magic-related functionality for IPython.
301 """
298 """
302 # Non-configurable class attributes
299 # Non-configurable class attributes
303
300
304 # A two-level dict, first keyed by magic type, then by magic function, and
301 # A two-level dict, first keyed by magic type, then by magic function, and
305 # holding the actual callable object as value. This is the dict used for
302 # holding the actual callable object as value. This is the dict used for
306 # magic function dispatch
303 # magic function dispatch
307 magics = Dict()
304 magics = Dict()
308
305
309 # A registry of the original objects that we've been given holding magics.
306 # A registry of the original objects that we've been given holding magics.
310 registry = Dict()
307 registry = Dict()
311
308
312 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
309 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
313
310
314 auto_magic = Bool(True, help=
311 auto_magic = Bool(True, help=
315 "Automatically call line magics without requiring explicit % prefix"
312 "Automatically call line magics without requiring explicit % prefix"
316 ).tag(config=True)
313 ).tag(config=True)
317 @observe('auto_magic')
314 @observe('auto_magic')
318 def _auto_magic_changed(self, change):
315 def _auto_magic_changed(self, change):
319 self.shell.automagic = change['new']
316 self.shell.automagic = change['new']
320
317
321 _auto_status = [
318 _auto_status = [
322 'Automagic is OFF, % prefix IS needed for line magics.',
319 'Automagic is OFF, % prefix IS needed for line magics.',
323 'Automagic is ON, % prefix IS NOT needed for line magics.']
320 'Automagic is ON, % prefix IS NOT needed for line magics.']
324
321
325 user_magics = Instance('IPython.core.magics.UserMagics', allow_none=True)
322 user_magics = Instance('IPython.core.magics.UserMagics', allow_none=True)
326
323
327 def __init__(self, shell=None, config=None, user_magics=None, **traits):
324 def __init__(self, shell=None, config=None, user_magics=None, **traits):
328
325
329 super(MagicsManager, self).__init__(shell=shell, config=config,
326 super(MagicsManager, self).__init__(shell=shell, config=config,
330 user_magics=user_magics, **traits)
327 user_magics=user_magics, **traits)
331 self.magics = dict(line={}, cell={})
328 self.magics = dict(line={}, cell={})
332 # Let's add the user_magics to the registry for uniformity, so *all*
329 # Let's add the user_magics to the registry for uniformity, so *all*
333 # registered magic containers can be found there.
330 # registered magic containers can be found there.
334 self.registry[user_magics.__class__.__name__] = user_magics
331 self.registry[user_magics.__class__.__name__] = user_magics
335
332
336 def auto_status(self):
333 def auto_status(self):
337 """Return descriptive string with automagic status."""
334 """Return descriptive string with automagic status."""
338 return self._auto_status[self.auto_magic]
335 return self._auto_status[self.auto_magic]
339
336
340 def lsmagic(self):
337 def lsmagic(self):
341 """Return a dict of currently available magic functions.
338 """Return a dict of currently available magic functions.
342
339
343 The return dict has the keys 'line' and 'cell', corresponding to the
340 The return dict has the keys 'line' and 'cell', corresponding to the
344 two types of magics we support. Each value is a list of names.
341 two types of magics we support. Each value is a list of names.
345 """
342 """
346 return self.magics
343 return self.magics
347
344
348 def lsmagic_docs(self, brief=False, missing=''):
345 def lsmagic_docs(self, brief=False, missing=''):
349 """Return dict of documentation of magic functions.
346 """Return dict of documentation of magic functions.
350
347
351 The return dict has the keys 'line' and 'cell', corresponding to the
348 The return dict has the keys 'line' and 'cell', corresponding to the
352 two types of magics we support. Each value is a dict keyed by magic
349 two types of magics we support. Each value is a dict keyed by magic
353 name whose value is the function docstring. If a docstring is
350 name whose value is the function docstring. If a docstring is
354 unavailable, the value of `missing` is used instead.
351 unavailable, the value of `missing` is used instead.
355
352
356 If brief is True, only the first line of each docstring will be returned.
353 If brief is True, only the first line of each docstring will be returned.
357 """
354 """
358 docs = {}
355 docs = {}
359 for m_type in self.magics:
356 for m_type in self.magics:
360 m_docs = {}
357 m_docs = {}
361 for m_name, m_func in self.magics[m_type].items():
358 for m_name, m_func in self.magics[m_type].items():
362 if m_func.__doc__:
359 if m_func.__doc__:
363 if brief:
360 if brief:
364 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
361 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
365 else:
362 else:
366 m_docs[m_name] = m_func.__doc__.rstrip()
363 m_docs[m_name] = m_func.__doc__.rstrip()
367 else:
364 else:
368 m_docs[m_name] = missing
365 m_docs[m_name] = missing
369 docs[m_type] = m_docs
366 docs[m_type] = m_docs
370 return docs
367 return docs
371
368
372 def register(self, *magic_objects):
369 def register(self, *magic_objects):
373 """Register one or more instances of Magics.
370 """Register one or more instances of Magics.
374
371
375 Take one or more classes or instances of classes that subclass the main
372 Take one or more classes or instances of classes that subclass the main
376 `core.Magic` class, and register them with IPython to use the magic
373 `core.Magic` class, and register them with IPython to use the magic
377 functions they provide. The registration process will then ensure that
374 functions they provide. The registration process will then ensure that
378 any methods that have decorated to provide line and/or cell magics will
375 any methods that have decorated to provide line and/or cell magics will
379 be recognized with the `%x`/`%%x` syntax as a line/cell magic
376 be recognized with the `%x`/`%%x` syntax as a line/cell magic
380 respectively.
377 respectively.
381
378
382 If classes are given, they will be instantiated with the default
379 If classes are given, they will be instantiated with the default
383 constructor. If your classes need a custom constructor, you should
380 constructor. If your classes need a custom constructor, you should
384 instanitate them first and pass the instance.
381 instanitate them first and pass the instance.
385
382
386 The provided arguments can be an arbitrary mix of classes and instances.
383 The provided arguments can be an arbitrary mix of classes and instances.
387
384
388 Parameters
385 Parameters
389 ----------
386 ----------
390 magic_objects : one or more classes or instances
387 *magic_objects : one or more classes or instances
391 """
388 """
392 # Start by validating them to ensure they have all had their magic
389 # Start by validating them to ensure they have all had their magic
393 # methods registered at the instance level
390 # methods registered at the instance level
394 for m in magic_objects:
391 for m in magic_objects:
395 if not m.registered:
392 if not m.registered:
396 raise ValueError("Class of magics %r was constructed without "
393 raise ValueError("Class of magics %r was constructed without "
397 "the @register_magics class decorator")
394 "the @register_magics class decorator")
398 if isinstance(m, type):
395 if isinstance(m, type):
399 # If we're given an uninstantiated class
396 # If we're given an uninstantiated class
400 m = m(shell=self.shell)
397 m = m(shell=self.shell)
401
398
402 # Now that we have an instance, we can register it and update the
399 # Now that we have an instance, we can register it and update the
403 # table of callables
400 # table of callables
404 self.registry[m.__class__.__name__] = m
401 self.registry[m.__class__.__name__] = m
405 for mtype in magic_kinds:
402 for mtype in magic_kinds:
406 self.magics[mtype].update(m.magics[mtype])
403 self.magics[mtype].update(m.magics[mtype])
407
404
408 def register_function(self, func, magic_kind='line', magic_name=None):
405 def register_function(self, func, magic_kind='line', magic_name=None):
409 """Expose a standalone function as magic function for IPython.
406 """Expose a standalone function as magic function for IPython.
410
407
411 This will create an IPython magic (line, cell or both) from a
408 This will create an IPython magic (line, cell or both) from a
412 standalone function. The functions should have the following
409 standalone function. The functions should have the following
413 signatures:
410 signatures:
414
411
415 * For line magics: `def f(line)`
412 * For line magics: `def f(line)`
416 * For cell magics: `def f(line, cell)`
413 * For cell magics: `def f(line, cell)`
417 * For a function that does both: `def f(line, cell=None)`
414 * For a function that does both: `def f(line, cell=None)`
418
415
419 In the latter case, the function will be called with `cell==None` when
416 In the latter case, the function will be called with `cell==None` when
420 invoked as `%f`, and with cell as a string when invoked as `%%f`.
417 invoked as `%f`, and with cell as a string when invoked as `%%f`.
421
418
422 Parameters
419 Parameters
423 ----------
420 ----------
424 func : callable
421 func : callable
425 Function to be registered as a magic.
422 Function to be registered as a magic.
426
427 magic_kind : str
423 magic_kind : str
428 Kind of magic, one of 'line', 'cell' or 'line_cell'
424 Kind of magic, one of 'line', 'cell' or 'line_cell'
429
430 magic_name : optional str
425 magic_name : optional str
431 If given, the name the magic will have in the IPython namespace. By
426 If given, the name the magic will have in the IPython namespace. By
432 default, the name of the function itself is used.
427 default, the name of the function itself is used.
433 """
428 """
434
429
435 # Create the new method in the user_magics and register it in the
430 # Create the new method in the user_magics and register it in the
436 # global table
431 # global table
437 validate_type(magic_kind)
432 validate_type(magic_kind)
438 magic_name = func.__name__ if magic_name is None else magic_name
433 magic_name = func.__name__ if magic_name is None else magic_name
439 setattr(self.user_magics, magic_name, func)
434 setattr(self.user_magics, magic_name, func)
440 record_magic(self.magics, magic_kind, magic_name, func)
435 record_magic(self.magics, magic_kind, magic_name, func)
441
436
442 def register_alias(self, alias_name, magic_name, magic_kind='line', magic_params=None):
437 def register_alias(self, alias_name, magic_name, magic_kind='line', magic_params=None):
443 """Register an alias to a magic function.
438 """Register an alias to a magic function.
444
439
445 The alias is an instance of :class:`MagicAlias`, which holds the
440 The alias is an instance of :class:`MagicAlias`, which holds the
446 name and kind of the magic it should call. Binding is done at
441 name and kind of the magic it should call. Binding is done at
447 call time, so if the underlying magic function is changed the alias
442 call time, so if the underlying magic function is changed the alias
448 will call the new function.
443 will call the new function.
449
444
450 Parameters
445 Parameters
451 ----------
446 ----------
452 alias_name : str
447 alias_name : str
453 The name of the magic to be registered.
448 The name of the magic to be registered.
454
455 magic_name : str
449 magic_name : str
456 The name of an existing magic.
450 The name of an existing magic.
457
458 magic_kind : str
451 magic_kind : str
459 Kind of magic, one of 'line' or 'cell'
452 Kind of magic, one of 'line' or 'cell'
460 """
453 """
461
454
462 # `validate_type` is too permissive, as it allows 'line_cell'
455 # `validate_type` is too permissive, as it allows 'line_cell'
463 # which we do not handle.
456 # which we do not handle.
464 if magic_kind not in magic_kinds:
457 if magic_kind not in magic_kinds:
465 raise ValueError('magic_kind must be one of %s, %s given' %
458 raise ValueError('magic_kind must be one of %s, %s given' %
466 magic_kinds, magic_kind)
459 magic_kinds, magic_kind)
467
460
468 alias = MagicAlias(self.shell, magic_name, magic_kind, magic_params)
461 alias = MagicAlias(self.shell, magic_name, magic_kind, magic_params)
469 setattr(self.user_magics, alias_name, alias)
462 setattr(self.user_magics, alias_name, alias)
470 record_magic(self.magics, magic_kind, alias_name, alias)
463 record_magic(self.magics, magic_kind, alias_name, alias)
471
464
472 # Key base class that provides the central functionality for magics.
465 # Key base class that provides the central functionality for magics.
473
466
474
467
475 class Magics(Configurable):
468 class Magics(Configurable):
476 """Base class for implementing magic functions.
469 """Base class for implementing magic functions.
477
470
478 Shell functions which can be reached as %function_name. All magic
471 Shell functions which can be reached as %function_name. All magic
479 functions should accept a string, which they can parse for their own
472 functions should accept a string, which they can parse for their own
480 needs. This can make some functions easier to type, eg `%cd ../`
473 needs. This can make some functions easier to type, eg `%cd ../`
481 vs. `%cd("../")`
474 vs. `%cd("../")`
482
475
483 Classes providing magic functions need to subclass this class, and they
476 Classes providing magic functions need to subclass this class, and they
484 MUST:
477 MUST:
485
478
486 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
479 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
487 individual methods as magic functions, AND
480 individual methods as magic functions, AND
488
481
489 - Use the class decorator `@magics_class` to ensure that the magic
482 - Use the class decorator `@magics_class` to ensure that the magic
490 methods are properly registered at the instance level upon instance
483 methods are properly registered at the instance level upon instance
491 initialization.
484 initialization.
492
485
493 See :mod:`magic_functions` for examples of actual implementation classes.
486 See :mod:`magic_functions` for examples of actual implementation classes.
494 """
487 """
495 # Dict holding all command-line options for each magic.
488 # Dict holding all command-line options for each magic.
496 options_table = None
489 options_table = None
497 # Dict for the mapping of magic names to methods, set by class decorator
490 # Dict for the mapping of magic names to methods, set by class decorator
498 magics = None
491 magics = None
499 # Flag to check that the class decorator was properly applied
492 # Flag to check that the class decorator was properly applied
500 registered = False
493 registered = False
501 # Instance of IPython shell
494 # Instance of IPython shell
502 shell = None
495 shell = None
503
496
504 def __init__(self, shell=None, **kwargs):
497 def __init__(self, shell=None, **kwargs):
505 if not(self.__class__.registered):
498 if not(self.__class__.registered):
506 raise ValueError('Magics subclass without registration - '
499 raise ValueError('Magics subclass without registration - '
507 'did you forget to apply @magics_class?')
500 'did you forget to apply @magics_class?')
508 if shell is not None:
501 if shell is not None:
509 if hasattr(shell, 'configurables'):
502 if hasattr(shell, 'configurables'):
510 shell.configurables.append(self)
503 shell.configurables.append(self)
511 if hasattr(shell, 'config'):
504 if hasattr(shell, 'config'):
512 kwargs.setdefault('parent', shell)
505 kwargs.setdefault('parent', shell)
513
506
514 self.shell = shell
507 self.shell = shell
515 self.options_table = {}
508 self.options_table = {}
516 # The method decorators are run when the instance doesn't exist yet, so
509 # The method decorators are run when the instance doesn't exist yet, so
517 # they can only record the names of the methods they are supposed to
510 # they can only record the names of the methods they are supposed to
518 # grab. Only now, that the instance exists, can we create the proper
511 # grab. Only now, that the instance exists, can we create the proper
519 # mapping to bound methods. So we read the info off the original names
512 # mapping to bound methods. So we read the info off the original names
520 # table and replace each method name by the actual bound method.
513 # table and replace each method name by the actual bound method.
521 # But we mustn't clobber the *class* mapping, in case of multiple instances.
514 # But we mustn't clobber the *class* mapping, in case of multiple instances.
522 class_magics = self.magics
515 class_magics = self.magics
523 self.magics = {}
516 self.magics = {}
524 for mtype in magic_kinds:
517 for mtype in magic_kinds:
525 tab = self.magics[mtype] = {}
518 tab = self.magics[mtype] = {}
526 cls_tab = class_magics[mtype]
519 cls_tab = class_magics[mtype]
527 for magic_name, meth_name in cls_tab.items():
520 for magic_name, meth_name in cls_tab.items():
528 if isinstance(meth_name, str):
521 if isinstance(meth_name, str):
529 # it's a method name, grab it
522 # it's a method name, grab it
530 tab[magic_name] = getattr(self, meth_name)
523 tab[magic_name] = getattr(self, meth_name)
531 else:
524 else:
532 # it's the real thing
525 # it's the real thing
533 tab[magic_name] = meth_name
526 tab[magic_name] = meth_name
534 # Configurable **needs** to be initiated at the end or the config
527 # Configurable **needs** to be initiated at the end or the config
535 # magics get screwed up.
528 # magics get screwed up.
536 super(Magics, self).__init__(**kwargs)
529 super(Magics, self).__init__(**kwargs)
537
530
538 def arg_err(self,func):
531 def arg_err(self,func):
539 """Print docstring if incorrect arguments were passed"""
532 """Print docstring if incorrect arguments were passed"""
540 print('Error in arguments:')
533 print('Error in arguments:')
541 print(oinspect.getdoc(func))
534 print(oinspect.getdoc(func))
542
535
543 def format_latex(self, strng):
536 def format_latex(self, strng):
544 """Format a string for latex inclusion."""
537 """Format a string for latex inclusion."""
545
538
546 # Characters that need to be escaped for latex:
539 # Characters that need to be escaped for latex:
547 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
540 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
548 # Magic command names as headers:
541 # Magic command names as headers:
549 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
542 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
550 re.MULTILINE)
543 re.MULTILINE)
551 # Magic commands
544 # Magic commands
552 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
545 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
553 re.MULTILINE)
546 re.MULTILINE)
554 # Paragraph continue
547 # Paragraph continue
555 par_re = re.compile(r'\\$',re.MULTILINE)
548 par_re = re.compile(r'\\$',re.MULTILINE)
556
549
557 # The "\n" symbol
550 # The "\n" symbol
558 newline_re = re.compile(r'\\n')
551 newline_re = re.compile(r'\\n')
559
552
560 # Now build the string for output:
553 # Now build the string for output:
561 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
554 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
562 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
555 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
563 strng)
556 strng)
564 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
557 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
565 strng = par_re.sub(r'\\\\',strng)
558 strng = par_re.sub(r'\\\\',strng)
566 strng = escape_re.sub(r'\\\1',strng)
559 strng = escape_re.sub(r'\\\1',strng)
567 strng = newline_re.sub(r'\\textbackslash{}n',strng)
560 strng = newline_re.sub(r'\\textbackslash{}n',strng)
568 return strng
561 return strng
569
562
570 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
563 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
571 """Parse options passed to an argument string.
564 """Parse options passed to an argument string.
572
565
573 The interface is similar to that of :func:`getopt.getopt`, but it
566 The interface is similar to that of :func:`getopt.getopt`, but it
574 returns a :class:`~IPython.utils.struct.Struct` with the options as keys
567 returns a :class:`~IPython.utils.struct.Struct` with the options as keys
575 and the stripped argument string still as a string.
568 and the stripped argument string still as a string.
576
569
577 arg_str is quoted as a true sys.argv vector by using shlex.split.
570 arg_str is quoted as a true sys.argv vector by using shlex.split.
578 This allows us to easily expand variables, glob files, quote
571 This allows us to easily expand variables, glob files, quote
579 arguments, etc.
572 arguments, etc.
580
573
581 Parameters
574 Parameters
582 ----------
575 ----------
583
584 arg_str : str
576 arg_str : str
585 The arguments to parse.
577 The arguments to parse.
586
587 opt_str : str
578 opt_str : str
588 The options specification.
579 The options specification.
589
590 mode : str, default 'string'
580 mode : str, default 'string'
591 If given as 'list', the argument string is returned as a list (split
581 If given as 'list', the argument string is returned as a list (split
592 on whitespace) instead of a string.
582 on whitespace) instead of a string.
593
594 list_all : bool, default False
583 list_all : bool, default False
595 Put all option values in lists. Normally only options
584 Put all option values in lists. Normally only options
596 appearing more than once are put in a list.
585 appearing more than once are put in a list.
597
598 posix : bool, default True
586 posix : bool, default True
599 Whether to split the input line in POSIX mode or not, as per the
587 Whether to split the input line in POSIX mode or not, as per the
600 conventions outlined in the :mod:`shlex` module from the standard
588 conventions outlined in the :mod:`shlex` module from the standard
601 library.
589 library.
602 """
590 """
603
591
604 # inject default options at the beginning of the input line
592 # inject default options at the beginning of the input line
605 caller = sys._getframe(1).f_code.co_name
593 caller = sys._getframe(1).f_code.co_name
606 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
594 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
607
595
608 mode = kw.get('mode','string')
596 mode = kw.get('mode','string')
609 if mode not in ['string','list']:
597 if mode not in ['string','list']:
610 raise ValueError('incorrect mode given: %s' % mode)
598 raise ValueError('incorrect mode given: %s' % mode)
611 # Get options
599 # Get options
612 list_all = kw.get('list_all',0)
600 list_all = kw.get('list_all',0)
613 posix = kw.get('posix', os.name == 'posix')
601 posix = kw.get('posix', os.name == 'posix')
614 strict = kw.get('strict', True)
602 strict = kw.get('strict', True)
615
603
616 preserve_non_opts = kw.get("preserve_non_opts", False)
604 preserve_non_opts = kw.get("preserve_non_opts", False)
617 remainder_arg_str = arg_str
605 remainder_arg_str = arg_str
618
606
619 # Check if we have more than one argument to warrant extra processing:
607 # Check if we have more than one argument to warrant extra processing:
620 odict = {} # Dictionary with options
608 odict = {} # Dictionary with options
621 args = arg_str.split()
609 args = arg_str.split()
622 if len(args) >= 1:
610 if len(args) >= 1:
623 # If the list of inputs only has 0 or 1 thing in it, there's no
611 # If the list of inputs only has 0 or 1 thing in it, there's no
624 # need to look for options
612 # need to look for options
625 argv = arg_split(arg_str, posix, strict)
613 argv = arg_split(arg_str, posix, strict)
626 # Do regular option processing
614 # Do regular option processing
627 try:
615 try:
628 opts,args = getopt(argv, opt_str, long_opts)
616 opts,args = getopt(argv, opt_str, long_opts)
629 except GetoptError as e:
617 except GetoptError as e:
630 raise UsageError(
618 raise UsageError(
631 '%s ( allowed: "%s" %s)' % (e.msg, opt_str, " ".join(long_opts))
619 '%s ( allowed: "%s" %s)' % (e.msg, opt_str, " ".join(long_opts))
632 ) from e
620 ) from e
633 for o, a in opts:
621 for o, a in opts:
634 if mode == "string" and preserve_non_opts:
622 if mode == "string" and preserve_non_opts:
635 # remove option-parts from the original args-string and preserve remaining-part.
623 # remove option-parts from the original args-string and preserve remaining-part.
636 # This relies on the arg_split(...) and getopt(...)'s impl spec, that the parsed options are
624 # This relies on the arg_split(...) and getopt(...)'s impl spec, that the parsed options are
637 # returned in the original order.
625 # returned in the original order.
638 remainder_arg_str = remainder_arg_str.replace(o, "", 1).replace(
626 remainder_arg_str = remainder_arg_str.replace(o, "", 1).replace(
639 a, "", 1
627 a, "", 1
640 )
628 )
641 if o.startswith("--"):
629 if o.startswith("--"):
642 o = o[2:]
630 o = o[2:]
643 else:
631 else:
644 o = o[1:]
632 o = o[1:]
645 try:
633 try:
646 odict[o].append(a)
634 odict[o].append(a)
647 except AttributeError:
635 except AttributeError:
648 odict[o] = [odict[o],a]
636 odict[o] = [odict[o],a]
649 except KeyError:
637 except KeyError:
650 if list_all:
638 if list_all:
651 odict[o] = [a]
639 odict[o] = [a]
652 else:
640 else:
653 odict[o] = a
641 odict[o] = a
654
642
655 # Prepare opts,args for return
643 # Prepare opts,args for return
656 opts = Struct(odict)
644 opts = Struct(odict)
657 if mode == 'string':
645 if mode == 'string':
658 if preserve_non_opts:
646 if preserve_non_opts:
659 args = remainder_arg_str.lstrip()
647 args = remainder_arg_str.lstrip()
660 else:
648 else:
661 args = " ".join(args)
649 args = " ".join(args)
662
650
663 return opts,args
651 return opts,args
664
652
665 def default_option(self, fn, optstr):
653 def default_option(self, fn, optstr):
666 """Make an entry in the options_table for fn, with value optstr"""
654 """Make an entry in the options_table for fn, with value optstr"""
667
655
668 if fn not in self.lsmagic():
656 if fn not in self.lsmagic():
669 error("%s is not a magic function" % fn)
657 error("%s is not a magic function" % fn)
670 self.options_table[fn] = optstr
658 self.options_table[fn] = optstr
671
659
672
660
673 class MagicAlias(object):
661 class MagicAlias(object):
674 """An alias to another magic function.
662 """An alias to another magic function.
675
663
676 An alias is determined by its magic name and magic kind. Lookup
664 An alias is determined by its magic name and magic kind. Lookup
677 is done at call time, so if the underlying magic changes the alias
665 is done at call time, so if the underlying magic changes the alias
678 will call the new function.
666 will call the new function.
679
667
680 Use the :meth:`MagicsManager.register_alias` method or the
668 Use the :meth:`MagicsManager.register_alias` method or the
681 `%alias_magic` magic function to create and register a new alias.
669 `%alias_magic` magic function to create and register a new alias.
682 """
670 """
683 def __init__(self, shell, magic_name, magic_kind, magic_params=None):
671 def __init__(self, shell, magic_name, magic_kind, magic_params=None):
684 self.shell = shell
672 self.shell = shell
685 self.magic_name = magic_name
673 self.magic_name = magic_name
686 self.magic_params = magic_params
674 self.magic_params = magic_params
687 self.magic_kind = magic_kind
675 self.magic_kind = magic_kind
688
676
689 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
677 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
690 self.__doc__ = "Alias for `%s`." % self.pretty_target
678 self.__doc__ = "Alias for `%s`." % self.pretty_target
691
679
692 self._in_call = False
680 self._in_call = False
693
681
694 def __call__(self, *args, **kwargs):
682 def __call__(self, *args, **kwargs):
695 """Call the magic alias."""
683 """Call the magic alias."""
696 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
684 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
697 if fn is None:
685 if fn is None:
698 raise UsageError("Magic `%s` not found." % self.pretty_target)
686 raise UsageError("Magic `%s` not found." % self.pretty_target)
699
687
700 # Protect against infinite recursion.
688 # Protect against infinite recursion.
701 if self._in_call:
689 if self._in_call:
702 raise UsageError("Infinite recursion detected; "
690 raise UsageError("Infinite recursion detected; "
703 "magic aliases cannot call themselves.")
691 "magic aliases cannot call themselves.")
704 self._in_call = True
692 self._in_call = True
705 try:
693 try:
706 if self.magic_params:
694 if self.magic_params:
707 args_list = list(args)
695 args_list = list(args)
708 args_list[0] = self.magic_params + " " + args[0]
696 args_list[0] = self.magic_params + " " + args[0]
709 args = tuple(args_list)
697 args = tuple(args_list)
710 return fn(*args, **kwargs)
698 return fn(*args, **kwargs)
711 finally:
699 finally:
712 self._in_call = False
700 self._in_call = False
@@ -1,345 +1,345 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Notes
5 Notes
6 -----
6 -----
7
7
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
8 For now this uses IPython hooks, so it can't be in IPython.utils. If we can get
9 rid of that dependency, we could move it there.
9 rid of that dependency, we could move it there.
10 -----
10 -----
11 """
11 """
12
12
13 # Copyright (c) IPython Development Team.
13 # Copyright (c) IPython Development Team.
14 # Distributed under the terms of the Modified BSD License.
14 # Distributed under the terms of the Modified BSD License.
15
15
16
16
17 import os
17 import os
18 import io
18 import io
19 import re
19 import re
20 import sys
20 import sys
21 import tempfile
21 import tempfile
22 import subprocess
22 import subprocess
23
23
24 from io import UnsupportedOperation
24 from io import UnsupportedOperation
25 from pathlib import Path
25 from pathlib import Path
26
26
27 from IPython import get_ipython
27 from IPython import get_ipython
28 from IPython.display import display
28 from IPython.display import display
29 from IPython.core.error import TryNext
29 from IPython.core.error import TryNext
30 from IPython.utils.data import chop
30 from IPython.utils.data import chop
31 from IPython.utils.process import system
31 from IPython.utils.process import system
32 from IPython.utils.terminal import get_terminal_size
32 from IPython.utils.terminal import get_terminal_size
33 from IPython.utils import py3compat
33 from IPython.utils import py3compat
34
34
35
35
36 def display_page(strng, start=0, screen_lines=25):
36 def display_page(strng, start=0, screen_lines=25):
37 """Just display, no paging. screen_lines is ignored."""
37 """Just display, no paging. screen_lines is ignored."""
38 if isinstance(strng, dict):
38 if isinstance(strng, dict):
39 data = strng
39 data = strng
40 else:
40 else:
41 if start:
41 if start:
42 strng = u'\n'.join(strng.splitlines()[start:])
42 strng = u'\n'.join(strng.splitlines()[start:])
43 data = { 'text/plain': strng }
43 data = { 'text/plain': strng }
44 display(data, raw=True)
44 display(data, raw=True)
45
45
46
46
47 def as_hook(page_func):
47 def as_hook(page_func):
48 """Wrap a pager func to strip the `self` arg
48 """Wrap a pager func to strip the `self` arg
49
49
50 so it can be called as a hook.
50 so it can be called as a hook.
51 """
51 """
52 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
52 return lambda self, *args, **kwargs: page_func(*args, **kwargs)
53
53
54
54
55 esc_re = re.compile(r"(\x1b[^m]+m)")
55 esc_re = re.compile(r"(\x1b[^m]+m)")
56
56
57 def page_dumb(strng, start=0, screen_lines=25):
57 def page_dumb(strng, start=0, screen_lines=25):
58 """Very dumb 'pager' in Python, for when nothing else works.
58 """Very dumb 'pager' in Python, for when nothing else works.
59
59
60 Only moves forward, same interface as page(), except for pager_cmd and
60 Only moves forward, same interface as page(), except for pager_cmd and
61 mode.
61 mode.
62 """
62 """
63 if isinstance(strng, dict):
63 if isinstance(strng, dict):
64 strng = strng.get('text/plain', '')
64 strng = strng.get('text/plain', '')
65 out_ln = strng.splitlines()[start:]
65 out_ln = strng.splitlines()[start:]
66 screens = chop(out_ln,screen_lines-1)
66 screens = chop(out_ln,screen_lines-1)
67 if len(screens) == 1:
67 if len(screens) == 1:
68 print(os.linesep.join(screens[0]))
68 print(os.linesep.join(screens[0]))
69 else:
69 else:
70 last_escape = ""
70 last_escape = ""
71 for scr in screens[0:-1]:
71 for scr in screens[0:-1]:
72 hunk = os.linesep.join(scr)
72 hunk = os.linesep.join(scr)
73 print(last_escape + hunk)
73 print(last_escape + hunk)
74 if not page_more():
74 if not page_more():
75 return
75 return
76 esc_list = esc_re.findall(hunk)
76 esc_list = esc_re.findall(hunk)
77 if len(esc_list) > 0:
77 if len(esc_list) > 0:
78 last_escape = esc_list[-1]
78 last_escape = esc_list[-1]
79 print(last_escape + os.linesep.join(screens[-1]))
79 print(last_escape + os.linesep.join(screens[-1]))
80
80
81 def _detect_screen_size(screen_lines_def):
81 def _detect_screen_size(screen_lines_def):
82 """Attempt to work out the number of lines on the screen.
82 """Attempt to work out the number of lines on the screen.
83
83
84 This is called by page(). It can raise an error (e.g. when run in the
84 This is called by page(). It can raise an error (e.g. when run in the
85 test suite), so it's separated out so it can easily be called in a try block.
85 test suite), so it's separated out so it can easily be called in a try block.
86 """
86 """
87 TERM = os.environ.get('TERM',None)
87 TERM = os.environ.get('TERM',None)
88 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
88 if not((TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5'):
89 # curses causes problems on many terminals other than xterm, and
89 # curses causes problems on many terminals other than xterm, and
90 # some termios calls lock up on Sun OS5.
90 # some termios calls lock up on Sun OS5.
91 return screen_lines_def
91 return screen_lines_def
92
92
93 try:
93 try:
94 import termios
94 import termios
95 import curses
95 import curses
96 except ImportError:
96 except ImportError:
97 return screen_lines_def
97 return screen_lines_def
98
98
99 # There is a bug in curses, where *sometimes* it fails to properly
99 # There is a bug in curses, where *sometimes* it fails to properly
100 # initialize, and then after the endwin() call is made, the
100 # initialize, and then after the endwin() call is made, the
101 # terminal is left in an unusable state. Rather than trying to
101 # terminal is left in an unusable state. Rather than trying to
102 # check every time for this (by requesting and comparing termios
102 # check every time for this (by requesting and comparing termios
103 # flags each time), we just save the initial terminal state and
103 # flags each time), we just save the initial terminal state and
104 # unconditionally reset it every time. It's cheaper than making
104 # unconditionally reset it every time. It's cheaper than making
105 # the checks.
105 # the checks.
106 try:
106 try:
107 term_flags = termios.tcgetattr(sys.stdout)
107 term_flags = termios.tcgetattr(sys.stdout)
108 except termios.error as err:
108 except termios.error as err:
109 # can fail on Linux 2.6, pager_page will catch the TypeError
109 # can fail on Linux 2.6, pager_page will catch the TypeError
110 raise TypeError('termios error: {0}'.format(err)) from err
110 raise TypeError('termios error: {0}'.format(err)) from err
111
111
112 try:
112 try:
113 scr = curses.initscr()
113 scr = curses.initscr()
114 except AttributeError:
114 except AttributeError:
115 # Curses on Solaris may not be complete, so we can't use it there
115 # Curses on Solaris may not be complete, so we can't use it there
116 return screen_lines_def
116 return screen_lines_def
117
117
118 screen_lines_real,screen_cols = scr.getmaxyx()
118 screen_lines_real,screen_cols = scr.getmaxyx()
119 curses.endwin()
119 curses.endwin()
120
120
121 # Restore terminal state in case endwin() didn't.
121 # Restore terminal state in case endwin() didn't.
122 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
122 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
123 # Now we have what we needed: the screen size in rows/columns
123 # Now we have what we needed: the screen size in rows/columns
124 return screen_lines_real
124 return screen_lines_real
125 #print '***Screen size:',screen_lines_real,'lines x',\
125 #print '***Screen size:',screen_lines_real,'lines x',\
126 #screen_cols,'columns.' # dbg
126 #screen_cols,'columns.' # dbg
127
127
128 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
128 def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):
129 """Display a string, piping through a pager after a certain length.
129 """Display a string, piping through a pager after a certain length.
130
130
131 strng can be a mime-bundle dict, supplying multiple representations,
131 strng can be a mime-bundle dict, supplying multiple representations,
132 keyed by mime-type.
132 keyed by mime-type.
133
133
134 The screen_lines parameter specifies the number of *usable* lines of your
134 The screen_lines parameter specifies the number of *usable* lines of your
135 terminal screen (total lines minus lines you need to reserve to show other
135 terminal screen (total lines minus lines you need to reserve to show other
136 information).
136 information).
137
137
138 If you set screen_lines to a number <=0, page() will try to auto-determine
138 If you set screen_lines to a number <=0, page() will try to auto-determine
139 your screen size and will only use up to (screen_size+screen_lines) for
139 your screen size and will only use up to (screen_size+screen_lines) for
140 printing, paging after that. That is, if you want auto-detection but need
140 printing, paging after that. That is, if you want auto-detection but need
141 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
141 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
142 auto-detection without any lines reserved simply use screen_lines = 0.
142 auto-detection without any lines reserved simply use screen_lines = 0.
143
143
144 If a string won't fit in the allowed lines, it is sent through the
144 If a string won't fit in the allowed lines, it is sent through the
145 specified pager command. If none given, look for PAGER in the environment,
145 specified pager command. If none given, look for PAGER in the environment,
146 and ultimately default to less.
146 and ultimately default to less.
147
147
148 If no system pager works, the string is sent through a 'dumb pager'
148 If no system pager works, the string is sent through a 'dumb pager'
149 written in python, very simplistic.
149 written in python, very simplistic.
150 """
150 """
151
151
152 # for compatibility with mime-bundle form:
152 # for compatibility with mime-bundle form:
153 if isinstance(strng, dict):
153 if isinstance(strng, dict):
154 strng = strng['text/plain']
154 strng = strng['text/plain']
155
155
156 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
156 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
157 TERM = os.environ.get('TERM','dumb')
157 TERM = os.environ.get('TERM','dumb')
158 if TERM in ['dumb','emacs'] and os.name != 'nt':
158 if TERM in ['dumb','emacs'] and os.name != 'nt':
159 print(strng)
159 print(strng)
160 return
160 return
161 # chop off the topmost part of the string we don't want to see
161 # chop off the topmost part of the string we don't want to see
162 str_lines = strng.splitlines()[start:]
162 str_lines = strng.splitlines()[start:]
163 str_toprint = os.linesep.join(str_lines)
163 str_toprint = os.linesep.join(str_lines)
164 num_newlines = len(str_lines)
164 num_newlines = len(str_lines)
165 len_str = len(str_toprint)
165 len_str = len(str_toprint)
166
166
167 # Dumb heuristics to guesstimate number of on-screen lines the string
167 # Dumb heuristics to guesstimate number of on-screen lines the string
168 # takes. Very basic, but good enough for docstrings in reasonable
168 # takes. Very basic, but good enough for docstrings in reasonable
169 # terminals. If someone later feels like refining it, it's not hard.
169 # terminals. If someone later feels like refining it, it's not hard.
170 numlines = max(num_newlines,int(len_str/80)+1)
170 numlines = max(num_newlines,int(len_str/80)+1)
171
171
172 screen_lines_def = get_terminal_size()[1]
172 screen_lines_def = get_terminal_size()[1]
173
173
174 # auto-determine screen size
174 # auto-determine screen size
175 if screen_lines <= 0:
175 if screen_lines <= 0:
176 try:
176 try:
177 screen_lines += _detect_screen_size(screen_lines_def)
177 screen_lines += _detect_screen_size(screen_lines_def)
178 except (TypeError, UnsupportedOperation):
178 except (TypeError, UnsupportedOperation):
179 print(str_toprint)
179 print(str_toprint)
180 return
180 return
181
181
182 #print 'numlines',numlines,'screenlines',screen_lines # dbg
182 #print 'numlines',numlines,'screenlines',screen_lines # dbg
183 if numlines <= screen_lines :
183 if numlines <= screen_lines :
184 #print '*** normal print' # dbg
184 #print '*** normal print' # dbg
185 print(str_toprint)
185 print(str_toprint)
186 else:
186 else:
187 # Try to open pager and default to internal one if that fails.
187 # Try to open pager and default to internal one if that fails.
188 # All failure modes are tagged as 'retval=1', to match the return
188 # All failure modes are tagged as 'retval=1', to match the return
189 # value of a failed system command. If any intermediate attempt
189 # value of a failed system command. If any intermediate attempt
190 # sets retval to 1, at the end we resort to our own page_dumb() pager.
190 # sets retval to 1, at the end we resort to our own page_dumb() pager.
191 pager_cmd = get_pager_cmd(pager_cmd)
191 pager_cmd = get_pager_cmd(pager_cmd)
192 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
192 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
193 if os.name == 'nt':
193 if os.name == 'nt':
194 if pager_cmd.startswith('type'):
194 if pager_cmd.startswith('type'):
195 # The default WinXP 'type' command is failing on complex strings.
195 # The default WinXP 'type' command is failing on complex strings.
196 retval = 1
196 retval = 1
197 else:
197 else:
198 fd, tmpname = tempfile.mkstemp('.txt')
198 fd, tmpname = tempfile.mkstemp('.txt')
199 tmppath = Path(tmpname)
199 tmppath = Path(tmpname)
200 try:
200 try:
201 os.close(fd)
201 os.close(fd)
202 with tmppath.open("wt") as tmpfile:
202 with tmppath.open("wt") as tmpfile:
203 tmpfile.write(strng)
203 tmpfile.write(strng)
204 cmd = "%s < %s" % (pager_cmd, tmppath)
204 cmd = "%s < %s" % (pager_cmd, tmppath)
205 # tmpfile needs to be closed for windows
205 # tmpfile needs to be closed for windows
206 if os.system(cmd):
206 if os.system(cmd):
207 retval = 1
207 retval = 1
208 else:
208 else:
209 retval = None
209 retval = None
210 finally:
210 finally:
211 Path.unlink(tmppath)
211 Path.unlink(tmppath)
212 else:
212 else:
213 try:
213 try:
214 retval = None
214 retval = None
215 # Emulate os.popen, but redirect stderr
215 # Emulate os.popen, but redirect stderr
216 proc = subprocess.Popen(pager_cmd,
216 proc = subprocess.Popen(pager_cmd,
217 shell=True,
217 shell=True,
218 stdin=subprocess.PIPE,
218 stdin=subprocess.PIPE,
219 stderr=subprocess.DEVNULL
219 stderr=subprocess.DEVNULL
220 )
220 )
221 pager = os._wrap_close(io.TextIOWrapper(proc.stdin), proc)
221 pager = os._wrap_close(io.TextIOWrapper(proc.stdin), proc)
222 try:
222 try:
223 pager_encoding = pager.encoding or sys.stdout.encoding
223 pager_encoding = pager.encoding or sys.stdout.encoding
224 pager.write(strng)
224 pager.write(strng)
225 finally:
225 finally:
226 retval = pager.close()
226 retval = pager.close()
227 except IOError as msg: # broken pipe when user quits
227 except IOError as msg: # broken pipe when user quits
228 if msg.args == (32, 'Broken pipe'):
228 if msg.args == (32, 'Broken pipe'):
229 retval = None
229 retval = None
230 else:
230 else:
231 retval = 1
231 retval = 1
232 except OSError:
232 except OSError:
233 # Other strange problems, sometimes seen in Win2k/cygwin
233 # Other strange problems, sometimes seen in Win2k/cygwin
234 retval = 1
234 retval = 1
235 if retval is not None:
235 if retval is not None:
236 page_dumb(strng,screen_lines=screen_lines)
236 page_dumb(strng,screen_lines=screen_lines)
237
237
238
238
239 def page(data, start=0, screen_lines=0, pager_cmd=None):
239 def page(data, start=0, screen_lines=0, pager_cmd=None):
240 """Display content in a pager, piping through a pager after a certain length.
240 """Display content in a pager, piping through a pager after a certain length.
241
241
242 data can be a mime-bundle dict, supplying multiple representations,
242 data can be a mime-bundle dict, supplying multiple representations,
243 keyed by mime-type, or text.
243 keyed by mime-type, or text.
244
244
245 Pager is dispatched via the `show_in_pager` IPython hook.
245 Pager is dispatched via the `show_in_pager` IPython hook.
246 If no hook is registered, `pager_page` will be used.
246 If no hook is registered, `pager_page` will be used.
247 """
247 """
248 # Some routines may auto-compute start offsets incorrectly and pass a
248 # Some routines may auto-compute start offsets incorrectly and pass a
249 # negative value. Offset to 0 for robustness.
249 # negative value. Offset to 0 for robustness.
250 start = max(0, start)
250 start = max(0, start)
251
251
252 # first, try the hook
252 # first, try the hook
253 ip = get_ipython()
253 ip = get_ipython()
254 if ip:
254 if ip:
255 try:
255 try:
256 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
256 ip.hooks.show_in_pager(data, start=start, screen_lines=screen_lines)
257 return
257 return
258 except TryNext:
258 except TryNext:
259 pass
259 pass
260
260
261 # fallback on default pager
261 # fallback on default pager
262 return pager_page(data, start, screen_lines, pager_cmd)
262 return pager_page(data, start, screen_lines, pager_cmd)
263
263
264
264
265 def page_file(fname, start=0, pager_cmd=None):
265 def page_file(fname, start=0, pager_cmd=None):
266 """Page a file, using an optional pager command and starting line.
266 """Page a file, using an optional pager command and starting line.
267 """
267 """
268
268
269 pager_cmd = get_pager_cmd(pager_cmd)
269 pager_cmd = get_pager_cmd(pager_cmd)
270 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
270 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
271
271
272 try:
272 try:
273 if os.environ['TERM'] in ['emacs','dumb']:
273 if os.environ['TERM'] in ['emacs','dumb']:
274 raise EnvironmentError
274 raise EnvironmentError
275 system(pager_cmd + ' ' + fname)
275 system(pager_cmd + ' ' + fname)
276 except:
276 except:
277 try:
277 try:
278 if start > 0:
278 if start > 0:
279 start -= 1
279 start -= 1
280 page(open(fname).read(),start)
280 page(open(fname).read(),start)
281 except:
281 except:
282 print('Unable to show file',repr(fname))
282 print('Unable to show file',repr(fname))
283
283
284
284
285 def get_pager_cmd(pager_cmd=None):
285 def get_pager_cmd(pager_cmd=None):
286 """Return a pager command.
286 """Return a pager command.
287
287
288 Makes some attempts at finding an OS-correct one.
288 Makes some attempts at finding an OS-correct one.
289 """
289 """
290 if os.name == 'posix':
290 if os.name == 'posix':
291 default_pager_cmd = 'less -R' # -R for color control sequences
291 default_pager_cmd = 'less -R' # -R for color control sequences
292 elif os.name in ['nt','dos']:
292 elif os.name in ['nt','dos']:
293 default_pager_cmd = 'type'
293 default_pager_cmd = 'type'
294
294
295 if pager_cmd is None:
295 if pager_cmd is None:
296 try:
296 try:
297 pager_cmd = os.environ['PAGER']
297 pager_cmd = os.environ['PAGER']
298 except:
298 except:
299 pager_cmd = default_pager_cmd
299 pager_cmd = default_pager_cmd
300
300
301 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower():
301 if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower():
302 pager_cmd += ' -R'
302 pager_cmd += ' -R'
303
303
304 return pager_cmd
304 return pager_cmd
305
305
306
306
307 def get_pager_start(pager, start):
307 def get_pager_start(pager, start):
308 """Return the string for paging files with an offset.
308 """Return the string for paging files with an offset.
309
309
310 This is the '+N' argument which less and more (under Unix) accept.
310 This is the '+N' argument which less and more (under Unix) accept.
311 """
311 """
312
312
313 if pager in ['less','more']:
313 if pager in ['less','more']:
314 if start:
314 if start:
315 start_string = '+' + str(start)
315 start_string = '+' + str(start)
316 else:
316 else:
317 start_string = ''
317 start_string = ''
318 else:
318 else:
319 start_string = ''
319 start_string = ''
320 return start_string
320 return start_string
321
321
322
322
323 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
323 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
324 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
324 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
325 import msvcrt
325 import msvcrt
326 def page_more():
326 def page_more():
327 """ Smart pausing between pages
327 """ Smart pausing between pages
328
328
329 @return: True if need print more lines, False if quit
329 @return: True if need print more lines, False if quit
330 """
330 """
331 sys.stdout.write('---Return to continue, q to quit--- ')
331 sys.stdout.write('---Return to continue, q to quit--- ')
332 ans = msvcrt.getwch()
332 ans = msvcrt.getwch()
333 if ans in ("q", "Q"):
333 if ans in ("q", "Q"):
334 result = False
334 result = False
335 else:
335 else:
336 result = True
336 result = True
337 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
337 sys.stdout.write("\b"*37 + " "*37 + "\b"*37)
338 return result
338 return result
339 else:
339 else:
340 def page_more():
340 def page_more():
341 ans = py3compat.input('---Return to continue, q to quit--- ')
341 ans = py3compat.input('---Return to continue, q to quit--- ')
342 if ans.lower().startswith('q'):
342 if ans.lower().startswith('q'):
343 return False
343 return False
344 else:
344 else:
345 return True
345 return True
@@ -1,52 +1,51 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A payload based version of page."""
2 """A payload based version of page."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import warnings
7 import warnings
8 from IPython.core.getipython import get_ipython
8 from IPython.core.getipython import get_ipython
9
9
10
10
11 def page(strng, start=0, screen_lines=0, pager_cmd=None):
11 def page(strng, start=0, screen_lines=0, pager_cmd=None):
12 """Print a string, piping through a pager.
12 """Print a string, piping through a pager.
13
13
14 This version ignores the screen_lines and pager_cmd arguments and uses
14 This version ignores the screen_lines and pager_cmd arguments and uses
15 IPython's payload system instead.
15 IPython's payload system instead.
16
16
17 Parameters
17 Parameters
18 ----------
18 ----------
19 strng : str or mime-dict
19 strng : str or mime-dict
20 Text to page, or a mime-type keyed dict of already formatted data.
20 Text to page, or a mime-type keyed dict of already formatted data.
21
22 start : int
21 start : int
23 Starting line at which to place the display.
22 Starting line at which to place the display.
24 """
23 """
25
24
26 # Some routines may auto-compute start offsets incorrectly and pass a
25 # Some routines may auto-compute start offsets incorrectly and pass a
27 # negative value. Offset to 0 for robustness.
26 # negative value. Offset to 0 for robustness.
28 start = max(0, start)
27 start = max(0, start)
29 shell = get_ipython()
28 shell = get_ipython()
30
29
31 if isinstance(strng, dict):
30 if isinstance(strng, dict):
32 data = strng
31 data = strng
33 else:
32 else:
34 data = {'text/plain' : strng}
33 data = {'text/plain' : strng}
35 payload = dict(
34 payload = dict(
36 source='page',
35 source='page',
37 data=data,
36 data=data,
38 start=start,
37 start=start,
39 )
38 )
40 shell.payload_manager.write_payload(payload)
39 shell.payload_manager.write_payload(payload)
41
40
42
41
43 def install_payload_page():
42 def install_payload_page():
44 """DEPRECATED, use show_in_pager hook
43 """DEPRECATED, use show_in_pager hook
45
44
46 Install this version of page as IPython.core.page.page.
45 Install this version of page as IPython.core.page.page.
47 """
46 """
48 warnings.warn("""install_payload_page is deprecated.
47 warnings.warn("""install_payload_page is deprecated.
49 Use `ip.set_hook('show_in_pager, page.as_hook(payloadpage.page))`
48 Use `ip.set_hook('show_in_pager, page.as_hook(payloadpage.page))`
50 """)
49 """)
51 from IPython.core import page as corepage
50 from IPython.core import page as corepage
52 corepage.page = page
51 corepage.page = page
@@ -1,425 +1,424 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities."""
2 """Pylab (matplotlib) support utilities."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from io import BytesIO
7 from io import BytesIO
8 from binascii import b2a_base64
8 from binascii import b2a_base64
9 from functools import partial
9 from functools import partial
10 import warnings
10 import warnings
11
11
12 from IPython.core.display import _pngxy
12 from IPython.core.display import _pngxy
13 from IPython.utils.decorators import flag_calls
13 from IPython.utils.decorators import flag_calls
14
14
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
16 # user's mpl default from the mpl rc structure
16 # user's mpl default from the mpl rc structure
17 backends = {
17 backends = {
18 "tk": "TkAgg",
18 "tk": "TkAgg",
19 "gtk": "GTKAgg",
19 "gtk": "GTKAgg",
20 "gtk3": "GTK3Agg",
20 "gtk3": "GTK3Agg",
21 "gtk4": "GTK4Agg",
21 "gtk4": "GTK4Agg",
22 "wx": "WXAgg",
22 "wx": "WXAgg",
23 "qt4": "Qt4Agg",
23 "qt4": "Qt4Agg",
24 "qt5": "Qt5Agg",
24 "qt5": "Qt5Agg",
25 "qt6": "QtAgg",
25 "qt6": "QtAgg",
26 "qt": "Qt5Agg",
26 "qt": "Qt5Agg",
27 "osx": "MacOSX",
27 "osx": "MacOSX",
28 "nbagg": "nbAgg",
28 "nbagg": "nbAgg",
29 "notebook": "nbAgg",
29 "notebook": "nbAgg",
30 "agg": "agg",
30 "agg": "agg",
31 "svg": "svg",
31 "svg": "svg",
32 "pdf": "pdf",
32 "pdf": "pdf",
33 "ps": "ps",
33 "ps": "ps",
34 "inline": "module://matplotlib_inline.backend_inline",
34 "inline": "module://matplotlib_inline.backend_inline",
35 "ipympl": "module://ipympl.backend_nbagg",
35 "ipympl": "module://ipympl.backend_nbagg",
36 "widget": "module://ipympl.backend_nbagg",
36 "widget": "module://ipympl.backend_nbagg",
37 }
37 }
38
38
39 # We also need a reverse backends2guis mapping that will properly choose which
39 # We also need a reverse backends2guis mapping that will properly choose which
40 # GUI support to activate based on the desired matplotlib backend. For the
40 # GUI support to activate based on the desired matplotlib backend. For the
41 # most part it's just a reverse of the above dict, but we also need to add a
41 # most part it's just a reverse of the above dict, but we also need to add a
42 # few others that map to the same GUI manually:
42 # few others that map to the same GUI manually:
43 backend2gui = dict(zip(backends.values(), backends.keys()))
43 backend2gui = dict(zip(backends.values(), backends.keys()))
44 # In the reverse mapping, there are a few extra valid matplotlib backends that
44 # In the reverse mapping, there are a few extra valid matplotlib backends that
45 # map to the same GUI support
45 # map to the same GUI support
46 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
46 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
47 backend2gui["GTK3Cairo"] = "gtk3"
47 backend2gui["GTK3Cairo"] = "gtk3"
48 backend2gui["GTK4Cairo"] = "gtk4"
48 backend2gui["GTK4Cairo"] = "gtk4"
49 backend2gui["WX"] = "wx"
49 backend2gui["WX"] = "wx"
50 backend2gui["CocoaAgg"] = "osx"
50 backend2gui["CocoaAgg"] = "osx"
51 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
51 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
52 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
52 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
53 # and Qt6.
53 # and Qt6.
54 backend2gui["QtAgg"] = "qt"
54 backend2gui["QtAgg"] = "qt"
55 backend2gui["Qt4Agg"] = "qt"
55 backend2gui["Qt4Agg"] = "qt"
56 backend2gui["Qt5Agg"] = "qt"
56 backend2gui["Qt5Agg"] = "qt"
57
57
58 # And some backends that don't need GUI integration
58 # And some backends that don't need GUI integration
59 del backend2gui["nbAgg"]
59 del backend2gui["nbAgg"]
60 del backend2gui["agg"]
60 del backend2gui["agg"]
61 del backend2gui["svg"]
61 del backend2gui["svg"]
62 del backend2gui["pdf"]
62 del backend2gui["pdf"]
63 del backend2gui["ps"]
63 del backend2gui["ps"]
64 del backend2gui["module://matplotlib_inline.backend_inline"]
64 del backend2gui["module://matplotlib_inline.backend_inline"]
65 del backend2gui["module://ipympl.backend_nbagg"]
65 del backend2gui["module://ipympl.backend_nbagg"]
66
66
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # Matplotlib utilities
68 # Matplotlib utilities
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70
70
71
71
72 def getfigs(*fig_nums):
72 def getfigs(*fig_nums):
73 """Get a list of matplotlib figures by figure numbers.
73 """Get a list of matplotlib figures by figure numbers.
74
74
75 If no arguments are given, all available figures are returned. If the
75 If no arguments are given, all available figures are returned. If the
76 argument list contains references to invalid figures, a warning is printed
76 argument list contains references to invalid figures, a warning is printed
77 but the function continues pasting further figures.
77 but the function continues pasting further figures.
78
78
79 Parameters
79 Parameters
80 ----------
80 ----------
81 figs : tuple
81 figs : tuple
82 A tuple of ints giving the figure numbers of the figures to return.
82 A tuple of ints giving the figure numbers of the figures to return.
83 """
83 """
84 from matplotlib._pylab_helpers import Gcf
84 from matplotlib._pylab_helpers import Gcf
85 if not fig_nums:
85 if not fig_nums:
86 fig_managers = Gcf.get_all_fig_managers()
86 fig_managers = Gcf.get_all_fig_managers()
87 return [fm.canvas.figure for fm in fig_managers]
87 return [fm.canvas.figure for fm in fig_managers]
88 else:
88 else:
89 figs = []
89 figs = []
90 for num in fig_nums:
90 for num in fig_nums:
91 f = Gcf.figs.get(num)
91 f = Gcf.figs.get(num)
92 if f is None:
92 if f is None:
93 print('Warning: figure %s not available.' % num)
93 print('Warning: figure %s not available.' % num)
94 else:
94 else:
95 figs.append(f.canvas.figure)
95 figs.append(f.canvas.figure)
96 return figs
96 return figs
97
97
98
98
99 def figsize(sizex, sizey):
99 def figsize(sizex, sizey):
100 """Set the default figure size to be [sizex, sizey].
100 """Set the default figure size to be [sizex, sizey].
101
101
102 This is just an easy to remember, convenience wrapper that sets::
102 This is just an easy to remember, convenience wrapper that sets::
103
103
104 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
104 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
105 """
105 """
106 import matplotlib
106 import matplotlib
107 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
107 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
108
108
109
109
110 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
110 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
111 """Print a figure to an image, and return the resulting file data
111 """Print a figure to an image, and return the resulting file data
112
112
113 Returned data will be bytes unless ``fmt='svg'``,
113 Returned data will be bytes unless ``fmt='svg'``,
114 in which case it will be unicode.
114 in which case it will be unicode.
115
115
116 Any keyword args are passed to fig.canvas.print_figure,
116 Any keyword args are passed to fig.canvas.print_figure,
117 such as ``quality`` or ``bbox_inches``.
117 such as ``quality`` or ``bbox_inches``.
118
118
119 If `base64` is True, return base64-encoded str instead of raw bytes
119 If `base64` is True, return base64-encoded str instead of raw bytes
120 for binary-encoded image formats
120 for binary-encoded image formats
121
121
122 .. versionadded:: 7.29
122 .. versionadded:: 7.29
123 base64 argument
123 base64 argument
124 """
124 """
125 # When there's an empty figure, we shouldn't return anything, otherwise we
125 # When there's an empty figure, we shouldn't return anything, otherwise we
126 # get big blank areas in the qt console.
126 # get big blank areas in the qt console.
127 if not fig.axes and not fig.lines:
127 if not fig.axes and not fig.lines:
128 return
128 return
129
129
130 dpi = fig.dpi
130 dpi = fig.dpi
131 if fmt == 'retina':
131 if fmt == 'retina':
132 dpi = dpi * 2
132 dpi = dpi * 2
133 fmt = 'png'
133 fmt = 'png'
134
134
135 # build keyword args
135 # build keyword args
136 kw = {
136 kw = {
137 "format":fmt,
137 "format":fmt,
138 "facecolor":fig.get_facecolor(),
138 "facecolor":fig.get_facecolor(),
139 "edgecolor":fig.get_edgecolor(),
139 "edgecolor":fig.get_edgecolor(),
140 "dpi":dpi,
140 "dpi":dpi,
141 "bbox_inches":bbox_inches,
141 "bbox_inches":bbox_inches,
142 }
142 }
143 # **kwargs get higher priority
143 # **kwargs get higher priority
144 kw.update(kwargs)
144 kw.update(kwargs)
145
145
146 bytes_io = BytesIO()
146 bytes_io = BytesIO()
147 if fig.canvas is None:
147 if fig.canvas is None:
148 from matplotlib.backend_bases import FigureCanvasBase
148 from matplotlib.backend_bases import FigureCanvasBase
149 FigureCanvasBase(fig)
149 FigureCanvasBase(fig)
150
150
151 fig.canvas.print_figure(bytes_io, **kw)
151 fig.canvas.print_figure(bytes_io, **kw)
152 data = bytes_io.getvalue()
152 data = bytes_io.getvalue()
153 if fmt == 'svg':
153 if fmt == 'svg':
154 data = data.decode('utf-8')
154 data = data.decode('utf-8')
155 elif base64:
155 elif base64:
156 data = b2a_base64(data).decode("ascii")
156 data = b2a_base64(data).decode("ascii")
157 return data
157 return data
158
158
159 def retina_figure(fig, base64=False, **kwargs):
159 def retina_figure(fig, base64=False, **kwargs):
160 """format a figure as a pixel-doubled (retina) PNG
160 """format a figure as a pixel-doubled (retina) PNG
161
161
162 If `base64` is True, return base64-encoded str instead of raw bytes
162 If `base64` is True, return base64-encoded str instead of raw bytes
163 for binary-encoded image formats
163 for binary-encoded image formats
164
164
165 .. versionadded:: 7.29
165 .. versionadded:: 7.29
166 base64 argument
166 base64 argument
167 """
167 """
168 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
168 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
169 # Make sure that retina_figure acts just like print_figure and returns
169 # Make sure that retina_figure acts just like print_figure and returns
170 # None when the figure is empty.
170 # None when the figure is empty.
171 if pngdata is None:
171 if pngdata is None:
172 return
172 return
173 w, h = _pngxy(pngdata)
173 w, h = _pngxy(pngdata)
174 metadata = {"width": w//2, "height":h//2}
174 metadata = {"width": w//2, "height":h//2}
175 if base64:
175 if base64:
176 pngdata = b2a_base64(pngdata).decode("ascii")
176 pngdata = b2a_base64(pngdata).decode("ascii")
177 return pngdata, metadata
177 return pngdata, metadata
178
178
179
179
180 # We need a little factory function here to create the closure where
180 # We need a little factory function here to create the closure where
181 # safe_execfile can live.
181 # safe_execfile can live.
182 def mpl_runner(safe_execfile):
182 def mpl_runner(safe_execfile):
183 """Factory to return a matplotlib-enabled runner for %run.
183 """Factory to return a matplotlib-enabled runner for %run.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 safe_execfile : function
187 safe_execfile : function
188 This must be a function with the same interface as the
188 This must be a function with the same interface as the
189 :meth:`safe_execfile` method of IPython.
189 :meth:`safe_execfile` method of IPython.
190
190
191 Returns
191 Returns
192 -------
192 -------
193 A function suitable for use as the ``runner`` argument of the %run magic
193 A function suitable for use as the ``runner`` argument of the %run magic
194 function.
194 function.
195 """
195 """
196
196
197 def mpl_execfile(fname,*where,**kw):
197 def mpl_execfile(fname,*where,**kw):
198 """matplotlib-aware wrapper around safe_execfile.
198 """matplotlib-aware wrapper around safe_execfile.
199
199
200 Its interface is identical to that of the :func:`execfile` builtin.
200 Its interface is identical to that of the :func:`execfile` builtin.
201
201
202 This is ultimately a call to execfile(), but wrapped in safeties to
202 This is ultimately a call to execfile(), but wrapped in safeties to
203 properly handle interactive rendering."""
203 properly handle interactive rendering."""
204
204
205 import matplotlib
205 import matplotlib
206 import matplotlib.pyplot as plt
206 import matplotlib.pyplot as plt
207
207
208 #print '*** Matplotlib runner ***' # dbg
208 #print '*** Matplotlib runner ***' # dbg
209 # turn off rendering until end of script
209 # turn off rendering until end of script
210 is_interactive = matplotlib.rcParams['interactive']
210 is_interactive = matplotlib.rcParams['interactive']
211 matplotlib.interactive(False)
211 matplotlib.interactive(False)
212 safe_execfile(fname,*where,**kw)
212 safe_execfile(fname,*where,**kw)
213 matplotlib.interactive(is_interactive)
213 matplotlib.interactive(is_interactive)
214 # make rendering call now, if the user tried to do it
214 # make rendering call now, if the user tried to do it
215 if plt.draw_if_interactive.called:
215 if plt.draw_if_interactive.called:
216 plt.draw()
216 plt.draw()
217 plt.draw_if_interactive.called = False
217 plt.draw_if_interactive.called = False
218
218
219 # re-draw everything that is stale
219 # re-draw everything that is stale
220 try:
220 try:
221 da = plt.draw_all
221 da = plt.draw_all
222 except AttributeError:
222 except AttributeError:
223 pass
223 pass
224 else:
224 else:
225 da()
225 da()
226
226
227 return mpl_execfile
227 return mpl_execfile
228
228
229
229
230 def _reshow_nbagg_figure(fig):
230 def _reshow_nbagg_figure(fig):
231 """reshow an nbagg figure"""
231 """reshow an nbagg figure"""
232 try:
232 try:
233 reshow = fig.canvas.manager.reshow
233 reshow = fig.canvas.manager.reshow
234 except AttributeError as e:
234 except AttributeError as e:
235 raise NotImplementedError() from e
235 raise NotImplementedError() from e
236 else:
236 else:
237 reshow()
237 reshow()
238
238
239
239
240 def select_figure_formats(shell, formats, **kwargs):
240 def select_figure_formats(shell, formats, **kwargs):
241 """Select figure formats for the inline backend.
241 """Select figure formats for the inline backend.
242
242
243 Parameters
243 Parameters
244 ==========
244 ----------
245 shell : InteractiveShell
245 shell : InteractiveShell
246 The main IPython instance.
246 The main IPython instance.
247 formats : str or set
247 formats : str or set
248 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
248 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
249 **kwargs : any
249 **kwargs : any
250 Extra keyword arguments to be passed to fig.canvas.print_figure.
250 Extra keyword arguments to be passed to fig.canvas.print_figure.
251 """
251 """
252 import matplotlib
252 import matplotlib
253 from matplotlib.figure import Figure
253 from matplotlib.figure import Figure
254
254
255 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
255 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
256 png_formatter = shell.display_formatter.formatters['image/png']
256 png_formatter = shell.display_formatter.formatters['image/png']
257 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
257 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
258 pdf_formatter = shell.display_formatter.formatters['application/pdf']
258 pdf_formatter = shell.display_formatter.formatters['application/pdf']
259
259
260 if isinstance(formats, str):
260 if isinstance(formats, str):
261 formats = {formats}
261 formats = {formats}
262 # cast in case of list / tuple
262 # cast in case of list / tuple
263 formats = set(formats)
263 formats = set(formats)
264
264
265 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
265 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
266 mplbackend = matplotlib.get_backend().lower()
266 mplbackend = matplotlib.get_backend().lower()
267 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
267 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
268 formatter = shell.display_formatter.ipython_display_formatter
268 formatter = shell.display_formatter.ipython_display_formatter
269 formatter.for_type(Figure, _reshow_nbagg_figure)
269 formatter.for_type(Figure, _reshow_nbagg_figure)
270
270
271 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
271 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
272 bad = formats.difference(supported)
272 bad = formats.difference(supported)
273 if bad:
273 if bad:
274 bs = "%s" % ','.join([repr(f) for f in bad])
274 bs = "%s" % ','.join([repr(f) for f in bad])
275 gs = "%s" % ','.join([repr(f) for f in supported])
275 gs = "%s" % ','.join([repr(f) for f in supported])
276 raise ValueError("supported formats are: %s not %s" % (gs, bs))
276 raise ValueError("supported formats are: %s not %s" % (gs, bs))
277
277
278 if "png" in formats:
278 if "png" in formats:
279 png_formatter.for_type(
279 png_formatter.for_type(
280 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
280 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
281 )
281 )
282 if "retina" in formats or "png2x" in formats:
282 if "retina" in formats or "png2x" in formats:
283 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
283 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
284 if "jpg" in formats or "jpeg" in formats:
284 if "jpg" in formats or "jpeg" in formats:
285 jpg_formatter.for_type(
285 jpg_formatter.for_type(
286 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
286 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
287 )
287 )
288 if "svg" in formats:
288 if "svg" in formats:
289 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
289 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
290 if "pdf" in formats:
290 if "pdf" in formats:
291 pdf_formatter.for_type(
291 pdf_formatter.for_type(
292 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
292 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
293 )
293 )
294
294
295 #-----------------------------------------------------------------------------
295 #-----------------------------------------------------------------------------
296 # Code for initializing matplotlib and importing pylab
296 # Code for initializing matplotlib and importing pylab
297 #-----------------------------------------------------------------------------
297 #-----------------------------------------------------------------------------
298
298
299
299
300 def find_gui_and_backend(gui=None, gui_select=None):
300 def find_gui_and_backend(gui=None, gui_select=None):
301 """Given a gui string return the gui and mpl backend.
301 """Given a gui string return the gui and mpl backend.
302
302
303 Parameters
303 Parameters
304 ----------
304 ----------
305 gui : str
305 gui : str
306 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
306 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
307 gui_select : str
307 gui_select : str
308 Can be one of ('tk','gtk','wx','qt','qt4','inline').
308 Can be one of ('tk','gtk','wx','qt','qt4','inline').
309 This is any gui already selected by the shell.
309 This is any gui already selected by the shell.
310
310
311 Returns
311 Returns
312 -------
312 -------
313 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
313 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
314 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
314 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
315 """
315 """
316
316
317 import matplotlib
317 import matplotlib
318
318
319 if gui and gui != 'auto':
319 if gui and gui != 'auto':
320 # select backend based on requested gui
320 # select backend based on requested gui
321 backend = backends[gui]
321 backend = backends[gui]
322 if gui == 'agg':
322 if gui == 'agg':
323 gui = None
323 gui = None
324 else:
324 else:
325 # We need to read the backend from the original data structure, *not*
325 # We need to read the backend from the original data structure, *not*
326 # from mpl.rcParams, since a prior invocation of %matplotlib may have
326 # from mpl.rcParams, since a prior invocation of %matplotlib may have
327 # overwritten that.
327 # overwritten that.
328 # WARNING: this assumes matplotlib 1.1 or newer!!
328 # WARNING: this assumes matplotlib 1.1 or newer!!
329 backend = matplotlib.rcParamsOrig['backend']
329 backend = matplotlib.rcParamsOrig['backend']
330 # In this case, we need to find what the appropriate gui selection call
330 # In this case, we need to find what the appropriate gui selection call
331 # should be for IPython, so we can activate inputhook accordingly
331 # should be for IPython, so we can activate inputhook accordingly
332 gui = backend2gui.get(backend, None)
332 gui = backend2gui.get(backend, None)
333
333
334 # If we have already had a gui active, we need it and inline are the
334 # If we have already had a gui active, we need it and inline are the
335 # ones allowed.
335 # ones allowed.
336 if gui_select and gui != gui_select:
336 if gui_select and gui != gui_select:
337 gui = gui_select
337 gui = gui_select
338 backend = backends[gui]
338 backend = backends[gui]
339
339
340 return gui, backend
340 return gui, backend
341
341
342
342
343 def activate_matplotlib(backend):
343 def activate_matplotlib(backend):
344 """Activate the given backend and set interactive to True."""
344 """Activate the given backend and set interactive to True."""
345
345
346 import matplotlib
346 import matplotlib
347 matplotlib.interactive(True)
347 matplotlib.interactive(True)
348
348
349 # Matplotlib had a bug where even switch_backend could not force
349 # Matplotlib had a bug where even switch_backend could not force
350 # the rcParam to update. This needs to be set *before* the module
350 # the rcParam to update. This needs to be set *before* the module
351 # magic of switch_backend().
351 # magic of switch_backend().
352 matplotlib.rcParams['backend'] = backend
352 matplotlib.rcParams['backend'] = backend
353
353
354 # Due to circular imports, pyplot may be only partially initialised
354 # Due to circular imports, pyplot may be only partially initialised
355 # when this function runs.
355 # when this function runs.
356 # So avoid needing matplotlib attribute-lookup to access pyplot.
356 # So avoid needing matplotlib attribute-lookup to access pyplot.
357 from matplotlib import pyplot as plt
357 from matplotlib import pyplot as plt
358
358
359 plt.switch_backend(backend)
359 plt.switch_backend(backend)
360
360
361 plt.show._needmain = False
361 plt.show._needmain = False
362 # We need to detect at runtime whether show() is called by the user.
362 # We need to detect at runtime whether show() is called by the user.
363 # For this, we wrap it into a decorator which adds a 'called' flag.
363 # For this, we wrap it into a decorator which adds a 'called' flag.
364 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
364 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
365
365
366
366
367 def import_pylab(user_ns, import_all=True):
367 def import_pylab(user_ns, import_all=True):
368 """Populate the namespace with pylab-related values.
368 """Populate the namespace with pylab-related values.
369
369
370 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
370 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
371
371
372 Also imports a few names from IPython (figsize, display, getfigs)
372 Also imports a few names from IPython (figsize, display, getfigs)
373
373
374 """
374 """
375
375
376 # Import numpy as np/pyplot as plt are conventions we're trying to
376 # Import numpy as np/pyplot as plt are conventions we're trying to
377 # somewhat standardize on. Making them available to users by default
377 # somewhat standardize on. Making them available to users by default
378 # will greatly help this.
378 # will greatly help this.
379 s = ("import numpy\n"
379 s = ("import numpy\n"
380 "import matplotlib\n"
380 "import matplotlib\n"
381 "from matplotlib import pylab, mlab, pyplot\n"
381 "from matplotlib import pylab, mlab, pyplot\n"
382 "np = numpy\n"
382 "np = numpy\n"
383 "plt = pyplot\n"
383 "plt = pyplot\n"
384 )
384 )
385 exec(s, user_ns)
385 exec(s, user_ns)
386
386
387 if import_all:
387 if import_all:
388 s = ("from matplotlib.pylab import *\n"
388 s = ("from matplotlib.pylab import *\n"
389 "from numpy import *\n")
389 "from numpy import *\n")
390 exec(s, user_ns)
390 exec(s, user_ns)
391
391
392 # IPython symbols to add
392 # IPython symbols to add
393 user_ns['figsize'] = figsize
393 user_ns['figsize'] = figsize
394 from IPython.display import display
394 from IPython.display import display
395 # Add display and getfigs to the user's namespace
395 # Add display and getfigs to the user's namespace
396 user_ns['display'] = display
396 user_ns['display'] = display
397 user_ns['getfigs'] = getfigs
397 user_ns['getfigs'] = getfigs
398
398
399
399
400 def configure_inline_support(shell, backend):
400 def configure_inline_support(shell, backend):
401 """
401 """
402 .. deprecated:: 7.23
402 .. deprecated:: 7.23
403
403
404 use `matplotlib_inline.backend_inline.configure_inline_support()`
404 use `matplotlib_inline.backend_inline.configure_inline_support()`
405
405
406 Configure an IPython shell object for matplotlib use.
406 Configure an IPython shell object for matplotlib use.
407
407
408 Parameters
408 Parameters
409 ----------
409 ----------
410 shell : InteractiveShell instance
410 shell : InteractiveShell instance
411
412 backend : matplotlib backend
411 backend : matplotlib backend
413 """
412 """
414 warnings.warn(
413 warnings.warn(
415 "`configure_inline_support` is deprecated since IPython 7.23, directly "
414 "`configure_inline_support` is deprecated since IPython 7.23, directly "
416 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
415 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
417 DeprecationWarning,
416 DeprecationWarning,
418 stacklevel=2,
417 stacklevel=2,
419 )
418 )
420
419
421 from matplotlib_inline.backend_inline import (
420 from matplotlib_inline.backend_inline import (
422 configure_inline_support as configure_inline_support_orig,
421 configure_inline_support as configure_inline_support_orig,
423 )
422 )
424
423
425 configure_inline_support_orig(shell, backend)
424 configure_inline_support_orig(shell, backend)
@@ -1,1132 +1,1132 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencrypted
44 potentially leak sensitive information like access keys, or unencrypted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 - Neutral: a neutral color scheme that should be readable on both light and
70 - Neutral: a neutral color scheme that should be readable on both light and
71 dark background
71 dark background
72
72
73 You can implement other color schemes easily, the syntax is fairly
73 You can implement other color schemes easily, the syntax is fairly
74 self-explanatory. Please send back new schemes you develop to the author for
74 self-explanatory. Please send back new schemes you develop to the author for
75 possible inclusion in future releases.
75 possible inclusion in future releases.
76
76
77 Inheritance diagram:
77 Inheritance diagram:
78
78
79 .. inheritance-diagram:: IPython.core.ultratb
79 .. inheritance-diagram:: IPython.core.ultratb
80 :parts: 3
80 :parts: 3
81 """
81 """
82
82
83 #*****************************************************************************
83 #*****************************************************************************
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 #
86 #
87 # Distributed under the terms of the BSD License. The full license is in
87 # Distributed under the terms of the BSD License. The full license is in
88 # the file COPYING, distributed as part of this software.
88 # the file COPYING, distributed as part of this software.
89 #*****************************************************************************
89 #*****************************************************************************
90
90
91
91
92 import inspect
92 import inspect
93 import linecache
93 import linecache
94 import pydoc
94 import pydoc
95 import sys
95 import sys
96 import time
96 import time
97 import traceback
97 import traceback
98
98
99 import stack_data
99 import stack_data
100 from pygments.formatters.terminal256 import Terminal256Formatter
100 from pygments.formatters.terminal256 import Terminal256Formatter
101 from pygments.styles import get_style_by_name
101 from pygments.styles import get_style_by_name
102
102
103 # IPython's own modules
103 # IPython's own modules
104 from IPython import get_ipython
104 from IPython import get_ipython
105 from IPython.core import debugger
105 from IPython.core import debugger
106 from IPython.core.display_trap import DisplayTrap
106 from IPython.core.display_trap import DisplayTrap
107 from IPython.core.excolors import exception_colors
107 from IPython.core.excolors import exception_colors
108 from IPython.utils import path as util_path
108 from IPython.utils import path as util_path
109 from IPython.utils import py3compat
109 from IPython.utils import py3compat
110 from IPython.utils.terminal import get_terminal_size
110 from IPython.utils.terminal import get_terminal_size
111
111
112 import IPython.utils.colorable as colorable
112 import IPython.utils.colorable as colorable
113
113
114 # Globals
114 # Globals
115 # amount of space to put line numbers before verbose tracebacks
115 # amount of space to put line numbers before verbose tracebacks
116 INDENT_SIZE = 8
116 INDENT_SIZE = 8
117
117
118 # Default color scheme. This is used, for example, by the traceback
118 # Default color scheme. This is used, for example, by the traceback
119 # formatter. When running in an actual IPython instance, the user's rc.colors
119 # formatter. When running in an actual IPython instance, the user's rc.colors
120 # value is used, but having a module global makes this functionality available
120 # value is used, but having a module global makes this functionality available
121 # to users of ultratb who are NOT running inside ipython.
121 # to users of ultratb who are NOT running inside ipython.
122 DEFAULT_SCHEME = 'NoColor'
122 DEFAULT_SCHEME = 'NoColor'
123
123
124 # ---------------------------------------------------------------------------
124 # ---------------------------------------------------------------------------
125 # Code begins
125 # Code begins
126
126
127 # Helper function -- largely belongs to VerboseTB, but we need the same
127 # Helper function -- largely belongs to VerboseTB, but we need the same
128 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
128 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
129 # can be recognized properly by ipython.el's py-traceback-line-re
129 # can be recognized properly by ipython.el's py-traceback-line-re
130 # (SyntaxErrors have to be treated specially because they have no traceback)
130 # (SyntaxErrors have to be treated specially because they have no traceback)
131
131
132
132
133 def _format_traceback_lines(lines, Colors, has_colors, lvals):
133 def _format_traceback_lines(lines, Colors, has_colors, lvals):
134 """
134 """
135 Format tracebacks lines with pointing arrow, leading numbers...
135 Format tracebacks lines with pointing arrow, leading numbers...
136
136
137 Parameters
137 Parameters
138 ----------
138 ----------
139 lines : list[Line]
139 lines : list[Line]
140 Colors
140 Colors
141 ColorScheme used.
141 ColorScheme used.
142 lvals : str
142 lvals : str
143 Values of local variables, already colored, to inject just after the error line.
143 Values of local variables, already colored, to inject just after the error line.
144 """
144 """
145 numbers_width = INDENT_SIZE - 1
145 numbers_width = INDENT_SIZE - 1
146 res = []
146 res = []
147
147
148 for stack_line in lines:
148 for stack_line in lines:
149 if stack_line is stack_data.LINE_GAP:
149 if stack_line is stack_data.LINE_GAP:
150 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
150 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
151 continue
151 continue
152
152
153 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
153 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
154 lineno = stack_line.lineno
154 lineno = stack_line.lineno
155 if stack_line.is_current:
155 if stack_line.is_current:
156 # This is the line with the error
156 # This is the line with the error
157 pad = numbers_width - len(str(lineno))
157 pad = numbers_width - len(str(lineno))
158 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
158 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
159 start_color = Colors.linenoEm
159 start_color = Colors.linenoEm
160 else:
160 else:
161 num = '%*s' % (numbers_width, lineno)
161 num = '%*s' % (numbers_width, lineno)
162 start_color = Colors.lineno
162 start_color = Colors.lineno
163
163
164 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
164 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
165
165
166 res.append(line)
166 res.append(line)
167 if lvals and stack_line.is_current:
167 if lvals and stack_line.is_current:
168 res.append(lvals + '\n')
168 res.append(lvals + '\n')
169 return res
169 return res
170
170
171
171
172 def _format_filename(file, ColorFilename, ColorNormal):
172 def _format_filename(file, ColorFilename, ColorNormal):
173 """
173 """
174 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module.
174 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module.
175
175
176 Parameters
176 Parameters
177 ----------
177 ----------
178 file : str
178 file : str
179 ColorFilename
179 ColorFilename
180 ColorScheme's filename coloring to be used.
180 ColorScheme's filename coloring to be used.
181 ColorNormal
181 ColorNormal
182 ColorScheme's normal coloring to be used.
182 ColorScheme's normal coloring to be used.
183 """
183 """
184 ipinst = get_ipython()
184 ipinst = get_ipython()
185
185
186 if ipinst is not None and file in ipinst.compile._filename_map:
186 if ipinst is not None and file in ipinst.compile._filename_map:
187 file = "[%s]" % ipinst.compile._filename_map[file]
187 file = "[%s]" % ipinst.compile._filename_map[file]
188 tpl_link = "In %s%%s%s" % (ColorFilename, ColorNormal)
188 tpl_link = "In %s%%s%s" % (ColorFilename, ColorNormal)
189 else:
189 else:
190 file = util_path.compress_user(
190 file = util_path.compress_user(
191 py3compat.cast_unicode(file, util_path.fs_encoding)
191 py3compat.cast_unicode(file, util_path.fs_encoding)
192 )
192 )
193 tpl_link = "File %s%%s%s" % (ColorFilename, ColorNormal)
193 tpl_link = "File %s%%s%s" % (ColorFilename, ColorNormal)
194
194
195 return tpl_link % file
195 return tpl_link % file
196
196
197 #---------------------------------------------------------------------------
197 #---------------------------------------------------------------------------
198 # Module classes
198 # Module classes
199 class TBTools(colorable.Colorable):
199 class TBTools(colorable.Colorable):
200 """Basic tools used by all traceback printer classes."""
200 """Basic tools used by all traceback printer classes."""
201
201
202 # Number of frames to skip when reporting tracebacks
202 # Number of frames to skip when reporting tracebacks
203 tb_offset = 0
203 tb_offset = 0
204
204
205 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
205 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
206 # Whether to call the interactive pdb debugger after printing
206 # Whether to call the interactive pdb debugger after printing
207 # tracebacks or not
207 # tracebacks or not
208 super(TBTools, self).__init__(parent=parent, config=config)
208 super(TBTools, self).__init__(parent=parent, config=config)
209 self.call_pdb = call_pdb
209 self.call_pdb = call_pdb
210
210
211 # Output stream to write to. Note that we store the original value in
211 # Output stream to write to. Note that we store the original value in
212 # a private attribute and then make the public ostream a property, so
212 # a private attribute and then make the public ostream a property, so
213 # that we can delay accessing sys.stdout until runtime. The way
213 # that we can delay accessing sys.stdout until runtime. The way
214 # things are written now, the sys.stdout object is dynamically managed
214 # things are written now, the sys.stdout object is dynamically managed
215 # so a reference to it should NEVER be stored statically. This
215 # so a reference to it should NEVER be stored statically. This
216 # property approach confines this detail to a single location, and all
216 # property approach confines this detail to a single location, and all
217 # subclasses can simply access self.ostream for writing.
217 # subclasses can simply access self.ostream for writing.
218 self._ostream = ostream
218 self._ostream = ostream
219
219
220 # Create color table
220 # Create color table
221 self.color_scheme_table = exception_colors()
221 self.color_scheme_table = exception_colors()
222
222
223 self.set_colors(color_scheme)
223 self.set_colors(color_scheme)
224 self.old_scheme = color_scheme # save initial value for toggles
224 self.old_scheme = color_scheme # save initial value for toggles
225
225
226 if call_pdb:
226 if call_pdb:
227 self.pdb = debugger.Pdb()
227 self.pdb = debugger.Pdb()
228 else:
228 else:
229 self.pdb = None
229 self.pdb = None
230
230
231 def _get_ostream(self):
231 def _get_ostream(self):
232 """Output stream that exceptions are written to.
232 """Output stream that exceptions are written to.
233
233
234 Valid values are:
234 Valid values are:
235
235
236 - None: the default, which means that IPython will dynamically resolve
236 - None: the default, which means that IPython will dynamically resolve
237 to sys.stdout. This ensures compatibility with most tools, including
237 to sys.stdout. This ensures compatibility with most tools, including
238 Windows (where plain stdout doesn't recognize ANSI escapes).
238 Windows (where plain stdout doesn't recognize ANSI escapes).
239
239
240 - Any object with 'write' and 'flush' attributes.
240 - Any object with 'write' and 'flush' attributes.
241 """
241 """
242 return sys.stdout if self._ostream is None else self._ostream
242 return sys.stdout if self._ostream is None else self._ostream
243
243
244 def _set_ostream(self, val):
244 def _set_ostream(self, val):
245 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
245 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
246 self._ostream = val
246 self._ostream = val
247
247
248 ostream = property(_get_ostream, _set_ostream)
248 ostream = property(_get_ostream, _set_ostream)
249
249
250 def get_parts_of_chained_exception(self, evalue):
250 def get_parts_of_chained_exception(self, evalue):
251 def get_chained_exception(exception_value):
251 def get_chained_exception(exception_value):
252 cause = getattr(exception_value, '__cause__', None)
252 cause = getattr(exception_value, '__cause__', None)
253 if cause:
253 if cause:
254 return cause
254 return cause
255 if getattr(exception_value, '__suppress_context__', False):
255 if getattr(exception_value, '__suppress_context__', False):
256 return None
256 return None
257 return getattr(exception_value, '__context__', None)
257 return getattr(exception_value, '__context__', None)
258
258
259 chained_evalue = get_chained_exception(evalue)
259 chained_evalue = get_chained_exception(evalue)
260
260
261 if chained_evalue:
261 if chained_evalue:
262 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
262 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
263
263
264 def prepare_chained_exception_message(self, cause):
264 def prepare_chained_exception_message(self, cause):
265 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
265 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
266 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
266 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
267
267
268 if cause:
268 if cause:
269 message = [[direct_cause]]
269 message = [[direct_cause]]
270 else:
270 else:
271 message = [[exception_during_handling]]
271 message = [[exception_during_handling]]
272 return message
272 return message
273
273
274 @property
274 @property
275 def has_colors(self):
275 def has_colors(self):
276 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
276 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
277
277
278 def set_colors(self, *args, **kw):
278 def set_colors(self, *args, **kw):
279 """Shorthand access to the color table scheme selector method."""
279 """Shorthand access to the color table scheme selector method."""
280
280
281 # Set own color table
281 # Set own color table
282 self.color_scheme_table.set_active_scheme(*args, **kw)
282 self.color_scheme_table.set_active_scheme(*args, **kw)
283 # for convenience, set Colors to the active scheme
283 # for convenience, set Colors to the active scheme
284 self.Colors = self.color_scheme_table.active_colors
284 self.Colors = self.color_scheme_table.active_colors
285 # Also set colors of debugger
285 # Also set colors of debugger
286 if hasattr(self, 'pdb') and self.pdb is not None:
286 if hasattr(self, 'pdb') and self.pdb is not None:
287 self.pdb.set_colors(*args, **kw)
287 self.pdb.set_colors(*args, **kw)
288
288
289 def color_toggle(self):
289 def color_toggle(self):
290 """Toggle between the currently active color scheme and NoColor."""
290 """Toggle between the currently active color scheme and NoColor."""
291
291
292 if self.color_scheme_table.active_scheme_name == 'NoColor':
292 if self.color_scheme_table.active_scheme_name == 'NoColor':
293 self.color_scheme_table.set_active_scheme(self.old_scheme)
293 self.color_scheme_table.set_active_scheme(self.old_scheme)
294 self.Colors = self.color_scheme_table.active_colors
294 self.Colors = self.color_scheme_table.active_colors
295 else:
295 else:
296 self.old_scheme = self.color_scheme_table.active_scheme_name
296 self.old_scheme = self.color_scheme_table.active_scheme_name
297 self.color_scheme_table.set_active_scheme('NoColor')
297 self.color_scheme_table.set_active_scheme('NoColor')
298 self.Colors = self.color_scheme_table.active_colors
298 self.Colors = self.color_scheme_table.active_colors
299
299
300 def stb2text(self, stb):
300 def stb2text(self, stb):
301 """Convert a structured traceback (a list) to a string."""
301 """Convert a structured traceback (a list) to a string."""
302 return '\n'.join(stb)
302 return '\n'.join(stb)
303
303
304 def text(self, etype, value, tb, tb_offset=None, context=5):
304 def text(self, etype, value, tb, tb_offset=None, context=5):
305 """Return formatted traceback.
305 """Return formatted traceback.
306
306
307 Subclasses may override this if they add extra arguments.
307 Subclasses may override this if they add extra arguments.
308 """
308 """
309 tb_list = self.structured_traceback(etype, value, tb,
309 tb_list = self.structured_traceback(etype, value, tb,
310 tb_offset, context)
310 tb_offset, context)
311 return self.stb2text(tb_list)
311 return self.stb2text(tb_list)
312
312
313 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
313 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
314 context=5, mode=None):
314 context=5, mode=None):
315 """Return a list of traceback frames.
315 """Return a list of traceback frames.
316
316
317 Must be implemented by each class.
317 Must be implemented by each class.
318 """
318 """
319 raise NotImplementedError()
319 raise NotImplementedError()
320
320
321
321
322 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
323 class ListTB(TBTools):
323 class ListTB(TBTools):
324 """Print traceback information from a traceback list, with optional color.
324 """Print traceback information from a traceback list, with optional color.
325
325
326 Calling requires 3 arguments: (etype, evalue, elist)
326 Calling requires 3 arguments: (etype, evalue, elist)
327 as would be obtained by::
327 as would be obtained by::
328
328
329 etype, evalue, tb = sys.exc_info()
329 etype, evalue, tb = sys.exc_info()
330 if tb:
330 if tb:
331 elist = traceback.extract_tb(tb)
331 elist = traceback.extract_tb(tb)
332 else:
332 else:
333 elist = None
333 elist = None
334
334
335 It can thus be used by programs which need to process the traceback before
335 It can thus be used by programs which need to process the traceback before
336 printing (such as console replacements based on the code module from the
336 printing (such as console replacements based on the code module from the
337 standard library).
337 standard library).
338
338
339 Because they are meant to be called without a full traceback (only a
339 Because they are meant to be called without a full traceback (only a
340 list), instances of this class can't call the interactive pdb debugger."""
340 list), instances of this class can't call the interactive pdb debugger."""
341
341
342 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
342 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
343 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
343 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
344 ostream=ostream, parent=parent,config=config)
344 ostream=ostream, parent=parent,config=config)
345
345
346 def __call__(self, etype, value, elist):
346 def __call__(self, etype, value, elist):
347 self.ostream.flush()
347 self.ostream.flush()
348 self.ostream.write(self.text(etype, value, elist))
348 self.ostream.write(self.text(etype, value, elist))
349 self.ostream.write('\n')
349 self.ostream.write('\n')
350
350
351 def _extract_tb(self, tb):
351 def _extract_tb(self, tb):
352 if tb:
352 if tb:
353 return traceback.extract_tb(tb)
353 return traceback.extract_tb(tb)
354 else:
354 else:
355 return None
355 return None
356
356
357 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
357 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
358 context=5):
358 context=5):
359 """Return a color formatted string with the traceback info.
359 """Return a color formatted string with the traceback info.
360
360
361 Parameters
361 Parameters
362 ----------
362 ----------
363 etype : exception type
363 etype : exception type
364 Type of the exception raised.
364 Type of the exception raised.
365 evalue : object
365 evalue : object
366 Data stored in the exception
366 Data stored in the exception
367 etb : object
367 etb : object
368 If list: List of frames, see class docstring for details.
368 If list: List of frames, see class docstring for details.
369 If Traceback: Traceback of the exception.
369 If Traceback: Traceback of the exception.
370 tb_offset : int, optional
370 tb_offset : int, optional
371 Number of frames in the traceback to skip. If not given, the
371 Number of frames in the traceback to skip. If not given, the
372 instance evalue is used (set in constructor).
372 instance evalue is used (set in constructor).
373 context : int, optional
373 context : int, optional
374 Number of lines of context information to print.
374 Number of lines of context information to print.
375
375
376 Returns
376 Returns
377 -------
377 -------
378 String with formatted exception.
378 String with formatted exception.
379 """
379 """
380 # This is a workaround to get chained_exc_ids in recursive calls
380 # This is a workaround to get chained_exc_ids in recursive calls
381 # etb should not be a tuple if structured_traceback is not recursive
381 # etb should not be a tuple if structured_traceback is not recursive
382 if isinstance(etb, tuple):
382 if isinstance(etb, tuple):
383 etb, chained_exc_ids = etb
383 etb, chained_exc_ids = etb
384 else:
384 else:
385 chained_exc_ids = set()
385 chained_exc_ids = set()
386
386
387 if isinstance(etb, list):
387 if isinstance(etb, list):
388 elist = etb
388 elist = etb
389 elif etb is not None:
389 elif etb is not None:
390 elist = self._extract_tb(etb)
390 elist = self._extract_tb(etb)
391 else:
391 else:
392 elist = []
392 elist = []
393 tb_offset = self.tb_offset if tb_offset is None else tb_offset
393 tb_offset = self.tb_offset if tb_offset is None else tb_offset
394 Colors = self.Colors
394 Colors = self.Colors
395 out_list = []
395 out_list = []
396 if elist:
396 if elist:
397
397
398 if tb_offset and len(elist) > tb_offset:
398 if tb_offset and len(elist) > tb_offset:
399 elist = elist[tb_offset:]
399 elist = elist[tb_offset:]
400
400
401 out_list.append('Traceback %s(most recent call last)%s:' %
401 out_list.append('Traceback %s(most recent call last)%s:' %
402 (Colors.normalEm, Colors.Normal) + '\n')
402 (Colors.normalEm, Colors.Normal) + '\n')
403 out_list.extend(self._format_list(elist))
403 out_list.extend(self._format_list(elist))
404 # The exception info should be a single entry in the list.
404 # The exception info should be a single entry in the list.
405 lines = ''.join(self._format_exception_only(etype, evalue))
405 lines = ''.join(self._format_exception_only(etype, evalue))
406 out_list.append(lines)
406 out_list.append(lines)
407
407
408 exception = self.get_parts_of_chained_exception(evalue)
408 exception = self.get_parts_of_chained_exception(evalue)
409
409
410 if exception and not id(exception[1]) in chained_exc_ids:
410 if exception and not id(exception[1]) in chained_exc_ids:
411 chained_exception_message = self.prepare_chained_exception_message(
411 chained_exception_message = self.prepare_chained_exception_message(
412 evalue.__cause__)[0]
412 evalue.__cause__)[0]
413 etype, evalue, etb = exception
413 etype, evalue, etb = exception
414 # Trace exception to avoid infinite 'cause' loop
414 # Trace exception to avoid infinite 'cause' loop
415 chained_exc_ids.add(id(exception[1]))
415 chained_exc_ids.add(id(exception[1]))
416 chained_exceptions_tb_offset = 0
416 chained_exceptions_tb_offset = 0
417 out_list = (
417 out_list = (
418 self.structured_traceback(
418 self.structured_traceback(
419 etype, evalue, (etb, chained_exc_ids),
419 etype, evalue, (etb, chained_exc_ids),
420 chained_exceptions_tb_offset, context)
420 chained_exceptions_tb_offset, context)
421 + chained_exception_message
421 + chained_exception_message
422 + out_list)
422 + out_list)
423
423
424 return out_list
424 return out_list
425
425
426 def _format_list(self, extracted_list):
426 def _format_list(self, extracted_list):
427 """Format a list of traceback entry tuples for printing.
427 """Format a list of traceback entry tuples for printing.
428
428
429 Given a list of tuples as returned by extract_tb() or
429 Given a list of tuples as returned by extract_tb() or
430 extract_stack(), return a list of strings ready for printing.
430 extract_stack(), return a list of strings ready for printing.
431 Each string in the resulting list corresponds to the item with the
431 Each string in the resulting list corresponds to the item with the
432 same index in the argument list. Each string ends in a newline;
432 same index in the argument list. Each string ends in a newline;
433 the strings may contain internal newlines as well, for those items
433 the strings may contain internal newlines as well, for those items
434 whose source text line is not None.
434 whose source text line is not None.
435
435
436 Lifted almost verbatim from traceback.py
436 Lifted almost verbatim from traceback.py
437 """
437 """
438
438
439 Colors = self.Colors
439 Colors = self.Colors
440 list = []
440 list = []
441 for filename, lineno, name, line in extracted_list[:-1]:
441 for filename, lineno, name, line in extracted_list[:-1]:
442 item = " %s, line %s%d%s, in %s%s%s\n" % (
442 item = " %s, line %s%d%s, in %s%s%s\n" % (
443 _format_filename(filename, Colors.filename, Colors.Normal),
443 _format_filename(filename, Colors.filename, Colors.Normal),
444 Colors.lineno,
444 Colors.lineno,
445 lineno,
445 lineno,
446 Colors.Normal,
446 Colors.Normal,
447 Colors.name,
447 Colors.name,
448 name,
448 name,
449 Colors.Normal,
449 Colors.Normal,
450 )
450 )
451 if line:
451 if line:
452 item += ' %s\n' % line.strip()
452 item += ' %s\n' % line.strip()
453 list.append(item)
453 list.append(item)
454 # Emphasize the last entry
454 # Emphasize the last entry
455 filename, lineno, name, line = extracted_list[-1]
455 filename, lineno, name, line = extracted_list[-1]
456 item = "%s %s, line %s%d%s, in %s%s%s%s\n" % (
456 item = "%s %s, line %s%d%s, in %s%s%s%s\n" % (
457 Colors.normalEm,
457 Colors.normalEm,
458 _format_filename(filename, Colors.filenameEm, Colors.normalEm),
458 _format_filename(filename, Colors.filenameEm, Colors.normalEm),
459 Colors.linenoEm,
459 Colors.linenoEm,
460 lineno,
460 lineno,
461 Colors.normalEm,
461 Colors.normalEm,
462 Colors.nameEm,
462 Colors.nameEm,
463 name,
463 name,
464 Colors.normalEm,
464 Colors.normalEm,
465 Colors.Normal,
465 Colors.Normal,
466 )
466 )
467 if line:
467 if line:
468 item += '%s %s%s\n' % (Colors.line, line.strip(),
468 item += '%s %s%s\n' % (Colors.line, line.strip(),
469 Colors.Normal)
469 Colors.Normal)
470 list.append(item)
470 list.append(item)
471 return list
471 return list
472
472
473 def _format_exception_only(self, etype, value):
473 def _format_exception_only(self, etype, value):
474 """Format the exception part of a traceback.
474 """Format the exception part of a traceback.
475
475
476 The arguments are the exception type and value such as given by
476 The arguments are the exception type and value such as given by
477 sys.exc_info()[:2]. The return value is a list of strings, each ending
477 sys.exc_info()[:2]. The return value is a list of strings, each ending
478 in a newline. Normally, the list contains a single string; however,
478 in a newline. Normally, the list contains a single string; however,
479 for SyntaxError exceptions, it contains several lines that (when
479 for SyntaxError exceptions, it contains several lines that (when
480 printed) display detailed information about where the syntax error
480 printed) display detailed information about where the syntax error
481 occurred. The message indicating which exception occurred is the
481 occurred. The message indicating which exception occurred is the
482 always last string in the list.
482 always last string in the list.
483
483
484 Also lifted nearly verbatim from traceback.py
484 Also lifted nearly verbatim from traceback.py
485 """
485 """
486 have_filedata = False
486 have_filedata = False
487 Colors = self.Colors
487 Colors = self.Colors
488 list = []
488 list = []
489 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
489 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
490 if value is None:
490 if value is None:
491 # Not sure if this can still happen in Python 2.6 and above
491 # Not sure if this can still happen in Python 2.6 and above
492 list.append(stype + '\n')
492 list.append(stype + '\n')
493 else:
493 else:
494 if issubclass(etype, SyntaxError):
494 if issubclass(etype, SyntaxError):
495 have_filedata = True
495 have_filedata = True
496 if not value.filename: value.filename = "<string>"
496 if not value.filename: value.filename = "<string>"
497 if value.lineno:
497 if value.lineno:
498 lineno = value.lineno
498 lineno = value.lineno
499 textline = linecache.getline(value.filename, value.lineno)
499 textline = linecache.getline(value.filename, value.lineno)
500 else:
500 else:
501 lineno = "unknown"
501 lineno = "unknown"
502 textline = ""
502 textline = ""
503 list.append(
503 list.append(
504 "%s %s, line %s%s%s\n"
504 "%s %s, line %s%s%s\n"
505 % (
505 % (
506 Colors.normalEm,
506 Colors.normalEm,
507 _format_filename(
507 _format_filename(
508 value.filename, Colors.filenameEm, Colors.normalEm
508 value.filename, Colors.filenameEm, Colors.normalEm
509 ),
509 ),
510 Colors.linenoEm,
510 Colors.linenoEm,
511 lineno,
511 lineno,
512 Colors.Normal,
512 Colors.Normal,
513 )
513 )
514 )
514 )
515 if textline == "":
515 if textline == "":
516 textline = py3compat.cast_unicode(value.text, "utf-8")
516 textline = py3compat.cast_unicode(value.text, "utf-8")
517
517
518 if textline is not None:
518 if textline is not None:
519 i = 0
519 i = 0
520 while i < len(textline) and textline[i].isspace():
520 while i < len(textline) and textline[i].isspace():
521 i += 1
521 i += 1
522 list.append('%s %s%s\n' % (Colors.line,
522 list.append('%s %s%s\n' % (Colors.line,
523 textline.strip(),
523 textline.strip(),
524 Colors.Normal))
524 Colors.Normal))
525 if value.offset is not None:
525 if value.offset is not None:
526 s = ' '
526 s = ' '
527 for c in textline[i:value.offset - 1]:
527 for c in textline[i:value.offset - 1]:
528 if c.isspace():
528 if c.isspace():
529 s += c
529 s += c
530 else:
530 else:
531 s += ' '
531 s += ' '
532 list.append('%s%s^%s\n' % (Colors.caret, s,
532 list.append('%s%s^%s\n' % (Colors.caret, s,
533 Colors.Normal))
533 Colors.Normal))
534
534
535 try:
535 try:
536 s = value.msg
536 s = value.msg
537 except Exception:
537 except Exception:
538 s = self._some_str(value)
538 s = self._some_str(value)
539 if s:
539 if s:
540 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
540 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
541 Colors.Normal, s))
541 Colors.Normal, s))
542 else:
542 else:
543 list.append('%s\n' % stype)
543 list.append('%s\n' % stype)
544
544
545 # sync with user hooks
545 # sync with user hooks
546 if have_filedata:
546 if have_filedata:
547 ipinst = get_ipython()
547 ipinst = get_ipython()
548 if ipinst is not None:
548 if ipinst is not None:
549 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
549 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
550
550
551 return list
551 return list
552
552
553 def get_exception_only(self, etype, value):
553 def get_exception_only(self, etype, value):
554 """Only print the exception type and message, without a traceback.
554 """Only print the exception type and message, without a traceback.
555
555
556 Parameters
556 Parameters
557 ----------
557 ----------
558 etype : exception type
558 etype : exception type
559 evalue : exception value
559 value : exception value
560 """
560 """
561 return ListTB.structured_traceback(self, etype, value)
561 return ListTB.structured_traceback(self, etype, value)
562
562
563 def show_exception_only(self, etype, evalue):
563 def show_exception_only(self, etype, evalue):
564 """Only print the exception type and message, without a traceback.
564 """Only print the exception type and message, without a traceback.
565
565
566 Parameters
566 Parameters
567 ----------
567 ----------
568 etype : exception type
568 etype : exception type
569 evalue : exception value
569 evalue : exception value
570 """
570 """
571 # This method needs to use __call__ from *this* class, not the one from
571 # This method needs to use __call__ from *this* class, not the one from
572 # a subclass whose signature or behavior may be different
572 # a subclass whose signature or behavior may be different
573 ostream = self.ostream
573 ostream = self.ostream
574 ostream.flush()
574 ostream.flush()
575 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
575 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
576 ostream.flush()
576 ostream.flush()
577
577
578 def _some_str(self, value):
578 def _some_str(self, value):
579 # Lifted from traceback.py
579 # Lifted from traceback.py
580 try:
580 try:
581 return py3compat.cast_unicode(str(value))
581 return py3compat.cast_unicode(str(value))
582 except:
582 except:
583 return u'<unprintable %s object>' % type(value).__name__
583 return u'<unprintable %s object>' % type(value).__name__
584
584
585
585
586 #----------------------------------------------------------------------------
586 #----------------------------------------------------------------------------
587 class VerboseTB(TBTools):
587 class VerboseTB(TBTools):
588 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
588 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
589 of HTML. Requires inspect and pydoc. Crazy, man.
589 of HTML. Requires inspect and pydoc. Crazy, man.
590
590
591 Modified version which optionally strips the topmost entries from the
591 Modified version which optionally strips the topmost entries from the
592 traceback, to be used with alternate interpreters (because their own code
592 traceback, to be used with alternate interpreters (because their own code
593 would appear in the traceback)."""
593 would appear in the traceback)."""
594
594
595 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
595 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
596 tb_offset=0, long_header=False, include_vars=True,
596 tb_offset=0, long_header=False, include_vars=True,
597 check_cache=None, debugger_cls = None,
597 check_cache=None, debugger_cls = None,
598 parent=None, config=None):
598 parent=None, config=None):
599 """Specify traceback offset, headers and color scheme.
599 """Specify traceback offset, headers and color scheme.
600
600
601 Define how many frames to drop from the tracebacks. Calling it with
601 Define how many frames to drop from the tracebacks. Calling it with
602 tb_offset=1 allows use of this handler in interpreters which will have
602 tb_offset=1 allows use of this handler in interpreters which will have
603 their own code at the top of the traceback (VerboseTB will first
603 their own code at the top of the traceback (VerboseTB will first
604 remove that frame before printing the traceback info)."""
604 remove that frame before printing the traceback info)."""
605 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
605 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
606 ostream=ostream, parent=parent, config=config)
606 ostream=ostream, parent=parent, config=config)
607 self.tb_offset = tb_offset
607 self.tb_offset = tb_offset
608 self.long_header = long_header
608 self.long_header = long_header
609 self.include_vars = include_vars
609 self.include_vars = include_vars
610 # By default we use linecache.checkcache, but the user can provide a
610 # By default we use linecache.checkcache, but the user can provide a
611 # different check_cache implementation. This is used by the IPython
611 # different check_cache implementation. This is used by the IPython
612 # kernel to provide tracebacks for interactive code that is cached,
612 # kernel to provide tracebacks for interactive code that is cached,
613 # by a compiler instance that flushes the linecache but preserves its
613 # by a compiler instance that flushes the linecache but preserves its
614 # own code cache.
614 # own code cache.
615 if check_cache is None:
615 if check_cache is None:
616 check_cache = linecache.checkcache
616 check_cache = linecache.checkcache
617 self.check_cache = check_cache
617 self.check_cache = check_cache
618
618
619 self.debugger_cls = debugger_cls or debugger.Pdb
619 self.debugger_cls = debugger_cls or debugger.Pdb
620 self.skip_hidden = True
620 self.skip_hidden = True
621
621
622 def format_record(self, frame_info):
622 def format_record(self, frame_info):
623 """Format a single stack frame"""
623 """Format a single stack frame"""
624 Colors = self.Colors # just a shorthand + quicker name lookup
624 Colors = self.Colors # just a shorthand + quicker name lookup
625 ColorsNormal = Colors.Normal # used a lot
625 ColorsNormal = Colors.Normal # used a lot
626
626
627 if isinstance(frame_info, stack_data.RepeatedFrames):
627 if isinstance(frame_info, stack_data.RepeatedFrames):
628 return ' %s[... skipping similar frames: %s]%s\n' % (
628 return ' %s[... skipping similar frames: %s]%s\n' % (
629 Colors.excName, frame_info.description, ColorsNormal)
629 Colors.excName, frame_info.description, ColorsNormal)
630
630
631 indent = ' ' * INDENT_SIZE
631 indent = ' ' * INDENT_SIZE
632 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
632 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
633 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
633 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
634 ColorsNormal)
634 ColorsNormal)
635 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
635 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
636 (Colors.vName, Colors.valEm, ColorsNormal)
636 (Colors.vName, Colors.valEm, ColorsNormal)
637 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
637 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
638
638
639 link = _format_filename(frame_info.filename, Colors.filenameEm, ColorsNormal)
639 link = _format_filename(frame_info.filename, Colors.filenameEm, ColorsNormal)
640 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
640 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
641
641
642 func = frame_info.executing.code_qualname()
642 func = frame_info.executing.code_qualname()
643 if func == '<module>':
643 if func == '<module>':
644 call = tpl_call % (func, '')
644 call = tpl_call % (func, '')
645 else:
645 else:
646 # Decide whether to include variable details or not
646 # Decide whether to include variable details or not
647 var_repr = eqrepr if self.include_vars else nullrepr
647 var_repr = eqrepr if self.include_vars else nullrepr
648 try:
648 try:
649 call = tpl_call % (func, inspect.formatargvalues(args,
649 call = tpl_call % (func, inspect.formatargvalues(args,
650 varargs, varkw,
650 varargs, varkw,
651 locals_, formatvalue=var_repr))
651 locals_, formatvalue=var_repr))
652 except KeyError:
652 except KeyError:
653 # This happens in situations like errors inside generator
653 # This happens in situations like errors inside generator
654 # expressions, where local variables are listed in the
654 # expressions, where local variables are listed in the
655 # line, but can't be extracted from the frame. I'm not
655 # line, but can't be extracted from the frame. I'm not
656 # 100% sure this isn't actually a bug in inspect itself,
656 # 100% sure this isn't actually a bug in inspect itself,
657 # but since there's no info for us to compute with, the
657 # but since there's no info for us to compute with, the
658 # best we can do is report the failure and move on. Here
658 # best we can do is report the failure and move on. Here
659 # we must *not* call any traceback construction again,
659 # we must *not* call any traceback construction again,
660 # because that would mess up use of %debug later on. So we
660 # because that would mess up use of %debug later on. So we
661 # simply report the failure and move on. The only
661 # simply report the failure and move on. The only
662 # limitation will be that this frame won't have locals
662 # limitation will be that this frame won't have locals
663 # listed in the call signature. Quite subtle problem...
663 # listed in the call signature. Quite subtle problem...
664 # I can't think of a good way to validate this in a unit
664 # I can't think of a good way to validate this in a unit
665 # test, but running a script consisting of:
665 # test, but running a script consisting of:
666 # dict( (k,v.strip()) for (k,v) in range(10) )
666 # dict( (k,v.strip()) for (k,v) in range(10) )
667 # will illustrate the error, if this exception catch is
667 # will illustrate the error, if this exception catch is
668 # disabled.
668 # disabled.
669 call = tpl_call_fail % func
669 call = tpl_call_fail % func
670
670
671 lvals = ''
671 lvals = ''
672 lvals_list = []
672 lvals_list = []
673 if self.include_vars:
673 if self.include_vars:
674 try:
674 try:
675 # we likely want to fix stackdata at some point, but
675 # we likely want to fix stackdata at some point, but
676 # still need a workaround.
676 # still need a workaround.
677 fibp = frame_info.variables_in_executing_piece
677 fibp = frame_info.variables_in_executing_piece
678 for var in fibp:
678 for var in fibp:
679 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
679 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
680 except Exception:
680 except Exception:
681 lvals_list.append(
681 lvals_list.append(
682 "Exception trying to inspect frame. No more locals available."
682 "Exception trying to inspect frame. No more locals available."
683 )
683 )
684 if lvals_list:
684 if lvals_list:
685 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
685 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
686
686
687 result = "%s, %s\n" % (link, call)
687 result = "%s, %s\n" % (link, call)
688
688
689 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
689 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
690 return result
690 return result
691
691
692 def prepare_header(self, etype, long_version=False):
692 def prepare_header(self, etype, long_version=False):
693 colors = self.Colors # just a shorthand + quicker name lookup
693 colors = self.Colors # just a shorthand + quicker name lookup
694 colorsnormal = colors.Normal # used a lot
694 colorsnormal = colors.Normal # used a lot
695 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
695 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
696 width = min(75, get_terminal_size()[0])
696 width = min(75, get_terminal_size()[0])
697 if long_version:
697 if long_version:
698 # Header with the exception type, python version, and date
698 # Header with the exception type, python version, and date
699 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
699 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
700 date = time.ctime(time.time())
700 date = time.ctime(time.time())
701
701
702 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
702 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
703 exc, ' ' * (width - len(str(etype)) - len(pyver)),
703 exc, ' ' * (width - len(str(etype)) - len(pyver)),
704 pyver, date.rjust(width) )
704 pyver, date.rjust(width) )
705 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
705 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
706 "\ncalls leading up to the error, with the most recent (innermost) call last."
706 "\ncalls leading up to the error, with the most recent (innermost) call last."
707 else:
707 else:
708 # Simplified header
708 # Simplified header
709 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
709 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
710 rjust(width - len(str(etype))) )
710 rjust(width - len(str(etype))) )
711
711
712 return head
712 return head
713
713
714 def format_exception(self, etype, evalue):
714 def format_exception(self, etype, evalue):
715 colors = self.Colors # just a shorthand + quicker name lookup
715 colors = self.Colors # just a shorthand + quicker name lookup
716 colorsnormal = colors.Normal # used a lot
716 colorsnormal = colors.Normal # used a lot
717 # Get (safely) a string form of the exception info
717 # Get (safely) a string form of the exception info
718 try:
718 try:
719 etype_str, evalue_str = map(str, (etype, evalue))
719 etype_str, evalue_str = map(str, (etype, evalue))
720 except:
720 except:
721 # User exception is improperly defined.
721 # User exception is improperly defined.
722 etype, evalue = str, sys.exc_info()[:2]
722 etype, evalue = str, sys.exc_info()[:2]
723 etype_str, evalue_str = map(str, (etype, evalue))
723 etype_str, evalue_str = map(str, (etype, evalue))
724 # ... and format it
724 # ... and format it
725 return ['%s%s%s: %s' % (colors.excName, etype_str,
725 return ['%s%s%s: %s' % (colors.excName, etype_str,
726 colorsnormal, py3compat.cast_unicode(evalue_str))]
726 colorsnormal, py3compat.cast_unicode(evalue_str))]
727
727
728 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
728 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
729 """Formats the header, traceback and exception message for a single exception.
729 """Formats the header, traceback and exception message for a single exception.
730
730
731 This may be called multiple times by Python 3 exception chaining
731 This may be called multiple times by Python 3 exception chaining
732 (PEP 3134).
732 (PEP 3134).
733 """
733 """
734 # some locals
734 # some locals
735 orig_etype = etype
735 orig_etype = etype
736 try:
736 try:
737 etype = etype.__name__
737 etype = etype.__name__
738 except AttributeError:
738 except AttributeError:
739 pass
739 pass
740
740
741 tb_offset = self.tb_offset if tb_offset is None else tb_offset
741 tb_offset = self.tb_offset if tb_offset is None else tb_offset
742 head = self.prepare_header(etype, self.long_header)
742 head = self.prepare_header(etype, self.long_header)
743 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
743 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
744
744
745 frames = []
745 frames = []
746 skipped = 0
746 skipped = 0
747 lastrecord = len(records) - 1
747 lastrecord = len(records) - 1
748 for i, r in enumerate(records):
748 for i, r in enumerate(records):
749 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
749 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
750 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
750 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
751 skipped += 1
751 skipped += 1
752 continue
752 continue
753 if skipped:
753 if skipped:
754 Colors = self.Colors # just a shorthand + quicker name lookup
754 Colors = self.Colors # just a shorthand + quicker name lookup
755 ColorsNormal = Colors.Normal # used a lot
755 ColorsNormal = Colors.Normal # used a lot
756 frames.append(
756 frames.append(
757 " %s[... skipping hidden %s frame]%s\n"
757 " %s[... skipping hidden %s frame]%s\n"
758 % (Colors.excName, skipped, ColorsNormal)
758 % (Colors.excName, skipped, ColorsNormal)
759 )
759 )
760 skipped = 0
760 skipped = 0
761 frames.append(self.format_record(r))
761 frames.append(self.format_record(r))
762 if skipped:
762 if skipped:
763 Colors = self.Colors # just a shorthand + quicker name lookup
763 Colors = self.Colors # just a shorthand + quicker name lookup
764 ColorsNormal = Colors.Normal # used a lot
764 ColorsNormal = Colors.Normal # used a lot
765 frames.append(
765 frames.append(
766 " %s[... skipping hidden %s frame]%s\n"
766 " %s[... skipping hidden %s frame]%s\n"
767 % (Colors.excName, skipped, ColorsNormal)
767 % (Colors.excName, skipped, ColorsNormal)
768 )
768 )
769
769
770 formatted_exception = self.format_exception(etype, evalue)
770 formatted_exception = self.format_exception(etype, evalue)
771 if records:
771 if records:
772 frame_info = records[-1]
772 frame_info = records[-1]
773 ipinst = get_ipython()
773 ipinst = get_ipython()
774 if ipinst is not None:
774 if ipinst is not None:
775 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
775 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
776
776
777 return [[head] + frames + [''.join(formatted_exception[0])]]
777 return [[head] + frames + [''.join(formatted_exception[0])]]
778
778
779 def get_records(self, etb, number_of_lines_of_context, tb_offset):
779 def get_records(self, etb, number_of_lines_of_context, tb_offset):
780 context = number_of_lines_of_context - 1
780 context = number_of_lines_of_context - 1
781 after = context // 2
781 after = context // 2
782 before = context - after
782 before = context - after
783 if self.has_colors:
783 if self.has_colors:
784 style = get_style_by_name('default')
784 style = get_style_by_name('default')
785 style = stack_data.style_with_executing_node(style, 'bg:#00005f')
785 style = stack_data.style_with_executing_node(style, 'bg:#00005f')
786 formatter = Terminal256Formatter(style=style)
786 formatter = Terminal256Formatter(style=style)
787 else:
787 else:
788 formatter = None
788 formatter = None
789 options = stack_data.Options(
789 options = stack_data.Options(
790 before=before,
790 before=before,
791 after=after,
791 after=after,
792 pygments_formatter=formatter,
792 pygments_formatter=formatter,
793 )
793 )
794 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
794 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
795
795
796 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
796 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
797 number_of_lines_of_context=5):
797 number_of_lines_of_context=5):
798 """Return a nice text document describing the traceback."""
798 """Return a nice text document describing the traceback."""
799
799
800 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
800 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
801 tb_offset)
801 tb_offset)
802
802
803 colors = self.Colors # just a shorthand + quicker name lookup
803 colors = self.Colors # just a shorthand + quicker name lookup
804 colorsnormal = colors.Normal # used a lot
804 colorsnormal = colors.Normal # used a lot
805 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
805 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
806 structured_traceback_parts = [head]
806 structured_traceback_parts = [head]
807 chained_exceptions_tb_offset = 0
807 chained_exceptions_tb_offset = 0
808 lines_of_context = 3
808 lines_of_context = 3
809 formatted_exceptions = formatted_exception
809 formatted_exceptions = formatted_exception
810 exception = self.get_parts_of_chained_exception(evalue)
810 exception = self.get_parts_of_chained_exception(evalue)
811 if exception:
811 if exception:
812 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
812 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
813 etype, evalue, etb = exception
813 etype, evalue, etb = exception
814 else:
814 else:
815 evalue = None
815 evalue = None
816 chained_exc_ids = set()
816 chained_exc_ids = set()
817 while evalue:
817 while evalue:
818 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
818 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
819 chained_exceptions_tb_offset)
819 chained_exceptions_tb_offset)
820 exception = self.get_parts_of_chained_exception(evalue)
820 exception = self.get_parts_of_chained_exception(evalue)
821
821
822 if exception and not id(exception[1]) in chained_exc_ids:
822 if exception and not id(exception[1]) in chained_exc_ids:
823 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
823 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
824 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
824 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
825 etype, evalue, etb = exception
825 etype, evalue, etb = exception
826 else:
826 else:
827 evalue = None
827 evalue = None
828
828
829 # we want to see exceptions in a reversed order:
829 # we want to see exceptions in a reversed order:
830 # the first exception should be on top
830 # the first exception should be on top
831 for formatted_exception in reversed(formatted_exceptions):
831 for formatted_exception in reversed(formatted_exceptions):
832 structured_traceback_parts += formatted_exception
832 structured_traceback_parts += formatted_exception
833
833
834 return structured_traceback_parts
834 return structured_traceback_parts
835
835
836 def debugger(self, force=False):
836 def debugger(self, force=False):
837 """Call up the pdb debugger if desired, always clean up the tb
837 """Call up the pdb debugger if desired, always clean up the tb
838 reference.
838 reference.
839
839
840 Keywords:
840 Keywords:
841
841
842 - force(False): by default, this routine checks the instance call_pdb
842 - force(False): by default, this routine checks the instance call_pdb
843 flag and does not actually invoke the debugger if the flag is false.
843 flag and does not actually invoke the debugger if the flag is false.
844 The 'force' option forces the debugger to activate even if the flag
844 The 'force' option forces the debugger to activate even if the flag
845 is false.
845 is false.
846
846
847 If the call_pdb flag is set, the pdb interactive debugger is
847 If the call_pdb flag is set, the pdb interactive debugger is
848 invoked. In all cases, the self.tb reference to the current traceback
848 invoked. In all cases, the self.tb reference to the current traceback
849 is deleted to prevent lingering references which hamper memory
849 is deleted to prevent lingering references which hamper memory
850 management.
850 management.
851
851
852 Note that each call to pdb() does an 'import readline', so if your app
852 Note that each call to pdb() does an 'import readline', so if your app
853 requires a special setup for the readline completers, you'll have to
853 requires a special setup for the readline completers, you'll have to
854 fix that by hand after invoking the exception handler."""
854 fix that by hand after invoking the exception handler."""
855
855
856 if force or self.call_pdb:
856 if force or self.call_pdb:
857 if self.pdb is None:
857 if self.pdb is None:
858 self.pdb = self.debugger_cls()
858 self.pdb = self.debugger_cls()
859 # the system displayhook may have changed, restore the original
859 # the system displayhook may have changed, restore the original
860 # for pdb
860 # for pdb
861 display_trap = DisplayTrap(hook=sys.__displayhook__)
861 display_trap = DisplayTrap(hook=sys.__displayhook__)
862 with display_trap:
862 with display_trap:
863 self.pdb.reset()
863 self.pdb.reset()
864 # Find the right frame so we don't pop up inside ipython itself
864 # Find the right frame so we don't pop up inside ipython itself
865 if hasattr(self, 'tb') and self.tb is not None:
865 if hasattr(self, 'tb') and self.tb is not None:
866 etb = self.tb
866 etb = self.tb
867 else:
867 else:
868 etb = self.tb = sys.last_traceback
868 etb = self.tb = sys.last_traceback
869 while self.tb is not None and self.tb.tb_next is not None:
869 while self.tb is not None and self.tb.tb_next is not None:
870 self.tb = self.tb.tb_next
870 self.tb = self.tb.tb_next
871 if etb and etb.tb_next:
871 if etb and etb.tb_next:
872 etb = etb.tb_next
872 etb = etb.tb_next
873 self.pdb.botframe = etb.tb_frame
873 self.pdb.botframe = etb.tb_frame
874 self.pdb.interaction(None, etb)
874 self.pdb.interaction(None, etb)
875
875
876 if hasattr(self, 'tb'):
876 if hasattr(self, 'tb'):
877 del self.tb
877 del self.tb
878
878
879 def handler(self, info=None):
879 def handler(self, info=None):
880 (etype, evalue, etb) = info or sys.exc_info()
880 (etype, evalue, etb) = info or sys.exc_info()
881 self.tb = etb
881 self.tb = etb
882 ostream = self.ostream
882 ostream = self.ostream
883 ostream.flush()
883 ostream.flush()
884 ostream.write(self.text(etype, evalue, etb))
884 ostream.write(self.text(etype, evalue, etb))
885 ostream.write('\n')
885 ostream.write('\n')
886 ostream.flush()
886 ostream.flush()
887
887
888 # Changed so an instance can just be called as VerboseTB_inst() and print
888 # Changed so an instance can just be called as VerboseTB_inst() and print
889 # out the right info on its own.
889 # out the right info on its own.
890 def __call__(self, etype=None, evalue=None, etb=None):
890 def __call__(self, etype=None, evalue=None, etb=None):
891 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
891 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
892 if etb is None:
892 if etb is None:
893 self.handler()
893 self.handler()
894 else:
894 else:
895 self.handler((etype, evalue, etb))
895 self.handler((etype, evalue, etb))
896 try:
896 try:
897 self.debugger()
897 self.debugger()
898 except KeyboardInterrupt:
898 except KeyboardInterrupt:
899 print("\nKeyboardInterrupt")
899 print("\nKeyboardInterrupt")
900
900
901
901
902 #----------------------------------------------------------------------------
902 #----------------------------------------------------------------------------
903 class FormattedTB(VerboseTB, ListTB):
903 class FormattedTB(VerboseTB, ListTB):
904 """Subclass ListTB but allow calling with a traceback.
904 """Subclass ListTB but allow calling with a traceback.
905
905
906 It can thus be used as a sys.excepthook for Python > 2.1.
906 It can thus be used as a sys.excepthook for Python > 2.1.
907
907
908 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
908 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
909
909
910 Allows a tb_offset to be specified. This is useful for situations where
910 Allows a tb_offset to be specified. This is useful for situations where
911 one needs to remove a number of topmost frames from the traceback (such as
911 one needs to remove a number of topmost frames from the traceback (such as
912 occurs with python programs that themselves execute other python code,
912 occurs with python programs that themselves execute other python code,
913 like Python shells). """
913 like Python shells). """
914
914
915 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
915 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
916 ostream=None,
916 ostream=None,
917 tb_offset=0, long_header=False, include_vars=False,
917 tb_offset=0, long_header=False, include_vars=False,
918 check_cache=None, debugger_cls=None,
918 check_cache=None, debugger_cls=None,
919 parent=None, config=None):
919 parent=None, config=None):
920
920
921 # NEVER change the order of this list. Put new modes at the end:
921 # NEVER change the order of this list. Put new modes at the end:
922 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
922 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
923 self.verbose_modes = self.valid_modes[1:3]
923 self.verbose_modes = self.valid_modes[1:3]
924
924
925 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
925 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
926 ostream=ostream, tb_offset=tb_offset,
926 ostream=ostream, tb_offset=tb_offset,
927 long_header=long_header, include_vars=include_vars,
927 long_header=long_header, include_vars=include_vars,
928 check_cache=check_cache, debugger_cls=debugger_cls,
928 check_cache=check_cache, debugger_cls=debugger_cls,
929 parent=parent, config=config)
929 parent=parent, config=config)
930
930
931 # Different types of tracebacks are joined with different separators to
931 # Different types of tracebacks are joined with different separators to
932 # form a single string. They are taken from this dict
932 # form a single string. They are taken from this dict
933 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
933 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
934 Minimal='')
934 Minimal='')
935 # set_mode also sets the tb_join_char attribute
935 # set_mode also sets the tb_join_char attribute
936 self.set_mode(mode)
936 self.set_mode(mode)
937
937
938 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
938 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
939 tb_offset = self.tb_offset if tb_offset is None else tb_offset
939 tb_offset = self.tb_offset if tb_offset is None else tb_offset
940 mode = self.mode
940 mode = self.mode
941 if mode in self.verbose_modes:
941 if mode in self.verbose_modes:
942 # Verbose modes need a full traceback
942 # Verbose modes need a full traceback
943 return VerboseTB.structured_traceback(
943 return VerboseTB.structured_traceback(
944 self, etype, value, tb, tb_offset, number_of_lines_of_context
944 self, etype, value, tb, tb_offset, number_of_lines_of_context
945 )
945 )
946 elif mode == 'Minimal':
946 elif mode == 'Minimal':
947 return ListTB.get_exception_only(self, etype, value)
947 return ListTB.get_exception_only(self, etype, value)
948 else:
948 else:
949 # We must check the source cache because otherwise we can print
949 # We must check the source cache because otherwise we can print
950 # out-of-date source code.
950 # out-of-date source code.
951 self.check_cache()
951 self.check_cache()
952 # Now we can extract and format the exception
952 # Now we can extract and format the exception
953 return ListTB.structured_traceback(
953 return ListTB.structured_traceback(
954 self, etype, value, tb, tb_offset, number_of_lines_of_context
954 self, etype, value, tb, tb_offset, number_of_lines_of_context
955 )
955 )
956
956
957 def stb2text(self, stb):
957 def stb2text(self, stb):
958 """Convert a structured traceback (a list) to a string."""
958 """Convert a structured traceback (a list) to a string."""
959 return self.tb_join_char.join(stb)
959 return self.tb_join_char.join(stb)
960
960
961
961
962 def set_mode(self, mode=None):
962 def set_mode(self, mode=None):
963 """Switch to the desired mode.
963 """Switch to the desired mode.
964
964
965 If mode is not specified, cycles through the available modes."""
965 If mode is not specified, cycles through the available modes."""
966
966
967 if not mode:
967 if not mode:
968 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
968 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
969 len(self.valid_modes)
969 len(self.valid_modes)
970 self.mode = self.valid_modes[new_idx]
970 self.mode = self.valid_modes[new_idx]
971 elif mode not in self.valid_modes:
971 elif mode not in self.valid_modes:
972 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
972 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
973 'Valid modes: ' + str(self.valid_modes))
973 'Valid modes: ' + str(self.valid_modes))
974 else:
974 else:
975 self.mode = mode
975 self.mode = mode
976 # include variable details only in 'Verbose' mode
976 # include variable details only in 'Verbose' mode
977 self.include_vars = (self.mode == self.valid_modes[2])
977 self.include_vars = (self.mode == self.valid_modes[2])
978 # Set the join character for generating text tracebacks
978 # Set the join character for generating text tracebacks
979 self.tb_join_char = self._join_chars[self.mode]
979 self.tb_join_char = self._join_chars[self.mode]
980
980
981 # some convenient shortcuts
981 # some convenient shortcuts
982 def plain(self):
982 def plain(self):
983 self.set_mode(self.valid_modes[0])
983 self.set_mode(self.valid_modes[0])
984
984
985 def context(self):
985 def context(self):
986 self.set_mode(self.valid_modes[1])
986 self.set_mode(self.valid_modes[1])
987
987
988 def verbose(self):
988 def verbose(self):
989 self.set_mode(self.valid_modes[2])
989 self.set_mode(self.valid_modes[2])
990
990
991 def minimal(self):
991 def minimal(self):
992 self.set_mode(self.valid_modes[3])
992 self.set_mode(self.valid_modes[3])
993
993
994
994
995 #----------------------------------------------------------------------------
995 #----------------------------------------------------------------------------
996 class AutoFormattedTB(FormattedTB):
996 class AutoFormattedTB(FormattedTB):
997 """A traceback printer which can be called on the fly.
997 """A traceback printer which can be called on the fly.
998
998
999 It will find out about exceptions by itself.
999 It will find out about exceptions by itself.
1000
1000
1001 A brief example::
1001 A brief example::
1002
1002
1003 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1003 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1004 try:
1004 try:
1005 ...
1005 ...
1006 except:
1006 except:
1007 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1007 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1008 """
1008 """
1009
1009
1010 def __call__(self, etype=None, evalue=None, etb=None,
1010 def __call__(self, etype=None, evalue=None, etb=None,
1011 out=None, tb_offset=None):
1011 out=None, tb_offset=None):
1012 """Print out a formatted exception traceback.
1012 """Print out a formatted exception traceback.
1013
1013
1014 Optional arguments:
1014 Optional arguments:
1015 - out: an open file-like object to direct output to.
1015 - out: an open file-like object to direct output to.
1016
1016
1017 - tb_offset: the number of frames to skip over in the stack, on a
1017 - tb_offset: the number of frames to skip over in the stack, on a
1018 per-call basis (this overrides temporarily the instance's tb_offset
1018 per-call basis (this overrides temporarily the instance's tb_offset
1019 given at initialization time."""
1019 given at initialization time."""
1020
1020
1021 if out is None:
1021 if out is None:
1022 out = self.ostream
1022 out = self.ostream
1023 out.flush()
1023 out.flush()
1024 out.write(self.text(etype, evalue, etb, tb_offset))
1024 out.write(self.text(etype, evalue, etb, tb_offset))
1025 out.write('\n')
1025 out.write('\n')
1026 out.flush()
1026 out.flush()
1027 # FIXME: we should remove the auto pdb behavior from here and leave
1027 # FIXME: we should remove the auto pdb behavior from here and leave
1028 # that to the clients.
1028 # that to the clients.
1029 try:
1029 try:
1030 self.debugger()
1030 self.debugger()
1031 except KeyboardInterrupt:
1031 except KeyboardInterrupt:
1032 print("\nKeyboardInterrupt")
1032 print("\nKeyboardInterrupt")
1033
1033
1034 def structured_traceback(self, etype=None, value=None, tb=None,
1034 def structured_traceback(self, etype=None, value=None, tb=None,
1035 tb_offset=None, number_of_lines_of_context=5):
1035 tb_offset=None, number_of_lines_of_context=5):
1036 if etype is None:
1036 if etype is None:
1037 etype, value, tb = sys.exc_info()
1037 etype, value, tb = sys.exc_info()
1038 if isinstance(tb, tuple):
1038 if isinstance(tb, tuple):
1039 # tb is a tuple if this is a chained exception.
1039 # tb is a tuple if this is a chained exception.
1040 self.tb = tb[0]
1040 self.tb = tb[0]
1041 else:
1041 else:
1042 self.tb = tb
1042 self.tb = tb
1043 return FormattedTB.structured_traceback(
1043 return FormattedTB.structured_traceback(
1044 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1044 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1045
1045
1046
1046
1047 #---------------------------------------------------------------------------
1047 #---------------------------------------------------------------------------
1048
1048
1049 # A simple class to preserve Nathan's original functionality.
1049 # A simple class to preserve Nathan's original functionality.
1050 class ColorTB(FormattedTB):
1050 class ColorTB(FormattedTB):
1051 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1051 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1052
1052
1053 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1053 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1054 FormattedTB.__init__(self, color_scheme=color_scheme,
1054 FormattedTB.__init__(self, color_scheme=color_scheme,
1055 call_pdb=call_pdb, **kwargs)
1055 call_pdb=call_pdb, **kwargs)
1056
1056
1057
1057
1058 class SyntaxTB(ListTB):
1058 class SyntaxTB(ListTB):
1059 """Extension which holds some state: the last exception value"""
1059 """Extension which holds some state: the last exception value"""
1060
1060
1061 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1061 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1062 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1062 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1063 self.last_syntax_error = None
1063 self.last_syntax_error = None
1064
1064
1065 def __call__(self, etype, value, elist):
1065 def __call__(self, etype, value, elist):
1066 self.last_syntax_error = value
1066 self.last_syntax_error = value
1067
1067
1068 ListTB.__call__(self, etype, value, elist)
1068 ListTB.__call__(self, etype, value, elist)
1069
1069
1070 def structured_traceback(self, etype, value, elist, tb_offset=None,
1070 def structured_traceback(self, etype, value, elist, tb_offset=None,
1071 context=5):
1071 context=5):
1072 # If the source file has been edited, the line in the syntax error can
1072 # If the source file has been edited, the line in the syntax error can
1073 # be wrong (retrieved from an outdated cache). This replaces it with
1073 # be wrong (retrieved from an outdated cache). This replaces it with
1074 # the current value.
1074 # the current value.
1075 if isinstance(value, SyntaxError) \
1075 if isinstance(value, SyntaxError) \
1076 and isinstance(value.filename, str) \
1076 and isinstance(value.filename, str) \
1077 and isinstance(value.lineno, int):
1077 and isinstance(value.lineno, int):
1078 linecache.checkcache(value.filename)
1078 linecache.checkcache(value.filename)
1079 newtext = linecache.getline(value.filename, value.lineno)
1079 newtext = linecache.getline(value.filename, value.lineno)
1080 if newtext:
1080 if newtext:
1081 value.text = newtext
1081 value.text = newtext
1082 self.last_syntax_error = value
1082 self.last_syntax_error = value
1083 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1083 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1084 tb_offset=tb_offset, context=context)
1084 tb_offset=tb_offset, context=context)
1085
1085
1086 def clear_err_state(self):
1086 def clear_err_state(self):
1087 """Return the current error state and clear it"""
1087 """Return the current error state and clear it"""
1088 e = self.last_syntax_error
1088 e = self.last_syntax_error
1089 self.last_syntax_error = None
1089 self.last_syntax_error = None
1090 return e
1090 return e
1091
1091
1092 def stb2text(self, stb):
1092 def stb2text(self, stb):
1093 """Convert a structured traceback (a list) to a string."""
1093 """Convert a structured traceback (a list) to a string."""
1094 return ''.join(stb)
1094 return ''.join(stb)
1095
1095
1096
1096
1097 # some internal-use functions
1097 # some internal-use functions
1098 def text_repr(value):
1098 def text_repr(value):
1099 """Hopefully pretty robust repr equivalent."""
1099 """Hopefully pretty robust repr equivalent."""
1100 # this is pretty horrible but should always return *something*
1100 # this is pretty horrible but should always return *something*
1101 try:
1101 try:
1102 return pydoc.text.repr(value)
1102 return pydoc.text.repr(value)
1103 except KeyboardInterrupt:
1103 except KeyboardInterrupt:
1104 raise
1104 raise
1105 except:
1105 except:
1106 try:
1106 try:
1107 return repr(value)
1107 return repr(value)
1108 except KeyboardInterrupt:
1108 except KeyboardInterrupt:
1109 raise
1109 raise
1110 except:
1110 except:
1111 try:
1111 try:
1112 # all still in an except block so we catch
1112 # all still in an except block so we catch
1113 # getattr raising
1113 # getattr raising
1114 name = getattr(value, '__name__', None)
1114 name = getattr(value, '__name__', None)
1115 if name:
1115 if name:
1116 # ick, recursion
1116 # ick, recursion
1117 return text_repr(name)
1117 return text_repr(name)
1118 klass = getattr(value, '__class__', None)
1118 klass = getattr(value, '__class__', None)
1119 if klass:
1119 if klass:
1120 return '%s instance' % text_repr(klass)
1120 return '%s instance' % text_repr(klass)
1121 except KeyboardInterrupt:
1121 except KeyboardInterrupt:
1122 raise
1122 raise
1123 except:
1123 except:
1124 return 'UNRECOVERABLE REPR FAILURE'
1124 return 'UNRECOVERABLE REPR FAILURE'
1125
1125
1126
1126
1127 def eqrepr(value, repr=text_repr):
1127 def eqrepr(value, repr=text_repr):
1128 return '=%s' % repr(value)
1128 return '=%s' % repr(value)
1129
1129
1130
1130
1131 def nullrepr(value, repr=text_repr):
1131 def nullrepr(value, repr=text_repr):
1132 return ''
1132 return ''
General Comments 0
You need to be logged in to leave comments. Login now