Show More
@@ -568,239 +568,22 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
568 | 568 | SKIP = doctest.register_optionflag('SKIP') |
|
569 | 569 | |
|
570 | 570 | |
|
571 | class IPDocTestRunner(doctest.DocTestRunner): | |
|
572 | ||
|
573 | # Unfortunately, doctest uses a private method (__run) for the actual run | |
|
574 | # execution, so we can't cleanly override just that part. Instead, we have | |
|
575 | # to copy/paste the entire run() implementation so we can call our own | |
|
576 | # customized runner. | |
|
577 | ||
|
578 | #///////////////////////////////////////////////////////////////// | |
|
579 | # DocTest Running | |
|
580 | #///////////////////////////////////////////////////////////////// | |
|
581 | ||
|
582 | __LINECACHE_FILENAME_RE = re.compile(r'<doctest ' | |
|
583 | r'(?P<name>[\w\.]+)' | |
|
584 | r'\[(?P<examplenum>\d+)\]>$') | |
|
585 | ||
|
586 | def __patched_linecache_getlines(self, filename, module_globals=None): | |
|
587 | m = self.__LINECACHE_FILENAME_RE.match(filename) | |
|
588 | if m and m.group('name') == self.test.name: | |
|
589 | example = self.test.examples[int(m.group('examplenum'))] | |
|
590 | return example.source.splitlines(True) | |
|
591 | else: | |
|
592 | return self.save_linecache_getlines(filename, module_globals) | |
|
593 | ||
|
594 | ||
|
595 | def _run_ip(self, test, compileflags, out): | |
|
571 | class IPDocTestRunner(doctest.DocTestRunner,object): | |
|
572 | """Test runner that synchronizes the IPython namespace with test globals. | |
|
596 | 573 |
|
|
597 | Run the examples in `test`. Write the outcome of each example | |
|
598 | with one of the `DocTestRunner.report_*` methods, using the | |
|
599 | writer function `out`. `compileflags` is the set of compiler | |
|
600 | flags that should be used to execute examples. Return a tuple | |
|
601 | `(f, t)`, where `t` is the number of examples tried, and `f` | |
|
602 | is the number of examples that failed. The examples are run | |
|
603 | in the namespace `test.globs`. | |
|
604 | """ | |
|
605 | ||
|
606 | #print 'Custom ip runner! __run' # dbg | |
|
607 | ||
|
608 | # Keep track of the number of failures and tries. | |
|
609 | failures = tries = 0 | |
|
610 | ||
|
611 | # Save the option flags (since option directives can be used | |
|
612 | # to modify them). | |
|
613 | original_optionflags = self.optionflags | |
|
614 | ||
|
615 | SUCCESS, FAILURE, BOOM = range(3) # `outcome` state | |
|
616 | ||
|
617 | check = self._checker.check_output | |
|
618 | ||
|
619 | # Process each example. | |
|
620 | for examplenum, example in enumerate(test.examples): | |
|
621 | ||
|
622 | # If REPORT_ONLY_FIRST_FAILURE is set, then supress | |
|
623 | # reporting after the first failure. | |
|
624 | quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and | |
|
625 | failures > 0) | |
|
626 | ||
|
627 | # Merge in the example's options. | |
|
628 | self.optionflags = original_optionflags | |
|
629 | if example.options: | |
|
630 | for (optionflag, val) in example.options.items(): | |
|
631 | if val: | |
|
632 | self.optionflags |= optionflag | |
|
633 | else: | |
|
634 | self.optionflags &= ~optionflag | |
|
635 | ||
|
636 | # If 'SKIP' is set, then skip this example. | |
|
637 | if self.optionflags & SKIP: | |
|
638 | continue | |
|
639 | ||
|
640 | # Record that we started this example. | |
|
641 | tries += 1 | |
|
642 | if not quiet: | |
|
643 | self.report_start(out, test, example) | |
|
644 | ||
|
645 | # Use a special filename for compile(), so we can retrieve | |
|
646 | # the source code during interactive debugging (see | |
|
647 | # __patched_linecache_getlines). | |
|
648 | filename = '<doctest %s[%d]>' % (test.name, examplenum) | |
|
649 | ||
|
650 | # Run the example in the given context (globs), and record | |
|
651 | # any exception that gets raised. (But don't intercept | |
|
652 | # keyboard interrupts.) | |
|
653 | try: | |
|
654 | # Don't blink! This is where the user's code gets run. | |
|
655 | ||
|
656 | # Hack: ipython needs access to the execution context of the | |
|
657 | # example, so that it can propagate user variables loaded by | |
|
658 | # %run into test.globs. We put them here into our modified | |
|
659 | # %run as a function attribute. Our new %run will then only | |
|
660 | # make the namespace update when called (rather than | |
|
661 | # unconconditionally updating test.globs here for all examples, | |
|
662 | # most of which won't be calling %run anyway). | |
|
663 | _run_ns_sync.test_globs = test.globs | |
|
664 | ||
|
665 | exec compile(example.source, filename, "single", | |
|
666 | compileflags, 1) in test.globs | |
|
667 | self.debugger.set_continue() # ==== Example Finished ==== | |
|
668 | exception = None | |
|
669 | except KeyboardInterrupt: | |
|
670 | raise | |
|
671 | except: | |
|
672 | exception = sys.exc_info() | |
|
673 | self.debugger.set_continue() # ==== Example Finished ==== | |
|
674 | ||
|
675 | got = self._fakeout.getvalue() # the actual output | |
|
676 | self._fakeout.truncate(0) | |
|
677 | outcome = FAILURE # guilty until proved innocent or insane | |
|
678 | ||
|
679 | # If the example executed without raising any exceptions, | |
|
680 | # verify its output. | |
|
681 | if exception is None: | |
|
682 | if check(example.want, got, self.optionflags): | |
|
683 | outcome = SUCCESS | |
|
684 | ||
|
685 | # The example raised an exception: check if it was expected. | |
|
686 | else: | |
|
687 | exc_info = sys.exc_info() | |
|
688 | exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] | |
|
689 | if not quiet: | |
|
690 | got += _exception_traceback(exc_info) | |
|
691 | ||
|
692 | # If `example.exc_msg` is None, then we weren't expecting | |
|
693 | # an exception. | |
|
694 | if example.exc_msg is None: | |
|
695 | outcome = BOOM | |
|
696 | ||
|
697 | # We expected an exception: see whether it matches. | |
|
698 | elif check(example.exc_msg, exc_msg, self.optionflags): | |
|
699 | outcome = SUCCESS | |
|
700 | ||
|
701 | # Another chance if they didn't care about the detail. | |
|
702 | elif self.optionflags & IGNORE_EXCEPTION_DETAIL: | |
|
703 | m1 = re.match(r'[^:]*:', example.exc_msg) | |
|
704 | m2 = re.match(r'[^:]*:', exc_msg) | |
|
705 | if m1 and m2 and check(m1.group(0), m2.group(0), | |
|
706 | self.optionflags): | |
|
707 | outcome = SUCCESS | |
|
708 | ||
|
709 | # Report the outcome. | |
|
710 | if outcome is SUCCESS: | |
|
711 | if not quiet: | |
|
712 | self.report_success(out, test, example, got) | |
|
713 | elif outcome is FAILURE: | |
|
714 | if not quiet: | |
|
715 | self.report_failure(out, test, example, got) | |
|
716 | failures += 1 | |
|
717 | elif outcome is BOOM: | |
|
718 | if not quiet: | |
|
719 | self.report_unexpected_exception(out, test, example, | |
|
720 | exc_info) | |
|
721 | failures += 1 | |
|
722 | else: | |
|
723 | assert False, ("unknown outcome", outcome) | |
|
724 | ||
|
725 | # Restore the option flags (in case they were modified) | |
|
726 | self.optionflags = original_optionflags | |
|
727 | ||
|
728 | # Record and return the number of failures and tries. | |
|
729 | ||
|
730 | # Hack to access a parent private method by working around Python's | |
|
731 | # name mangling (which is fortunately simple). | |
|
732 | #self.__record_outcome(test, failures, tries) | |
|
733 | doctest.DocTestRunner._DocTestRunner__record_outcome(self,test, | |
|
734 | failures, tries) | |
|
735 | ||
|
736 | return failures, tries | |
|
737 | ||
|
738 | ||
|
739 | # Unfortunately doctest has chosen to implement a couple of key methods as | |
|
740 | # private (__run, in particular). We are forced to copy the entire run | |
|
741 | # method here just so we can override that one. Ugh. | |
|
742 | 574 | |
|
743 | 575 | def run(self, test, compileflags=None, out=None, clear_globs=True): |
|
744 | """ | |
|
745 | Run the examples in `test`, and display the results using the | |
|
746 | writer function `out`. | |
|
747 | ||
|
748 | The examples are run in the namespace `test.globs`. If | |
|
749 | `clear_globs` is true (the default), then this namespace will | |
|
750 | be cleared after the test runs, to help with garbage | |
|
751 | collection. If you would like to examine the namespace after | |
|
752 | the test completes, then use `clear_globs=False`. | |
|
753 | ||
|
754 | `compileflags` gives the set of flags that should be used by | |
|
755 | the Python compiler when running the examples. If not | |
|
756 | specified, then it will default to the set of future-import | |
|
757 | flags that apply to `globs`. | |
|
758 | ||
|
759 | The output of each example is checked using | |
|
760 | `DocTestRunner.check_output`, and the results are formatted by | |
|
761 | the `DocTestRunner.report_*` methods. | |
|
762 | """ | |
|
763 | #print 'Custom ip runner!' # dbg | |
|
764 | ||
|
765 | self.test = test | |
|
766 | ||
|
767 | if compileflags is None: | |
|
768 | compileflags = _extract_future_flags(test.globs) | |
|
769 | ||
|
770 | save_stdout = sys.stdout | |
|
771 | if out is None: | |
|
772 | out = save_stdout.write | |
|
773 | sys.stdout = self._fakeout | |
|
774 | 576 | |
|
775 | # Patch pdb.set_trace to restore sys.stdout during interactive | |
|
776 | # debugging (so it's not still redirected to self._fakeout). | |
|
777 | # Note that the interactive output will go to *our* | |
|
778 | # save_stdout, even if that's not the real sys.stdout; this | |
|
779 | # allows us to write test cases for the set_trace behavior. | |
|
780 | save_set_trace = pdb.set_trace | |
|
781 | self.debugger = _OutputRedirectingPdb(save_stdout) | |
|
782 | self.debugger.reset() | |
|
783 | pdb.set_trace = self.debugger.set_trace | |
|
784 | ||
|
785 | # Patch linecache.getlines, so we can see the example's source | |
|
786 | # when we're inside the debugger. | |
|
787 | self.save_linecache_getlines = linecache.getlines | |
|
788 | linecache.getlines = self.__patched_linecache_getlines | |
|
577 | # Hack: ipython needs access to the execution context of the example, | |
|
578 | # so that it can propagate user variables loaded by %run into | |
|
579 | # test.globs. We put them here into our modified %run as a function | |
|
580 | # attribute. Our new %run will then only make the namespace update | |
|
581 | # when called (rather than unconconditionally updating test.globs here | |
|
582 | # for all examples, most of which won't be calling %run anyway). | |
|
583 | _run_ns_sync.test_globs = test.globs | |
|
789 | 584 | |
|
790 | try: | |
|
791 | # Hack to access a parent private method by working around Python's | |
|
792 | # name mangling (which is fortunately simple). | |
|
793 | #return self.__run(test, compileflags, out) | |
|
794 | return self._run_ip(test, compileflags, out) | |
|
795 | #return doctest.DocTestRunner._DocTestRunner__run(self,test, | |
|
796 | # compileflags, out) | |
|
797 | finally: | |
|
798 | _ip.user_ns.update(test.globs) | |
|
799 | sys.stdout = save_stdout | |
|
800 | pdb.set_trace = save_set_trace | |
|
801 | linecache.getlines = self.save_linecache_getlines | |
|
802 | if clear_globs: | |
|
803 | test.globs.clear() | |
|
585 | return super(IPDocTestRunner,self).run(test, | |
|
586 | compileflags,out,clear_globs) | |
|
804 | 587 | |
|
805 | 588 | |
|
806 | 589 | class DocFileCase(doctest.DocFileCase): |
General Comments 0
You need to be logged in to leave comments.
Login now