From 5b25c1d0f6e6cf7216fd8e0124df233edf30e836 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Mar 2022 18:06:00 -0800 Subject: [PATCH 1/2] sage.features: Refactor StaticFile, Executable through a new base class FileFeature --- src/sage/features/__init__.py | 57 ++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 10d7d871b83..8203682397b 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -419,7 +419,38 @@ def package_systems(): return _cache_package_systems -class Executable(Feature): +class FileFeature(Feature): + r""" + Base class for features that describe a file or directory in the file system. + + A subclass should implement a method :meth:`absolute_path`. + + EXAMPLES:: + + sage: from sage.features import StaticFile, Executable, FileFeature + sage: issubclass(StaticFile, FileFeature) + True + sage: issubclass(Executable, FileFeature) + True + """ + def _is_present(self): + r""" + Whether the file is present. + + EXAMPLES:: + + sage: from sage.features import StaticFile + sage: StaticFile(name="no_such_file", filename="KaT1aihu", spkg="some_spkg", url="http://rand.om").is_present() + FeatureTestResult('no_such_file', False) + """ + try: + abspath = self.absolute_path() + return FeatureTestResult(self, True, reason="Found at `{abspath}`.".format(abspath=abspath)) + except FeatureNotPresentError as e: + return FeatureTestResult(self, False, reason=e.reason, resolution=e.resolution) + + +class Executable(FileFeature): r""" A feature describing an executable in the ``PATH``. @@ -463,11 +494,9 @@ def _is_present(self): sage: Executable(name="sh", executable="sh").is_present() FeatureTestResult('sh', True) """ - try: - abspath = self.absolute_path() - return FeatureTestResult(self, True, reason="Found at `{abspath}`.".format(abspath=abspath)) - except FeatureNotPresentError as e: - return FeatureTestResult(self, False, reason=e.reason, resolution=e.resolution) + result = FileFeature._is_present(self) + if not result: + return result return self.is_functional() def is_functional(self): @@ -510,7 +539,7 @@ def absolute_path(self) -> str: resolution=self.resolution()) -class StaticFile(Feature): +class StaticFile(FileFeature): r""" A :class:`Feature` which describes the presence of a certain file such as a database. @@ -541,20 +570,6 @@ def __init__(self, name, filename, search_path=None, **kwds): else: self.search_path = list(search_path) - def _is_present(self): - r""" - Whether the static file is present. - - sage: from sage.features import StaticFile - sage: StaticFile(name="no_such_file", filename="KaT1aihu", spkg="some_spkg", url="http://rand.om").is_present() - FeatureTestResult('no_such_file', False) - """ - try: - abspath = self.absolute_path() - return FeatureTestResult(self, True, reason="Found at `{abspath}`.".format(abspath=abspath)) - except FeatureNotPresentError as e: - return FeatureTestResult(self, False, reason=e.reason, resolution=e.resolution) - def absolute_path(self) -> str: r""" The absolute path of the file. From 6c3571755e46ca99c02114e02afa767e56dde1cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Mar 2022 18:20:26 -0800 Subject: [PATCH 2/2] sage.features.FileFeature: Replace method absolute_path by absolute_filename, with deprecation --- src/sage/databases/conway.py | 2 +- src/sage/databases/cremona.py | 2 +- src/sage/databases/jones.py | 2 +- src/sage/features/__init__.py | 40 +++++++++++++++++++++++++++-------- src/sage/features/latex.py | 4 ++-- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/sage/databases/conway.py b/src/sage/databases/conway.py index 2119549c13d..6ef5c61bf47 100644 --- a/src/sage/databases/conway.py +++ b/src/sage/databases/conway.py @@ -101,7 +101,7 @@ def __init__(self): """ global _conwaydict if _conwaydict is None: - _CONWAYDATA = DatabaseConwayPolynomials().absolute_path() + _CONWAYDATA = DatabaseConwayPolynomials().absolute_filename() with open(_CONWAYDATA, 'rb') as f: _conwaydict = pickle.load(f) self._store = _conwaydict diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 6353ad7bbfe..f6364976dc7 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -669,7 +669,7 @@ def __init__(self, name, read_only=True, build=False): """ self.name = name name = name.replace(' ', '_') - db_path = DatabaseCremona(name=name).absolute_path() + db_path = DatabaseCremona(name=name).absolute_filename() if build: if read_only: raise RuntimeError('The database must not be read_only.') diff --git a/src/sage/databases/jones.py b/src/sage/databases/jones.py index d6eef45cafd..da1e730c65c 100644 --- a/src/sage/databases/jones.py +++ b/src/sage/databases/jones.py @@ -225,7 +225,7 @@ def get(self, S, var='a'): ValueError: S must be a list of primes """ if self.root is None: - self.root = load(DatabaseJones().absolute_path()) + self.root = load(DatabaseJones().absolute_filename()) try: S = list(S) except TypeError: diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 8203682397b..41bf8e49f32 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -423,7 +423,7 @@ class FileFeature(Feature): r""" Base class for features that describe a file or directory in the file system. - A subclass should implement a method :meth:`absolute_path`. + A subclass should implement a method :meth:`absolute_filename`. EXAMPLES:: @@ -444,11 +444,33 @@ def _is_present(self): FeatureTestResult('no_such_file', False) """ try: - abspath = self.absolute_path() + abspath = self.absolute_filename() return FeatureTestResult(self, True, reason="Found at `{abspath}`.".format(abspath=abspath)) except FeatureNotPresentError as e: return FeatureTestResult(self, False, reason=e.reason, resolution=e.resolution) + def absolute_path(self): + r""" + Deprecated alias for :meth:`absolute_filename`. + + Deprecated to make way for a method of this name returning a ``Path``. + + EXAMPLES:: + + sage: from sage.features import Executable + sage: Executable(name="sh", executable="sh").absolute_path() + doctest:warning... + DeprecationWarning: method absolute_path has been replaced by absolute_filename + See https://trac.sagemath.org/31292 for details. + '/...bin/sh' + """ + try: + from sage.misc.superseded import deprecation + except ImportError: + pass + deprecation(31292, 'method absolute_path has been replaced by absolute_filename') + return self.absolute_filename() + class Executable(FileFeature): r""" @@ -513,14 +535,14 @@ def is_functional(self): """ return FeatureTestResult(self, True) - def absolute_path(self) -> str: + def absolute_filename(self) -> str: r""" - The absolute path of the executable. + The absolute path of the executable as a string. EXAMPLES:: sage: from sage.features import Executable - sage: Executable(name="sh", executable="sh").absolute_path() + sage: Executable(name="sh", executable="sh").absolute_filename() '/...bin/sh' A :class:`FeatureNotPresentError` is raised if the file cannot be found:: @@ -570,9 +592,9 @@ def __init__(self, name, filename, search_path=None, **kwds): else: self.search_path = list(search_path) - def absolute_path(self) -> str: + def absolute_filename(self) -> str: r""" - The absolute path of the file. + The absolute path of the file as a string. EXAMPLES:: @@ -583,13 +605,13 @@ def absolute_path(self) -> str: sage: open(file_path, 'a').close() # make sure the file exists sage: search_path = ( '/foo/bar', dir_with_file ) # file is somewhere in the search path sage: feature = StaticFile(name="file", filename="file.txt", search_path=search_path) - sage: feature.absolute_path() == file_path + sage: feature.absolute_filename() == file_path True A :class:`FeatureNotPresentError` is raised if the file cannot be found:: sage: from sage.features import StaticFile - sage: StaticFile(name="no_such_file", filename="KaT1aihu", search_path=(), spkg="some_spkg", url="http://rand.om").absolute_path() # optional - sage_spkg + sage: StaticFile(name="no_such_file", filename="KaT1aihu", search_path=(), spkg="some_spkg", url="http://rand.om").absolute_filename() # optional - sage_spkg Traceback (most recent call last): ... FeatureNotPresentError: no_such_file is not available. diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index eba827a4978..b8915502582 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -153,7 +153,7 @@ class TeXFile(StaticFile): def __init__(self, name, filename, **kwds): StaticFile.__init__(self, name, filename, search_path=[], **kwds) - def absolute_path(self): + def absolute_filename(self) -> str: r""" The absolute path of the file. @@ -161,7 +161,7 @@ def absolute_path(self): sage: from sage.features.latex import TeXFile sage: feature = TeXFile('latex_class_article', 'article.cls') - sage: feature.absolute_path() # optional - pdflatex + sage: feature.absolute_filename() # optional - pdflatex '.../latex/base/article.cls' """ from subprocess import run, CalledProcessError, PIPE