Skip to content
Merged
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
5 changes: 3 additions & 2 deletions src/sage/doctest/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -1577,8 +1577,9 @@ def run(self):
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))
for f in self.options.hidden_features:
f.unhide()
self.log("Features that have been hidden: " + ','.join(available_software.hidden()))
self.cleanup()
return self.reporter.error_status

Expand Down
52 changes: 42 additions & 10 deletions src/sage/doctest/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ def __init__(self):
self._features = sorted(features, key=lambda feature: feature.name)
self._indices = {feature.name: idx for idx, feature in enumerate(self._features)}
self._seen = Array('i', len(self._features)) # initialized to zeroes
self._hidden = Array('i', len(self._features)) # initialized to zeroes

def __contains__(self, item):
"""
Expand All @@ -444,19 +445,26 @@ def __contains__(self, item):
idx = self._indices[item]
except KeyError:
return False
if not self._seen[idx]:
if not self._allow_external and self._features[idx] in self._external_features:
self._seen[idx] = -1 # not available
elif self._features[idx].is_present():
self._seen[idx] = 1 # available
feature = self._features[idx]
if feature.is_hidden():
if not self._hidden[idx]:
self._hidden[idx] = 1
available = False # a hidden feature is considered to be not available
else:
if not self._allow_external and feature in self._external_features:
# an external feature is considered to be not available
# if this is not allowed
available = False
elif feature.is_present():
available = True
else:
self._seen[idx] = -1 # not available
if self._seen[idx] == 1:
available = False
if available:
if not self._seen[idx]:
self._seen[idx] = 1
return True
elif self._seen[idx] == -1:
return False
else:
raise AssertionError("Invalid value for self.seen")
return False

def issuperset(self, other):
"""
Expand Down Expand Up @@ -495,5 +503,29 @@ def seen(self):
for feature, seen in zip(self._features, self._seen)
if seen > 0]

def hidden(self):
"""
Return the list of detected hidden external software.

EXAMPLES::

sage: # needs conway_polynomials database_cremona_mini_ellcurve database_ellcurves database_graphs
sage: from sage.doctest.external import available_software
sage: from sage.features.databases import all_features
sage: for f in all_features():
....: f.hide()
....: if f._spkg_type() == 'standard':
....: test = f.name in available_software
....: f.unhide()
sage: sorted(available_software.hidden())
[...'conway_polynomials',...
'database_cremona_mini_ellcurve',...
'database_ellcurves',...
'database_graphs'...]
"""
return [feature.name
for feature, hidden in zip(self._features, self._hidden)
if hidden > 0]


available_software = AvailableSoftware()
37 changes: 17 additions & 20 deletions src/sage/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,6 @@ 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, lock=False)

try:
from sage.misc.package import spkg_type
except ImportError: # may have been surgically removed in a downstream distribution
Expand Down Expand Up @@ -220,10 +214,6 @@ def is_present(self):
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
Expand Down Expand Up @@ -354,7 +344,6 @@ def is_standard(self):
sage: from sage.features.databases import DatabaseCremona
sage: DatabaseCremona().is_standard()
False

"""
if self.name.startswith('sage.'):
return True
Expand All @@ -369,7 +358,6 @@ def is_optional(self):
sage: from sage.features.databases import DatabaseCremona
sage: DatabaseCremona().is_optional()
True

"""
return self._spkg_type() == 'optional'

Expand All @@ -394,34 +382,43 @@ def hide(self):
Use method `unhide` to make it available again.

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` did.

OUTPUT: The number of events a present feature has been hidden.

EXAMPLES:

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)

def is_hidden(self):
r"""
Return whether ``self`` is present but currently hidden.

EXAMPLES:

sage: from sage.features.sagemath import sage__plot
sage: sage__plot().hide()
sage: sage__plot().is_hidden() # needs sage.plot
True
sage: sage__plot().unhide()
sage: sage__plot().is_hidden()
False
"""
if self._hidden and self._is_present():
return True
return False

class FeatureNotPresentError(RuntimeError):
r"""
Expand Down
9 changes: 2 additions & 7 deletions src/sage/features/join_feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@ def unhide(self):
r"""
Revert what :meth:`hide` did.

OUTPUT: The number of events a present feature has been hidden.

EXAMPLES::

sage: from sage.features.sagemath import sage__groups
Expand All @@ -167,14 +165,11 @@ 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:
num_hidings += f.unhide()
num_hidings += super().unhide()
return num_hidings
f.unhide()
super().unhide()