diff --git a/src/sage/features/interfaces.py b/src/sage/features/interfaces.py index ddfc3b9b7ee..cf82182dec1 100644 --- a/src/sage/features/interfaces.py +++ b/src/sage/features/interfaces.py @@ -14,7 +14,7 @@ import importlib -from . import Feature, FeatureTestResult, PythonModule +from . import Executable, Feature, FeatureTestResult, PythonModule class InterfaceFeature(Feature): @@ -37,7 +37,7 @@ class InterfaceFeature(Feature): "Interface also_broken_interface cannot be imported: module 'sage.interfaces.interface' has no attribute 'also_broken_interface'" """ @staticmethod - def __classcall__(cls, name, module, description=None): + def __classcall__(cls, name, module, description=None, **kwds): """ TESTS:: @@ -49,9 +49,9 @@ def __classcall__(cls, name, module, description=None): """ if isinstance(module, str): module = PythonModule(module) - return Feature.__classcall__(cls, name, module, description) + return Feature.__classcall__(cls, name, module, description, **kwds) - def __init__(self, name, module, description): + def __init__(self, name, module, description, **kwds): """ TESTS:: @@ -60,7 +60,7 @@ def __init__(self, name, module, description): sage: isinstance(f, InterfaceFeature) True """ - super().__init__(name, description=description) + super().__init__(name, description=description, **kwds) self.module = module def _is_present(self): @@ -90,6 +90,38 @@ def _is_present(self): reason=f"Interface {interface} is not functional: {exception}") +class FriCASExecutable(Executable): + r""" + A :class:`~sage.features.Feature` describing whether :class:`sage.interfaces.fricas.FriCAS` + is present and functional. + + EXAMPLES:: + + sage: from sage.features.interfaces import FriCASExecutable + sage: FriCASExecutable().is_present() # random + FeatureTestResult('fricas_exe', False) + """ + @staticmethod + def __classcall__(cls): + return Executable.__classcall__(cls, 'fricas_exe', 'fricas', spkg='fricas') + + +class FriCAS(InterfaceFeature): + r""" + A :class:`~sage.features.Feature` describing whether :class:`sage.interfaces.fricas.FriCAS` + is present and functional. + + EXAMPLES:: + + sage: from sage.features.interfaces import FriCAS + sage: FriCAS().is_present() # random + FeatureTestResult('fricas', False) + """ + @staticmethod + def __classcall__(cls): + return InterfaceFeature.__classcall__(cls, 'fricas', 'sage.interfaces.fricas', spkg='fricas') + + # The following are provided by external software only (no SPKG) class Magma(InterfaceFeature): @@ -219,7 +251,8 @@ def all_features(): sage: from sage.features.interfaces import all_features sage: list(all_features()) - [Feature('magma'), + [Feature('fricas'), + Feature('magma'), Feature('matlab'), Feature('mathematica'), Feature('maple'), @@ -227,7 +260,8 @@ def all_features(): Feature('octave'), Feature('scilab')] """ - return [Magma(), + return [FriCAS(), + Magma(), Matlab(), Mathematica(), Maple(), diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index c771aea716c..04258a5e71c 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -264,7 +264,7 @@ class FriCAS(ExtraTabCompletion, Expect): """ Interface to a FriCAS interpreter. """ - def __init__(self, name='fricas', command='fricas -nosman', + def __init__(self, name='fricas', command=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None): """ @@ -289,6 +289,10 @@ def __init__(self, name='fricas', command='fricas -nosman', sage: fricas(I*x).sage() # optional - fricas I*x """ + if command is None: + from sage.features.interfaces import FriCASExecutable + fricas_exe = FriCASExecutable().absolute_filename() + command = f'{fricas_exe} -nosman' eval_using_file_cutoff = 4096 - 5 # magic number from Expect._eval_line (there might be a bug) assert max(len(c) for c in FRICAS_INIT_CODE) < eval_using_file_cutoff self.__eval_using_file_cutoff = eval_using_file_cutoff