diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py index bdc6399b82e..2889ef24d25 100644 --- a/src/sage/features/four_ti_2.py +++ b/src/sage/features/four_ti_2.py @@ -1,6 +1,8 @@ from sage.env import SAGE_ENV -from sage.features import Executable +from . import Executable +from .join_feature import JoinFeature + class FourTi2Executable(Executable): r""" @@ -11,3 +13,21 @@ def __init__(self, name): name="4ti2-" + name, executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, spkg="4ti2") + + +class FourTi2(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of the ``4ti2`` executables. + + EXAMPLES:: + + sage: from sage.features.four_ti_2 import FourTi2 + sage: FourTi2().is_present() # optional - 4ti2 + FeatureTestResult('4ti2', True) + """ + def __init__(self): + JoinFeature.__init__(self, '4ti2', + [FourTi2Executable(x) + # same list is tested in build/pkgs/4ti2/spkg-configure.m4 + for x in ('hilbert', 'markov', 'graver', 'zsolve', 'qsolve', + 'rays', 'ppi', 'circuits', 'groebner')]) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py new file mode 100644 index 00000000000..f011b40a7f6 --- /dev/null +++ b/src/sage/features/join_feature.py @@ -0,0 +1,82 @@ +r""" +Join features +""" + +from . import Feature, FeatureTestResult + + +class JoinFeature(Feature): + r""" + Join of several :class:`sage.features.Feature` instances. + + EXAMPLES:: + + sage: from sage.features import Executable + sage: from sage.features.join_feature import JoinFeature + sage: F = JoinFeature("shell-boolean", + ....: (Executable('shell-true', 'true'), + ....: Executable('shell-false', 'false'))) + sage: F.is_present() + FeatureTestResult('shell-boolean', True) + sage: F = JoinFeature("asdfghjkl", + ....: (Executable('shell-true', 'true'), + ....: Executable('xxyyyy', 'xxyyyy-does-not-exist'))) + sage: F.is_present() + FeatureTestResult('xxyyyy', False) + """ + def __init__(self, name, features, spkg=None, url=None): + """ + TESTS: + + The empty join feature is present:: + + sage: from sage.features.join_feature import JoinFeature + sage: JoinFeature("empty", ()).is_present() + FeatureTestResult('empty', True) + """ + if spkg is None: + spkgs = set(f.spkg for f in features if f.spkg) + if len(spkgs) > 1: + raise ValueError('given features have more than one spkg; provide spkg argument') + elif len(spkgs) == 1: + spkg = next(iter(spkgs)) + if url is None: + urls = set(f.url for f in features if f.url) + if len(urls) > 1: + raise ValueError('given features have more than one url; provide url argument') + elif len(urls) == 1: + url = next(iter(urls)) + super().__init__(name, spkg=spkg, url=url) + self._features = features + + def _is_present(self): + r""" + Test for the presence of the join feature. + + EXAMPLES:: + + sage: from sage.features.latte import Latte + sage: Latte()._is_present() # optional - latte_int + FeatureTestResult('LattE', True) + """ + for f in self._features: + test = f._is_present() + if not test: + return test + return FeatureTestResult(self, True) + + def is_functional(self): + r""" + Test whether the join feature is functional. + + EXAMPLES:: + + sage: from sage.features.latte import Latte + sage: Latte().is_functional() # optional - latte_int + FeatureTestResult('LattE', True) + """ + for f in self._features: + test = f.is_functional() + if not test: + return test + return FeatureTestResult(self, True) diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 5462331177d..6abc450281c 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -3,6 +3,8 @@ Check for LattE """ from . import Executable, Feature, FeatureTestResult +from .join_feature import JoinFeature + LATTE_URL = "https://www.math.ucdavis.edu/~latte/software.php" @@ -27,7 +29,7 @@ def __init__(self): url=LATTE_URL) -class Latte(Feature): +class Latte(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of the ``LattE`` binaries which comes as a part of ``latte_int``. @@ -46,39 +48,5 @@ def __init__(self): sage: isinstance(Latte(), Latte) True """ - Feature.__init__(self, "LattE") - - def _is_present(self): - r""" - Test for the presence of LattE binaries. - - EXAMPLES:: - - sage: from sage.features.latte import Latte - sage: Latte()._is_present() # optional - latte_int - FeatureTestResult('LattE', True) - """ - - test = (Latte_count()._is_present() and - Latte_integrate()._is_present()) - if not test: - return test - - return FeatureTestResult(self, True) - - def is_functional(self): - r""" - Test whether count and integrate are functionals. - - EXAMPLES:: - - sage: from sage.features.latte import Latte - sage: Latte().is_functional() # optional - latte_int - FeatureTestResult('LattE', True) - """ - test = (Latte_count().is_functional() and - Latte_integrate().is_functional()) - if not test: - return test - - return FeatureTestResult(self, True) + JoinFeature.__init__(self, "LattE", + (Latte_count(), Latte_integrate()))