python subprocess.call() not working as expected

By default subprocess.call doesn't use a shell to run our commands you so can't shell commands like cd.

To use a shell to run your commands use shell=True as parameter. In that case it is recommended to pass your commands as a single string rather than as a list. And as it's run by a shell you can use ~/ in your path, too:

subprocess.call("(cd ~/catkin_ws/src && catkin_make)", shell=True)

subprocess.call() expects a list, with first item obviously being a legitimate shell command. Compare this for instance:

>>> subprocess.call(['echo hello'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 523, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
>>> subprocess.call(['echo', 'hello'])
hello
0

In your case , subprocess.call(["(cd "+ os.path.expanduser('~') + "/catkin_ws/src)"]) will expect to find binary that looks like so(note backslash designating space charater):

 cd\ /home/user/catkin_ws/src

That is treated as one single name that is to be expected to live somewhere on your system. What you really would wanna do is:

 subprocess.call(["cd", os.path.expanduser('~') + "/catkin_ws/src"])

Note that I have removed parenthesis around the comma, as there is no reason to use subshell.

EDIT:

But it has been already mentioned by progo in the comments that using cd in this case is redundant. Florian's answer also properly mentions that subprocess.call() doesn't use shell. You could approach that in two ways. One , you could use subprocess.call("command string",shell=True)

The other way , is to call specific shell explicitly. This is especially useful if you want to run a script that requires specific shell. Thus you could do:

subprocess.call(['bash' , os.path.expanduser('~')  + "/catkin_ws/src"  ) ] )

Use os.chdir() instead.

Apart from the issues, mentioned in the existing answers, I wouldn't prefer using shell=True, nor subprocess.call() here to change directory.

Python has its own way of changing directory in os.chdir() (don't forget to import os). ~ ("home") can be defined in several ways, a.o. os.environ["HOME"].

Reasons to prefer that over shell=True can be read a.o. here