Ticket #13610: 13610.patch

File 13610.patch, 5.7 KB (added by roed, 7 years ago)
  • sage/doctest/control.py

    # HG changeset patch
    # User David Roe <roed.math@gmail.com>
    # Date 1350460030 21600
    # Node ID bd3657429ed38fff5e43320f2cd567dc39e69d23
    # Parent  b490b4633c02fa95fe9978d8c7738755751c608e
    Adds a feature to doctesting code that can drop a user into a debug prompt when a doctest fails.
    
    diff --git a/sage/doctest/control.py b/sage/doctest/control.py
    a b  
    867867    # We need the following if we're not in DOCTEST_MODE
    868868    # Tell IPython to avoid colors: it screws up the output checking.
    869869    if not save_dtmode:
     870        if options.debug:
     871            raise ValueError("You should not try to run doctests with a debugger from within Sage: IPython objects to embedded shells")
    870872        IP = get_ipython()
    871873        old_color = IP.colors
    872874        IP.run_line_magic('colors','NoColor')
  • sage/doctest/forker.py

    diff --git a/sage/doctest/forker.py b/sage/doctest/forker.py
    a b  
    10071007                1764
    10081008            Got:
    10091009                BAD ANSWER
     1010
     1011        TESTS:
     1012
     1013        If debugging is turned on this function starts an IPython
     1014        prompt when a test returns an incorrect answer::
     1015
     1016            sage: import os
     1017            sage: os.environ['SAGE_PEXPECT_LOG'] = "1"
     1018            sage: sage0.quit()
     1019            sage: _ = sage0.eval("import doctest, sys, os, multiprocessing, subprocess")
     1020            sage: _ = sage0.eval("from sage.doctest.parsing import SageOutputChecker")
     1021            sage: _ = sage0.eval("import sage.doctest.forker as sdf")
     1022            sage: _ = sage0.eval("from sage.doctest.control import DocTestDefaults")
     1023            sage: _ = sage0.eval("DD = DocTestDefaults(debug=True)")
     1024            sage: _ = sage0.eval("ex1 = doctest.Example('a = 17', '')")
     1025            sage: _ = sage0.eval("ex2 = doctest.Example('2*a', '1')")
     1026            sage: _ = sage0.eval("DT = doctest.DocTest([ex1,ex2], globals(), 'doubling', None, 0, None)")
     1027            sage: _ = sage0.eval("DTR = sdf.SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS)")
     1028            sage: sage0._prompt = r"debug: "
     1029            sage: print sage0.eval("DTR.run(DT, clear_globs=False)") # indirect doctest
     1030            **********************************************************************
     1031            Line 1, in doubling
     1032            Failed example:
     1033                2*a
     1034            Expected:
     1035                1
     1036            Got:
     1037                34
     1038            ********************************************************************************
     1039            Previously executed commands:
     1040            ...
     1041            sage: sage0.eval("a")
     1042            '...17'
     1043            sage: sage0._prompt = "sage: "
     1044            sage: sage0.eval("quit")
     1045            'Returning to doctests...TestResults(failed=1, attempted=2)'
    10101046        """
    10111047        if not self.options.initial or self.no_failure_yet:
    10121048            self.no_failure_yet = False
    1013             doctest.DocTestRunner.report_failure(self, out, test, example, got)
     1049            returnval = doctest.DocTestRunner.report_failure(self, out, test, example, got)
     1050            if self.options.debug:
     1051                self._fakeout.stop_spoofing()
     1052                restore_tcpgrp = None
     1053                try:
     1054                    if os.isatty(0):
     1055                        # In order to read from the terminal, we need
     1056                        # to make the current process group the
     1057                        # foreground group.
     1058                        restore_tcpgrp = os.tcgetpgrp(0)
     1059                        signal.signal(signal.SIGTTIN, signal.SIG_IGN)
     1060                        signal.signal(signal.SIGTTOU, signal.SIG_IGN)
     1061                        os.tcsetpgrp(0, os.getpgrp())
     1062                    print("*" * 80)
     1063                    print("Previously executed commands:")
     1064                    for ex in test.examples:
     1065                        if ex is example:
     1066                            break
     1067                        if hasattr(ex, 'sage_source'):
     1068                            src = '    sage: ' + ex.sage_source
     1069                        else:
     1070                            src = '    sage: ' + ex.source
     1071                        if src[-1] == '\n':
     1072                            src = src[:-1]
     1073                        src = src.replace('\n', '\n    ....: ')
     1074                        print(src)
     1075                        if ex.want:
     1076                            print(doctest._indent(ex.want[:-1]))
     1077                    from sage.misc.interpreter import DEFAULT_SAGE_CONFIG
     1078                    from IPython import embed
     1079                    cfg = DEFAULT_SAGE_CONFIG.copy()
     1080                    prompt_config = cfg.PromptManager
     1081                    prompt_config.in_template = 'debug: '
     1082                    prompt_config.in2_template = '.....: '
     1083                    embed(config=cfg, banner1='', user_ns=dict(globs))
     1084                except KeyboardInterrupt:
     1085                    # Assume this is a *real* interrupt. We need to
     1086                    # escalate this to the master docbuilding process.
     1087                    if not self.options.serial:
     1088                        os.kill(os.getppid(), signal.SIGINT)
     1089                    raise
     1090                finally:
     1091                    # Restore the foreground process group.
     1092                    if restore_tcpgrp is not None:
     1093                        os.tcsetpgrp(0, restore_tcpgrp)
     1094                        signal.signal(signal.SIGTTIN, signal.SIG_DFL)
     1095                        signal.signal(signal.SIGTTOU, signal.SIG_DFL)
     1096                    print("Returning to doctests...")
     1097                    self._fakeout.start_spoofing()
     1098            return returnval
    10141099
    10151100    def report_overtime(self, out, test, example, got):
    10161101        """