Show More
@@ -232,6 +232,8 b' class TaskRejectError(KernelError):' | |||
|
232 | 232 | |
|
233 | 233 | class CompositeError(RemoteError): |
|
234 | 234 | """Error for representing possibly multiple errors on engines""" |
|
235 | tb_limit = 4 # limit on how many tracebacks to draw | |
|
236 | ||
|
235 | 237 | def __init__(self, message, elist): |
|
236 | 238 | Exception.__init__(self, *(message, elist)) |
|
237 | 239 | # Don't use pack_exception because it will conflict with the .message |
@@ -256,9 +258,11 b' class CompositeError(RemoteError):' | |||
|
256 | 258 | |
|
257 | 259 | def __str__(self): |
|
258 | 260 | s = str(self.msg) |
|
259 | for en, ev, etb, ei in self.elist: | |
|
261 | for en, ev, etb, ei in self.elist[:self.tb_limit]: | |
|
260 | 262 | engine_str = self._get_engine_str(ei) |
|
261 | 263 | s = s + '\n' + engine_str + en + ': ' + str(ev) |
|
264 | if len(self.elist) > self.tb_limit: | |
|
265 | s = s + '\n.... %i more exceptions ...' % (len(self.elist) - self.tb_limit) | |
|
262 | 266 | return s |
|
263 | 267 | |
|
264 | 268 | def __repr__(self): |
@@ -268,10 +272,14 b' class CompositeError(RemoteError):' | |||
|
268 | 272 | """render one or all of my tracebacks to a list of lines""" |
|
269 | 273 | lines = [] |
|
270 | 274 | if excid is None: |
|
271 | for (en,ev,etb,ei) in self.elist: | |
|
275 | for (en,ev,etb,ei) in self.elist[:self.tb_limit]: | |
|
272 | 276 | lines.append(self._get_engine_str(ei)) |
|
273 | 277 | lines.extend((etb or 'No traceback available').splitlines()) |
|
274 | 278 | lines.append('') |
|
279 | if len(self.elist) > self.tb_limit: | |
|
280 | lines.append( | |
|
281 | '... %i more exceptions ...' % (len(self.elist) - self.tb_limit) | |
|
282 | ) | |
|
275 | 283 | else: |
|
276 | 284 | try: |
|
277 | 285 | en,ev,etb,ei = self.elist[excid] |
@@ -622,6 +622,33 b' class TestView(ClusterTestCase, ParametricTestCase):' | |||
|
622 | 622 | self.assertEqual(io.stdout.count('by zero'), len(view), io.stdout) |
|
623 | 623 | self.assertEqual(io.stdout.count(':execute'), len(view), io.stdout) |
|
624 | 624 | |
|
625 | def test_compositeerror_truncate(self): | |
|
626 | """Truncate CompositeErrors with many exceptions""" | |
|
627 | view = self.client[:] | |
|
628 | msg_ids = [] | |
|
629 | for i in range(10): | |
|
630 | ar = view.execute("1/0") | |
|
631 | msg_ids.extend(ar.msg_ids) | |
|
632 | ||
|
633 | ar = self.client.get_result(msg_ids) | |
|
634 | try: | |
|
635 | ar.get() | |
|
636 | except error.CompositeError as e: | |
|
637 | pass | |
|
638 | else: | |
|
639 | self.fail("Should have raised CompositeError") | |
|
640 | ||
|
641 | lines = e.render_traceback() | |
|
642 | with capture_output() as io: | |
|
643 | e.print_traceback() | |
|
644 | ||
|
645 | self.assertTrue("more exceptions" in lines[-1]) | |
|
646 | count = e.tb_limit | |
|
647 | ||
|
648 | self.assertEqual(io.stdout.count('ZeroDivisionError'), 2 * count, io.stdout) | |
|
649 | self.assertEqual(io.stdout.count('by zero'), count, io.stdout) | |
|
650 | self.assertEqual(io.stdout.count(':execute'), count, io.stdout) | |
|
651 | ||
|
625 | 652 | @dec.skipif_not_matplotlib |
|
626 | 653 | def test_magic_pylab(self): |
|
627 | 654 | """%pylab works on engines""" |
@@ -560,25 +560,25 b' more other types of exceptions. Here is how it works:' | |||
|
560 | 560 | In [79]: dview.execute("1/0") |
|
561 | 561 | [0:execute]: |
|
562 | 562 | --------------------------------------------------------------------------- |
|
563 |
ZeroDivisionError Traceback (most recent call last) |
|
|
563 | ZeroDivisionError Traceback (most recent call last) | |
|
564 | 564 | ----> 1 1/0 |
|
565 | 565 | ZeroDivisionError: integer division or modulo by zero |
|
566 | 566 | |
|
567 | 567 | [1:execute]: |
|
568 | 568 | --------------------------------------------------------------------------- |
|
569 |
ZeroDivisionError Traceback (most recent call last) |
|
|
569 | ZeroDivisionError Traceback (most recent call last) | |
|
570 | 570 | ----> 1 1/0 |
|
571 | 571 | ZeroDivisionError: integer division or modulo by zero |
|
572 | 572 | |
|
573 | 573 | [2:execute]: |
|
574 | 574 | --------------------------------------------------------------------------- |
|
575 |
ZeroDivisionError Traceback (most recent call last) |
|
|
575 | ZeroDivisionError Traceback (most recent call last) | |
|
576 | 576 | ----> 1 1/0 |
|
577 | 577 | ZeroDivisionError: integer division or modulo by zero |
|
578 | 578 | |
|
579 | 579 | [3:execute]: |
|
580 | 580 | --------------------------------------------------------------------------- |
|
581 |
ZeroDivisionError Traceback (most recent call last) |
|
|
581 | ZeroDivisionError Traceback (most recent call last) | |
|
582 | 582 | ----> 1 1/0 |
|
583 | 583 | ZeroDivisionError: integer division or modulo by zero |
|
584 | 584 | |
@@ -595,7 +595,7 b' If you want, you can even raise one of these original exceptions:' | |||
|
595 | 595 | ....: |
|
596 | 596 | ....: |
|
597 | 597 | --------------------------------------------------------------------------- |
|
598 |
ZeroDivisionError Traceback (most recent call last) |
|
|
598 | ZeroDivisionError Traceback (most recent call last) | |
|
599 | 599 | ----> 1 1/0 |
|
600 | 600 | ZeroDivisionError: integer division or modulo by zero |
|
601 | 601 | |
@@ -608,25 +608,25 b' instance:' | |||
|
608 | 608 | In [81]: dview.execute('1/0') |
|
609 | 609 | [0:execute]: |
|
610 | 610 | --------------------------------------------------------------------------- |
|
611 |
ZeroDivisionError Traceback (most recent call last) |
|
|
611 | ZeroDivisionError Traceback (most recent call last) | |
|
612 | 612 | ----> 1 1/0 |
|
613 | 613 | ZeroDivisionError: integer division or modulo by zero |
|
614 | 614 | |
|
615 | 615 | [1:execute]: |
|
616 | 616 | --------------------------------------------------------------------------- |
|
617 |
ZeroDivisionError Traceback (most recent call last) |
|
|
617 | ZeroDivisionError Traceback (most recent call last) | |
|
618 | 618 | ----> 1 1/0 |
|
619 | 619 | ZeroDivisionError: integer division or modulo by zero |
|
620 | 620 | |
|
621 | 621 | [2:execute]: |
|
622 | 622 | --------------------------------------------------------------------------- |
|
623 |
ZeroDivisionError Traceback (most recent call last) |
|
|
623 | ZeroDivisionError Traceback (most recent call last) | |
|
624 | 624 | ----> 1 1/0 |
|
625 | 625 | ZeroDivisionError: integer division or modulo by zero |
|
626 | 626 | |
|
627 | 627 | [3:execute]: |
|
628 | 628 | --------------------------------------------------------------------------- |
|
629 |
ZeroDivisionError Traceback (most recent call last) |
|
|
629 | ZeroDivisionError Traceback (most recent call last) | |
|
630 | 630 | ----> 1 1/0 |
|
631 | 631 | ZeroDivisionError: integer division or modulo by zero |
|
632 | 632 | |
@@ -654,11 +654,31 b' instance:' | |||
|
654 | 654 | ipdb> e.print_traceback(1) |
|
655 | 655 | [1:execute]: |
|
656 | 656 | --------------------------------------------------------------------------- |
|
657 |
ZeroDivisionError Traceback (most recent call last) |
|
|
657 | ZeroDivisionError Traceback (most recent call last) | |
|
658 | 658 | ----> 1 1/0 |
|
659 | 659 | ZeroDivisionError: integer division or modulo by zero |
|
660 | 660 | |
|
661 | 661 | |
|
662 | Since you might have 100 engines, you probably don't want to see 100 tracebacks | |
|
663 | for a simple NameError because of a typo. | |
|
664 | For this reason, CompositeError truncates the list of exceptions it will print | |
|
665 | to :attr:`CompositeError.tb_limit` (default is five). | |
|
666 | You can change this limit to suit your needs with: | |
|
667 | ||
|
668 | .. sourcecode:: ipython | |
|
669 | ||
|
670 | In [20]: from IPython.parallel import CompositeError | |
|
671 | In [21]: CompositeError.tb_limit = 1 | |
|
672 | In [22]: %px a=b | |
|
673 | [0:execute]: | |
|
674 | --------------------------------------------------------------------------- | |
|
675 | NameError Traceback (most recent call last) | |
|
676 | ----> 1 a=b | |
|
677 | NameError: name 'b' is not defined | |
|
678 | ||
|
679 | ... 3 more exceptions ... | |
|
680 | ||
|
681 | ||
|
662 | 682 | All of this same error handling magic even works in non-blocking mode: |
|
663 | 683 | |
|
664 | 684 | .. sourcecode:: ipython |
@@ -670,25 +690,8 b' All of this same error handling magic even works in non-blocking mode:' | |||
|
670 | 690 | In [85]: ar.get() |
|
671 | 691 | [0:execute]: |
|
672 | 692 | --------------------------------------------------------------------------- |
|
673 |
ZeroDivisionError Traceback (most recent call last) |
|
|
674 | ----> 1 1/0 | |
|
675 | ZeroDivisionError: integer division or modulo by zero | |
|
676 | ||
|
677 | [1:execute]: | |
|
678 | --------------------------------------------------------------------------- | |
|
679 | ZeroDivisionError Traceback (most recent call last)<ipython-input-1-05c9758a9c21> in <module>() | |
|
680 | ----> 1 1/0 | |
|
681 | ZeroDivisionError: integer division or modulo by zero | |
|
682 | ||
|
683 | [2:execute]: | |
|
684 | --------------------------------------------------------------------------- | |
|
685 | ZeroDivisionError Traceback (most recent call last)<ipython-input-1-05c9758a9c21> in <module>() | |
|
686 | ----> 1 1/0 | |
|
687 | ZeroDivisionError: integer division or modulo by zero | |
|
688 | ||
|
689 | [3:execute]: | |
|
690 | --------------------------------------------------------------------------- | |
|
691 | ZeroDivisionError Traceback (most recent call last)<ipython-input-1-05c9758a9c21> in <module>() | |
|
693 | ZeroDivisionError Traceback (most recent call last) | |
|
692 | 694 | ----> 1 1/0 |
|
693 | 695 | ZeroDivisionError: integer division or modulo by zero |
|
694 | 696 | |
|
697 | ... 3 more exceptions ... |
General Comments 0
You need to be logged in to leave comments.
Login now