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