views:

686

answers:

11

I am using Python on Mac OSX Leopard.

I am trying to run the program 'dot' (part of Graphviz) from Python:

# -*- coding: utf-8 -*-
import os

print os.environ['PATH']
print os.system("ls >> a.txt")
print os.system("dot -o9.png -Tpng ./6.dot")

The command "ls" is there just to make sure that python is in the correct directory. It is. The result that I get is:

/usr/bin:/bin:/usr/sbin:/sbin 0 32512

My understanding is that 32512 error means that python could not find the file, and since the file 6.dot is there (If I run "dot -o9.png -Tpng ./6.dot" from the terminal I receive no error, and 9.png gets produced), I assume Python can't find the dot file.

I probably need to add the dot file to the path. But I don't know where is it. If I run:

whereis dot

I receive no answer.

How can I find the dot executable?
Alternatively, can I run the dot program as a command from inside Python?

+10  A: 

whereis locates man pages, which locates binaries. So try which dot.

laalto
+2  A: 

Troubleshooting tips:

A. add

print os.getcwd()

on the line before os.system("dot etc.

Just to make sure that the current directory is the one with the 6.dot file.

B. Make sure that the dot program is in your path.

which dot

C. Use the full path to the dot program in your os.system command, see what happens then.

codeape
+3  A: 

You need to add the path to the 'dot' executable in Python's environment. You can do this by modifying the PATH variable in os.environ

alxp
+2  A: 

Two suggestions

  1. Don't use PATH, instead use "which" to just find the executable instead
  2. You don't use ";" (semi-colon) to separate paths, but ":" (colon). Once you change this it should be able to find your dot program.

Change this

os.environ['PATH'] += ";"+"/usr/local/bin/dot"

to this

os.environ['PATH'] += ":"+"/usr/local/bin"

Then your good.

EDIT: Note that I forgot to remove the /dot from the PATH variable myself (oops) - PATH is a colon delimited list of directories.

Petriborg
+1  A: 

Instead of:

print os.system("dot -o9.png -Tpng ./6.dot")

try this:

from subprocess import check_call
print check_call("dot -o9.png -Tpng ./6.dot")

If exit status of dot program is 0, the status is printed. If dot returns non-zero status, it raises CalledProcessError (and shows returned status). If dot doesn't exist in current path, OSError is raised on Linux or WindowsErroor on Windows (I don't know which exception is raised under Mac OS, but I assume OSError).

EDIT: Code above will give you the hint if you have no dot executable or 6.dot file in current path settings.

paffnucy
+2  A: 

If you also generate your Dot files in Python, pydot does what you want in a more Pythonic way:

import pydot
dot = pydot.Dot()
n1, n2 = pydot.Node("a"), pydot.Node("b")
dot.add_node(n1)
dot.add_node(n2)
dot.add_edge(pydot.Edge(n1,n2))
dot.write_png("graph.png", prog='neato')
wr
This might be the right place to mention the python-graph library (http://code.google.com/p/python-graph/) which wraps pydot.
othercriteria
+2  A: 

Often the solution is in front of us,

print os.system("/usr/local/bin/dot -o9.png -Tpng 6.dot")

Also you can try for all the dots in a specified folder

import glob
for filedot in glob.glob('*.dot')
    print os.system("/usr/local/bin/dot -o9.png -Tpng %(filedot)s"%locals())
    #print os.system("/usr/local/bin/dot -o9.png -Tpng %s"%filedot)

Edit:

I cannot recall btw if it is

/usr/local/bin/dot -o9.png -Tpng fdot.dot

or

/usr/local/bin/dot -o 9.png -Tpng fdot.dot
WorldCitizeN
+2  A: 

You should change the PATH line so it includes the directory which contains dot. That directory is /usr/local/bin, without /dot.

Peter Stuifzand
+1  A: 

check_call does not use the same syntax as os.system, so you should try changing the corresponding line this way:

print check_call(["dot", "-o9.png", "-Tpng", "./6.dot"])

The executable name is the first item in the array, and each parameter must be in another item of the array. Otherwise you will always get a "No such file" error because there is no executable named "dot -o9.png ..." in your PATH.

Schnouki
+1  A: 

One problem is in this line:

os.environ['PATH'] += ":"+"/usr/local/bin/dot"

You don't put the name of the executable in the path, but the directory containing the executable. So that should be:

os.environ['PATH'] += ":"+"/usr/local/bin"

And as pointed out in another comment, the arguments to check_call are not the same as os.system.

retracile
Thanks, this was actually part of the solution.
Pietro Speroni
+2  A: 

Try this:

# -*- coding: utf-8 -*-
import os
import sys

print os.environ['PATH']

os.environ['PATH'] += ":"+"/usr/local/bin"
print os.environ['PATH']

print os.getcwd()

from subprocess import check_call
print check_call(["dot", "-o9.png", "-Tpng", "./6.dot"])

Taken from the question to try and maintain some sort of sanity here.

Geoffrey Chetwood
It's far too late to talk of sanity. Let's talk instead of the bigger issue: how can (and should) SO be improved to handle troubleshooting conversations?
Pesto
@Pesto: It wouldn't be necessary if authors wouldn't sit there and troubleshoot on SO. They should be asking one question, and when that issues is resolved, asking a new one. This kind of stuff is bred from OPs who simply refuse to understand what SO is for and how it works.
Geoffrey Chetwood
@Rich, @Pesto: The solution is simpler. For some reason Firefox is not letting me comment, vote, chose an answer or open the WYSIWYG edit program. Without all this everything I write looks horrible, I cannot give feedback, and add details. In short I am forced to edit back the question area, and add the new material there. Now I am able to comment as I am using a different browser.And Rich has a bias against what I do here, so he immediately assumes bad faith.
Pietro Speroni
@Pietro: Stop disabling Javascript.
Geoffrey Chetwood