##// END OF EJS Templates
Vastly cleaner solution for the namespace problem!
Fernando Perez -
Show More
@@ -568,239 +568,22 b' class IPDocTestParser(doctest.DocTestParser):'
568 SKIP = doctest.register_optionflag('SKIP')
568 SKIP = doctest.register_optionflag('SKIP')
569
569
570
570
571 class IPDocTestRunner(doctest.DocTestRunner):
571 class IPDocTestRunner(doctest.DocTestRunner,object):
572
572 """Test runner that synchronizes the IPython namespace with test globals.
573 # Unfortunately, doctest uses a private method (__run) for the actual run
573 """
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):
596 """
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 def run(self, test, compileflags=None, out=None, clear_globs=True):
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
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
789
576
790 try:
577 # Hack: ipython needs access to the execution context of the example,
791 # Hack to access a parent private method by working around Python's
578 # so that it can propagate user variables loaded by %run into
792 # name mangling (which is fortunately simple).
579 # test.globs. We put them here into our modified %run as a function
793 #return self.__run(test, compileflags, out)
580 # attribute. Our new %run will then only make the namespace update
794 return self._run_ip(test, compileflags, out)
581 # when called (rather than unconconditionally updating test.globs here
795 #return doctest.DocTestRunner._DocTestRunner__run(self,test,
582 # for all examples, most of which won't be calling %run anyway).
796 # compileflags, out)
583 _run_ns_sync.test_globs = test.globs
797 finally:
584
798 _ip.user_ns.update(test.globs)
585 return super(IPDocTestRunner,self).run(test,
799 sys.stdout = save_stdout
586 compileflags,out,clear_globs)
800 pdb.set_trace = save_set_trace
801 linecache.getlines = self.save_linecache_getlines
802 if clear_globs:
803 test.globs.clear()
804
587
805
588
806 class DocFileCase(doctest.DocFileCase):
589 class DocFileCase(doctest.DocFileCase):
General Comments 0
You need to be logged in to leave comments. Login now