@@ -657,7 +657,7 @@ def absolute_filename(self) -> str:
657657
658658class Executable (FileFeature ):
659659 r"""
660- A feature describing an executable in the ``PATH`` .
660+ A feature describing an executable.
661661
662662 In an installation of Sage with ``SAGE_LOCAL`` different from ``SAGE_VENV``, the
663663 executable is searched first in ``SAGE_VENV/bin``, then in ``SAGE_LOCAL/bin``,
@@ -680,7 +680,9 @@ class Executable(FileFeature):
680680 sage: Executable(name='does-not-exist', executable='does-not-exist-xxxxyxyyxyy').is_present()
681681 FeatureTestResult('does-not-exist', False)
682682 """
683- def __init__ (self , name , executable , ** kwds ):
683+ executable : Path
684+
685+ def __init__ (self , name : str , executable : Path | str , ** kwds ) -> None :
684686 r"""
685687 TESTS::
686688
@@ -689,9 +691,9 @@ def __init__(self, name, executable, **kwds):
689691 True
690692 """
691693 Feature .__init__ (self , name , ** kwds )
692- self .executable = executable
694+ self .executable = Path ( executable )
693695
694- def _is_present (self ):
696+ def _is_present (self ) -> FeatureTestResult :
695697 r"""
696698 Test whether the executable is on the current PATH and functional.
697699
@@ -708,7 +710,7 @@ def _is_present(self):
708710 return result
709711 return self .is_functional ()
710712
711- def is_functional (self ):
713+ def is_functional (self ) -> FeatureTestResult :
712714 r"""
713715 Return whether an executable in the path is functional.
714716
@@ -744,22 +746,31 @@ def absolute_filename(self) -> str:
744746 sage.features.FeatureNotPresentError: does-not-exist is not available.
745747 Executable 'does-not-exist-xxxxyxyyxyy' not found on PATH.
746748 """
747- if SAGE_LOCAL :
748- if Path (SAGE_VENV ).resolve () != Path (SAGE_LOCAL ).resolve ():
749- # As sage.env currently gives SAGE_LOCAL a fallback value from SAGE_VENV,
750- # SAGE_LOCAL is never unset. So we only use it if it differs from SAGE_VENV.
751- search_path = ':' .join ([os .path .join (SAGE_VENV , 'bin' ),
752- os .path .join (SAGE_LOCAL , 'bin' )])
753- path = shutil .which (self .executable , path = search_path )
754- if path is not None :
755- return path
749+ if self .executable .is_absolute () and self .executable .exists ():
750+ return str (self .executable .resolve ())
751+
752+ if (
753+ SAGE_LOCAL
754+ and SAGE_VENV
755+ and Path (SAGE_VENV ).resolve () != Path (SAGE_LOCAL ).resolve ()
756+ ):
757+ # As sage.env currently gives SAGE_LOCAL a fallback value from SAGE_VENV,
758+ # SAGE_LOCAL is never unset. So we only use it if it differs from SAGE_VENV.
759+ search_paths = os .pathsep .join (
760+ [os .path .join (SAGE_VENV , "bin" ), os .path .join (SAGE_LOCAL , "bin" )]
761+ )
762+ path = shutil .which (self .executable , path = search_paths )
763+ if path is not None :
764+ return path
756765 # Now look up in the regular PATH.
757766 path = shutil .which (self .executable )
758767 if path is not None :
759768 return path
760- raise FeatureNotPresentError (self ,
761- reason = "Executable {executable!r} not found on PATH." .format (executable = self .executable ),
762- resolution = self .resolution ())
769+ raise FeatureNotPresentError (
770+ self ,
771+ reason = f"Executable { self .executable !r} not found on PATH." ,
772+ resolution = self .resolution (),
773+ )
763774
764775
765776class StaticFile (FileFeature ):
0 commit comments