##// END OF EJS Templates
Remove clearly marked python 2 imports.
Terry Davis -
Show More
@@ -1,639 +1,637 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 https://docs.python.org/2/license.html
17 17 """
18 18
19 19 #*****************************************************************************
20 20 #
21 21 # This file is licensed under the PSF license.
22 22 #
23 23 # Copyright (C) 2001 Python Software Foundation, www.python.org
24 24 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
25 25 #
26 26 #
27 27 #*****************************************************************************
28 28
29 29 import bdb
30 30 import functools
31 31 import inspect
32 32 import linecache
33 33 import sys
34 34 import warnings
35 35 import re
36 36
37 37 from IPython import get_ipython
38 38 from IPython.utils import PyColorize
39 39 from IPython.utils import coloransi, py3compat
40 40 from IPython.core.excolors import exception_colors
41 41 from IPython.testing.skipdoctest import skip_doctest
42 42
43 43
44 44 prompt = 'ipdb> '
45 45
46 46 #We have to check this directly from sys.argv, config struct not yet available
47 47 from pdb import Pdb as OldPdb
48 48
49 49 # Allow the set_trace code to operate outside of an ipython instance, even if
50 50 # it does so with some limitations. The rest of this support is implemented in
51 51 # the Tracer constructor.
52 52
53 53 def make_arrow(pad):
54 54 """generate the leading arrow in front of traceback or debugger"""
55 55 if pad >= 2:
56 56 return '-'*(pad-2) + '> '
57 57 elif pad == 1:
58 58 return '>'
59 59 return ''
60 60
61 61
62 62 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
63 63 """Exception hook which handles `BdbQuit` exceptions.
64 64
65 65 All other exceptions are processed using the `excepthook`
66 66 parameter.
67 67 """
68 68 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
69 69 DeprecationWarning, stacklevel=2)
70 70 if et==bdb.BdbQuit:
71 71 print('Exiting Debugger.')
72 72 elif excepthook is not None:
73 73 excepthook(et, ev, tb)
74 74 else:
75 75 # Backwards compatibility. Raise deprecation warning?
76 76 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
77 77
78 78
79 79 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
80 80 warnings.warn(
81 81 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
82 82 DeprecationWarning, stacklevel=2)
83 83 print('Exiting Debugger.')
84 84
85 85
86 86 class Tracer(object):
87 87 """
88 88 DEPRECATED
89 89
90 90 Class for local debugging, similar to pdb.set_trace.
91 91
92 92 Instances of this class, when called, behave like pdb.set_trace, but
93 93 providing IPython's enhanced capabilities.
94 94
95 95 This is implemented as a class which must be initialized in your own code
96 96 and not as a standalone function because we need to detect at runtime
97 97 whether IPython is already active or not. That detection is done in the
98 98 constructor, ensuring that this code plays nicely with a running IPython,
99 99 while functioning acceptably (though with limitations) if outside of it.
100 100 """
101 101
102 102 @skip_doctest
103 103 def __init__(self, colors=None):
104 104 """
105 105 DEPRECATED
106 106
107 107 Create a local debugger instance.
108 108
109 109 Parameters
110 110 ----------
111 111
112 112 colors : str, optional
113 113 The name of the color scheme to use, it must be one of IPython's
114 114 valid color schemes. If not given, the function will default to
115 115 the current IPython scheme when running inside IPython, and to
116 116 'NoColor' otherwise.
117 117
118 118 Examples
119 119 --------
120 120 ::
121 121
122 122 from IPython.core.debugger import Tracer; debug_here = Tracer()
123 123
124 124 Later in your code::
125 125
126 126 debug_here() # -> will open up the debugger at that point.
127 127
128 128 Once the debugger activates, you can use all of its regular commands to
129 129 step through code, set breakpoints, etc. See the pdb documentation
130 130 from the Python standard library for usage details.
131 131 """
132 132 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
133 133 "`IPython.core.debugger.Pdb.set_trace()`",
134 134 DeprecationWarning, stacklevel=2)
135 135
136 136 ip = get_ipython()
137 137 if ip is None:
138 138 # Outside of ipython, we set our own exception hook manually
139 139 sys.excepthook = functools.partial(BdbQuit_excepthook,
140 140 excepthook=sys.excepthook)
141 141 def_colors = 'NoColor'
142 142 else:
143 143 # In ipython, we use its custom exception handler mechanism
144 144 def_colors = ip.colors
145 145 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
146 146
147 147 if colors is None:
148 148 colors = def_colors
149 149
150 150 # The stdlib debugger internally uses a modified repr from the `repr`
151 151 # module, that limits the length of printed strings to a hardcoded
152 152 # limit of 30 characters. That much trimming is too aggressive, let's
153 153 # at least raise that limit to 80 chars, which should be enough for
154 154 # most interactive uses.
155 155 try:
156 156 from reprlib import aRepr
157 157 aRepr.maxstring = 80
158 158 except:
159 159 # This is only a user-facing convenience, so any error we encounter
160 160 # here can be warned about but can be otherwise ignored. These
161 161 # printouts will tell us about problems if this API changes
162 162 import traceback
163 163 traceback.print_exc()
164 164
165 165 self.debugger = Pdb(colors)
166 166
167 167 def __call__(self):
168 168 """Starts an interactive debugger at the point where called.
169 169
170 170 This is similar to the pdb.set_trace() function from the std lib, but
171 171 using IPython's enhanced debugger."""
172 172
173 173 self.debugger.set_trace(sys._getframe().f_back)
174 174
175 175
176 176 RGX_EXTRA_INDENT = re.compile(r'(?<=\n)\s+')
177 177
178 178
179 179 def strip_indentation(multiline_string):
180 180 return RGX_EXTRA_INDENT.sub('', multiline_string)
181 181
182 182
183 183 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
184 184 """Make new_fn have old_fn's doc string. This is particularly useful
185 185 for the ``do_...`` commands that hook into the help system.
186 186 Adapted from from a comp.lang.python posting
187 187 by Duncan Booth."""
188 188 def wrapper(*args, **kw):
189 189 return new_fn(*args, **kw)
190 190 if old_fn.__doc__:
191 191 wrapper.__doc__ = strip_indentation(old_fn.__doc__) + additional_text
192 192 return wrapper
193 193
194 194
195 195 class Pdb(OldPdb):
196 196 """Modified Pdb class, does not load readline.
197 197
198 198 for a standalone version that uses prompt_toolkit, see
199 199 `IPython.terminal.debugger.TerminalPdb` and
200 200 `IPython.terminal.debugger.set_trace()`
201 201 """
202 202
203 203 def __init__(self, color_scheme=None, completekey=None,
204 204 stdin=None, stdout=None, context=5, **kwargs):
205 205 """Create a new IPython debugger.
206 206
207 207 :param color_scheme: Deprecated, do not use.
208 208 :param completekey: Passed to pdb.Pdb.
209 209 :param stdin: Passed to pdb.Pdb.
210 210 :param stdout: Passed to pdb.Pdb.
211 211 :param context: Number of lines of source code context to show when
212 212 displaying stacktrace information.
213 213 :param kwargs: Passed to pdb.Pdb.
214 214 The possibilities are python version dependent, see the python
215 215 docs for more info.
216 216 """
217 217
218 218 # Parent constructor:
219 219 try:
220 220 self.context = int(context)
221 221 if self.context <= 0:
222 222 raise ValueError("Context must be a positive integer")
223 223 except (TypeError, ValueError):
224 224 raise ValueError("Context must be a positive integer")
225 225
226 226 # `kwargs` ensures full compatibility with stdlib's `pdb.Pdb`.
227 227 OldPdb.__init__(self, completekey, stdin, stdout, **kwargs)
228 228
229 229 # IPython changes...
230 230 self.shell = get_ipython()
231 231
232 232 if self.shell is None:
233 233 save_main = sys.modules['__main__']
234 234 # No IPython instance running, we must create one
235 235 from IPython.terminal.interactiveshell import \
236 236 TerminalInteractiveShell
237 237 self.shell = TerminalInteractiveShell.instance()
238 238 # needed by any code which calls __import__("__main__") after
239 239 # the debugger was entered. See also #9941.
240 240 sys.modules['__main__'] = save_main
241 241
242 242 if color_scheme is not None:
243 243 warnings.warn(
244 244 "The `color_scheme` argument is deprecated since version 5.1",
245 245 DeprecationWarning, stacklevel=2)
246 246 else:
247 247 color_scheme = self.shell.colors
248 248
249 249 self.aliases = {}
250 250
251 251 # Create color table: we copy the default one from the traceback
252 252 # module and add a few attributes needed for debugging
253 253 self.color_scheme_table = exception_colors()
254 254
255 255 # shorthands
256 256 C = coloransi.TermColors
257 257 cst = self.color_scheme_table
258 258
259 259 cst['NoColor'].colors.prompt = C.NoColor
260 260 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
261 261 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
262 262
263 263 cst['Linux'].colors.prompt = C.Green
264 264 cst['Linux'].colors.breakpoint_enabled = C.LightRed
265 265 cst['Linux'].colors.breakpoint_disabled = C.Red
266 266
267 267 cst['LightBG'].colors.prompt = C.Blue
268 268 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
269 269 cst['LightBG'].colors.breakpoint_disabled = C.Red
270 270
271 271 cst['Neutral'].colors.prompt = C.Blue
272 272 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
273 273 cst['Neutral'].colors.breakpoint_disabled = C.Red
274 274
275 275
276 276 # Add a python parser so we can syntax highlight source while
277 277 # debugging.
278 278 self.parser = PyColorize.Parser(style=color_scheme)
279 279 self.set_colors(color_scheme)
280 280
281 281 # Set the prompt - the default prompt is '(Pdb)'
282 282 self.prompt = prompt
283 283
284 284 def set_colors(self, scheme):
285 285 """Shorthand access to the color table scheme selector method."""
286 286 self.color_scheme_table.set_active_scheme(scheme)
287 287 self.parser.style = scheme
288 288
289 289 def interaction(self, frame, traceback):
290 290 try:
291 291 OldPdb.interaction(self, frame, traceback)
292 292 except KeyboardInterrupt:
293 293 self.stdout.write('\n' + self.shell.get_exception_only())
294 294
295 295 def new_do_up(self, arg):
296 296 OldPdb.do_up(self, arg)
297 297 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
298 298
299 299 def new_do_down(self, arg):
300 300 OldPdb.do_down(self, arg)
301 301
302 302 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
303 303
304 304 def new_do_frame(self, arg):
305 305 OldPdb.do_frame(self, arg)
306 306
307 307 def new_do_quit(self, arg):
308 308
309 309 if hasattr(self, 'old_all_completions'):
310 310 self.shell.Completer.all_completions=self.old_all_completions
311 311
312 312 return OldPdb.do_quit(self, arg)
313 313
314 314 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
315 315
316 316 def new_do_restart(self, arg):
317 317 """Restart command. In the context of ipython this is exactly the same
318 318 thing as 'quit'."""
319 319 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
320 320 return self.do_quit(arg)
321 321
322 322 def print_stack_trace(self, context=None):
323 323 if context is None:
324 324 context = self.context
325 325 try:
326 326 context=int(context)
327 327 if context <= 0:
328 328 raise ValueError("Context must be a positive integer")
329 329 except (TypeError, ValueError):
330 330 raise ValueError("Context must be a positive integer")
331 331 try:
332 332 for frame_lineno in self.stack:
333 333 self.print_stack_entry(frame_lineno, context=context)
334 334 except KeyboardInterrupt:
335 335 pass
336 336
337 337 def print_stack_entry(self, frame_lineno, prompt_prefix='\n-> ',
338 338 context=None):
339 339 if context is None:
340 340 context = self.context
341 341 try:
342 342 context=int(context)
343 343 if context <= 0:
344 344 raise ValueError("Context must be a positive integer")
345 345 except (TypeError, ValueError):
346 346 raise ValueError("Context must be a positive integer")
347 347 print(self.format_stack_entry(frame_lineno, '', context), file=self.stdout)
348 348
349 349 # vds: >>
350 350 frame, lineno = frame_lineno
351 351 filename = frame.f_code.co_filename
352 352 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
353 353 # vds: <<
354 354
355 355 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
356 356 if context is None:
357 357 context = self.context
358 358 try:
359 359 context=int(context)
360 360 if context <= 0:
361 361 print("Context must be a positive integer", file=self.stdout)
362 362 except (TypeError, ValueError):
363 363 print("Context must be a positive integer", file=self.stdout)
364 try:
365 import reprlib # Py 3
366 except ImportError:
367 import repr as reprlib # Py 2
364
365 import reprlib
368 366
369 367 ret = []
370 368
371 369 Colors = self.color_scheme_table.active_colors
372 370 ColorsNormal = Colors.Normal
373 371 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
374 372 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
375 373 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
376 374 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
377 375 ColorsNormal)
378 376
379 377 frame, lineno = frame_lineno
380 378
381 379 return_value = ''
382 380 if '__return__' in frame.f_locals:
383 381 rv = frame.f_locals['__return__']
384 382 #return_value += '->'
385 383 return_value += reprlib.repr(rv) + '\n'
386 384 ret.append(return_value)
387 385
388 386 #s = filename + '(' + `lineno` + ')'
389 387 filename = self.canonic(frame.f_code.co_filename)
390 388 link = tpl_link % py3compat.cast_unicode(filename)
391 389
392 390 if frame.f_code.co_name:
393 391 func = frame.f_code.co_name
394 392 else:
395 393 func = "<lambda>"
396 394
397 395 call = ''
398 396 if func != '?':
399 397 if '__args__' in frame.f_locals:
400 398 args = reprlib.repr(frame.f_locals['__args__'])
401 399 else:
402 400 args = '()'
403 401 call = tpl_call % (func, args)
404 402
405 403 # The level info should be generated in the same format pdb uses, to
406 404 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
407 405 if frame is self.curframe:
408 406 ret.append('> ')
409 407 else:
410 408 ret.append(' ')
411 409 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
412 410
413 411 start = lineno - 1 - context//2
414 412 lines = linecache.getlines(filename)
415 413 start = min(start, len(lines) - context)
416 414 start = max(start, 0)
417 415 lines = lines[start : start + context]
418 416
419 417 for i,line in enumerate(lines):
420 418 show_arrow = (start + 1 + i == lineno)
421 419 linetpl = (frame is self.curframe or show_arrow) \
422 420 and tpl_line_em \
423 421 or tpl_line
424 422 ret.append(self.__format_line(linetpl, filename,
425 423 start + 1 + i, line,
426 424 arrow = show_arrow) )
427 425 return ''.join(ret)
428 426
429 427 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
430 428 bp_mark = ""
431 429 bp_mark_color = ""
432 430
433 431 new_line, err = self.parser.format2(line, 'str')
434 432 if not err:
435 433 line = new_line
436 434
437 435 bp = None
438 436 if lineno in self.get_file_breaks(filename):
439 437 bps = self.get_breaks(filename, lineno)
440 438 bp = bps[-1]
441 439
442 440 if bp:
443 441 Colors = self.color_scheme_table.active_colors
444 442 bp_mark = str(bp.number)
445 443 bp_mark_color = Colors.breakpoint_enabled
446 444 if not bp.enabled:
447 445 bp_mark_color = Colors.breakpoint_disabled
448 446
449 447 numbers_width = 7
450 448 if arrow:
451 449 # This is the line with the error
452 450 pad = numbers_width - len(str(lineno)) - len(bp_mark)
453 451 num = '%s%s' % (make_arrow(pad), str(lineno))
454 452 else:
455 453 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
456 454
457 455 return tpl_line % (bp_mark_color + bp_mark, num, line)
458 456
459 457
460 458 def print_list_lines(self, filename, first, last):
461 459 """The printing (as opposed to the parsing part of a 'list'
462 460 command."""
463 461 try:
464 462 Colors = self.color_scheme_table.active_colors
465 463 ColorsNormal = Colors.Normal
466 464 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
467 465 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
468 466 src = []
469 467 if filename == "<string>" and hasattr(self, "_exec_filename"):
470 468 filename = self._exec_filename
471 469
472 470 for lineno in range(first, last+1):
473 471 line = linecache.getline(filename, lineno)
474 472 if not line:
475 473 break
476 474
477 475 if lineno == self.curframe.f_lineno:
478 476 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
479 477 else:
480 478 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
481 479
482 480 src.append(line)
483 481 self.lineno = lineno
484 482
485 483 print(''.join(src), file=self.stdout)
486 484
487 485 except KeyboardInterrupt:
488 486 pass
489 487
490 488 def do_list(self, arg):
491 489 """Print lines of code from the current stack frame
492 490 """
493 491 self.lastcmd = 'list'
494 492 last = None
495 493 if arg:
496 494 try:
497 495 x = eval(arg, {}, {})
498 496 if type(x) == type(()):
499 497 first, last = x
500 498 first = int(first)
501 499 last = int(last)
502 500 if last < first:
503 501 # Assume it's a count
504 502 last = first + last
505 503 else:
506 504 first = max(1, int(x) - 5)
507 505 except:
508 506 print('*** Error in argument:', repr(arg), file=self.stdout)
509 507 return
510 508 elif self.lineno is None:
511 509 first = max(1, self.curframe.f_lineno - 5)
512 510 else:
513 511 first = self.lineno + 1
514 512 if last is None:
515 513 last = first + 10
516 514 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
517 515
518 516 # vds: >>
519 517 lineno = first
520 518 filename = self.curframe.f_code.co_filename
521 519 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
522 520 # vds: <<
523 521
524 522 do_l = do_list
525 523
526 524 def getsourcelines(self, obj):
527 525 lines, lineno = inspect.findsource(obj)
528 526 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
529 527 # must be a module frame: do not try to cut a block out of it
530 528 return lines, 1
531 529 elif inspect.ismodule(obj):
532 530 return lines, 1
533 531 return inspect.getblock(lines[lineno:]), lineno+1
534 532
535 533 def do_longlist(self, arg):
536 534 """Print lines of code from the current stack frame.
537 535
538 536 Shows more lines than 'list' does.
539 537 """
540 538 self.lastcmd = 'longlist'
541 539 try:
542 540 lines, lineno = self.getsourcelines(self.curframe)
543 541 except OSError as err:
544 542 self.error(err)
545 543 return
546 544 last = lineno + len(lines)
547 545 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
548 546 do_ll = do_longlist
549 547
550 548 def do_debug(self, arg):
551 549 """debug code
552 550 Enter a recursive debugger that steps through the code
553 551 argument (which is an arbitrary expression or statement to be
554 552 executed in the current environment).
555 553 """
556 554 sys.settrace(None)
557 555 globals = self.curframe.f_globals
558 556 locals = self.curframe_locals
559 557 p = self.__class__(completekey=self.completekey,
560 558 stdin=self.stdin, stdout=self.stdout)
561 559 p.use_rawinput = self.use_rawinput
562 560 p.prompt = "(%s) " % self.prompt.strip()
563 561 self.message("ENTERING RECURSIVE DEBUGGER")
564 562 sys.call_tracing(p.run, (arg, globals, locals))
565 563 self.message("LEAVING RECURSIVE DEBUGGER")
566 564 sys.settrace(self.trace_dispatch)
567 565 self.lastcmd = p.lastcmd
568 566
569 567 def do_pdef(self, arg):
570 568 """Print the call signature for any callable object.
571 569
572 570 The debugger interface to %pdef"""
573 571 namespaces = [('Locals', self.curframe.f_locals),
574 572 ('Globals', self.curframe.f_globals)]
575 573 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
576 574
577 575 def do_pdoc(self, arg):
578 576 """Print the docstring for an object.
579 577
580 578 The debugger interface to %pdoc."""
581 579 namespaces = [('Locals', self.curframe.f_locals),
582 580 ('Globals', self.curframe.f_globals)]
583 581 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
584 582
585 583 def do_pfile(self, arg):
586 584 """Print (or run through pager) the file where an object is defined.
587 585
588 586 The debugger interface to %pfile.
589 587 """
590 588 namespaces = [('Locals', self.curframe.f_locals),
591 589 ('Globals', self.curframe.f_globals)]
592 590 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
593 591
594 592 def do_pinfo(self, arg):
595 593 """Provide detailed information about an object.
596 594
597 595 The debugger interface to %pinfo, i.e., obj?."""
598 596 namespaces = [('Locals', self.curframe.f_locals),
599 597 ('Globals', self.curframe.f_globals)]
600 598 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
601 599
602 600 def do_pinfo2(self, arg):
603 601 """Provide extra detailed information about an object.
604 602
605 603 The debugger interface to %pinfo2, i.e., obj??."""
606 604 namespaces = [('Locals', self.curframe.f_locals),
607 605 ('Globals', self.curframe.f_globals)]
608 606 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
609 607
610 608 def do_psource(self, arg):
611 609 """Print (or run through pager) the source code for an object."""
612 610 namespaces = [('Locals', self.curframe.f_locals),
613 611 ('Globals', self.curframe.f_globals)]
614 612 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
615 613
616 614 def do_where(self, arg):
617 615 """w(here)
618 616 Print a stack trace, with the most recent frame at the bottom.
619 617 An arrow indicates the "current frame", which determines the
620 618 context of most commands. 'bt' is an alias for this command.
621 619
622 620 Take a number as argument as an (optional) number of context line to
623 621 print"""
624 622 if arg:
625 623 context = int(arg)
626 624 self.print_stack_trace(context)
627 625 else:
628 626 self.print_stack_trace()
629 627
630 628 do_w = do_where
631 629
632 630
633 631 def set_trace(frame=None):
634 632 """
635 633 Start debugging from `frame`.
636 634
637 635 If frame is not specified, debugging starts from caller's frame.
638 636 """
639 637 Pdb().set_trace(frame or sys._getframe().f_back)
@@ -1,225 +1,222 b''
1 1 """Tests for debugging machinery.
2 2 """
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 sys
8 8 import warnings
9 9
10 10 import nose.tools as nt
11 11
12 12 from IPython.core import debugger
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Helper classes, from CPython's Pdb test suite
16 16 #-----------------------------------------------------------------------------
17 17
18 18 class _FakeInput(object):
19 19 """
20 20 A fake input stream for pdb's interactive debugger. Whenever a
21 21 line is read, print it (to simulate the user typing it), and then
22 22 return it. The set of lines to return is specified in the
23 23 constructor; they should not have trailing newlines.
24 24 """
25 25 def __init__(self, lines):
26 26 self.lines = iter(lines)
27 27
28 28 def readline(self):
29 29 line = next(self.lines)
30 30 print(line)
31 31 return line+'\n'
32 32
33 33 class PdbTestInput(object):
34 34 """Context manager that makes testing Pdb in doctests easier."""
35 35
36 36 def __init__(self, input):
37 37 self.input = input
38 38
39 39 def __enter__(self):
40 40 self.real_stdin = sys.stdin
41 41 sys.stdin = _FakeInput(self.input)
42 42
43 43 def __exit__(self, *exc):
44 44 sys.stdin = self.real_stdin
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Tests
48 48 #-----------------------------------------------------------------------------
49 49
50 50 def test_longer_repr():
51 try:
52 from reprlib import repr as trepr # Py 3
53 except ImportError:
54 from repr import repr as trepr # Py 2
51 from reprlib import repr as trepr
55 52
56 53 a = '1234567890'* 7
57 54 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
58 55 a_trunc = "'123456789012...8901234567890'"
59 56 nt.assert_equal(trepr(a), a_trunc)
60 57 # The creation of our tracer modifies the repr module's repr function
61 58 # in-place, since that global is used directly by the stdlib's pdb module.
62 59 with warnings.catch_warnings():
63 60 warnings.simplefilter('ignore', DeprecationWarning)
64 61 debugger.Tracer()
65 62 nt.assert_equal(trepr(a), ar)
66 63
67 64 def test_ipdb_magics():
68 65 '''Test calling some IPython magics from ipdb.
69 66
70 67 First, set up some test functions and classes which we can inspect.
71 68
72 69 >>> class ExampleClass(object):
73 70 ... """Docstring for ExampleClass."""
74 71 ... def __init__(self):
75 72 ... """Docstring for ExampleClass.__init__"""
76 73 ... pass
77 74 ... def __str__(self):
78 75 ... return "ExampleClass()"
79 76
80 77 >>> def example_function(x, y, z="hello"):
81 78 ... """Docstring for example_function."""
82 79 ... pass
83 80
84 81 >>> old_trace = sys.gettrace()
85 82
86 83 Create a function which triggers ipdb.
87 84
88 85 >>> def trigger_ipdb():
89 86 ... a = ExampleClass()
90 87 ... debugger.Pdb().set_trace()
91 88
92 89 >>> with PdbTestInput([
93 90 ... 'pdef example_function',
94 91 ... 'pdoc ExampleClass',
95 92 ... 'up',
96 93 ... 'down',
97 94 ... 'list',
98 95 ... 'pinfo a',
99 96 ... 'll',
100 97 ... 'continue',
101 98 ... ]):
102 99 ... trigger_ipdb()
103 100 --Return--
104 101 None
105 102 > <doctest ...>(3)trigger_ipdb()
106 103 1 def trigger_ipdb():
107 104 2 a = ExampleClass()
108 105 ----> 3 debugger.Pdb().set_trace()
109 106 <BLANKLINE>
110 107 ipdb> pdef example_function
111 108 example_function(x, y, z='hello')
112 109 ipdb> pdoc ExampleClass
113 110 Class docstring:
114 111 Docstring for ExampleClass.
115 112 Init docstring:
116 113 Docstring for ExampleClass.__init__
117 114 ipdb> up
118 115 > <doctest ...>(11)<module>()
119 116 7 'pinfo a',
120 117 8 'll',
121 118 9 'continue',
122 119 10 ]):
123 120 ---> 11 trigger_ipdb()
124 121 <BLANKLINE>
125 122 ipdb> down
126 123 None
127 124 > <doctest ...>(3)trigger_ipdb()
128 125 1 def trigger_ipdb():
129 126 2 a = ExampleClass()
130 127 ----> 3 debugger.Pdb().set_trace()
131 128 <BLANKLINE>
132 129 ipdb> list
133 130 1 def trigger_ipdb():
134 131 2 a = ExampleClass()
135 132 ----> 3 debugger.Pdb().set_trace()
136 133 <BLANKLINE>
137 134 ipdb> pinfo a
138 135 Type: ExampleClass
139 136 String form: ExampleClass()
140 137 Namespace: Local...
141 138 Docstring: Docstring for ExampleClass.
142 139 Init docstring: Docstring for ExampleClass.__init__
143 140 ipdb> ll
144 141 1 def trigger_ipdb():
145 142 2 a = ExampleClass()
146 143 ----> 3 debugger.Pdb().set_trace()
147 144 <BLANKLINE>
148 145 ipdb> continue
149 146
150 147 Restore previous trace function, e.g. for coverage.py
151 148
152 149 >>> sys.settrace(old_trace)
153 150 '''
154 151
155 152 def test_ipdb_magics2():
156 153 '''Test ipdb with a very short function.
157 154
158 155 >>> old_trace = sys.gettrace()
159 156
160 157 >>> def bar():
161 158 ... pass
162 159
163 160 Run ipdb.
164 161
165 162 >>> with PdbTestInput([
166 163 ... 'continue',
167 164 ... ]):
168 165 ... debugger.Pdb().runcall(bar)
169 166 > <doctest ...>(2)bar()
170 167 1 def bar():
171 168 ----> 2 pass
172 169 <BLANKLINE>
173 170 ipdb> continue
174 171
175 172 Restore previous trace function, e.g. for coverage.py
176 173
177 174 >>> sys.settrace(old_trace)
178 175 '''
179 176
180 177 def can_quit():
181 178 '''Test that quit work in ipydb
182 179
183 180 >>> old_trace = sys.gettrace()
184 181
185 182 >>> def bar():
186 183 ... pass
187 184
188 185 >>> with PdbTestInput([
189 186 ... 'quit',
190 187 ... ]):
191 188 ... debugger.Pdb().runcall(bar)
192 189 > <doctest ...>(2)bar()
193 190 1 def bar():
194 191 ----> 2 pass
195 192 <BLANKLINE>
196 193 ipdb> quit
197 194
198 195 Restore previous trace function, e.g. for coverage.py
199 196
200 197 >>> sys.settrace(old_trace)
201 198 '''
202 199
203 200
204 201 def can_exit():
205 202 '''Test that quit work in ipydb
206 203
207 204 >>> old_trace = sys.gettrace()
208 205
209 206 >>> def bar():
210 207 ... pass
211 208
212 209 >>> with PdbTestInput([
213 210 ... 'exit',
214 211 ... ]):
215 212 ... debugger.Pdb().runcall(bar)
216 213 > <doctest ...>(2)bar()
217 214 1 def bar():
218 215 ----> 2 pass
219 216 <BLANKLINE>
220 217 ipdb> exit
221 218
222 219 Restore previous trace function, e.g. for coverage.py
223 220
224 221 >>> sys.settrace(old_trace)
225 222 '''
@@ -1,654 +1,651 b''
1 1 """Various display related classes.
2 2
3 3 Authors : MinRK, gregcaporaso, dannystaple
4 4 """
5 5 from html import escape as html_escape
6 6 from os.path import exists, isfile, splitext, abspath, join, isdir
7 7 from os import walk, sep, fsdecode
8 8
9 9 from IPython.core.display import DisplayObject, TextDisplayObject
10 10
11 11 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
12 12 'FileLink', 'FileLinks', 'Code']
13 13
14 14
15 15 class Audio(DisplayObject):
16 16 """Create an audio object.
17 17
18 18 When this object is returned by an input cell or passed to the
19 19 display function, it will result in Audio controls being displayed
20 20 in the frontend (only works in the notebook).
21 21
22 22 Parameters
23 23 ----------
24 24 data : numpy array, list, unicode, str or bytes
25 25 Can be one of
26 26
27 27 * Numpy 1d array containing the desired waveform (mono)
28 28 * Numpy 2d array containing waveforms for each channel.
29 29 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
30 30 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
31 31 * List of float or integer representing the waveform (mono)
32 32 * String containing the filename
33 33 * Bytestring containing raw PCM data or
34 34 * URL pointing to a file on the web.
35 35
36 36 If the array option is used, the waveform will be normalized.
37 37
38 38 If a filename or url is used, the format support will be browser
39 39 dependent.
40 40 url : unicode
41 41 A URL to download the data from.
42 42 filename : unicode
43 43 Path to a local file to load the data from.
44 44 embed : boolean
45 45 Should the audio data be embedded using a data URI (True) or should
46 46 the original source be referenced. Set this to True if you want the
47 47 audio to playable later with no internet connection in the notebook.
48 48
49 49 Default is `True`, unless the keyword argument `url` is set, then
50 50 default value is `False`.
51 51 rate : integer
52 52 The sampling rate of the raw data.
53 53 Only required when data parameter is being used as an array
54 54 autoplay : bool
55 55 Set to True if the audio should immediately start playing.
56 56 Default is `False`.
57 57 normalize : bool
58 58 Whether audio should be normalized (rescaled) to the maximum possible
59 59 range. Default is `True`. When set to `False`, `data` must be between
60 60 -1 and 1 (inclusive), otherwise an error is raised.
61 61 Applies only when `data` is a list or array of samples; other types of
62 62 audio are never normalized.
63 63
64 64 Examples
65 65 --------
66 66 ::
67 67
68 68 # Generate a sound
69 69 import numpy as np
70 70 framerate = 44100
71 71 t = np.linspace(0,5,framerate*5)
72 72 data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)
73 73 Audio(data,rate=framerate)
74 74
75 75 # Can also do stereo or more channels
76 76 dataleft = np.sin(2*np.pi*220*t)
77 77 dataright = np.sin(2*np.pi*224*t)
78 78 Audio([dataleft, dataright],rate=framerate)
79 79
80 80 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # From URL
81 81 Audio(url="http://www.w3schools.com/html/horse.ogg")
82 82
83 83 Audio('/path/to/sound.wav') # From file
84 84 Audio(filename='/path/to/sound.ogg')
85 85
86 86 Audio(b'RAW_WAV_DATA..) # From bytes
87 87 Audio(data=b'RAW_WAV_DATA..)
88 88
89 89 See Also
90 90 --------
91 91
92 92 See also the ``Audio`` widgets form the ``ipywidget`` package for more flexibility and options.
93 93
94 94 """
95 95 _read_flags = 'rb'
96 96
97 97 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *,
98 98 element_id=None):
99 99 if filename is None and url is None and data is None:
100 100 raise ValueError("No audio data found. Expecting filename, url, or data.")
101 101 if embed is False and url is None:
102 102 raise ValueError("No url found. Expecting url when embed=False")
103 103
104 104 if url is not None and embed is not True:
105 105 self.embed = False
106 106 else:
107 107 self.embed = True
108 108 self.autoplay = autoplay
109 109 self.element_id = element_id
110 110 super(Audio, self).__init__(data=data, url=url, filename=filename)
111 111
112 112 if self.data is not None and not isinstance(self.data, bytes):
113 113 if rate is None:
114 114 raise ValueError("rate must be specified when data is a numpy array or list of audio samples.")
115 115 self.data = Audio._make_wav(data, rate, normalize)
116 116
117 117 def reload(self):
118 118 """Reload the raw data from file or URL."""
119 119 import mimetypes
120 120 if self.embed:
121 121 super(Audio, self).reload()
122 122
123 123 if self.filename is not None:
124 124 self.mimetype = mimetypes.guess_type(self.filename)[0]
125 125 elif self.url is not None:
126 126 self.mimetype = mimetypes.guess_type(self.url)[0]
127 127 else:
128 128 self.mimetype = "audio/wav"
129 129
130 130 @staticmethod
131 131 def _make_wav(data, rate, normalize):
132 132 """ Transform a numpy array to a PCM bytestring """
133 133 from io import BytesIO
134 134 import wave
135 135
136 136 try:
137 137 scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize)
138 138 except ImportError:
139 139 scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize)
140 140
141 141 fp = BytesIO()
142 142 waveobj = wave.open(fp,mode='wb')
143 143 waveobj.setnchannels(nchan)
144 144 waveobj.setframerate(rate)
145 145 waveobj.setsampwidth(2)
146 146 waveobj.setcomptype('NONE','NONE')
147 147 waveobj.writeframes(scaled)
148 148 val = fp.getvalue()
149 149 waveobj.close()
150 150
151 151 return val
152 152
153 153 @staticmethod
154 154 def _validate_and_normalize_with_numpy(data, normalize):
155 155 import numpy as np
156 156
157 157 data = np.array(data, dtype=float)
158 158 if len(data.shape) == 1:
159 159 nchan = 1
160 160 elif len(data.shape) == 2:
161 161 # In wave files,channels are interleaved. E.g.,
162 162 # "L1R1L2R2..." for stereo. See
163 163 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
164 164 # for channel ordering
165 165 nchan = data.shape[0]
166 166 data = data.T.ravel()
167 167 else:
168 168 raise ValueError('Array audio input must be a 1D or 2D array')
169 169
170 170 max_abs_value = np.max(np.abs(data))
171 171 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
172 172 scaled = data / normalization_factor * 32767
173 173 return scaled.astype('<h').tostring(), nchan
174 174
175 175
176 176 @staticmethod
177 177 def _validate_and_normalize_without_numpy(data, normalize):
178 178 import array
179 179 import sys
180 180
181 181 data = array.array('f', data)
182 182
183 183 try:
184 184 max_abs_value = float(max([abs(x) for x in data]))
185 185 except TypeError:
186 186 raise TypeError('Only lists of mono audio are '
187 187 'supported if numpy is not installed')
188 188
189 189 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
190 190 scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data])
191 191 if sys.byteorder == 'big':
192 192 scaled.byteswap()
193 193 nchan = 1
194 194 return scaled.tobytes(), nchan
195 195
196 196 @staticmethod
197 197 def _get_normalization_factor(max_abs_value, normalize):
198 198 if not normalize and max_abs_value > 1:
199 199 raise ValueError('Audio data must be between -1 and 1 when normalize=False.')
200 200 return max_abs_value if normalize else 1
201 201
202 202 def _data_and_metadata(self):
203 203 """shortcut for returning metadata with url information, if defined"""
204 204 md = {}
205 205 if self.url:
206 206 md['url'] = self.url
207 207 if md:
208 208 return self.data, md
209 209 else:
210 210 return self.data
211 211
212 212 def _repr_html_(self):
213 213 src = """
214 214 <audio {element_id} controls="controls" {autoplay}>
215 215 <source src="{src}" type="{type}" />
216 216 Your browser does not support the audio element.
217 217 </audio>
218 218 """
219 219 return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(),
220 220 element_id=self.element_id_attr())
221 221
222 222 def src_attr(self):
223 223 import base64
224 224 if self.embed and (self.data is not None):
225 225 data = base64=base64.b64encode(self.data).decode('ascii')
226 226 return """data:{type};base64,{base64}""".format(type=self.mimetype,
227 227 base64=data)
228 228 elif self.url is not None:
229 229 return self.url
230 230 else:
231 231 return ""
232 232
233 233 def autoplay_attr(self):
234 234 if(self.autoplay):
235 235 return 'autoplay="autoplay"'
236 236 else:
237 237 return ''
238 238
239 239 def element_id_attr(self):
240 240 if (self.element_id):
241 241 return 'id="{element_id}"'.format(element_id=self.element_id)
242 242 else:
243 243 return ''
244 244
245 245 class IFrame(object):
246 246 """
247 247 Generic class to embed an iframe in an IPython notebook
248 248 """
249 249
250 250 iframe = """
251 251 <iframe
252 252 width="{width}"
253 253 height="{height}"
254 254 src="{src}{params}"
255 255 frameborder="0"
256 256 allowfullscreen
257 257 ></iframe>
258 258 """
259 259
260 260 def __init__(self, src, width, height, **kwargs):
261 261 self.src = src
262 262 self.width = width
263 263 self.height = height
264 264 self.params = kwargs
265 265
266 266 def _repr_html_(self):
267 267 """return the embed iframe"""
268 268 if self.params:
269 try:
270 from urllib.parse import urlencode # Py 3
271 except ImportError:
272 from urllib import urlencode
269 from urllib.parse import urlencode
273 270 params = "?" + urlencode(self.params)
274 271 else:
275 272 params = ""
276 273 return self.iframe.format(src=self.src,
277 274 width=self.width,
278 275 height=self.height,
279 276 params=params)
280 277
281 278 class YouTubeVideo(IFrame):
282 279 """Class for embedding a YouTube Video in an IPython session, based on its video id.
283 280
284 281 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
285 282 do::
286 283
287 284 vid = YouTubeVideo("foo")
288 285 display(vid)
289 286
290 287 To start from 30 seconds::
291 288
292 289 vid = YouTubeVideo("abc", start=30)
293 290 display(vid)
294 291
295 292 To calculate seconds from time as hours, minutes, seconds use
296 293 :class:`datetime.timedelta`::
297 294
298 295 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
299 296
300 297 Other parameters can be provided as documented at
301 298 https://developers.google.com/youtube/player_parameters#Parameters
302 299
303 300 When converting the notebook using nbconvert, a jpeg representation of the video
304 301 will be inserted in the document.
305 302 """
306 303
307 304 def __init__(self, id, width=400, height=300, **kwargs):
308 305 self.id=id
309 306 src = "https://www.youtube.com/embed/{0}".format(id)
310 307 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
311 308
312 309 def _repr_jpeg_(self):
313 310 # Deferred import
314 311 from urllib.request import urlopen
315 312
316 313 try:
317 314 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
318 315 except IOError:
319 316 return None
320 317
321 318 class VimeoVideo(IFrame):
322 319 """
323 320 Class for embedding a Vimeo video in an IPython session, based on its video id.
324 321 """
325 322
326 323 def __init__(self, id, width=400, height=300, **kwargs):
327 324 src="https://player.vimeo.com/video/{0}".format(id)
328 325 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
329 326
330 327 class ScribdDocument(IFrame):
331 328 """
332 329 Class for embedding a Scribd document in an IPython session
333 330
334 331 Use the start_page params to specify a starting point in the document
335 332 Use the view_mode params to specify display type one off scroll | slideshow | book
336 333
337 334 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
338 335
339 336 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
340 337 """
341 338
342 339 def __init__(self, id, width=400, height=300, **kwargs):
343 340 src="https://www.scribd.com/embeds/{0}/content".format(id)
344 341 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
345 342
346 343 class FileLink(object):
347 344 """Class for embedding a local file link in an IPython session, based on path
348 345
349 346 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
350 347
351 348 you would do::
352 349
353 350 local_file = FileLink("my/data.txt")
354 351 display(local_file)
355 352
356 353 or in the HTML notebook, just::
357 354
358 355 FileLink("my/data.txt")
359 356 """
360 357
361 358 html_link_str = "<a href='%s' target='_blank'>%s</a>"
362 359
363 360 def __init__(self,
364 361 path,
365 362 url_prefix='',
366 363 result_html_prefix='',
367 364 result_html_suffix='<br>'):
368 365 """
369 366 Parameters
370 367 ----------
371 368 path : str
372 369 path to the file or directory that should be formatted
373 370 url_prefix : str
374 371 prefix to be prepended to all files to form a working link [default:
375 372 '']
376 373 result_html_prefix : str
377 374 text to append to beginning to link [default: '']
378 375 result_html_suffix : str
379 376 text to append at the end of link [default: '<br>']
380 377 """
381 378 if isdir(path):
382 379 raise ValueError("Cannot display a directory using FileLink. "
383 380 "Use FileLinks to display '%s'." % path)
384 381 self.path = fsdecode(path)
385 382 self.url_prefix = url_prefix
386 383 self.result_html_prefix = result_html_prefix
387 384 self.result_html_suffix = result_html_suffix
388 385
389 386 def _format_path(self):
390 387 fp = ''.join([self.url_prefix, html_escape(self.path)])
391 388 return ''.join([self.result_html_prefix,
392 389 self.html_link_str % \
393 390 (fp, html_escape(self.path, quote=False)),
394 391 self.result_html_suffix])
395 392
396 393 def _repr_html_(self):
397 394 """return html link to file
398 395 """
399 396 if not exists(self.path):
400 397 return ("Path (<tt>%s</tt>) doesn't exist. "
401 398 "It may still be in the process of "
402 399 "being generated, or you may have the "
403 400 "incorrect path." % self.path)
404 401
405 402 return self._format_path()
406 403
407 404 def __repr__(self):
408 405 """return absolute path to file
409 406 """
410 407 return abspath(self.path)
411 408
412 409 class FileLinks(FileLink):
413 410 """Class for embedding local file links in an IPython session, based on path
414 411
415 412 e.g. to embed links to files that were generated in the IPython notebook
416 413 under ``my/data``, you would do::
417 414
418 415 local_files = FileLinks("my/data")
419 416 display(local_files)
420 417
421 418 or in the HTML notebook, just::
422 419
423 420 FileLinks("my/data")
424 421 """
425 422 def __init__(self,
426 423 path,
427 424 url_prefix='',
428 425 included_suffixes=None,
429 426 result_html_prefix='',
430 427 result_html_suffix='<br>',
431 428 notebook_display_formatter=None,
432 429 terminal_display_formatter=None,
433 430 recursive=True):
434 431 """
435 432 See :class:`FileLink` for the ``path``, ``url_prefix``,
436 433 ``result_html_prefix`` and ``result_html_suffix`` parameters.
437 434
438 435 included_suffixes : list
439 436 Filename suffixes to include when formatting output [default: include
440 437 all files]
441 438
442 439 notebook_display_formatter : function
443 440 Used to format links for display in the notebook. See discussion of
444 441 formatter functions below.
445 442
446 443 terminal_display_formatter : function
447 444 Used to format links for display in the terminal. See discussion of
448 445 formatter functions below.
449 446
450 447 Formatter functions must be of the form::
451 448
452 449 f(dirname, fnames, included_suffixes)
453 450
454 451 dirname : str
455 452 The name of a directory
456 453 fnames : list
457 454 The files in that directory
458 455 included_suffixes : list
459 456 The file suffixes that should be included in the output (passing None
460 457 meansto include all suffixes in the output in the built-in formatters)
461 458 recursive : boolean
462 459 Whether to recurse into subdirectories. Default is True.
463 460
464 461 The function should return a list of lines that will be printed in the
465 462 notebook (if passing notebook_display_formatter) or the terminal (if
466 463 passing terminal_display_formatter). This function is iterated over for
467 464 each directory in self.path. Default formatters are in place, can be
468 465 passed here to support alternative formatting.
469 466
470 467 """
471 468 if isfile(path):
472 469 raise ValueError("Cannot display a file using FileLinks. "
473 470 "Use FileLink to display '%s'." % path)
474 471 self.included_suffixes = included_suffixes
475 472 # remove trailing slashes for more consistent output formatting
476 473 path = path.rstrip('/')
477 474
478 475 self.path = path
479 476 self.url_prefix = url_prefix
480 477 self.result_html_prefix = result_html_prefix
481 478 self.result_html_suffix = result_html_suffix
482 479
483 480 self.notebook_display_formatter = \
484 481 notebook_display_formatter or self._get_notebook_display_formatter()
485 482 self.terminal_display_formatter = \
486 483 terminal_display_formatter or self._get_terminal_display_formatter()
487 484
488 485 self.recursive = recursive
489 486
490 487 def _get_display_formatter(self,
491 488 dirname_output_format,
492 489 fname_output_format,
493 490 fp_format,
494 491 fp_cleaner=None):
495 492 """ generate built-in formatter function
496 493
497 494 this is used to define both the notebook and terminal built-in
498 495 formatters as they only differ by some wrapper text for each entry
499 496
500 497 dirname_output_format: string to use for formatting directory
501 498 names, dirname will be substituted for a single "%s" which
502 499 must appear in this string
503 500 fname_output_format: string to use for formatting file names,
504 501 if a single "%s" appears in the string, fname will be substituted
505 502 if two "%s" appear in the string, the path to fname will be
506 503 substituted for the first and fname will be substituted for the
507 504 second
508 505 fp_format: string to use for formatting filepaths, must contain
509 506 exactly two "%s" and the dirname will be substituted for the first
510 507 and fname will be substituted for the second
511 508 """
512 509 def f(dirname, fnames, included_suffixes=None):
513 510 result = []
514 511 # begin by figuring out which filenames, if any,
515 512 # are going to be displayed
516 513 display_fnames = []
517 514 for fname in fnames:
518 515 if (isfile(join(dirname,fname)) and
519 516 (included_suffixes is None or
520 517 splitext(fname)[1] in included_suffixes)):
521 518 display_fnames.append(fname)
522 519
523 520 if len(display_fnames) == 0:
524 521 # if there are no filenames to display, don't print anything
525 522 # (not even the directory name)
526 523 pass
527 524 else:
528 525 # otherwise print the formatted directory name followed by
529 526 # the formatted filenames
530 527 dirname_output_line = dirname_output_format % dirname
531 528 result.append(dirname_output_line)
532 529 for fname in display_fnames:
533 530 fp = fp_format % (dirname,fname)
534 531 if fp_cleaner is not None:
535 532 fp = fp_cleaner(fp)
536 533 try:
537 534 # output can include both a filepath and a filename...
538 535 fname_output_line = fname_output_format % (fp, fname)
539 536 except TypeError:
540 537 # ... or just a single filepath
541 538 fname_output_line = fname_output_format % fname
542 539 result.append(fname_output_line)
543 540 return result
544 541 return f
545 542
546 543 def _get_notebook_display_formatter(self,
547 544 spacer="&nbsp;&nbsp;"):
548 545 """ generate function to use for notebook formatting
549 546 """
550 547 dirname_output_format = \
551 548 self.result_html_prefix + "%s/" + self.result_html_suffix
552 549 fname_output_format = \
553 550 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
554 551 fp_format = self.url_prefix + '%s/%s'
555 552 if sep == "\\":
556 553 # Working on a platform where the path separator is "\", so
557 554 # must convert these to "/" for generating a URI
558 555 def fp_cleaner(fp):
559 556 # Replace all occurrences of backslash ("\") with a forward
560 557 # slash ("/") - this is necessary on windows when a path is
561 558 # provided as input, but we must link to a URI
562 559 return fp.replace('\\','/')
563 560 else:
564 561 fp_cleaner = None
565 562
566 563 return self._get_display_formatter(dirname_output_format,
567 564 fname_output_format,
568 565 fp_format,
569 566 fp_cleaner)
570 567
571 568 def _get_terminal_display_formatter(self,
572 569 spacer=" "):
573 570 """ generate function to use for terminal formatting
574 571 """
575 572 dirname_output_format = "%s/"
576 573 fname_output_format = spacer + "%s"
577 574 fp_format = '%s/%s'
578 575
579 576 return self._get_display_formatter(dirname_output_format,
580 577 fname_output_format,
581 578 fp_format)
582 579
583 580 def _format_path(self):
584 581 result_lines = []
585 582 if self.recursive:
586 583 walked_dir = list(walk(self.path))
587 584 else:
588 585 walked_dir = [next(walk(self.path))]
589 586 walked_dir.sort()
590 587 for dirname, subdirs, fnames in walked_dir:
591 588 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
592 589 return '\n'.join(result_lines)
593 590
594 591 def __repr__(self):
595 592 """return newline-separated absolute paths
596 593 """
597 594 result_lines = []
598 595 if self.recursive:
599 596 walked_dir = list(walk(self.path))
600 597 else:
601 598 walked_dir = [next(walk(self.path))]
602 599 walked_dir.sort()
603 600 for dirname, subdirs, fnames in walked_dir:
604 601 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
605 602 return '\n'.join(result_lines)
606 603
607 604
608 605 class Code(TextDisplayObject):
609 606 """Display syntax-highlighted source code.
610 607
611 608 This uses Pygments to highlight the code for HTML and Latex output.
612 609
613 610 Parameters
614 611 ----------
615 612 data : str
616 613 The code as a string
617 614 url : str
618 615 A URL to fetch the code from
619 616 filename : str
620 617 A local filename to load the code from
621 618 language : str
622 619 The short name of a Pygments lexer to use for highlighting.
623 620 If not specified, it will guess the lexer based on the filename
624 621 or the code. Available lexers: http://pygments.org/docs/lexers/
625 622 """
626 623 def __init__(self, data=None, url=None, filename=None, language=None):
627 624 self.language = language
628 625 super().__init__(data=data, url=url, filename=filename)
629 626
630 627 def _get_lexer(self):
631 628 if self.language:
632 629 from pygments.lexers import get_lexer_by_name
633 630 return get_lexer_by_name(self.language)
634 631 elif self.filename:
635 632 from pygments.lexers import get_lexer_for_filename
636 633 return get_lexer_for_filename(self.filename)
637 634 else:
638 635 from pygments.lexers import guess_lexer
639 636 return guess_lexer(self.data)
640 637
641 638 def __repr__(self):
642 639 return self.data
643 640
644 641 def _repr_html_(self):
645 642 from pygments import highlight
646 643 from pygments.formatters import HtmlFormatter
647 644 fmt = HtmlFormatter()
648 645 style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html'))
649 646 return style + highlight(self.data, self._get_lexer(), fmt)
650 647
651 648 def _repr_latex_(self):
652 649 from pygments import highlight
653 650 from pygments.formatters import LatexFormatter
654 651 return highlight(self.data, self._get_lexer(), LatexFormatter())
@@ -1,666 +1,663 b''
1 1 # coding: utf-8
2 2 """
3 3 Deprecated since IPython 5.0
4 4
5 5 Inputhook management for GUI event loop integration.
6 6 """
7 7
8 8 # Copyright (c) IPython Development Team.
9 9 # Distributed under the terms of the Modified BSD License.
10 10
11 11 try:
12 12 import ctypes
13 13 except ImportError:
14 14 ctypes = None
15 15 except SystemError: # IronPython issue, 2/8/2014
16 16 ctypes = None
17 17 import os
18 18 import platform
19 19 import sys
20 20 from distutils.version import LooseVersion as V
21 21
22 22 from warnings import warn
23 23
24 24
25 25 warn("`IPython.lib.inputhook` is deprecated since IPython 5.0 and will be removed in future versions.",
26 26 DeprecationWarning, stacklevel=2)
27 27
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Constants
31 31 #-----------------------------------------------------------------------------
32 32
33 33 # Constants for identifying the GUI toolkits.
34 34 GUI_WX = 'wx'
35 35 GUI_QT = 'qt'
36 36 GUI_QT4 = 'qt4'
37 37 GUI_GTK = 'gtk'
38 38 GUI_TK = 'tk'
39 39 GUI_OSX = 'osx'
40 40 GUI_GLUT = 'glut'
41 41 GUI_PYGLET = 'pyglet'
42 42 GUI_GTK3 = 'gtk3'
43 43 GUI_NONE = 'none' # i.e. disable
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Utilities
47 47 #-----------------------------------------------------------------------------
48 48
49 49 def _stdin_ready_posix():
50 50 """Return True if there's something to read on stdin (posix version)."""
51 51 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
52 52 return bool(infds)
53 53
54 54 def _stdin_ready_nt():
55 55 """Return True if there's something to read on stdin (nt version)."""
56 56 return msvcrt.kbhit()
57 57
58 58 def _stdin_ready_other():
59 59 """Return True, assuming there's something to read on stdin."""
60 60 return True
61 61
62 62 def _use_appnope():
63 63 """Should we use appnope for dealing with OS X app nap?
64 64
65 65 Checks if we are on OS X 10.9 or greater.
66 66 """
67 67 return sys.platform == 'darwin' and V(platform.mac_ver()[0]) >= V('10.9')
68 68
69 69 def _ignore_CTRL_C_posix():
70 70 """Ignore CTRL+C (SIGINT)."""
71 71 signal.signal(signal.SIGINT, signal.SIG_IGN)
72 72
73 73 def _allow_CTRL_C_posix():
74 74 """Take CTRL+C into account (SIGINT)."""
75 75 signal.signal(signal.SIGINT, signal.default_int_handler)
76 76
77 77 def _ignore_CTRL_C_other():
78 78 """Ignore CTRL+C (not implemented)."""
79 79 pass
80 80
81 81 def _allow_CTRL_C_other():
82 82 """Take CTRL+C into account (not implemented)."""
83 83 pass
84 84
85 85 if os.name == 'posix':
86 86 import select
87 87 import signal
88 88 stdin_ready = _stdin_ready_posix
89 89 ignore_CTRL_C = _ignore_CTRL_C_posix
90 90 allow_CTRL_C = _allow_CTRL_C_posix
91 91 elif os.name == 'nt':
92 92 import msvcrt
93 93 stdin_ready = _stdin_ready_nt
94 94 ignore_CTRL_C = _ignore_CTRL_C_other
95 95 allow_CTRL_C = _allow_CTRL_C_other
96 96 else:
97 97 stdin_ready = _stdin_ready_other
98 98 ignore_CTRL_C = _ignore_CTRL_C_other
99 99 allow_CTRL_C = _allow_CTRL_C_other
100 100
101 101
102 102 #-----------------------------------------------------------------------------
103 103 # Main InputHookManager class
104 104 #-----------------------------------------------------------------------------
105 105
106 106
107 107 class InputHookManager(object):
108 108 """DEPRECATED since IPython 5.0
109 109
110 110 Manage PyOS_InputHook for different GUI toolkits.
111 111
112 112 This class installs various hooks under ``PyOSInputHook`` to handle
113 113 GUI event loop integration.
114 114 """
115 115
116 116 def __init__(self):
117 117 if ctypes is None:
118 118 warn("IPython GUI event loop requires ctypes, %gui will not be available")
119 119 else:
120 120 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
121 121 self.guihooks = {}
122 122 self.aliases = {}
123 123 self.apps = {}
124 124 self._reset()
125 125
126 126 def _reset(self):
127 127 self._callback_pyfunctype = None
128 128 self._callback = None
129 129 self._installed = False
130 130 self._current_gui = None
131 131
132 132 def get_pyos_inputhook(self):
133 133 """DEPRECATED since IPython 5.0
134 134
135 135 Return the current PyOS_InputHook as a ctypes.c_void_p."""
136 136 warn("`get_pyos_inputhook` is deprecated since IPython 5.0 and will be removed in future versions.",
137 137 DeprecationWarning, stacklevel=2)
138 138 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
139 139
140 140 def get_pyos_inputhook_as_func(self):
141 141 """DEPRECATED since IPython 5.0
142 142
143 143 Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
144 144 warn("`get_pyos_inputhook_as_func` is deprecated since IPython 5.0 and will be removed in future versions.",
145 145 DeprecationWarning, stacklevel=2)
146 146 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
147 147
148 148 def set_inputhook(self, callback):
149 149 """DEPRECATED since IPython 5.0
150 150
151 151 Set PyOS_InputHook to callback and return the previous one."""
152 152 # On platforms with 'readline' support, it's all too likely to
153 153 # have a KeyboardInterrupt signal delivered *even before* an
154 154 # initial ``try:`` clause in the callback can be executed, so
155 155 # we need to disable CTRL+C in this situation.
156 156 ignore_CTRL_C()
157 157 self._callback = callback
158 158 self._callback_pyfunctype = self.PYFUNC(callback)
159 159 pyos_inputhook_ptr = self.get_pyos_inputhook()
160 160 original = self.get_pyos_inputhook_as_func()
161 161 pyos_inputhook_ptr.value = \
162 162 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
163 163 self._installed = True
164 164 return original
165 165
166 166 def clear_inputhook(self, app=None):
167 167 """DEPRECATED since IPython 5.0
168 168
169 169 Set PyOS_InputHook to NULL and return the previous one.
170 170
171 171 Parameters
172 172 ----------
173 173 app : optional, ignored
174 174 This parameter is allowed only so that clear_inputhook() can be
175 175 called with a similar interface as all the ``enable_*`` methods. But
176 176 the actual value of the parameter is ignored. This uniform interface
177 177 makes it easier to have user-level entry points in the main IPython
178 178 app like :meth:`enable_gui`."""
179 179 warn("`clear_inputhook` is deprecated since IPython 5.0 and will be removed in future versions.",
180 180 DeprecationWarning, stacklevel=2)
181 181 pyos_inputhook_ptr = self.get_pyos_inputhook()
182 182 original = self.get_pyos_inputhook_as_func()
183 183 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
184 184 allow_CTRL_C()
185 185 self._reset()
186 186 return original
187 187
188 188 def clear_app_refs(self, gui=None):
189 189 """DEPRECATED since IPython 5.0
190 190
191 191 Clear IPython's internal reference to an application instance.
192 192
193 193 Whenever we create an app for a user on qt4 or wx, we hold a
194 194 reference to the app. This is needed because in some cases bad things
195 195 can happen if a user doesn't hold a reference themselves. This
196 196 method is provided to clear the references we are holding.
197 197
198 198 Parameters
199 199 ----------
200 200 gui : None or str
201 201 If None, clear all app references. If ('wx', 'qt4') clear
202 202 the app for that toolkit. References are not held for gtk or tk
203 203 as those toolkits don't have the notion of an app.
204 204 """
205 205 warn("`clear_app_refs` is deprecated since IPython 5.0 and will be removed in future versions.",
206 206 DeprecationWarning, stacklevel=2)
207 207 if gui is None:
208 208 self.apps = {}
209 209 elif gui in self.apps:
210 210 del self.apps[gui]
211 211
212 212 def register(self, toolkitname, *aliases):
213 213 """DEPRECATED since IPython 5.0
214 214
215 215 Register a class to provide the event loop for a given GUI.
216 216
217 217 This is intended to be used as a class decorator. It should be passed
218 218 the names with which to register this GUI integration. The classes
219 219 themselves should subclass :class:`InputHookBase`.
220 220
221 221 ::
222 222
223 223 @inputhook_manager.register('qt')
224 224 class QtInputHook(InputHookBase):
225 225 def enable(self, app=None):
226 226 ...
227 227 """
228 228 warn("`register` is deprecated since IPython 5.0 and will be removed in future versions.",
229 229 DeprecationWarning, stacklevel=2)
230 230 def decorator(cls):
231 231 if ctypes is not None:
232 232 inst = cls(self)
233 233 self.guihooks[toolkitname] = inst
234 234 for a in aliases:
235 235 self.aliases[a] = toolkitname
236 236 return cls
237 237 return decorator
238 238
239 239 def current_gui(self):
240 240 """DEPRECATED since IPython 5.0
241 241
242 242 Return a string indicating the currently active GUI or None."""
243 243 warn("`current_gui` is deprecated since IPython 5.0 and will be removed in future versions.",
244 244 DeprecationWarning, stacklevel=2)
245 245 return self._current_gui
246 246
247 247 def enable_gui(self, gui=None, app=None):
248 248 """DEPRECATED since IPython 5.0
249 249
250 250 Switch amongst GUI input hooks by name.
251 251
252 252 This is a higher level method than :meth:`set_inputhook` - it uses the
253 253 GUI name to look up a registered object which enables the input hook
254 254 for that GUI.
255 255
256 256 Parameters
257 257 ----------
258 258 gui : optional, string or None
259 259 If None (or 'none'), clears input hook, otherwise it must be one
260 260 of the recognized GUI names (see ``GUI_*`` constants in module).
261 261
262 262 app : optional, existing application object.
263 263 For toolkits that have the concept of a global app, you can supply an
264 264 existing one. If not given, the toolkit will be probed for one, and if
265 265 none is found, a new one will be created. Note that GTK does not have
266 266 this concept, and passing an app if ``gui=="GTK"`` will raise an error.
267 267
268 268 Returns
269 269 -------
270 270 The output of the underlying gui switch routine, typically the actual
271 271 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
272 272 one.
273 273 """
274 274 warn("`enable_gui` is deprecated since IPython 5.0 and will be removed in future versions.",
275 275 DeprecationWarning, stacklevel=2)
276 276 if gui in (None, GUI_NONE):
277 277 return self.disable_gui()
278 278
279 279 if gui in self.aliases:
280 280 return self.enable_gui(self.aliases[gui], app)
281 281
282 282 try:
283 283 gui_hook = self.guihooks[gui]
284 284 except KeyError:
285 285 e = "Invalid GUI request {!r}, valid ones are: {}"
286 286 raise ValueError(e.format(gui, ', '.join(self.guihooks)))
287 287 self._current_gui = gui
288 288
289 289 app = gui_hook.enable(app)
290 290 if app is not None:
291 291 app._in_event_loop = True
292 292 self.apps[gui] = app
293 293 return app
294 294
295 295 def disable_gui(self):
296 296 """DEPRECATED since IPython 5.0
297 297
298 298 Disable GUI event loop integration.
299 299
300 300 If an application was registered, this sets its ``_in_event_loop``
301 301 attribute to False. It then calls :meth:`clear_inputhook`.
302 302 """
303 303 warn("`disable_gui` is deprecated since IPython 5.0 and will be removed in future versions.",
304 304 DeprecationWarning, stacklevel=2)
305 305 gui = self._current_gui
306 306 if gui in self.apps:
307 307 self.apps[gui]._in_event_loop = False
308 308 return self.clear_inputhook()
309 309
310 310 class InputHookBase(object):
311 311 """DEPRECATED since IPython 5.0
312 312
313 313 Base class for input hooks for specific toolkits.
314 314
315 315 Subclasses should define an :meth:`enable` method with one argument, ``app``,
316 316 which will either be an instance of the toolkit's application class, or None.
317 317 They may also define a :meth:`disable` method with no arguments.
318 318 """
319 319 def __init__(self, manager):
320 320 self.manager = manager
321 321
322 322 def disable(self):
323 323 pass
324 324
325 325 inputhook_manager = InputHookManager()
326 326
327 327 @inputhook_manager.register('osx')
328 328 class NullInputHook(InputHookBase):
329 329 """DEPRECATED since IPython 5.0
330 330
331 331 A null inputhook that doesn't need to do anything"""
332 332 def enable(self, app=None):
333 333 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
334 334 DeprecationWarning, stacklevel=2)
335 335
336 336 @inputhook_manager.register('wx')
337 337 class WxInputHook(InputHookBase):
338 338 def enable(self, app=None):
339 339 """DEPRECATED since IPython 5.0
340 340
341 341 Enable event loop integration with wxPython.
342 342
343 343 Parameters
344 344 ----------
345 345 app : WX Application, optional.
346 346 Running application to use. If not given, we probe WX for an
347 347 existing application object, and create a new one if none is found.
348 348
349 349 Notes
350 350 -----
351 351 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
352 352 the wxPython to integrate with terminal based applications like
353 353 IPython.
354 354
355 355 If ``app`` is not given we probe for an existing one, and return it if
356 356 found. If no existing app is found, we create an :class:`wx.App` as
357 357 follows::
358 358
359 359 import wx
360 360 app = wx.App(redirect=False, clearSigInt=False)
361 361 """
362 362 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
363 363 DeprecationWarning, stacklevel=2)
364 364 import wx
365 365
366 366 wx_version = V(wx.__version__).version
367 367
368 368 if wx_version < [2, 8]:
369 369 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
370 370
371 371 from IPython.lib.inputhookwx import inputhook_wx
372 372 self.manager.set_inputhook(inputhook_wx)
373 373 if _use_appnope():
374 374 from appnope import nope
375 375 nope()
376 376
377 377 import wx
378 378 if app is None:
379 379 app = wx.GetApp()
380 380 if app is None:
381 381 app = wx.App(redirect=False, clearSigInt=False)
382 382
383 383 return app
384 384
385 385 def disable(self):
386 386 """DEPRECATED since IPython 5.0
387 387
388 388 Disable event loop integration with wxPython.
389 389
390 390 This restores appnapp on OS X
391 391 """
392 392 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
393 393 DeprecationWarning, stacklevel=2)
394 394 if _use_appnope():
395 395 from appnope import nap
396 396 nap()
397 397
398 398 @inputhook_manager.register('qt', 'qt4')
399 399 class Qt4InputHook(InputHookBase):
400 400 def enable(self, app=None):
401 401 """DEPRECATED since IPython 5.0
402 402
403 403 Enable event loop integration with PyQt4.
404 404
405 405 Parameters
406 406 ----------
407 407 app : Qt Application, optional.
408 408 Running application to use. If not given, we probe Qt for an
409 409 existing application object, and create a new one if none is found.
410 410
411 411 Notes
412 412 -----
413 413 This methods sets the PyOS_InputHook for PyQt4, which allows
414 414 the PyQt4 to integrate with terminal based applications like
415 415 IPython.
416 416
417 417 If ``app`` is not given we probe for an existing one, and return it if
418 418 found. If no existing app is found, we create an :class:`QApplication`
419 419 as follows::
420 420
421 421 from PyQt4 import QtCore
422 422 app = QtGui.QApplication(sys.argv)
423 423 """
424 424 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
425 425 DeprecationWarning, stacklevel=2)
426 426 from IPython.lib.inputhookqt4 import create_inputhook_qt4
427 427 app, inputhook_qt4 = create_inputhook_qt4(self.manager, app)
428 428 self.manager.set_inputhook(inputhook_qt4)
429 429 if _use_appnope():
430 430 from appnope import nope
431 431 nope()
432 432
433 433 return app
434 434
435 435 def disable_qt4(self):
436 436 """DEPRECATED since IPython 5.0
437 437
438 438 Disable event loop integration with PyQt4.
439 439
440 440 This restores appnapp on OS X
441 441 """
442 442 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
443 443 DeprecationWarning, stacklevel=2)
444 444 if _use_appnope():
445 445 from appnope import nap
446 446 nap()
447 447
448 448
449 449 @inputhook_manager.register('qt5')
450 450 class Qt5InputHook(Qt4InputHook):
451 451 def enable(self, app=None):
452 452 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
453 453 DeprecationWarning, stacklevel=2)
454 454 os.environ['QT_API'] = 'pyqt5'
455 455 return Qt4InputHook.enable(self, app)
456 456
457 457
458 458 @inputhook_manager.register('gtk')
459 459 class GtkInputHook(InputHookBase):
460 460 def enable(self, app=None):
461 461 """DEPRECATED since IPython 5.0
462 462
463 463 Enable event loop integration with PyGTK.
464 464
465 465 Parameters
466 466 ----------
467 467 app : ignored
468 468 Ignored, it's only a placeholder to keep the call signature of all
469 469 gui activation methods consistent, which simplifies the logic of
470 470 supporting magics.
471 471
472 472 Notes
473 473 -----
474 474 This methods sets the PyOS_InputHook for PyGTK, which allows
475 475 the PyGTK to integrate with terminal based applications like
476 476 IPython.
477 477 """
478 478 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
479 479 DeprecationWarning, stacklevel=2)
480 480 import gtk
481 481 try:
482 482 gtk.set_interactive(True)
483 483 except AttributeError:
484 484 # For older versions of gtk, use our own ctypes version
485 485 from IPython.lib.inputhookgtk import inputhook_gtk
486 486 self.manager.set_inputhook(inputhook_gtk)
487 487
488 488
489 489 @inputhook_manager.register('tk')
490 490 class TkInputHook(InputHookBase):
491 491 def enable(self, app=None):
492 492 """DEPRECATED since IPython 5.0
493 493
494 494 Enable event loop integration with Tk.
495 495
496 496 Parameters
497 497 ----------
498 498 app : toplevel :class:`Tkinter.Tk` widget, optional.
499 499 Running toplevel widget to use. If not given, we probe Tk for an
500 500 existing one, and create a new one if none is found.
501 501
502 502 Notes
503 503 -----
504 504 If you have already created a :class:`Tkinter.Tk` object, the only
505 505 thing done by this method is to register with the
506 506 :class:`InputHookManager`, since creating that object automatically
507 507 sets ``PyOS_InputHook``.
508 508 """
509 509 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
510 510 DeprecationWarning, stacklevel=2)
511 511 if app is None:
512 try:
513 from tkinter import Tk # Py 3
514 except ImportError:
515 from Tkinter import Tk # Py 2
512 from tkinter import Tk
516 513 app = Tk()
517 514 app.withdraw()
518 515 self.manager.apps[GUI_TK] = app
519 516 return app
520 517
521 518
522 519 @inputhook_manager.register('glut')
523 520 class GlutInputHook(InputHookBase):
524 521 def enable(self, app=None):
525 522 """DEPRECATED since IPython 5.0
526 523
527 524 Enable event loop integration with GLUT.
528 525
529 526 Parameters
530 527 ----------
531 528
532 529 app : ignored
533 530 Ignored, it's only a placeholder to keep the call signature of all
534 531 gui activation methods consistent, which simplifies the logic of
535 532 supporting magics.
536 533
537 534 Notes
538 535 -----
539 536
540 537 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
541 538 integrate with terminal based applications like IPython. Due to GLUT
542 539 limitations, it is currently not possible to start the event loop
543 540 without first creating a window. You should thus not create another
544 541 window but use instead the created one. See 'gui-glut.py' in the
545 542 docs/examples/lib directory.
546 543
547 544 The default screen mode is set to:
548 545 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
549 546 """
550 547 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
551 548 DeprecationWarning, stacklevel=2)
552 549
553 550 import OpenGL.GLUT as glut
554 551 from IPython.lib.inputhookglut import glut_display_mode, \
555 552 glut_close, glut_display, \
556 553 glut_idle, inputhook_glut
557 554
558 555 if GUI_GLUT not in self.manager.apps:
559 556 glut.glutInit( sys.argv )
560 557 glut.glutInitDisplayMode( glut_display_mode )
561 558 # This is specific to freeglut
562 559 if bool(glut.glutSetOption):
563 560 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
564 561 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
565 562 glut.glutCreateWindow( sys.argv[0] )
566 563 glut.glutReshapeWindow( 1, 1 )
567 564 glut.glutHideWindow( )
568 565 glut.glutWMCloseFunc( glut_close )
569 566 glut.glutDisplayFunc( glut_display )
570 567 glut.glutIdleFunc( glut_idle )
571 568 else:
572 569 glut.glutWMCloseFunc( glut_close )
573 570 glut.glutDisplayFunc( glut_display )
574 571 glut.glutIdleFunc( glut_idle)
575 572 self.manager.set_inputhook( inputhook_glut )
576 573
577 574
578 575 def disable(self):
579 576 """DEPRECATED since IPython 5.0
580 577
581 578 Disable event loop integration with glut.
582 579
583 580 This sets PyOS_InputHook to NULL and set the display function to a
584 581 dummy one and set the timer to a dummy timer that will be triggered
585 582 very far in the future.
586 583 """
587 584 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
588 585 DeprecationWarning, stacklevel=2)
589 586 import OpenGL.GLUT as glut
590 587 from glut_support import glutMainLoopEvent
591 588
592 589 glut.glutHideWindow() # This is an event to be processed below
593 590 glutMainLoopEvent()
594 591 super(GlutInputHook, self).disable()
595 592
596 593 @inputhook_manager.register('pyglet')
597 594 class PygletInputHook(InputHookBase):
598 595 def enable(self, app=None):
599 596 """DEPRECATED since IPython 5.0
600 597
601 598 Enable event loop integration with pyglet.
602 599
603 600 Parameters
604 601 ----------
605 602 app : ignored
606 603 Ignored, it's only a placeholder to keep the call signature of all
607 604 gui activation methods consistent, which simplifies the logic of
608 605 supporting magics.
609 606
610 607 Notes
611 608 -----
612 609 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
613 610 pyglet to integrate with terminal based applications like
614 611 IPython.
615 612
616 613 """
617 614 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
618 615 DeprecationWarning, stacklevel=2)
619 616 from IPython.lib.inputhookpyglet import inputhook_pyglet
620 617 self.manager.set_inputhook(inputhook_pyglet)
621 618 return app
622 619
623 620
624 621 @inputhook_manager.register('gtk3')
625 622 class Gtk3InputHook(InputHookBase):
626 623 def enable(self, app=None):
627 624 """DEPRECATED since IPython 5.0
628 625
629 626 Enable event loop integration with Gtk3 (gir bindings).
630 627
631 628 Parameters
632 629 ----------
633 630 app : ignored
634 631 Ignored, it's only a placeholder to keep the call signature of all
635 632 gui activation methods consistent, which simplifies the logic of
636 633 supporting magics.
637 634
638 635 Notes
639 636 -----
640 637 This methods sets the PyOS_InputHook for Gtk3, which allows
641 638 the Gtk3 to integrate with terminal based applications like
642 639 IPython.
643 640 """
644 641 warn("This function is deprecated since IPython 5.0 and will be removed in future versions.",
645 642 DeprecationWarning, stacklevel=2)
646 643 from IPython.lib.inputhookgtk3 import inputhook_gtk3
647 644 self.manager.set_inputhook(inputhook_gtk3)
648 645
649 646
650 647 clear_inputhook = inputhook_manager.clear_inputhook
651 648 set_inputhook = inputhook_manager.set_inputhook
652 649 current_gui = inputhook_manager.current_gui
653 650 clear_app_refs = inputhook_manager.clear_app_refs
654 651 enable_gui = inputhook_manager.enable_gui
655 652 disable_gui = inputhook_manager.disable_gui
656 653 register = inputhook_manager.register
657 654 guis = inputhook_manager.guihooks
658 655
659 656
660 657 def _deprecated_disable():
661 658 warn("This function is deprecated since IPython 4.0 use disable_gui() instead",
662 659 DeprecationWarning, stacklevel=2)
663 660 inputhook_manager.disable_gui()
664 661
665 662 disable_wx = disable_qt4 = disable_gtk = disable_gtk3 = disable_glut = \
666 663 disable_pyglet = disable_osx = _deprecated_disable
General Comments 0
You need to be logged in to leave comments. Login now