Skip to content

Commit f96cbf7

Browse files
author
Release Manager
committed
Trac #30778: sage.doctest.control: Exclude doctests in files via file directives ''# sage.doctest: optional - xyz'
When a file is marked `# sage.doctest: optional - xyz`, we omit it from doctesting unless `--optional=xyz` is given. This will save us from having to add lots of `# optional - ...` tags to files in the course of modularization (#29705) We do this by extending `sage.doctest.control.skipfile`, which already parses files for `# nodoctest` file directives. Previous related proposals/discussions: #3260, #20427 Also related: #30746 URL: https://trac.sagemath.org/30778 Reported by: mkoeppe Ticket author(s): Matthias Koeppe, John Palmieri Reviewer(s): John Palmieri, Matthias Koeppe
2 parents 38556c2 + 5cc1288 commit f96cbf7

File tree

4 files changed

+155
-85
lines changed

4 files changed

+155
-85
lines changed

src/doc/en/developer/coding_basics.rst

+20
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,26 @@ framework. Here is a comprehensive list:
10791079

10801080
sage: SloaneEncyclopedia[60843] # optional - sloane_database
10811081

1082+
.. NOTE::
1083+
1084+
If one of the first 10 lines of a file starts with any of
1085+
``r""" sage.doctest: optional - keyword``
1086+
(or ``""" sage.doctest: optional - keyword``
1087+
or ``# sage.doctest: optional - keyword``
1088+
or ``% sage.doctest: optional - keyword``
1089+
or ``.. sage.doctest: optional - keyword``,
1090+
or any of these with different spacing),
1091+
then that file will be skipped unless
1092+
the ``--optional=keyword`` flag is passed to ``sage -t``.
1093+
1094+
This does not apply to files which are explicitly given
1095+
as command line arguments: those are always tested.
1096+
1097+
If you add such a line to a file, you are strongly encouraged
1098+
to add a note to the module-level documentation, saying that
1099+
the doctests in this file will be skipped unless the
1100+
appropriate conditions are met.
1101+
10821102
- **internet:** For lines that require an internet connection::
10831103

10841104
sage: oeis(60843) # optional - internet

src/sage/doctest/control.py

+38-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@
3838
from .reporting import DocTestReporter
3939
from .util import Timer, count_noun, dict_difference
4040
from .external import external_software, available_software
41+
from .parsing import parse_optional_tags
4142

4243
nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest')
4344
optionaltag_regex = re.compile(r'^\w+$')
45+
optionalfiledirective_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)')
4446

4547
# Optional tags which are always automatically added
4648

@@ -204,11 +206,23 @@ def skipdir(dirname):
204206
return True
205207
return False
206208

207-
def skipfile(filename):
209+
def skipfile(filename, tested_optional_tags=False):
208210
"""
209211
Return True if and only if the file ``filename`` should not be
210212
doctested.
211213
214+
INPUT:
215+
216+
- ``filename`` - name of a file
217+
218+
- ``tested_optional_tags`` - a list or tuple or set of optional tags to test,
219+
or ``False`` (no optional test) or ``True`` (all optional tests)
220+
221+
If ``filename`` contains a line of the form ``"# sage.doctest:
222+
optional - xyz")``, then this will return ``False`` if "xyz" is in
223+
``tested_optional_tags``. Otherwise, it returns the matching tag
224+
("optional - xyz").
225+
212226
EXAMPLES::
213227
214228
sage: from sage.doctest.control import skipfile
@@ -221,6 +235,18 @@ def skipfile(filename):
221235
....: _ = f.write("# nodoctest")
222236
sage: skipfile(filename)
223237
True
238+
sage: with open(filename, "w") as f:
239+
....: _ = f.write("# sage.doctest: optional - xyz")
240+
sage: skipfile(filename, False)
241+
'optional - xyz'
242+
sage: bool(skipfile(filename, False))
243+
True
244+
sage: skipfile(filename, ['abc'])
245+
'optional - xyz'
246+
sage: skipfile(filename, ['abc', 'xyz'])
247+
False
248+
sage: skipfile(filename, True)
249+
False
224250
"""
225251
base, ext = os.path.splitext(filename)
226252
if ext not in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst', '.tex'):
@@ -230,6 +256,16 @@ def skipfile(filename):
230256
for line in F:
231257
if nodoctest_regex.match(line):
232258
return True
259+
if tested_optional_tags is not True:
260+
# Adapted from code in SageDocTestParser.parse
261+
m = optionalfiledirective_regex.match(line)
262+
if m:
263+
if tested_optional_tags is False:
264+
return m.group(2)
265+
optional_tags = parse_optional_tags('#' + m.group(2))
266+
extra = optional_tags - set(tested_optional_tags)
267+
if extra:
268+
return m.group(2)
233269
line_count += 1
234270
if line_count >= 10:
235271
break
@@ -786,7 +822,7 @@ def expand():
786822
if dir[0] == "." or skipdir(os.path.join(root,dir)):
787823
dirs.remove(dir)
788824
for file in files:
789-
if not skipfile(os.path.join(root,file)):
825+
if not skipfile(os.path.join(root, file), self.options.optional):
790826
yield os.path.join(root, file)
791827
else:
792828
# the user input this file explicitly, so we don't skip it

0 commit comments

Comments
 (0)