Classes involved in doctesting#
This module controls the various classes involved in doctesting.
AUTHORS:
David Roe (2012-03-27) – initial version, based on Robert Bradshaw’s code.
- class sage.doctest.control.DocTestController(options, args)[source]#
Bases:
SageObject
This class controls doctesting of files.
After creating it with appropriate options, call the
run()
method to run the doctests.- add_files()[source]#
Checks for the flags ‘–all’ and ‘–new’.
For each one present, this function adds the appropriate directories and files to the todo list.
EXAMPLES:
sage: from sage.doctest.control import (DocTestDefaults, ....: DocTestController) sage: from sage.env import SAGE_SRC sage: import tempfile sage: with tempfile.NamedTemporaryFile() as f: ....: DD = DocTestDefaults(all=True, logfile=f.name) ....: DC = DocTestController(DD, []) ....: DC.add_files() Doctesting ... sage: os.path.join(SAGE_SRC, 'sage') in DC.files True
>>> from sage.all import * >>> from sage.doctest.control import (DocTestDefaults, ... DocTestController) >>> from sage.env import SAGE_SRC >>> import tempfile >>> with tempfile.NamedTemporaryFile() as f: ... DD = DocTestDefaults(all=True, logfile=f.name) ... DC = DocTestController(DD, []) ... DC.add_files() Doctesting ... >>> os.path.join(SAGE_SRC, 'sage') in DC.files True
sage: DD = DocTestDefaults(new = True) sage: DC = DocTestController(DD, []) sage: DC.add_files() Doctesting ...
>>> from sage.all import * >>> DD = DocTestDefaults(new = True) >>> DC = DocTestController(DD, []) >>> DC.add_files() Doctesting ...
- cleanup(final=True)[source]#
Runs cleanup activities after actually running doctests.
In particular, saves the stats to disk and closes the logfile.
INPUT:
final
– whether to close the logfile
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os sage: dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'all.py') sage: DD = DocTestDefaults() sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: DC.sources.sort(key=lambda s:s.basename) sage: for i, source in enumerate(DC.sources): ....: DC.stats[source.basename] = {'walltime': 0.1r * (i+1)} ....: sage: DC.run() Running doctests with ID ... Doctesting 1 file. sage -t .../rings/all.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0 sage: DC.cleanup()
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> from sage.env import SAGE_SRC >>> import os >>> dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'all.py') >>> DD = DocTestDefaults() >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> DC.sources.sort(key=lambda s:s.basename) >>> for i, source in enumerate(DC.sources): ... DC.stats[source.basename] = {'walltime': 0.1 * (i+Integer(1))} ....: >>> DC.run() Running doctests with ID ... Doctesting 1 file. sage -t .../rings/all.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0 >>> DC.cleanup()
- create_run_id()[source]#
Creates the run id.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DC = DocTestController(DocTestDefaults(), []) sage: DC.create_run_id() Running doctests with ID ...
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DC = DocTestController(DocTestDefaults(), []) >>> DC.create_run_id() Running doctests with ID ...
- expand_files_into_sources()[source]#
Expands
self.files
, which may include directories, into a list ofsage.doctest.FileDocTestSource
This function also handles the optional command line option.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os sage: dirname = os.path.join(SAGE_SRC, 'sage', 'doctest') sage: DD = DocTestDefaults(optional='all') sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: len(DC.sources) 12 sage: DC.sources[0].options.optional True
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> from sage.env import SAGE_SRC >>> import os >>> dirname = os.path.join(SAGE_SRC, 'sage', 'doctest') >>> DD = DocTestDefaults(optional='all') >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> len(DC.sources) 12 >>> DC.sources[Integer(0)].options.optional True
sage: DD = DocTestDefaults(optional='magma,guava') sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: all(t in DC.sources[0].options.optional for t in ['magma','guava']) True
>>> from sage.all import * >>> DD = DocTestDefaults(optional='magma,guava') >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> all(t in DC.sources[Integer(0)].options.optional for t in ['magma','guava']) True
We check that files are skipped appropriately:
sage: dirname = tmp_dir() sage: filename = os.path.join(dirname, 'not_tested.py') sage: with open(filename, 'w') as f: ....: _ = f.write("#"*80 + "\n\n\n\n## nodoctest\n sage: 1+1\n 4") sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: DC.sources []
>>> from sage.all import * >>> dirname = tmp_dir() >>> filename = os.path.join(dirname, 'not_tested.py') >>> with open(filename, 'w') as f: ... _ = f.write("#"*Integer(80) + "\n\n\n\n## nodoctest\n sage: 1+1\n 4") >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> DC.sources []
The directory
sage/doctest/tests
containsnodoctest.py
but the files should still be tested when that directory is explicitly given (as opposed to being recursed into):sage: DC = DocTestController(DD, [os.path.join(SAGE_SRC, 'sage', 'doctest', 'tests')]) sage: DC.expand_files_into_sources() sage: len(DC.sources) >= 10 True
>>> from sage.all import * >>> DC = DocTestController(DD, [os.path.join(SAGE_SRC, 'sage', 'doctest', 'tests')]) >>> DC.expand_files_into_sources() >>> len(DC.sources) >= Integer(10) True
- filter_sources()[source]#
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os sage: dirname = os.path.join(SAGE_SRC, 'sage', 'doctest') sage: DD = DocTestDefaults(failed=True) sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: for i, source in enumerate(DC.sources): ....: DC.stats[source.basename] = {'walltime': 0.1r * (i+1)} sage: DC.stats['sage.doctest.control'] = {'failed': True, 'walltime': 1.0r} sage: DC.filter_sources() Only doctesting files that failed last test. sage: len(DC.sources) 1
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> from sage.env import SAGE_SRC >>> import os >>> dirname = os.path.join(SAGE_SRC, 'sage', 'doctest') >>> DD = DocTestDefaults(failed=True) >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> for i, source in enumerate(DC.sources): ... DC.stats[source.basename] = {'walltime': 0.1 * (i+Integer(1))} >>> DC.stats['sage.doctest.control'] = {'failed': True, 'walltime': 1.0} >>> DC.filter_sources() Only doctesting files that failed last test. >>> len(DC.sources) 1
- load_baseline_stats(filename)[source]#
Load baseline stats.
This must be a JSON file in the same format that
load_stats()
expects.EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DC = DocTestController(DocTestDefaults(), []) sage: import json sage: filename = tmp_filename() sage: with open(filename, 'w') as stats_file: ....: json.dump({'sage.doctest.control':{'failed':True}}, stats_file) sage: DC.load_baseline_stats(filename) sage: DC.baseline_stats['sage.doctest.control'] {'failed': True}
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DC = DocTestController(DocTestDefaults(), []) >>> import json >>> filename = tmp_filename() >>> with open(filename, 'w') as stats_file: ... json.dump({'sage.doctest.control':{'failed':True}}, stats_file) >>> DC.load_baseline_stats(filename) >>> DC.baseline_stats['sage.doctest.control'] {'failed': True}
If the file doesn’t exist, nothing happens. If there is an error, print a message. In any case, leave the stats alone:
sage: d = tmp_dir() sage: DC.load_baseline_stats(os.path.join(d)) # Cannot read a directory Error loading baseline stats from ... sage: DC.load_baseline_stats(os.path.join(d, "no_such_file")) sage: DC.baseline_stats['sage.doctest.control'] {'failed': True}
>>> from sage.all import * >>> d = tmp_dir() >>> DC.load_baseline_stats(os.path.join(d)) # Cannot read a directory Error loading baseline stats from ... >>> DC.load_baseline_stats(os.path.join(d, "no_such_file")) >>> DC.baseline_stats['sage.doctest.control'] {'failed': True}
- load_environment()[source]#
Return the module that provides the global environment.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DC = DocTestController(DocTestDefaults(), []) sage: 'BipartiteGraph' in DC.load_environment().__dict__ True sage: DC = DocTestController(DocTestDefaults(environment='sage.doctest.all'), []) sage: 'BipartiteGraph' in DC.load_environment().__dict__ False sage: 'run_doctests' in DC.load_environment().__dict__ True
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DC = DocTestController(DocTestDefaults(), []) >>> 'BipartiteGraph' in DC.load_environment().__dict__ True >>> DC = DocTestController(DocTestDefaults(environment='sage.doctest.all'), []) >>> 'BipartiteGraph' in DC.load_environment().__dict__ False >>> 'run_doctests' in DC.load_environment().__dict__ True
- load_stats(filename)[source]#
Load stats from the most recent run(s).
Stats are stored as a JSON file, and include information on which files failed tests and the walltime used for execution of the doctests.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DC = DocTestController(DocTestDefaults(), []) sage: import json sage: filename = tmp_filename() sage: with open(filename, 'w') as stats_file: ....: json.dump({'sage.doctest.control': {'walltime': 1.0r}}, stats_file) sage: DC.load_stats(filename) sage: DC.stats['sage.doctest.control'] {'walltime': 1.0}
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DC = DocTestController(DocTestDefaults(), []) >>> import json >>> filename = tmp_filename() >>> with open(filename, 'w') as stats_file: ... json.dump({'sage.doctest.control': {'walltime': 1.0}}, stats_file) >>> DC.load_stats(filename) >>> DC.stats['sage.doctest.control'] {'walltime': 1.0}
If the file doesn’t exist, nothing happens. If there is an error, print a message. In any case, leave the stats alone:
sage: d = tmp_dir() sage: DC.load_stats(os.path.join(d)) # Cannot read a directory Error loading stats from ... sage: DC.load_stats(os.path.join(d, "no_such_file")) sage: DC.stats['sage.doctest.control'] {'walltime': 1.0}
>>> from sage.all import * >>> d = tmp_dir() >>> DC.load_stats(os.path.join(d)) # Cannot read a directory Error loading stats from ... >>> DC.load_stats(os.path.join(d, "no_such_file")) >>> DC.stats['sage.doctest.control'] {'walltime': 1.0}
- log(s, end='\n')[source]#
Log the string
s + end
(whereend
is a newline by default) to the logfile and print it to the standard output.EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DD = DocTestDefaults(logfile=tmp_filename()) sage: DC = DocTestController(DD, []) sage: DC.log("hello world") hello world sage: DC.logfile.close() sage: with open(DD.logfile) as f: ....: print(f.read()) hello world
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DD = DocTestDefaults(logfile=tmp_filename()) >>> DC = DocTestController(DD, []) >>> DC.log("hello world") hello world >>> DC.logfile.close() >>> with open(DD.logfile) as f: ... print(f.read()) hello world
In serial mode, check that logging works even if
stdout
is redirected:sage: DD = DocTestDefaults(logfile=tmp_filename(), serial=True) sage: DC = DocTestController(DD, []) sage: from sage.doctest.forker import SageSpoofInOut sage: with open(os.devnull, 'w') as devnull: ....: S = SageSpoofInOut(devnull) ....: S.start_spoofing() ....: DC.log("hello world") ....: S.stop_spoofing() hello world sage: DC.logfile.close() sage: with open(DD.logfile) as f: ....: print(f.read()) hello world
>>> from sage.all import * >>> DD = DocTestDefaults(logfile=tmp_filename(), serial=True) >>> DC = DocTestController(DD, []) >>> from sage.doctest.forker import SageSpoofInOut >>> with open(os.devnull, 'w') as devnull: ... S = SageSpoofInOut(devnull) ... S.start_spoofing() ... DC.log("hello world") ... S.stop_spoofing() hello world >>> DC.logfile.close() >>> with open(DD.logfile) as f: ... print(f.read()) hello world
Check that no duplicate logs appear, even when forking (Issue #15244):
sage: DD = DocTestDefaults(logfile=tmp_filename()) sage: DC = DocTestController(DD, []) sage: DC.log("hello world") hello world sage: if os.fork() == 0: ....: DC.logfile.close() ....: os._exit(0) sage: DC.logfile.close() sage: with open(DD.logfile) as f: ....: print(f.read()) hello world
>>> from sage.all import * >>> DD = DocTestDefaults(logfile=tmp_filename()) >>> DC = DocTestController(DD, []) >>> DC.log("hello world") hello world >>> if os.fork() == Integer(0): ... DC.logfile.close() ... os._exit(Integer(0)) >>> DC.logfile.close() >>> with open(DD.logfile) as f: ... print(f.read()) hello world
- run()[source]#
This function is called after initialization to set up and run all doctests.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os sage: DD = DocTestDefaults() sage: filename = os.path.join(SAGE_SRC, "sage", "sets", "non_negative_integers.py") sage: DC = DocTestController(DD, [filename]) sage: DC.run() Running doctests with ID ... Doctesting 1 file. sage -t .../sage/sets/non_negative_integers.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> from sage.env import SAGE_SRC >>> import os >>> DD = DocTestDefaults() >>> filename = os.path.join(SAGE_SRC, "sage", "sets", "non_negative_integers.py") >>> DC = DocTestController(DD, [filename]) >>> DC.run() Running doctests with ID ... Doctesting 1 file. sage -t .../sage/sets/non_negative_integers.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0
We check that Issue #25378 is fixed (testing external packages while providing a logfile does not raise a ValueError: I/O operation on closed file):
sage: logfile = tmp_filename(ext='.log') sage: DD = DocTestDefaults(optional=set(['sage', 'external']), logfile=logfile) sage: filename = tmp_filename(ext='.py') sage: DC = DocTestController(DD, [filename]) sage: DC.run() Running doctests with ID ... Using --optional=external,sage Features to be detected: ... Doctesting 1 file. sage -t ....py [0 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0
>>> from sage.all import * >>> logfile = tmp_filename(ext='.log') >>> DD = DocTestDefaults(optional=set(['sage', 'external']), logfile=logfile) >>> filename = tmp_filename(ext='.py') >>> DC = DocTestController(DD, [filename]) >>> DC.run() Running doctests with ID ... Using --optional=external,sage Features to be detected: ... Doctesting 1 file. sage -t ....py [0 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0
We test the
--hide
option (Issue #34185):sage: from sage.doctest.control import test_hide sage: filename = tmp_filename(ext='.py') sage: with open(filename, 'w') as f: ....: f.write(test_hide) ....: f.close() 714 sage: DF = DocTestDefaults(hide='buckygen,all') sage: DC = DocTestController(DF, [filename]) sage: DC.run() Running doctests with ID ... Using --optional=sage... Features to be detected: ... Doctesting 1 file. sage -t ....py [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0 sage: DF = DocTestDefaults(hide='benzene,optional') sage: DC = DocTestController(DF, [filename]) sage: DC.run() Running doctests with ID ... Using --optional=sage Features to be detected: ... Doctesting 1 file. sage -t ....py [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0
>>> from sage.all import * >>> from sage.doctest.control import test_hide >>> filename = tmp_filename(ext='.py') >>> with open(filename, 'w') as f: ... f.write(test_hide) ... f.close() 714 >>> DF = DocTestDefaults(hide='buckygen,all') >>> DC = DocTestController(DF, [filename]) >>> DC.run() Running doctests with ID ... Using --optional=sage... Features to be detected: ... Doctesting 1 file. sage -t ....py [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0 >>> DF = DocTestDefaults(hide='benzene,optional') >>> DC = DocTestController(DF, [filename]) >>> DC.run() Running doctests with ID ... Using --optional=sage Features to be detected: ... Doctesting 1 file. sage -t ....py [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... 0
Test Features that have been hidden message:
sage: DC.run() # optional - meataxe Running doctests with ID ... Using --optional=sage Features to be detected: ... Doctesting 1 file. sage -t ....py [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... Features that have been hidden: ...meataxe... 0
>>> from sage.all import * >>> DC.run() # optional - meataxe Running doctests with ID ... Using --optional=sage Features to be detected: ... Doctesting 1 file. sage -t ....py [4 tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected... Features that have been hidden: ...meataxe... 0
- run_doctests()[source]#
Actually runs the doctests.
This function is called by
run()
.EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os sage: dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'homset.py') sage: DD = DocTestDefaults() sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: DC.run_doctests() Doctesting 1 file. sage -t .../sage/rings/homset.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds...
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> from sage.env import SAGE_SRC >>> import os >>> dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'homset.py') >>> DD = DocTestDefaults() >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> DC.run_doctests() Doctesting 1 file. sage -t .../sage/rings/homset.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds...
- run_val_gdb(testing=False)[source]#
Spawns a subprocess to run tests under the control of gdb, lldb, or valgrind.
INPUT:
testing
– boolean; if True then the command to be run will be printed rather than a subprocess started.
EXAMPLES:
Note that the command lines include unexpanded environment variables. It is safer to let the shell expand them than to expand them here and risk insufficient quoting.
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DD = DocTestDefaults(gdb=True) sage: DC = DocTestController(DD, ["hello_world.py"]) sage: DC.run_val_gdb(testing=True) exec gdb --eval-command="run" --args ...python... sage-runtests --serial --timeout=0 hello_world.py
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DD = DocTestDefaults(gdb=True) >>> DC = DocTestController(DD, ["hello_world.py"]) >>> DC.run_val_gdb(testing=True) exec gdb --eval-command="run" --args ...python... sage-runtests --serial --timeout=0 hello_world.py
sage: DD = DocTestDefaults(valgrind=True, optional="all", timeout=172800) sage: DC = DocTestController(DD, ["hello_world.py"]) sage: DC.run_val_gdb(testing=True) exec valgrind --tool=memcheck --leak-resolution=high --leak-check=full --num-callers=25 --suppressions="...valgrind/pyalloc.supp" --suppressions="...valgrind/sage.supp" --suppressions="...valgrind/sage-additional.supp" --log-file=.../valgrind/sage-memcheck.%p... sage-runtests --serial --timeout=172800 --optional=all hello_world.py
>>> from sage.all import * >>> DD = DocTestDefaults(valgrind=True, optional="all", timeout=Integer(172800)) >>> DC = DocTestController(DD, ["hello_world.py"]) >>> DC.run_val_gdb(testing=True) exec valgrind --tool=memcheck --leak-resolution=high --leak-check=full --num-callers=25 --suppressions="...valgrind/pyalloc.supp" --suppressions="...valgrind/sage.supp" --suppressions="...valgrind/sage-additional.supp" --log-file=.../valgrind/sage-memcheck.%p... sage-runtests --serial --timeout=172800 --optional=all hello_world.py
- save_stats(filename)[source]#
Save stats from the most recent run as a JSON file.
WARNING: This function overwrites the file.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DC = DocTestController(DocTestDefaults(), []) sage: DC.stats['sage.doctest.control'] = {'walltime': 1.0r} sage: filename = tmp_filename() sage: DC.save_stats(filename) sage: import json sage: with open(filename) as f: ....: D = json.load(f) sage: D['sage.doctest.control'] {'walltime': 1.0}
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DC = DocTestController(DocTestDefaults(), []) >>> DC.stats['sage.doctest.control'] = {'walltime': 1.0} >>> filename = tmp_filename() >>> DC.save_stats(filename) >>> import json >>> with open(filename) as f: ... D = json.load(f) >>> D['sage.doctest.control'] {'walltime': 1.0}
- second_on_modern_computer()[source]#
Return the wall time equivalent of a second on a modern computer.
OUTPUT:
Float. The wall time on your computer that would be equivalent to one second on a modern computer. Unless you have kick-ass hardware this should always be >= 1.0. This raises a
RuntimeError
if there are no stored timings to use as benchmark.EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: DC = DocTestController(DocTestDefaults(), []) sage: DC.second_on_modern_computer() # not tested
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> DC = DocTestController(DocTestDefaults(), []) >>> DC.second_on_modern_computer() # not tested
- sort_sources()[source]#
This function sorts the sources so that slower doctests are run first.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: from sage.env import SAGE_SRC sage: import os sage: dirname = os.path.join(SAGE_SRC, 'sage', 'doctest') sage: DD = DocTestDefaults(nthreads=2) sage: DC = DocTestController(DD, [dirname]) sage: DC.expand_files_into_sources() sage: DC.sources.sort(key=lambda s:s.basename) sage: for i, source in enumerate(DC.sources): ....: DC.stats[source.basename] = {'walltime': 0.1r * (i+1)} sage: DC.sort_sources() Sorting sources by runtime so that slower doctests are run first.... sage: print("\n".join(source.basename for source in DC.sources)) sage.doctest.util sage.doctest.test sage.doctest.sources sage.doctest.reporting sage.doctest.parsing_test sage.doctest.parsing sage.doctest.forker sage.doctest.fixtures sage.doctest.external sage.doctest.control sage.doctest.all sage.doctest
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> from sage.env import SAGE_SRC >>> import os >>> dirname = os.path.join(SAGE_SRC, 'sage', 'doctest') >>> DD = DocTestDefaults(nthreads=Integer(2)) >>> DC = DocTestController(DD, [dirname]) >>> DC.expand_files_into_sources() >>> DC.sources.sort(key=lambda s:s.basename) >>> for i, source in enumerate(DC.sources): ... DC.stats[source.basename] = {'walltime': 0.1 * (i+Integer(1))} >>> DC.sort_sources() Sorting sources by runtime so that slower doctests are run first.... >>> print("\n".join(source.basename for source in DC.sources)) sage.doctest.util sage.doctest.test sage.doctest.sources sage.doctest.reporting sage.doctest.parsing_test sage.doctest.parsing sage.doctest.forker sage.doctest.fixtures sage.doctest.external sage.doctest.control sage.doctest.all sage.doctest
- source_baseline(source)[source]#
Return the
baseline_stats
value ofsource
.INPUT:
source
– aDocTestSource
instance
OUTPUT:
A dictionary.
EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults, DocTestController sage: filename = sage.doctest.util.__file__ sage: DD = DocTestDefaults() sage: DC = DocTestController(DD, [filename]) sage: DC.expand_files_into_sources() sage: DC.source_baseline(DC.sources[0]) {}
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults, DocTestController >>> filename = sage.doctest.util.__file__ >>> DD = DocTestDefaults() >>> DC = DocTestController(DD, [filename]) >>> DC.expand_files_into_sources() >>> DC.source_baseline(DC.sources[Integer(0)]) {}
- class sage.doctest.control.DocTestDefaults(**kwds)[source]#
Bases:
SageObject
This class is used for doctesting the Sage doctest module.
It fills in attributes to be the same as the defaults defined in
sage-runtests
, expect for a few places, which is mostly to make doctesting more predictable.EXAMPLES:
sage: from sage.doctest.control import DocTestDefaults sage: D = DocTestDefaults() sage: D DocTestDefaults() sage: D.timeout -1
>>> from sage.all import * >>> from sage.doctest.control import DocTestDefaults >>> D = DocTestDefaults() >>> D DocTestDefaults() >>> D.timeout -1
Keyword arguments become attributes:
sage: D = DocTestDefaults(timeout=100) sage: D DocTestDefaults(timeout=100) sage: D.timeout 100
>>> from sage.all import * >>> D = DocTestDefaults(timeout=Integer(100)) >>> D DocTestDefaults(timeout=100) >>> D.timeout 100
- class sage.doctest.control.Logger(*files)[source]#
Bases:
object
File-like object which implements writing to multiple files at once.
EXAMPLES:
sage: from sage.doctest.control import Logger sage: with open(tmp_filename(), "w+") as t: ....: L = Logger(sys.stdout, t) ....: _ = L.write("hello world\n") ....: _ = t.seek(0) ....: t.read() hello world 'hello world\n'
>>> from sage.all import * >>> from sage.doctest.control import Logger >>> with open(tmp_filename(), "w+") as t: ... L = Logger(sys.stdout, t) ... _ = L.write("hello world\n") ... _ = t.seek(Integer(0)) ... t.read() hello world 'hello world\n'
- sage.doctest.control.run_doctests(module, options=None)[source]#
Runs the doctests in a given file.
INPUT:
module
– a Sage module, a string, or a list of such.options
– a DocTestDefaults object or None.
EXAMPLES:
sage: run_doctests(sage.rings.all) Running doctests with ID ... Doctesting 1 file. sage -t .../sage/rings/all.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected...
>>> from sage.all import * >>> run_doctests(sage.rings.all) Running doctests with ID ... Doctesting 1 file. sage -t .../sage/rings/all.py [... tests, ... s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: ... seconds cpu time: ... seconds cumulative wall time: ... seconds Features detected...
- sage.doctest.control.skipdir(dirname)[source]#
Return True if and only if the directory
dirname
should not be doctested.EXAMPLES:
sage: from sage.doctest.control import skipdir sage: skipdir(sage.env.SAGE_SRC) False sage: skipdir(os.path.join(sage.env.SAGE_SRC, "sage", "doctest", "tests")) True
>>> from sage.all import * >>> from sage.doctest.control import skipdir >>> skipdir(sage.env.SAGE_SRC) False >>> skipdir(os.path.join(sage.env.SAGE_SRC, "sage", "doctest", "tests")) True
- sage.doctest.control.skipfile(filename, tested_optional_tags, if_installed, log=False)[source]#
Return
True
if and only if the filefilename
should not be doctested.INPUT:
filename
– name of a filetested_optional_tags
– a list or tuple or set of optional tags to test, orFalse
(no optional test) orTrue
(all optional tests)if_installed
– (boolean, defaultFalse
) whether to skip Python/Cython files that are not installed as moduleslog
– function to call with log messages, orNone
If
filename
contains a line of the form"# sage.doctest: optional - xyz")
, then this will returnFalse
if “xyz” is intested_optional_tags
. Otherwise, it returns the matching tag (“optional - xyz”).EXAMPLES:
sage: from sage.doctest.control import skipfile sage: skipfile("skipme.c") True sage: filename = tmp_filename(ext=".pyx") sage: skipfile(filename) False sage: with open(filename, "w") as f: ....: _ = f.write("# nodoctest") sage: skipfile(filename) True sage: with open(filename, "w") as f: ....: _ = f.write("# sage.doctest: " # broken in two source lines to avoid the pattern ....: "optional - xyz") # of relint (multiline_doctest_comment) sage: skipfile(filename, False) 'optional - xyz' sage: bool(skipfile(filename, False)) True sage: skipfile(filename, ['abc']) 'optional - xyz' sage: skipfile(filename, ['abc', 'xyz']) False sage: skipfile(filename, True) False
>>> from sage.all import * >>> from sage.doctest.control import skipfile >>> skipfile("skipme.c") True >>> filename = tmp_filename(ext=".pyx") >>> skipfile(filename) False >>> with open(filename, "w") as f: ... _ = f.write("# nodoctest") >>> skipfile(filename) True >>> with open(filename, "w") as f: ... _ = f.write("# sage.doctest: " # broken in two source lines to avoid the pattern ... "optional - xyz") # of relint (multiline_doctest_comment) >>> skipfile(filename, False) 'optional - xyz' >>> bool(skipfile(filename, False)) True >>> skipfile(filename, ['abc']) 'optional - xyz' >>> skipfile(filename, ['abc', 'xyz']) False >>> skipfile(filename, True) False