Skip to content

Commit

Permalink
gh-35668: Hide features (PR to migrated Trac ticket #34185)
Browse files Browse the repository at this point in the history
    
<!-- Please provide a concise, informative and self-explanatory title.
-->
<!-- Don't put issue numbers in the title. Put it in the Description
below. -->
<!-- For example, instead of "Fixes #12345", use "Add a new method to
multiply two integers" -->

### 📚 Description

See the description of the underlying migrated Trac ticket. This fixes
#34185.

<!-- Describe your changes here in detail. -->
<!-- Why is this change required? What problem does it solve? -->
<!-- If this PR resolves an open issue, please link to it here. For
example "Fixes #12345". -->
<!-- If your change requires a documentation PR, please link it
appropriately. -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. It should be `[x]` not `[x
]`. -->

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [x] I have linked a relevant issue or discussion.
- [x] I have created tests covering the changes.
- [x] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #35668
Reported by: Sebastian Oehms
Reviewer(s): Matthias Köppe, Sebastian Oehms
  • Loading branch information
Release Manager committed Jun 29, 2023
2 parents 39e0bc0 + 97eaac9 commit a6ab2f6
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 14 deletions.
4 changes: 4 additions & 0 deletions src/bin/sage-runtests
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ if __name__ == "__main__":
'if set to "all", then all tests will be run; '
'use "!FEATURE" to disable tests marked "# optional - FEATURE". '
'Note that "!" needs to be quoted or escaped in the shell.')
parser.add_argument("--hide", metavar="FEATURES", default="",
help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; '
'if "all" is listed, will also hide features corresponding to all optional or experimental packages; '
'if "optional" is listed, will also hide features corresponding to optional packages.')
parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests")
parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests",
default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED"))
Expand Down
119 changes: 118 additions & 1 deletion src/sage/doctest/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
except ImportError:
pass


class DocTestDefaults(SageObject):
"""
This class is used for doctesting the Sage doctest module.
Expand Down Expand Up @@ -137,6 +136,7 @@ def __init__(self, **kwds):
# displaying user-defined optional tags and we don't want to see
# the auto_optional_tags there.
self.optional = set(['sage']) | auto_optional_tags
self.hide = ''

# > 0: always run GC before every test
# < 0: disable GC
Expand Down Expand Up @@ -401,6 +401,27 @@ def __init__(self, options, args):
if options.verbose:
options.show_skipped = True

options.hidden_features = set()
if isinstance(options.hide, str):
if not len(options.hide):
options.hide = set([])
else:
s = options.hide.lower()
options.hide = set(s.split(','))
for h in options.hide:
if not optionaltag_regex.search(h):
raise ValueError('invalid optional tag {!r}'.format(h))
if 'all' in options.hide:
options.hide.discard('all')
from sage.features.all import all_features
feature_names = set([f.name for f in all_features() if not f.is_standard()])
options.hide = options.hide.union(feature_names)
if 'optional' in options.hide:
options.hide.discard('optional')
from sage.features.all import all_features
feature_names = set([f.name for f in all_features() if f.is_optional()])
options.hide = options.hide.union(feature_names)

options.disabled_optional = set()
if isinstance(options.optional, str):
s = options.optional.lower()
Expand All @@ -417,6 +438,8 @@ def __init__(self, options, args):
options.optional.discard('optional')
from sage.misc.package import list_packages
for pkg in list_packages('optional', local=True).values():
if pkg.name in options.hide:
continue
if pkg.is_installed() and pkg.installed_version == pkg.remote_version:
options.optional.add(pkg.name)

Expand Down Expand Up @@ -1330,6 +1353,49 @@ def run(self):
Features detected...
0
We test the ``--hide`` option (:trac:`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()
729
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
"""
opt = self.options
L = (opt.gdb, opt.lldb, opt.valgrind, opt.massif, opt.cachegrind, opt.omega)
Expand Down Expand Up @@ -1370,6 +1436,21 @@ def run(self):

self.log("Using --optional=" + self._optional_tags_string())
available_software._allow_external = self.options.optional is True or 'external' in self.options.optional

for h in self.options.hide:
try:
i = available_software._indices[h]
except KeyError:
pass
else:
f = available_software._features[i]
if f.is_present():
f.hide()
self.options.hidden_features.add(f)
for g in f.joined_features():
if g.name in self.options.optional:
self.options.optional.discard(g.name)

for o in self.options.disabled_optional:
try:
i = available_software._indices[o]
Expand All @@ -1379,12 +1460,17 @@ def run(self):
available_software._seen[i] = -1

self.log("Features to be detected: " + ','.join(available_software.detectable()))
if self.options.hidden_features:
self.log("Hidden features: " + ','.join([f.name for f in self.options.hidden_features]))
self.add_files()
self.expand_files_into_sources()
self.filter_sources()
self.sort_sources()
self.run_doctests()

for f in self.options.hidden_features:
f.unhide()

self.log("Features detected for doctesting: "
+ ','.join(available_software.seen()))
self.cleanup()
Expand Down Expand Up @@ -1465,3 +1551,34 @@ def stringify(x):
if not save_dtmode and IP is not None:
IP.run_line_magic('colors', old_color)
IP.config.TerminalInteractiveShell.colors = old_config_color


###############################################################################
# Declaration of doctest strings
###############################################################################

test_hide=r"""r{quotmark}
{prompt}: next(graphs.fullerenes(20))
Traceback (most recent call last):
...
FeatureNotPresentError: buckygen is not available.
...
{prompt}: next(graphs.fullerenes(20)) # optional buckygen
Graph on 20 vertices
{prompt}: len(list(graphs.fusenes(2)))
Traceback (most recent call last):
...
FeatureNotPresentError: benzene is not available.
...
{prompt}: len(list(graphs.fusenes(2))) # optional benzene
1
{prompt}: from sage.matrix.matrix_space import get_matrix_class
{prompt}: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe')
Failed lazy import:
sage.matrix.matrix_gfpn_dense is not available.
...
{prompt}: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') # optional meataxe
<class 'sage.matrix.matrix_gfpn_dense.Matrix_gfpn_dense'>
{quotmark}
""".format(quotmark='"""', prompt='sage') # using prompt to hide these lines from _test_enough_doctests
Loading

0 comments on commit a6ab2f6

Please sign in to comment.