diff --git a/pydot_ng/__init__.py b/pydot_ng/__init__.py index 1c752ca..4b54700 100644 --- a/pydot_ng/__init__.py +++ b/pydot_ng/__init__.py @@ -398,6 +398,25 @@ def graph_from_incidence_matrix(matrix, node_prefix='', directed=False): return graph +def is_quoted(path): + return path.startswith('"') and path.endswith('"') + + +def is_windows(): + return os.name == 'nt' + + +def is_anacoda(): + return os.path.exists(os.path.join(sys.prefix, 'conda-meta')) + + +def get_executable_extension(): + if is_windows(): + return '.bat' if is_anacoda() else '.exe' + else: + return '' + + def __find_executables(path): """Used by find_graphviz @@ -409,7 +428,8 @@ def __find_executables(path): Otherwise returns None """ - success = False + any_found = False + progs = { "dot": "", "twopi": "", @@ -419,11 +439,12 @@ def __find_executables(path): "sfdp": "", } - was_quoted = False path = path.strip() - if path.startswith('"') and path.endswith('"'): + path_template = "{}" + + if is_quoted(path): path = path[1:-1] - was_quoted = True + path_template = "\"{}\"" if not os.path.isdir(path): return None @@ -432,22 +453,14 @@ def __find_executables(path): if progs[prg]: continue - prg_path = os.path.join(path, prg) - prg_exe_path = prg_path + ".exe" + ext = get_executable_extension() + prg_path = os.path.join(path, prg + ext) if os.path.exists(prg_path): - if was_quoted: - prg_path = "\"{}\"".format(prg_path) - progs[prg] = prg_path - success = True - - elif os.path.exists(prg_exe_path): - if was_quoted: - prg_exe_path = "\"{}\"".format(prg_exe_path) - progs[prg] = prg_exe_path - success = True - - if success: + any_found = True + progs[prg] = path_template.format(prg_path) + + if any_found: return progs return None diff --git a/test/test_find_executables.py b/test/test_find_executables.py new file mode 100644 index 0000000..6770243 --- /dev/null +++ b/test/test_find_executables.py @@ -0,0 +1,81 @@ +import mock +import pytest + +import pydot_ng as pydot + + +def touch(path): + f = open(path, "w") + f.close() + + +def test_find_executables_fake_path(): + assert pydot.__find_executables("/fake/path/") is None + + +def test_find_executables_real_path_no_programs(tmpdir): + assert pydot.__find_executables(str(tmpdir)) is None + + +def test_find_executables_path_needs_strip(tmpdir): + path = tmpdir.mkdir("subdir") + prog_path = str(path.join("dot")) + + path_with_spaces = " {} ".format(path) + + with open(prog_path, "w"): + progs = pydot.__find_executables(path_with_spaces) + assert progs["dot"] == prog_path + assert sorted( + ("dot", "twopi", "neato", "circo", "fdp", "sfdp") + ) == sorted(progs) + + +@pytest.mark.parametrize("quoted", (True, False), ids=("quoted", "unqoted")) +@pytest.mark.parametrize( + "windows,conda,extension", + ( + (True, True, "bat"), + (True, False, "exe"), + (False, False, "unix"), + (False, True, "unix"), + ), +) +@pytest.mark.parametrize( + "program", ("dot", "twopi", "neato", "circo", "fdp", "sfdp") +) +@mock.patch.object(pydot, "is_anacoda") +@mock.patch.object(pydot, "is_windows") +def test_f_e( + mock_win, mock_conda, tmpdir, windows, conda, extension, program, quoted +): + path = tmpdir.mkdir("PYDOT is_da best!") + + mock_win.return_value = windows + mock_conda.return_value = conda + + unix_path = str(path.join(program)) + touch(unix_path) + + exe_path = str(path.join(program + ".exe")) + touch(exe_path) + + bat_path = str(path.join(program + ".bat")) + touch(bat_path) + + if quoted: + path = '"{}"'.format(path) + unix_path = '"{}"'.format(unix_path) + bat_path = '"{}"'.format(bat_path) + exe_path = '"{}"'.format(exe_path) + + progs = pydot.__find_executables(str(path)) + + if extension == "bat": + assert progs[program] == bat_path + elif extension == "exe": + assert progs[program] == exe_path + elif extension == "unix": + assert progs[program] == unix_path + else: + raise Exception("Unknown extension {}".format(extension)) diff --git a/test/test_pydot.py b/test/test_pydot.py index 594fc4d..f0abce2 100644 --- a/test/test_pydot.py +++ b/test/test_pydot.py @@ -8,8 +8,8 @@ import warnings from textwrap import dedent -import mock import pytest +import mock import pydot_ng as pydot @@ -279,58 +279,3 @@ def test_dotparser_import_warning(): del sys.modules["pydot_ng"] warnings.simplefilter("always") import pydot_ng # noqa: F401 - - -def test_find_executables_fake_path(): - assert pydot.__find_executables("/fake/path/") is None - - -def test_find_executables_real_path_no_programs(tmpdir): - assert pydot.__find_executables(str(tmpdir)) is None - - -def test_find_executables_path_needs_strip(tmpdir): - path = tmpdir.mkdir("subdir") - prog_path = str(path.join("dot")) - - path_with_spaces = " {} ".format(path) - - with open(prog_path, "w"): - progs = pydot.__find_executables(path_with_spaces) - assert progs["dot"] == prog_path - assert sorted( - ("dot", "twopi", "neato", "circo", "fdp", "sfdp") - ) == sorted(progs) - - -def test_find_executables_unix_and_exe_exists(tmpdir): - path = str(tmpdir) - prog_unix_path = str(tmpdir.join("dot")) - prog_exe_path = str(tmpdir.join("dot.exe")) - - with open(prog_unix_path, "w"): - with open(prog_exe_path, "w"): - progs = pydot.__find_executables(path) - assert progs["dot"] == prog_unix_path - assert progs["dot"] != prog_exe_path - - -@pytest.mark.parametrize("quoted", (True, False), ids=("quoted", "unqoted")) -@pytest.mark.parametrize("extension", ("", ".exe")) -@pytest.mark.parametrize( - "program", ("dot", "twopi", "neato", "circo", "fdp", "sfdp") -) -def test_find_executables(tmpdir, program, extension, quoted): - path = tmpdir.mkdir("PYDOT is_da best!") - prog_path = str(path.join(program + extension)) - - with open(prog_path, "w"): - if quoted: - path = "\"{}\"".format(path) - prog_path = "\"{}\"".format(prog_path) - - progs = pydot.__find_executables(str(path)) - assert progs[program] == prog_path - assert sorted( - ("dot", "twopi", "neato", "circo", "fdp", "sfdp") - ) == sorted(progs)