Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .github/workflows/ci-meson.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
test:
name: Conda (${{ matrix.os }}, Python ${{ matrix.python }}, ${{ matrix.tests }}${{ matrix.editable && ', editable' || '' }})
runs-on: ${{ matrix.os }}-latest
env:
SEPARATELY_TESTED_FLAKY_FILES: "src/sage/libs/singular/function.pyx src/sage/rings/polynomial/plural.pyx"

strategy:
fail-fast: false
Expand Down Expand Up @@ -168,9 +170,22 @@ jobs:
pytest --doctest-ignore-import-errors --doctest -rfEs -s src || true
else
pytest -rfEs -s src
./sage -t ${{ matrix.tests == 'all' && '--all' || '--new --long' }} -p4 --format github
./sage -t ${{
matrix.tests == 'all' &&
'--all-except="$SEPARATELY_TESTED_FLAKY_FILES"' ||
'--new --long' }} -p4 --format github
fi

- name: Test flaky files
# unknown issues with plural.pyx causes sporadic failure: https://github.com/sagemath/sage/issues/29528
# we rerun a few times, this step succeeds if any of the 5 runs succeed
if: runner.os != 'windows' && matrix.tests == 'all'
shell: bash -l {0}
run: |
for i in {1..5}; do
./sage -t -p4 --format github $SEPARATELY_TESTED_FLAKY_FILES && break
done

- name: Check that all modules can be imported
shell: bash -l {0}
run: |
Expand Down
10 changes: 7 additions & 3 deletions src/sage/doctest/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import os
import sys
import shlex

# Note: the DOT_SAGE and SAGE_STARTUP_FILE environment variables have already been set by sage-env
DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'),
Expand Down Expand Up @@ -53,6 +54,9 @@ def _make_parser():
parser.add_argument("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout")
what = parser.add_mutually_exclusive_group()
what.add_argument("-a", "--all", action="store_true", default=False, help="test all files in the Sage library")
what.add_argument("--all-except", type=shlex.split, default=None,
help="test all files in the Sage library except the specified space-separated list "
"(backslash or quote are needed to escape spaces or backslashes or quotes)")
what.add_argument("--installed", action="store_true", default=False, help="test all installed modules of the Sage library")
parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE")

Expand Down Expand Up @@ -163,7 +167,7 @@ def main():
in_filenames = False
afterlog = False
for arg in sys.argv[1:]:
if arg in ('-n', '--new', '-a', '--all', '--installed'):
if arg in ('-n', '--new', '-a', '--all', '--installed') or arg.startswith("--all-except"):
need_filenames = False
elif need_filenames and not (afterlog or in_filenames) and os.path.exists(arg):
in_filenames = True
Expand All @@ -174,8 +178,8 @@ def main():

args = parser.parse_args(new_arguments)

if not args.filenames and not (args.all or args.new or args.installed):
print('either use --new, --all, --installed, or some filenames')
if not args.filenames and not (args.all or args.new or args.installed) and args.all_except is None:
print('either use --new, --all, --all-except=..., --installed, or some filenames')
return 2

# Limit the number of threads to 2 to save system resources.
Expand Down
21 changes: 18 additions & 3 deletions src/sage/doctest/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class DocTestDefaults(SageObject):
"""
This class is used for doctesting the Sage doctest module.

The interface of this object should be compatible with the ``options`` input
to :class:`DocTestController`, that is, the same interface as the
argument object parsed by the :class:`argparse.ArgumentParser` in
:func:`sage.doctest.__main__._make_parser`.

INPUT:

- ``runtest_default`` -- boolean (default: ``False``); if ``True``,
Expand Down Expand Up @@ -118,6 +123,7 @@ def __init__(self, runtest_default=False, **kwds):
self.timeout = -1
self.die_timeout = -1
self.all = False
self.all_except = None
self.installed = False
self.logfile = None
self.long = False
Expand Down Expand Up @@ -410,7 +416,9 @@ def __init__(self, options, args):
INPUT:

- ``options`` -- either options generated from the command line by sage-runtests
or a DocTestDefaults object (possibly with some entries modified)
or a :class:`DocTestDefaults` object (possibly with some entries modified).
The attributes available in this object are defined by the :class:`argparse.ArgumentParser`
in :func:`sage.doctest.__main__._make_parser`.
- ``args`` -- list of filenames to doctest

EXAMPLES::
Expand Down Expand Up @@ -913,7 +921,7 @@ def all_doc_sources():
all_installed_modules()
all_installed_doc()

elif self.options.all or (self.options.new and not have_git):
elif self.options.all or self.options.all_except is not None or (self.options.new and not have_git):
all_files()
all_doc_sources()

Expand Down Expand Up @@ -1007,7 +1015,14 @@ def expand():
if_installed=self.options.if_installed,
log=self.log): # log when directly specified filenames are skipped
yield path
self.sources = [FileDocTestSource(path, self.options) for path in expand()]
paths = list(expand())
if self.options.all_except is not None:
paths_to_remove = set(os.path.abspath(x) for x in self.options.all_except)
if not paths_to_remove.issubset(paths):
raise ValueError(f"--all-except includes {paths_to_remove - set(paths)}, "
f"which are not found in {paths}")
paths = [path for path in paths if path not in paths_to_remove] # keep duplicates
self.sources = [FileDocTestSource(path, self.options) for path in paths]

def filter_sources(self):
"""
Expand Down
Loading