diff --git a/.gitignore b/.gitignore index 1d7eacdf9e4..70a6739c33b 100644 --- a/.gitignore +++ b/.gitignore @@ -261,6 +261,7 @@ build/pkgs/wheel/version_requirements.txt /src/doc/en/reference/*/sage_docbuild /src/doc/en/reference/sage /src/doc/en/reference/spkg/*.rst +!/src/doc/en/reference/spkg/index.rst /src/doc/output /src/doc/en/installation/*.txt /src/doc/en/reference/repl/*.txt diff --git a/Makefile b/Makefile index 00989597a11..53d2c689843 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,7 @@ distclean: build-clean bootstrap-clean: rm -rf config/install-sh config/compile config/config.guess config/config.sub config/missing configure build/make/Makefile-auto.in rm -f src/doc/en/installation/*.txt - rm -rf src/doc/en/reference/spkg/*.rst + find src/doc/en/reference/spkg -name index.rst -prune -o -maxdepth 1 -name "*.rst" -exec rm -f {} \+ for a in environment environment-optional src/environment src/environment-dev src/environment-optional; do rm -f $$a.yml $$a-3.[89].yml $$a-3.1[0-9].yml; done rm -f src/Pipfile rm -f src/requirements.txt diff --git a/bootstrap b/bootstrap index eb5bcd732b6..434a3b87396 100755 --- a/bootstrap +++ b/bootstrap @@ -234,7 +234,7 @@ save () { config/install-sh config/compile config/config.guess config/config.sub config/missing \ build/make/Makefile-auto.in \ src/doc/en/installation/*.txt \ - src/doc/en/reference/spkg/*.rst \ + $(find src/doc/en/reference/spkg -name index.rst -prune -o -maxdepth 1 -name "*.rst" -print) \ environment-3.[89].yml environment-3.1[0-9].yml \ src/environment-3.[89].yml src/environment-3.1[0-9].yml \ environment-optional-3.[89].yml environment-optional-3.1[0-9].yml \ diff --git a/src/doc/bootstrap b/src/doc/bootstrap index 32a31430554..e99ecd52c28 100755 --- a/src/doc/bootstrap +++ b/src/doc/bootstrap @@ -84,28 +84,15 @@ mkdir -p "$OUTPUT_DIR" if [ "${BOOTSTRAP_QUIET}" = "no" ]; then echo >&2 $0:$LINENO: installing "$OUTPUT_DIR"/"*.rst" fi -OUTPUT_INDEX="$OUTPUT_DIR"/index.rst -cat > "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" < "$OUTPUT_DIR"/index_standard.rst +(cat <> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" < "$OUTPUT_DIR"/index_optional.rst for PKG_BASE in $(sage-package list --has-file SPKG.rst | grep '^sagemath_'); do echo "* :ref:\`spkg_$PKG_BASE\`" -done >> "$OUTPUT_INDEX" -cat >> "$OUTPUT_INDEX" < "$OUTPUT_DIR"/index_sagemath.rst +(cat <> "$OUTPUT_INDEX" +done -cat >> "$OUTPUT_INDEX" <> "$OUTPUT_INDEX" - -cat >> "$OUTPUT_INDEX" < "$OUTPUT_DIR"/index_experimental.rst (cat < "$OUTPUT_INDEX" +) > "$OUTPUT_DIR"/index_alph.rst sage-package list --has-file SPKG.rst | OUTPUT_DIR=$OUTPUT_DIR OUTPUT_RST=1 xargs -P 99 -n 1 sage-spkg-info diff --git a/src/doc/en/reference/spkg/index.rst b/src/doc/en/reference/spkg/index.rst new file mode 100644 index 00000000000..e9ba934a540 --- /dev/null +++ b/src/doc/en/reference/spkg/index.rst @@ -0,0 +1,87 @@ +.. _spkg: + +Packages and Features +===================== + +Standard Packages +----------------- + +The Sage distribution includes most programs and libraries on which +Sage depends. It installs them automatically if it does not find +equivalent system packages. + +.. include:: index_standard.rst + + +Optional Packages +----------------- + +For additional functionality, you can install some of the following +optional packages. + +.. include:: index_optional.rst + + +Features +-------- + +.. toctree:: + :maxdepth: 1 + + sage/features + sage/features/join_feature + sage/features/all + sage/features/sagemath + sage/features/pkg_systems + sage/features/bliss + sage/features/csdp + sage/features/databases + sage/features/dvipng + sage/features/ffmpeg + sage/features/four_ti_2 + sage/features/gap + sage/features/graph_generators + sage/features/graphviz + sage/features/imagemagick + sage/features/interfaces + sage/features/internet + sage/features/kenzo + sage/features/latex + sage/features/latte + sage/features/lrs + sage/features/mcqd + sage/features/meataxe + sage/features/mip_backends + sage/features/normaliz + sage/features/pandoc + sage/features/pdf2svg + sage/features/polymake + sage/features/rubiks + sage/features/tdlib + sage/features/topcom + + +Distribution Packages of the Sage Library +----------------------------------------- + +.. include:: index_sagemath.rst + + +Experimental Packages +--------------------- + +Some packages that provide additional functionality are marked as +"experimental". Developers are needed in order to improve the +integration of these packages into the Sage distribution. + +.. include:: index_experimental.rst + + +All External Packages +--------------------- + +.. toctree:: + :maxdepth: 1 + + index_alph + diff --git a/src/sage/features/topcom.py b/src/sage/features/topcom.py new file mode 100644 index 00000000000..5256519ce3d --- /dev/null +++ b/src/sage/features/topcom.py @@ -0,0 +1,67 @@ +# sage_setup: distribution = sagemath-environment +r""" +Features for testing the presence of topcom executables +""" + +# ***************************************************************************** +# Copyright (C) 2022-2024 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from . import Executable +from .join_feature import JoinFeature + + +class TOPCOMExecutable(Executable): + r""" + A :class:`~sage.features.Feature` which checks for executables from the :ref:`TOPCOM ` package. + + EXAMPLES:: + + sage: from sage.features.topcom import TOPCOMExecutable + sage: TOPCOMExecutable('points2allfinetriangs').is_present() # optional - topcom + FeatureTestResult('topcom_points2allfinetriangs', True) + """ + def __init__(self, name): + r""" + TESTS:: + + sage: from sage.features.topcom import TOPCOMExecutable + sage: isinstance(TOPCOMExecutable('points2finetriangs'), TOPCOMExecutable) + True + """ + Executable.__init__(self, name=f"topcom_{name}", + executable=name, + spkg="topcom") + + +class TOPCOM(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of the executables + which comes as a part of :ref:`TOPCOM `. + + EXAMPLES:: + + sage: from sage.features.topcom import TOPCOM + sage: TOPCOM().is_present() # optional - topcom + FeatureTestResult('topcom', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.topcom import TOPCOM + sage: isinstance(TOPCOM(), TOPCOM) + True + """ + JoinFeature.__init__(self, "topcom", + [TOPCOMExecutable(name) + for name in ('points2allfinetriangs',)]) + + +def all_features(): + return [TOPCOM()] diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index b71ae4cb348..d515f43ec8a 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -18,11 +18,7 @@ Finding a single triangulation and listing all connected triangulations is implemented natively in this package. However, for -more advanced options [TOPCOM]_ needs to be installed. It is available -as an optional package for Sage, and you can install it with the -shell command :: - - sage -i topcom +more advanced options [TOPCOM]_ needs to be installed; see :ref:`spkg_topcom`. .. note:: @@ -184,6 +180,8 @@ import itertools +from sage.features import FeatureNotPresentError +from sage.features.topcom import TOPCOMExecutable from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import @@ -291,7 +289,7 @@ def _have_TOPCOM(cls): PointConfiguration._have_TOPCOM_cached = True assert out == '{{0,1}}',\ 'TOPCOM ran but did not produce the correct output!' - except pexpect.ExceptionPexpect: + except (FeatureNotPresentError, pexpect.ExceptionPexpect): PointConfiguration._have_TOPCOM_cached = False PointConfiguration.set_engine('auto') @@ -613,7 +611,9 @@ def _TOPCOM_exec(cls, executable, input_string, verbose=True): ['{{0,1,2,4},{1,2,3,4}}'] """ timeout = 600 - proc = pexpect.spawn(executable, timeout=timeout) + executable_name, *args = executable.split() + executable_absname = TOPCOMExecutable(executable_name).absolute_filename() + proc = pexpect.spawn(executable_absname, args, timeout=timeout) proc.expect(r'Evaluating Commandline Options \.\.\.') proc.expect(r'\.\.\. done\.') proc.setecho(0)