diff --git a/src/sage/features/nauty.py b/src/sage/features/nauty.py new file mode 100644 index 00000000000..7a3bf87b6cc --- /dev/null +++ b/src/sage/features/nauty.py @@ -0,0 +1,59 @@ +r""" +Features for testing the presence of nauty executables +""" + +from sage.env import SAGE_NAUTY_BINS_PREFIX + +from . import Executable +from .join_feature import JoinFeature + + +class NautyExecutable(Executable): + r""" + A :class:`~sage.features.Feature` which checks for nauty executables. + + EXAMPLES:: + + sage: from sage.features.nauty import NautyExecutable + sage: NautyExecutable('converseg').is_present() # optional - nauty + FeatureTestResult('nauty_converseg', True) + """ + def __init__(self, name): + r""" + TESTS:: + + sage: from sage.features.nauty import NautyExecutable + sage: isinstance(NautyExecutable('geng'), NautyExecutable) + True + """ + Executable.__init__(self, name=f"nauty_{name}", + executable=f"{SAGE_NAUTY_BINS_PREFIX}{name}", + spkg="nauty") + + +class Nauty(JoinFeature): + r""" + A :class:`~sage.features.Feature` describing the presence of the executables + which comes as a part of ``nauty``. + + EXAMPLES:: + + sage: from sage.features.nauty import Nauty + sage: Nauty().is_present() # optional - nauty + FeatureTestResult('nauty', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.nauty import Nauty + sage: isinstance(Nauty(), Nauty) + True + """ + JoinFeature.__init__(self, "nauty", + [NautyExecutable(name) + for name in ('directg', 'gentourng', 'geng', 'genbg', 'converseg')]) + + +def all_features(): + return [Nauty()] diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index 45bf0bb7f5b..b8a6fc1cc0a 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -63,7 +63,6 @@ # http://www.gnu.org/licenses/ ################################################################################ from sage.cpython.string import bytes_to_str -from sage.env import SAGE_NAUTY_BINS_PREFIX as nautyprefix import sys from sage.misc.randstate import current_randstate @@ -528,7 +527,12 @@ def tournaments_nauty(self, n, nauty_input += " " + str(n) + " " - sp = subprocess.Popen(nautyprefix+"gentourng {0}".format(nauty_input), shell=True, + import shlex + from sage.features.nauty import NautyExecutable + gentourng_path = NautyExecutable("gentourng").absolute_filename() + + sp = subprocess.Popen(shlex.quote(gentourng_path) + " {0}".format(nauty_input), + shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) @@ -636,8 +640,13 @@ def nauty_directg(self, graphs, options="", debug=False): options += ' -q' # Build directg input (graphs6 format) - input = ''.join(g.graph6_string()+'\n' for g in graphs) - sub = subprocess.Popen(nautyprefix+'directg {0}'.format(options), + input = ''.join(g.graph6_string() + '\n' for g in graphs) + + import shlex + from sage.features.nauty import NautyExecutable + directg_path = NautyExecutable("directg").absolute_filename() + + sub = subprocess.Popen(shlex.quote(directg_path) + ' {0}'.format(options), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 56b60252eb1..8dcceb07fe4 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -15,7 +15,6 @@ More interestingly, one can get the list of all graphs that Sage knows how to build by typing ``graphs.`` in Sage and then hitting tab. """ -from sage.env import SAGE_NAUTY_BINS_PREFIX as nautyprefix import subprocess @@ -956,8 +955,10 @@ def nauty_geng(self, options="", debug=False): sage: list(graphs.nauty_geng("-c 3", debug=True)) ['>A ...geng -cd1D2 n=3 e=2-3\n', Graph on 3 vertices, Graph on 3 vertices] """ - - sp = subprocess.Popen(nautyprefix+"geng {0}".format(options), shell=True, + import shlex + from sage.features.nauty import NautyExecutable + geng_path = NautyExecutable("geng").absolute_filename() + sp = subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding='latin-1') @@ -1292,7 +1293,9 @@ def fullerenes(self, order, ipr=False): from sage.features.graph_generators import Buckygen Buckygen().require() - command = 'buckygen -'+('I' if ipr else '')+'d {0}d'.format(order) + import shlex + command = shlex.quote(Buckygen().absolute_filename()) + command += ' -' + ('I' if ipr else '') + 'd {0}d'.format(order) sp = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -1379,7 +1382,9 @@ def fusenes(self, hexagon_count, benzenoids=False): from sage.features.graph_generators import Benzene Benzene().require() - command = 'benzene '+('b' if benzenoids else '')+' {0} p'.format(hexagon_count) + import shlex + command = shlex.quote(Benzene().absolute_filename()) + command += (' b' if benzenoids else '') + ' {0} p'.format(hexagon_count) sp = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -1563,7 +1568,10 @@ def plantri_gen(self, options=""): from sage.features.graph_generators import Plantri Plantri().require() - sp = subprocess.Popen('plantri {}'.format(options), shell=True, + import shlex + command = '{} {}'.format(shlex.quote(Plantri().absolute_filename()), + options) + sp = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding='latin-1') diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index 0894d5110bf..03b4c4343e0 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -30,7 +30,6 @@ Functions and methods --------------------- """ -from sage.env import SAGE_NAUTY_BINS_PREFIX as nautyprefix class HypergraphGenerators(): r""" @@ -149,6 +148,9 @@ def nauty(self, number_of_sets, number_of_vertices, raise ValueError("cannot have more than 64 sets+vertices") import subprocess + import shlex + from sage.features.nauty import NautyExecutable + genbgL_path = NautyExecutable("genbgL").absolute_filename() nauty_input = options @@ -181,7 +183,7 @@ def nauty(self, number_of_sets, number_of_vertices, nauty_input += " " + str(number_of_vertices) + " " + str(number_of_sets) + " " - sp = subprocess.Popen(nautyprefix + "genbgL {0}".format(nauty_input), shell=True, + sp = subprocess.Popen(shlex.quote(genbgL_path) + " {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)