Ticket #12415: 12415_review3.patch

File 12415_review3.patch, 37.5 KB (added by jdemeyer, 7 years ago)
  • doc/en/developer/conventions.rst

    # HG changeset patch
    # User Jeroen Demeyer <jdemeyer@cage.ugent.be>
    # Date 1362220623 -3600
    # Node ID c6c02a8ef10cd6ad04a7ebbebe6d7e835c4b7e17
    # Parent  bb609b0fd8a6e37c038ae783509cfe009d52d7a9
    More review changes to the doctesting framework
    
    diff --git a/doc/en/developer/conventions.rst b/doc/en/developer/conventions.rst
    a b  
    752752   framework.
    753753
    754754-  If a line contains the text ``long time`` then that line is not
    755    tested unless the ``-long`` option is given, e.g.
    756    ``sage -t -long f.py``. Use this to include examples that take more
     755   tested unless the ``--long`` option is given, e.g.
     756   ``sage -t --long f.py``. Use this to include examples that take more
    757757   than about a second to run. These will not be run regularly during
    758758   Sage development, but will get run before major releases. No
    759759   example should take more than about 30 seconds.
     
    830830   It is also immediately clear to the user that the indicated example
    831831   does not currently work.
    832832
    833 - If a line contains the text ``optional``, it is not tested unless
    834   either the ``--optional`` flag or the ``--only-optional`` flag is
    835   passed to ``sage -t``.  Mark a doctest as ``optional`` if it
    836   requires optional packages; even better, mark it as ``optional -
    837   PKG_NAME`` if it requires the package ``PKG_NAME``.  Running ``sage
    838   -t --optional f.py`` executes all doctests, including those marked
    839   as ``optional``.  Running ``sage -t --only-optional=sloane_database
    840   f.py`` runs only those doctests marked as ``# optional -
    841   sloane_database``.  For example, the file
     833- If a line contains ``# optional - PKGNAME`` (where the ``#`` may be any
     834  non-letter non-space character), it is not tested unless
     835  the ``--optional=PKGNAME`` flag is passed to ``sage -t``.
     836  Mark a doctest as ``optional`` if it requires optional packages.
     837  Running ``sage -t --optional=all f.py`` executes all doctests,
     838  including all optional tests.
     839  Running ``sage -t --optional=sage,sloane_database f.py`` runs the
     840  normal tests (because of ``--optional=sage``),
     841  as well as those marked as ``# optional - sloane_database``.
     842  For example, the file
    842843  ``SAGE_ROOT/devel/sage/sage/databases/sloane.py`` contains the lines
    843844
    844845  ::
    845846
    846847       sage: sloane_sequence(60843)       # optional - internet
    847848
    848   and
    849 
    850   ::
     849  and ::
    851850
    852851       sage: SloaneEncyclopedia[60843]    # optional - sloane_database
    853852
    854853  The first of these just needs internet access, while the second
    855854  requires that the "sloane_database" package be installed.  Calling
    856   ``sage -t --optional`` on this file runs both of these tests, while
    857   calling ``sage -t --only-optional=internet`` on it will only run the first
    858   test.  A test requiring several packages would be marked
    859   ``optional - pkg1 pkg2`` and executed by ``sage -t
    860   --only-optional=pkg1,pkg2 f.py``.
     855  ``sage -t --optional=all`` on this file runs both of these tests, while
     856  calling ``sage -t --optional=sage,internet`` on it will only run the
     857  first test.
     858  A test requiring several packages should be marked
     859  ``# optional - pkg1 pkg2`` and executed by
     860  ``sage -t --optional=sage,pkg1,pkg2 f.py``.
    861861
    862862  .. NOTE::
    863863
    864       Any text after ``optional`` is interpreted as a list of package
    865       names, separated by spaces, although the words "needs" and
    866       "requires" are ignored.  Colons, periods, commas, and hyphens
    867       are also ignored, and all text is converted to lower case.
    868       Therefore if the doctest is marked ``optional: needs package
    869       CHomP``, then it would be run by ``sage -t --optional f.py`` or
    870       ``sage -t --only-optional=chomp,package f.py``.  This is
    871       probably not what was intended: the doctest should have been
    872       labeled ``optional: needs CHomP`` or just ``optional: chomp``.
     864      Any words after ``# optional`` are
     865      interpreted as a list of package names, separated by spaces.
     866      Any punctuation (periods, commas, hyphens, semicolons, ...)
     867      after the first word ends the list of packages.
     868      Hyphens or colons between the word ``optional`` and the first
     869      package name are allowed.
     870      Also, all text is converted to lower case.
     871      Therefore, you should not write
     872      ``optional: needs package CHomP`` but simply ``optional: CHomP``.
    873873
    874874- If you are documenting a known bug in Sage, mark it as ``known bug``
    875875  or ``optional: bug``.  For example::
     
    880880        5
    881881
    882882  Then the doctest will be skipped by default, but could be revealed
    883   by running ``sage -t --only-optional=bug ...``.  (A doctest marked
    884   as ``known bug`` gets automatically converted to ``optional bug``,
    885   so it is also detected by ``--optional`` or  ``--only-optional=bug``.)
    886 
    887 -  If the entire documentation string contains all three words
    888    ``optional``, ``package``, and ``installed``, then the entire
    889    documentation string is not executed unless the ``--optional`` flag
    890    is passed to ``sage -t``. This is useful for a long sequence of
    891    examples that all require that an optional package be installed.
     883  by running ``sage -t --optional=sage,bug ...``.  (A doctest marked
     884  as ``known bug`` gets automatically converted to ``optional bug``).
    892885
    893886Using ``search_src`` from the Sage prompt (or ``grep``), one can
    894887easily find the aforementioned keywords. In the case of
     
    924917
    925918      sage -t [--verbose] [--optional]  [files and directories ... ]
    926919
    927 When you run ``sage -t <filename.py>``, Sage makes a copy of
    928 ``<filename.py>`` with all the ``sage`` prompts replaced by ``>>>``,
    929 then uses the standard Python doctest framework to test the
    930 documentation. More precisely, the Python script
    931 ``SAGE_LOCAL/bin/sage-doctest`` implements documentation testing, and it
    932 does the following when asked to test a file ``foo.py`` or
    933 ``foo.sage``.
     920The Sage doctesting framework is based on the standard Python doctest
     921module, but with many additional features (such as parallel testing,
     922timeouts, optional tests).
     923The Sage doctester recognizes ``sage:`` prompts
     924as well as ``>>>`` prompts.
     925It also preparses the doctests, just like in interactive Sage sessions.
    934926
    935 #. Create the directory given by the environment variable
    936    :envvar:`SAGE_TESTDIR` if it does not already exist. By default,
    937    this variable points to ``$DOT_SAGE/tmp``, and ``$DOT_SAGE`` has
    938    the default value of ``~/.sage``. See the `Sage Installation Guide
    939    <http://sagemath.org/doc/installation/source.html#environment-variables>`_
    940    for full descriptions of the environment variables used by Sage.
     927Your file passes the tests if the code in it will run when entered
     928at the ``sage:`` prompt with no extra imports. Thus users are
     929guaranteed to be able to exactly copy code out of the examples you
     930write for the documentation and have them work.
    941931
    942 #. If doctesting ``foo.py``: if it is not a file from the Sage
    943    library, then copy it to ``$SAGE_TESTDIR/foo_PID_orig.py``, where
    944    ``PID`` is the id number of the testing process. (This new name is
    945    intended to avoid possible race conditions: you can safely doctest
    946    the same file simultaneously in several different windows.)
    947    Regardless, create a file ``$SAGE_TESTDIR/foo_PID.py``.
    948 
    949 #. If doctesting ``foo.sage`` (necessarily a non-Sage library file),
    950    then copy it to ``$SAGE_TESTDIR/foo_PID.sage`` and preparse it to
    951    create a file ``$SAGE_TESTDIR/foo_PID_preparsed.py``. Also create a
    952    file ``$SAGE_TESTDIR/foo_PID.py``.
    953 
    954 #. The file ``$SAGE_TESTDIR/foo_PID.py`` contains functions for each
    955    docstring in ``foo.py`` or ``foo.sage``, but with ``from sage.all
    956    import *`` at the top. For non-library files, it also imports
    957    ``foo_PID_orig.py`` or ``foo_PID_preparsed.py``.  Each function's
    958    documentation is standard Python with ``>>>`` prompts, along with
    959    annotations giving information like its location in the original
    960    file. For example, a doctest like ::
    961 
    962        sage: 2+4
    963        6
    964 
    965    might get translated to
    966 
    967        >>> Integer(2)+Integer(4)###line 4:_sage_    >>> 2+4
    968        6
    969 
    970 #. The script ``SAGE_LOCAL/bin/sage-doctest`` then runs Sage's Python
    971    interpreter on ``$SAGE_TESTDIR/foo_PID.py``.
    972 
    973 Your file passes these tests if the code in it will run when entered
    974 at the ``sage:`` prompt with no special imports. Thus users are
    975 guaranteed to be able to exactly copy code out of the examples you
    976 write for the documentation and have them work. If all tests pass,
    977 then these temporary files are deleted; if tests fail, then the files
    978 are kept.
    979 
    980 (If doctesting many files in parallel using ``sage -tp ...`` -- see
    981 :ref:`chapter-doctesting` -- then all of this is done in a further
    982 subdirectory of ``$SAGE_TESTDIR`` with a name like
    983 ``sage.math.washington.edu-10345``: the name has the form
    984 ``HOSTNAME-PID``, where ``PID`` is the id of the main testing
    985 process.)
    986 
     932For more information, see :ref:`chapter-doctesting`.
    987933
    988934Testing ReST documentation
    989935--------------------------
    990936
    991937Run ``sage -t <filename.rst>`` to test the examples in verbatim
    992 environments in ReST documentation.  Sage creates a file
    993 ``.doctest_filename.py`` and tests it just as for ``.py``, ``.pyx``
    994 and ``.sage`` files.
     938environments in ReST documentation.
    995939
    996940Of course in ReST files, one often inserts explanatory texts between
    997941different verbatim environments. To link together verbatim
  • doc/en/developer/doctesting.rst

    diff --git a/doc/en/developer/doctesting.rst b/doc/en/developer/doctesting.rst
    a b  
    510510management or patching the main Sage library, a release manager would
    511511parallel test the library using 10 threads with the following command::
    512512
    513     [jdemeyer@sage sage-5.9]$ ./sage -tp 10 -long devel/sage-main/
     513    [jdemeyer@sage sage-5.9]$ ./sage -tp 10 --long devel/sage-main/
    514514
    515515Another way is run ``make ptestlong``, which builds Sage (if necessary),
    516516builds the Sage documentation (if necessary), and then runs parallel
     
    555555  * ``SAGE_ROOT/devel/sage/doc/fr``
    556556
    557557  and then the Sage library. Doctesting is run with the optional
    558   argument ``-long``. See the file ``SAGE_ROOT/Makefile`` for further
     558  argument ``--long``. See the file ``SAGE_ROOT/Makefile`` for further
    559559  details.
    560560
    561561* ``make ptest`` --- Similar to the commands ``make test`` and ``make
     
    563563  described above for ``make ptestlong``.
    564564
    565565* ``make ptestlong`` --- Similar to the command ``make ptest``, but
    566   using the optional argument ``-long`` for doctesting.
     566  using the optional argument ``--long`` for doctesting.
    567567
    568568
    569569Beyond the Sage library
  • sage/doctest/control.py

    diff --git a/sage/doctest/control.py b/sage/doctest/control.py
    a b  
    517517            Doctesting 1 file.
    518518            sage -t .../sage/rings/homset.py
    519519                [... tests, ... s]
    520             ------------------------------------------------------------------------
     520            ----------------------------------------------------------------------
    521521            All tests passed!
    522             ------------------------------------------------------------------------
     522            ----------------------------------------------------------------------
    523523            Total time for all tests: ... seconds
    524524                cpu time: ... seconds
    525525                cumulative wall time: ... seconds
    526 
    527526        """
    528527        nfiles = 0
    529528        nother = 0
     
    535534        if self.sources:
    536535            filestr = ", ".join(([count_noun(nfiles, "file")] if nfiles else []) +
    537536                                ([count_noun(nother, "other source")] if nother else []))
    538             if self.options.nthreads > len(self.sources):
    539                 self.options.nthreads = len(self.sources)
    540537            threads = " using %s threads"%(self.options.nthreads) if self.options.nthreads > 1 else ""
    541538            iterations = []
    542539            if self.options.global_iterations > 1:
     
    595592             Doctesting 1 file.
    596593             sage -t .../rings/infinity.py
    597594                 [... tests, ... s]
    598              ------------------------------------------------------------------------
     595             ----------------------------------------------------------------------
    599596             All tests passed!
    600              ------------------------------------------------------------------------
     597             ----------------------------------------------------------------------
    601598             Total time for all tests: ... seconds
    602599                 cpu time: ... seconds
    603600                 cumulative wall time: ... seconds
     
    754751            Doctesting 1 file.
    755752            sage -t .../sage/sets/non_negative_integers.py
    756753                [... tests, ... s]
    757             ------------------------------------------------------------------------
     754            ----------------------------------------------------------------------
    758755            All tests passed!
    759             ------------------------------------------------------------------------
     756            ----------------------------------------------------------------------
    760757            Total time for all tests: ... seconds
    761758                cpu time: ... seconds
    762759                cumulative wall time: ... seconds
     
    797794        Doctesting 1 file.
    798795        sage -t .../sage/rings/infinity.py
    799796            [... tests, ... s]
    800         ------------------------------------------------------------------------
     797        ----------------------------------------------------------------------
    801798        All tests passed!
    802         ------------------------------------------------------------------------
     799        ----------------------------------------------------------------------
    803800        Total time for all tests: ... seconds
    804801            cpu time: ... seconds
    805802            cumulative wall time: ... seconds
  • sage/doctest/forker.py

    diff --git a/sage/doctest/forker.py b/sage/doctest/forker.py
    a b  
    6464    import sage.misc.displayhook
    6565    sys.displayhook = sage.misc.displayhook.DisplayHook(sys.displayhook)
    6666
    67     # Do this *before* forking, because importing readline from a
    68     # child process can screw up the terminal.
    69     import readline
    70 
    7167    # Workaround for https://github.com/sagemath/sagenb/pull/84
    7268    import sagenb.notebook.misc
    7369
     
    14451441                        log(follow.messages, end="")
    14461442                        follow.messages = ""
    14471443        finally:
     1444            # Restore SIGCHLD handler (which is to ignore the signal)
     1445            signal.signal(signal.SIGCHLD, signal.SIG_DFL)
     1446
     1447            # Kill all remaining workers (in case we got interrupted)
    14481448            for w in workers:
    14491449                try:
    1450                     print("Killing test", w.source.printpath)
    14511450                    w.kill()
    14521451                except Exception:
    14531452                    pass
     1453                else:
     1454                    print("Killing test", w.source.printpath)
    14541455            # Fork a child process with the specific purpose of
    14551456            # killing the remaining workers.
    14561457            if len(workers) > 0 and os.fork() == 0:
     
    14671468                    finally:
    14681469                        os._exit(0)
    14691470
    1470             # Hack to ensure multiprocessing leaves these processes alone
     1471            # Hack to ensure multiprocessing leaves these processes
     1472            # alone (in particular, it doesn't wait for them when we
     1473            # exit).
    14711474            multiprocessing.current_process()._children = set()
    14721475
    14731476    def dispatch(self):
     
    15581561            Doctesting 1 file.
    15591562            sage -t .../sage/rings/big_oh.py
    15601563                [... tests, ... s]
    1561             ------------------------------------------------------------------------
     1564            ----------------------------------------------------------------------
    15621565            All tests passed!
    1563             ------------------------------------------------------------------------
     1566            ----------------------------------------------------------------------
    15641567            Total time for all tests: ... seconds
    15651568                cpu time: ... seconds
    15661569                cumulative wall time: ... seconds
     
    16041607            Doctesting 1 file.
    16051608            sage -t .../sage/symbolic/units.py
    16061609                [... tests, ... s]
    1607             ------------------------------------------------------------------------
     1610            ----------------------------------------------------------------------
    16081611            All tests passed!
    1609             ------------------------------------------------------------------------
     1612            ----------------------------------------------------------------------
    16101613            Total time for all tests: ... seconds
    16111614                cpu time: ... seconds
    16121615                cumulative wall time: ... seconds
     
    16171620        for f in self.funclist:
    16181621            f()
    16191622
     1623        # Write one byte to the pipe to signal to the master process
     1624        # that we have started properly.
     1625        os.write(self.wmessages, "X")
     1626
    16201627        task = DocTestTask(self.source)
    16211628
    16221629        # Ensure the Python stdin is the actual stdin
     
    16691676        # write to the pipe).
    16701677        os.close(self.wmessages)
    16711678
     1679        # Read one byte from the pipe as a sign that the child process
     1680        # has properly started (to avoid race conditions). In particular,
     1681        # it will have its process group changed.
     1682        os.read(self.rmessages, 1)
     1683
    16721684    def read_messages(self):
    16731685        """
    16741686        In the master process, read from the pipe and store the data
     
    17551767            sage: from sage.doctest.sources import FileDocTestSource
    17561768            sage: from sage.doctest.reporting import DocTestReporter
    17571769            sage: from sage.doctest.control import DocTestController, DocTestDefaults
    1758             sage: filename = os.path.join(os.environ['SAGE_ROOT'],'devel','sage','sage','doctest','util.py')
     1770            sage: filename = os.path.join(os.environ['SAGE_ROOT'],'devel','sage','sage','doctest','tests','99seconds.rst')
    17591771            sage: DD = DocTestDefaults()
    17601772            sage: FDS = FileDocTestSource(filename,True,False,set(['sage']),None)
    1761             sage: W = DocTestWorker(FDS, DD)
     1773
     1774        We set up the worker to start by blocking ``SIGHUP``, such that
     1775        killing will fail initially::
     1776
     1777            sage: from sage.ext.pselect import PSelecter
     1778            sage: import signal
     1779            sage: def block_hup():
     1780            ....:     # We never __exit__()
     1781            ....:     PSelecter([signal.SIGHUP]).__enter__()
     1782            sage: W = DocTestWorker(FDS, DD, [block_hup])
    17621783            sage: W.start()
    1763             sage: time.sleep(0.05)
    17641784            sage: W.killed
    17651785            False
    17661786            sage: W.kill()
    17671787            sage: W.killed
    17681788            True
    1769             sage: try:
    1770             ....:     W.kill()
    1771             ....: except OSError:
    1772             ....:     pass
    1773             sage: time.sleep(0.1)
     1789            sage: time.sleep(0.2)  # Worker doesn't die
     1790            sage: W.kill()         # Worker dies now
     1791            sage: time.sleep(0.2)
    17741792            sage: W.is_alive()
    17751793            False
    17761794        """
     
    18111829        sage: DC = DocTestController(DD,[filename])
    18121830        sage: ntests, results = DTT(options=DD)
    18131831        sage: ntests
    1814         273
     1832        275
    18151833        sage: sorted(results.keys())
    18161834        ['cputime', 'err', 'failures', 'walltime']
    18171835    """
  • sage/doctest/reporting.py

    diff --git a/sage/doctest/reporting.py b/sage/doctest/reporting.py
    a b  
    194194
    195195            sage: DTR.report(FDS, True, 0, None, "Output so far...")
    196196                Time out
    197             ********************************************************************************
     197            **********************************************************************
    198198            Tests run before process timed out:
    199199            Output so far...
    200             ********************************************************************************
     200            **********************************************************************
    201201            sage: DTR.stats
    202202            {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}}
    203203
     
    205205
    206206            sage: DTR.report(FDS, False, 3, None, "Output before trouble")
    207207                Bad exit: 3
    208             ********************************************************************************
     208            **********************************************************************
    209209            Tests run before process failed:
    210210            Output before trouble
    211             ********************************************************************************
     211            **********************************************************************
    212212            sage: DTR.stats
    213213            {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}}
    214214
     
    217217            sage: import signal
    218218            sage: DTR.report(FDS, False, -signal.SIGSEGV, None, "Output before trouble")
    219219                Killed due to segmentation fault
    220             ********************************************************************************
     220            **********************************************************************
    221221            Tests run before process failed:
    222222            Output before trouble
    223             ********************************************************************************
     223            **********************************************************************
    224224            sage: DTR.stats
    225225            {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}}
    226226
     
    228228
    229229            sage: DTR.report(FDS, True, -signal.SIGKILL, (1,None), "Output before trouble")
    230230                Time out after testing finished (and interrupt failed)
    231             ********************************************************************************
     231            **********************************************************************
    232232            Tests run before process timed out:
    233233            Output before trouble
    234             ********************************************************************************
     234            **********************************************************************
    235235            sage: DTR.stats
    236236            {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}}
    237237
     
    239239
    240240            sage: DTR.report(FDS, False, 0, None, "All output")
    241241                Error in doctesting framework (bad result returned)
    242             ********************************************************************************
     242            **********************************************************************
    243243            Tests run before error:
    244244            All output
    245             ********************************************************************************
     245            **********************************************************************
    246246            sage: DTR.stats
    247247            {'sage.doctest.reporting': {'failed': True, 'walltime': 1000000.0}}
    248248
     
    292292                        fail_msg += " (and interrupt failed)"
    293293                    else:
    294294                        fail_msg += " (with %s after interrupt)"%signal_name(-return_code)
    295                 log("    %s\n%s\nTests run before process timed out:"%(fail_msg, "*"*80))
     295                log("    %s\n%s\nTests run before process timed out:"%(fail_msg, "*"*70))
    296296                log(output)
    297                 log("*"*80)
     297                log("*"*70)
    298298                postscript['lines'].append(cmd + "  # %s"%fail_msg)
    299299                stats[basename] = dict(failed=True, walltime=1e6)
    300300                self.error_status |= 4
     
    305305                    fail_msg = "Killed due to %s"%signal_name(-return_code)
    306306                if ntests > 0:
    307307                    fail_msg += " after testing finished"
    308                 log("    %s\n%s\nTests run before process failed:"%(fail_msg,"*"*80))
     308                log("    %s\n%s\nTests run before process failed:"%(fail_msg,"*"*70))
    309309                log(output)
    310                 log("*"*80)
     310                log("*"*70)
    311311                postscript['lines'].append(cmd + "  # %s" % fail_msg)
    312312                stats[basename] = dict(failed=True, walltime=1e6)
    313313                self.error_status |= (8 if return_code > 0 else 16)
     
    321321                else:
    322322                    cpu = 1e6
    323323                if result_dict.err == 'badresult':
    324                     log("    Error in doctesting framework (bad result returned)\n%s\nTests run before error:"%("*"*80))
     324                    log("    Error in doctesting framework (bad result returned)\n%s\nTests run before error:"%("*"*70))
    325325                    log(output)
    326                     log("*"*80)
     326                    log("*"*70)
    327327                    postscript['lines'].append(cmd + "  # Testing error: bad result")
    328328                    self.error_status |= 64
    329329                elif result_dict.err == 'noresult':
    330                     log("    Error in doctesting framework (no result returned)\n%s\nTests run before error:"%("*"*80))
     330                    log("    Error in doctesting framework (no result returned)\n%s\nTests run before error:"%("*"*70))
    331331                    log(output)
    332                     log("*"*80)
     332                    log("*"*70)
    333333                    postscript['lines'].append(cmd + "  # Testing error: no result")
    334334                    self.error_status |= 64
    335335                elif result_dict.err == 'tab':
     
    352352                            err = repr(result_dict.err)
    353353                        fail_msg = "%s in doctesting framework"%err
    354354
    355                     log("    %s\n%s"%(fail_msg, "*"*80))
     355                    log("    %s\n%s"%(fail_msg, "*"*70))
    356356                    if output:
    357357                        log("Tests run before doctest exception:\n" + output)
    358                         log("*"*80)
     358                        log("*"*70)
    359359                    postscript['lines'].append(cmd + "  # %s"%fail_msg)
    360360                    if hasattr(result_dict, 'tb'):
    361361                        log(result_dict.tb)
     
    408408
    409409            sage: DTR.report(FDS, True, 0, None, "Output so far...")
    410410                Time out
    411             ********************************************************************************
     411            **********************************************************************
    412412            Tests run before process timed out:
    413413            Output so far...
    414             ********************************************************************************
     414            **********************************************************************
    415415            sage: DTR.report(FDS, False, 3, None, "Output before bad exit")
    416416                Bad exit: 3
    417             ********************************************************************************
     417            **********************************************************************
    418418            Tests run before process failed:
    419419            Output before bad exit
    420             ********************************************************************************
     420            **********************************************************************
    421421            sage: doctests, extras = FDS.create_doctests(globals())
    422422            sage: runner = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD,optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS)
    423423            sage: t = Timer().start().stop()
     
    438438
    439439            sage: DC.sources = [None] * 4 # to fool the finalize method
    440440            sage: DTR.finalize()
    441             ------------------------------------------------------------------------
     441            ----------------------------------------------------------------------
    442442            sage -t .../sage/doctest/reporting.py  # Time out
    443443            sage -t .../sage/doctest/reporting.py  # Bad exit: 3
    444444            sage -t .../sage/doctest/reporting.py  # 1 doctest failed
    445             ------------------------------------------------------------------------
     445            ----------------------------------------------------------------------
    446446            Total time for all tests: 0.0 seconds
    447447                cpu time: 0.0 seconds
    448448                cumulative wall time: 0.0 seconds
     
    453453            sage: DC.sources = [None] * 6
    454454            sage: DTR.finalize()
    455455            <BLANKLINE>
    456             ------------------------------------------------------------------------
     456            ----------------------------------------------------------------------
    457457            sage -t .../sage/doctest/reporting.py  # Time out
    458458            sage -t .../sage/doctest/reporting.py  # Bad exit: 3
    459459            sage -t .../sage/doctest/reporting.py  # 1 doctest failed
    460460            Doctests interrupted: 4/6 files tested
    461             ------------------------------------------------------------------------
     461            ----------------------------------------------------------------------
    462462            Total time for all tests: 0.0 seconds
    463463                cpu time: 0.0 seconds
    464464                cumulative wall time: 0.0 seconds
     
    470470            self.error_status |= 128
    471471        elif not postscript['lines']:
    472472            postscript['lines'].append("All tests passed!")
    473         log('-' * 72)
     473        log('-' * 70)
    474474        log("\n".join(postscript['lines']))
    475         log('-' * 72)
     475        log('-' * 70)
    476476        log("Total time for all tests: %.1f seconds" % self.controller.timer.walltime)
    477477        log("    cpu time: %.1f seconds" % postscript['cputime'])
    478478        log("    cumulative wall time: %.1f seconds" % postscript['walltime'])
  • sage/doctest/sources.py

    diff --git a/sage/doctest/sources.py b/sage/doctest/sources.py
    a b  
    613613            #sage: raise RuntimeError
    614614        """
    615615        if not os.path.exists(self.path):
    616             raise IOError("File does not exist")
     616            import errno
     617            raise IOError(errno.ENOENT, "File does not exist", self.path)
    617618        base, filename = os.path.split(self.path)
    618619        _, ext = os.path.splitext(filename)
    619620        if not self.in_lib and ext in ('.py', '.pyx', '.sage', '.spyx'):
     
    646647        TESTS::
    647648
    648649            sage: from sage.doctest.sources import FileDocTestSource
     650            sage: cwd = os.getcwd()
    649651            sage: os.chdir(os.path.join(os.environ['SAGE_ROOT'],'devel','sage'))
    650652            sage: import itertools
    651653            sage: for path, dirs, files in itertools.chain(os.walk('sage'), os.walk('doc')): # long time
     
    662664            There are 9 tests in sage/graphs/graph_plot.py that are not being run
    663665            There are 2 tests in sage/server/notebook/worksheet.py that are not being run
    664666            doctest:229: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
     667            sage: os.chdir(cwd)
    665668        """
    666669        expected = []
    667670        rest = isinstance(self, RestSource)
  • sage/doctest/test.py

    diff --git a/sage/doctest/test.py b/sage/doctest/test.py
    a b  
    3535        252
    3636    **********************************************************************
    3737    ...
    38     ------------------------------------------------------------------------
     38    ----------------------------------------------------------------------
    3939    sage -t initial.rst  # 5 doctests failed
    40     ------------------------------------------------------------------------
     40    ----------------------------------------------------------------------
    4141    ...
    4242    1
    4343
     
    4848    Doctesting 1 file.
    4949    sage -t 99seconds.rst
    5050        Time out
    51     ********************************************************************************
     51    **********************************************************************
    5252    Tests run before process timed out:
    5353    ...
    54     ------------------------------------------------------------------------
     54    ----------------------------------------------------------------------
    5555    sage -t 99seconds.rst  # Time out
    56     ------------------------------------------------------------------------
     56    ----------------------------------------------------------------------
    5757    ...
    5858    4
    5959
     
    7373        KeyboardInterrupt
    7474    **********************************************************************
    7575    ...
    76     ------------------------------------------------------------------------
     76    ----------------------------------------------------------------------
    7777    sage -t keyboardinterrupt.rst  # 1 doctest failed
    78     ------------------------------------------------------------------------
     78    ----------------------------------------------------------------------
    7979    ...
    8080    1
    8181
     
    8686    Doctesting 1 file.
    8787    sage -t interrupt.rst
    8888    Killing test interrupt.rst
    89     ------------------------------------------------------------------------
     89    ----------------------------------------------------------------------
    9090    Doctests interrupted: 0/1 files tested
    91     ------------------------------------------------------------------------
     91    ----------------------------------------------------------------------
    9292    ...
    9393    128
    9494
    95 Interrupt the doctester when a doctest cannot be interrupted::
     95Interrupt the doctester (while parallel testing) when a doctest cannot
     96be interrupted. We also test that passing a ridiculous number of threads
     97doesn't hurt::
    9698
    9799    sage: F = tmp_filename()
    98100    sage: env = dict(os.environ)
    99101    sage: env['DOCTEST_TEST_PID_FILE'] = F  # Doctester will write its PID in this file
    100     sage: subprocess.call(["sage", "-t", "-T", "120", "interrupt_diehard.rst"], cwd=tests_dir, env=env)  # long time
     102    sage: subprocess.call(["sage", "-tp", "1000000", "--timeout=120",  # long time
     103    ....:     "99seconds.rst", "interrupt_diehard.rst"], cwd=tests_dir, env=env)
    101104    Running doctests...
    102     Doctesting 1 file.
    103     sage -t interrupt_diehard.rst
     105    Doctesting 2 files using 1000000 threads.
     106    Killing test 99seconds.rst
    104107    Killing test interrupt_diehard.rst
    105     ------------------------------------------------------------------------
    106     Doctests interrupted: 0/1 files tested
    107     ------------------------------------------------------------------------
     108    ----------------------------------------------------------------------
     109    Doctests interrupted: 0/2 files tested
     110    ----------------------------------------------------------------------
    108111    ...
    109112    128
    110113
     
    128131    Doctesting 1 file.
    129132    sage -t abort.rst
    130133        Killed due to abort
    131     ********************************************************************************
     134    **********************************************************************
    132135    Tests run before process failed:
    133136    ...
    134137    ------------------------------------------------------------------------
     
    139142    Sage will now terminate.
    140143    ------------------------------------------------------------------------
    141144    ...
    142     ------------------------------------------------------------------------
     145    ----------------------------------------------------------------------
    143146    sage -t abort.rst  # Killed due to abort
    144     ------------------------------------------------------------------------
     147    ----------------------------------------------------------------------
    145148    ...
    146149    16
    147150
     
    152155    Doctesting 1 file.
    153156    sage -t fail_and_die.rst
    154157    **********************************************************************
    155     File "fail_and_die.rst", line 6, in sage.doctest.tests.fail_and_die
     158    File "fail_and_die.rst", line 5, in sage.doctest.tests.fail_and_die
    156159    Failed example:
    157160        this_gives_a_NameError
    158161    Exception raised:
     
    160163        ...
    161164        NameError: name 'this_gives_a_NameError' is not defined
    162165        Killed due to kill signal
    163     ********************************************************************************
     166    **********************************************************************
    164167    Tests run before process failed:
    165168    ...
    166     ------------------------------------------------------------------------
     169    ----------------------------------------------------------------------
    167170    sage -t fail_and_die.rst  # Killed due to kill signal
    168     ------------------------------------------------------------------------
     171    ----------------------------------------------------------------------
    169172    ...
    170173    16
    171174
     
    177180    Doctesting 1 file.
    178181    sage -t 1second.rst
    179182        [2 tests, 1.0 s]
    180     ------------------------------------------------------------------------
     183    ----------------------------------------------------------------------
    181184    All tests passed!
    182     ------------------------------------------------------------------------
     185    ----------------------------------------------------------------------
    183186    ...
    184187    0
    185188    sage: subprocess.call(["sage", "-t", "--gdb", "-T" "5", "99seconds.rst"], cwd=tests_dir, stdin=open(os.devnull))  # long time, optional: gdb
  • sage/doctest/tests/fail_and_die.rst

    diff --git a/sage/doctest/tests/fail_and_die.rst b/sage/doctest/tests/fail_and_die.rst
    a b  
    11The ``NameError`` raised on the second line should be displayed, even
    22if we crash immediately afterwards::
    33
    4     sage: import time
    5     sage: import signal
     4    sage: import time, signal
    65    sage: this_gives_a_NameError
    76    sage: os.kill(os.getpid(), signal.SIGKILL)
  • sage/geometry/triangulation/point_configuration.py

    diff --git a/sage/geometry/triangulation/point_configuration.py b/sage/geometry/triangulation/point_configuration.py
    a b  
    148148#       marked # optional - TOPCOM
    149149#       If you have it installed, run doctests as
    150150#
    151 #   sage -tp 4 -long -optional TOPCOM sage/geometry/triangulation/
     151#   sage -tp 4 --long --optional=sage,topcom sage/geometry/triangulation/
    152152########################################################################
    153153
    154154