Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
fix_doctest_hide_option initial
  • Loading branch information
soehms committed Nov 20, 2023
commit 8d0147fcb04e0ee774580f451cc0cf01778b2680
62 changes: 37 additions & 25 deletions src/sage/doctest/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def __init__(self, options, args):
if options.gc:
options.timeout *= 2
if options.nthreads == 0:
options.nthreads = int(os.getenv('SAGE_NUM_THREADS_PARALLEL',1))
options.nthreads = int(os.getenv('SAGE_NUM_THREADS_PARALLEL', 1))
if options.failed and not (args or options.new):
# If the user doesn't specify any files then we rerun all failed files.
options.all = True
Expand Down Expand Up @@ -457,15 +457,11 @@ def __init__(self, options, args):
options.hide.discard('all')
from sage.features.all import all_features
feature_names = {f.name for f in all_features() if not f.is_standard()}
from sage.doctest.external import external_software
feature_names.difference_update(external_software)
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 = {f.name for f in all_features() if f.is_optional()}
from sage.doctest.external import external_software
feature_names.difference_update(external_software)
options.hide = options.hide.union(feature_names)

options.disabled_optional = set()
Expand Down Expand Up @@ -1015,7 +1011,7 @@ def expand():
if os.path.isdir(path):
for root, dirs, files in os.walk(path):
for dir in list(dirs):
if dir[0] == "." or skipdir(os.path.join(root,dir)):
if dir[0] == "." or skipdir(os.path.join(root, dir)):
dirs.remove(dir)
for file in files:
if not skipfile(os.path.join(root, file),
Expand Down Expand Up @@ -1320,9 +1316,9 @@ def run_val_gdb(self, testing=False):
flags = os.getenv("SAGE_MEMCHECK_FLAGS")
if flags is None:
flags = "--leak-resolution=high --leak-check=full --num-callers=25 "
flags += '''--suppressions="%s" ''' % (os.path.join(SAGE_EXTCODE,"valgrind", "pyalloc.supp"))
flags += '''--suppressions="%s" ''' % (os.path.join(SAGE_EXTCODE,"valgrind", "sage.supp"))
flags += '''--suppressions="%s" ''' % (os.path.join(SAGE_EXTCODE,"valgrind", "sage-additional.supp"))
flags += '''--suppressions="%s" ''' % (os.path.join(SAGE_EXTCODE, "valgrind", "pyalloc.supp"))
flags += '''--suppressions="%s" ''' % (os.path.join(SAGE_EXTCODE, "valgrind", "sage.supp"))
flags += '''--suppressions="%s" ''' % (os.path.join(SAGE_EXTCODE, "valgrind", "sage-additional.supp"))
elif opt.massif:
toolname = "massif"
flags = os.getenv("SAGE_MASSIF_FLAGS", "--depth=6 ")
Expand All @@ -1337,7 +1333,7 @@ def run_val_gdb(self, testing=False):
if opt.omega:
toolname = "omega"
if "%s" in flags:
flags %= toolname + ".%p" # replace %s with toolname
flags %= toolname + ".%p" # replace %s with toolname
cmd += flags + sage_cmd

sys.stdout.flush()
Expand Down Expand Up @@ -1464,6 +1460,25 @@ def run(self):
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
"""
opt = self.options
L = (opt.gdb, opt.lldb, opt.valgrind, opt.massif, opt.cachegrind, opt.omega)
Expand Down Expand Up @@ -1491,10 +1506,10 @@ def run(self):
pass
try:
ref = subprocess.check_output(["git",
"--git-dir=" + SAGE_ROOT_GIT,
"describe",
"--always",
"--dirty"])
"--git-dir=" + SAGE_ROOT_GIT,
"describe",
"--always",
"--dirty"])
ref = ref.decode('utf-8')
self.log("Git ref: " + ref, end="")
except subprocess.CalledProcessError:
Expand All @@ -1512,12 +1527,11 @@ def run(self):
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)
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:
Expand All @@ -1528,8 +1542,6 @@ 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]))
if self.options.probe:
self.log("Features to be probed: " + ('all' if self.options.probe is True
else ','.join(self.options.probe)))
Expand All @@ -1539,11 +1551,11 @@ def run(self):
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()))
if self.options.hidden_features:
features_hidden = [f.name for f in self.options.hidden_features if f.unhide()]
self.log("Features that have been hidden: " + ','.join(features_hidden))
self.cleanup()
return self.reporter.error_status

Expand Down
55 changes: 32 additions & 23 deletions src/sage/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ def __init__(self, name, spkg=None, url=None, description=None, type='optional')
self._hidden = False
self._type = type

# For multiprocessing of doctests, the data self._num_hidings should be
# shared among subprocesses. Thus we use the Value class from the
# multiprocessing module (cf. self._seen of class AvailableSoftware)
from multiprocessing import Value
self._num_hidings = Value('i', 0)

try:
from sage.misc.package import spkg_type
except ImportError: # may have been surgically removed in a downstream distribution
Expand Down Expand Up @@ -205,15 +211,21 @@ def is_present(self):
sage: TestFeature("other").is_present()
FeatureTestResult('other', True)
"""
if self._hidden:
return FeatureTestResult(self, False, reason="Feature `{name}` is hidden.".format(name=self.name))
# We do not use @cached_method here because we wish to use
# Feature early in the build system of sagelib.
if self._cache_is_present is None:
res = self._is_present()
if not isinstance(res, FeatureTestResult):
res = FeatureTestResult(self, res)
self._cache_is_present = res

if self._hidden:
if self._num_hidings.value > 0:
self._num_hidings.value += 1
elif self._cache_is_present:
self._num_hidings.value = 1
return FeatureTestResult(self, False, reason="Feature `{name}` is hidden.".format(name=self.name))

return self._cache_is_present

def _is_present(self):
Expand Down Expand Up @@ -386,37 +398,34 @@ def hide(self):
Feature `benzene` is hidden.
Use method `unhide` to make it available again.

sage: Benzene().unhide()
sage: Benzene().unhide() # optional - benzene, needs sage.graphs
1
sage: len(list(graphs.fusenes(2))) # optional - benzene, needs sage.graphs
1
"""
self._hidden = True

def unhide(self):
r"""
Revert what :meth:`hide` does.
Revert what :meth:`hide` does. It returns the number of events
a present feature has been hidden.

EXAMPLES:

Polycyclic is a standard GAP package since 4.10 (see :trac:`26856`). The
following test just fails if it is hidden. Thus, in the second
invocation no optional tag is needed::

sage: from sage.features.gap import GapPackage
sage: Polycyclic = GapPackage("polycyclic", spkg="gap_packages")
sage: Polycyclic.hide()
sage: libgap(AbelianGroup(3, [0,3,4], names="abc")) # needs sage.libs.gap
Traceback (most recent call last):
...
FeatureNotPresentError: gap_package_polycyclic is not available.
Feature `gap_package_polycyclic` is hidden.
Use method `unhide` to make it available again.

sage: Polycyclic.unhide()
sage: libgap(AbelianGroup(3, [0,3,4], names="abc")) # needs sage.libs.gap
Pcp-group with orders [ 0, 3, 4 ]
sage: from sage.features.sagemath import sage__plot
sage: sage__plot().hide()
sage: sage__plot().is_present()
FeatureTestResult('sage.plot', False)
sage: sage__plot().unhide() # needs sage.plot
1
sage: sage__plot().is_present() # needs sage.plot
FeatureTestResult('sage.plot', True)
"""
num_hidings = self._num_hidings.value
self._num_hidings.value = 0
self._hidden = False
return int(num_hidings)


class FeatureNotPresentError(RuntimeError):
r"""
Expand Down Expand Up @@ -801,15 +810,15 @@ class StaticFile(FileFeature):
To install no_such_file...you can try to run...sage -i some_spkg...
Further installation instructions might be available at http://rand.om.
"""
def __init__(self, name, filename, search_path=None, **kwds):
def __init__(self, name, filename, search_path=None, type='optional', **kwds):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the * there was there intentionally. It marks the following parameters as keyword-only (cannot be passed as positional)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I will do this later on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This id done, now! I took the occasion to also improve some doctest tags concerning the Gap package Grape which I came across.

r"""
TESTS::

sage: from sage.features import StaticFile
sage: StaticFile(name="null", filename="null", search_path=("/dev",))
Feature('null')
"""
Feature.__init__(self, name, **kwds)
Feature.__init__(self, name, type=type, **kwds)
self.filename = filename
if search_path is None:
self.search_path = [SAGE_SHARE]
Expand Down
6 changes: 3 additions & 3 deletions src/sage/features/databases.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ class DatabaseCremona(StaticFile):
EXAMPLES::

sage: from sage.features.databases import DatabaseCremona
sage: DatabaseCremona('cremona_mini').is_present()
sage: DatabaseCremona('cremona_mini', type='sandard').is_present()
FeatureTestResult('database_cremona_mini_ellcurve', True)
sage: DatabaseCremona().is_present() # optional - database_cremona_ellcurve
FeatureTestResult('database_cremona_ellcurve', True)
"""
def __init__(self, name="cremona", spkg="database_cremona_ellcurve"):
def __init__(self, name="cremona", spkg="database_cremona_ellcurve", type='optional'):
r"""
TESTS::

Expand Down Expand Up @@ -198,7 +198,7 @@ def __init__(self, name='polytopes_db', dirname='Full3D'):

def all_features():
return [DatabaseConwayPolynomials(),
DatabaseCremona(), DatabaseCremona('cremona_mini'),
DatabaseCremona(), DatabaseCremona('cremona_mini', type='standard'),
DatabaseJones(),
DatabaseKnotInfo(),
DatabaseCubicHecke(),
Expand Down
10 changes: 7 additions & 3 deletions src/sage/features/join_feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ def hide(self):

def unhide(self):
r"""
Revert what :meth:`hide` does.
Revert what :meth:`hide` does. It returns the number of events
a present feature has been hidden.

EXAMPLES::

Expand All @@ -165,11 +166,14 @@ def unhide(self):
FeatureTestResult('sage.groups.perm_gps.permgroup', False)

sage: f.unhide()
4
sage: f.is_present() # optional sage.groups
FeatureTestResult('sage.groups', True)
sage: f._features[0].is_present() # optional sage.groups
FeatureTestResult('sage.groups.perm_gps.permgroup', True)
"""
num_hidings = 0
for f in self._features:
f.unhide()
super().unhide()
num_hidings += f.unhide()
num_hidings += super().unhide()
return num_hidings