58

I have a Python script that needs to invoke another Python script in the same directory. I did this:

from subprocess import call
call('somescript.py')

I get the following error:

call('somescript.py')
File "/usr/lib/python2.6/subprocess.py", line 480, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child

raise child_exception
OSError: [Errno 2] No such file or directory

I have the script somescript.py in the same folder though. Am I missing something here?

Venkatachalam
  • 16,288
  • 9
  • 49
  • 77
user514946
  • 1,165
  • 3
  • 12
  • 12
  • 1
    Is `.` in your `PATH`? Is somescript.py executable? – Wooble Aug 22 '11 at 19:17
  • 1
    Why are you trying to execute it? why not `import` it? – tMC Aug 22 '11 at 20:10
  • 1
    @wooble yes. It is in path and and executable too. Yes. I could also import it. But would eitherway like to know what i am doing wrong here since i think this is supposed to work. – user514946 Aug 22 '11 at 22:04
  • 2
    Why not import?! Many reasons: really execute, even if imported already; have `__name__ == '__main__`; run multiple times. – Tomasz Gandor Jun 09 '19 at 17:02
  • Also: if it's not Python 2, and the other script in the same directory - it will not just simply import. You might need to add its directory to `sys.path`, which you may not want to do for many reasons: security among them (name clashes...). – Tomasz Gandor Jun 09 '19 at 17:05

10 Answers10

61

If 'somescript.py' isn't something you could normally execute directly from the command line (I.e., $: somescript.py works), then you can't call it directly using call.

Remember that the way Popen works is that the first argument is the program that it executes, and the rest are the arguments passed to that program. In this case, the program is actually python, not your script. So the following will work as you expect:

subprocess.call(['python', 'somescript.py', somescript_arg1, somescript_val1,...])

This correctly calls the Python interpreter and tells it to execute your script with the given arguments.

Note that this is different from the above suggestion:

subprocess.call(['python somescript.py'])

That will try to execute the program called python somscript.py, which clearly doesn't exist.

call('python somescript.py', shell=True)

Will also work, but using strings as input to call is not cross platform, is dangerous if you aren't the one building the string, and should generally be avoided if at all possible.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
aruisdante
  • 8,875
  • 2
  • 30
  • 37
  • I have this issue, but the path to the script is in my basrc file so I can call it from terminal as myscript (args). When I try to do the above from python, I get a not found error? – Rankinstudio Jan 21 '18 at 16:36
  • 1
    According to the [documentation](https://docs.python.org/3/library/subprocess.html#older-high-level-api) in Python 3.5 on you can now use `run()` instead of `call()`. – Bill Jun 01 '18 at 16:30
  • This is a bit simplistic - why just `python` - is it on your path? Will it be the same interpreter, which you are running under? – Tomasz Gandor Jun 09 '19 at 17:03
  • 3
    I suggest to change `'python'` to `sys.executable` (https://stackoverflow.com/questions/2589711/find-full-path-of-the-python-interpreter, https://stackoverflow.com/questions/5927633/how-to-get-the-current-python-interpreter-path-from-inside-a-python-script), and it will be fine. – Tomasz Gandor Jun 09 '19 at 17:07
8

Windows? Unix?

Unix will need a shebang and exec attribute to work:

#!/usr/bin/env python

as the first line of script and:

chmod u+x script.py

at command-line or

call('python script.py'.split())

as mentioned previously.

Windows should work if you add the shell=True parameter to the "call" call.

Gringo Suave
  • 29,931
  • 6
  • 88
  • 75
  • 9
    `call('python script.py')` won't work on non-Windows systems. It should be `check_call([sys.executable or 'python', '/path/to/script.py'])`. And you don't need the shebang and executable permissions if `python` executable is specified. – jfs Apr 05 '14 at 11:30
  • sys.executable should be enough for all sane situations. – Stuart Axon Jan 17 '16 at 14:00
4

Check out this.

from subprocess import call 
with open('directory_of_logfile/logfile.txt', 'w') as f:
   call(['python', 'directory_of_called_python_file/called_python_file.py'], stdout=f)
tanmoy
  • 170
  • 7
4
import subprocess
command = 'home/project/python_files/run_file.py {} {} {}'.format(
        arg1, arg2, arg3) # if you want to pass any arguments
p = subprocess.Popen(
        [command],
        shell=True,
        stdin=None,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        close_fds=True)
out, err = p.communicate()
RokiDGupta
  • 371
  • 2
  • 7
  • 14
3

subprocess.call expects the same arguments as subprocess.Popen - that is a list of strings (the argv in C) rather than a single string.

It's quite possible that your child process attempted to run "s" with the parameters "o", "m", "e", ...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
immortal
  • 3,118
  • 20
  • 38
2

If you're on Linux/Unix you could avoid call() altogether and not execute an entirely new instance of the Python executable and its environment.

import os

cpid = os.fork()
if not cpid:
    import somescript
    os._exit(0)

os.waitpid(cpid, 0)

For what it's worth.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tMC
  • 18,105
  • 14
  • 62
  • 98
  • 1
    Only *nix: using fork you will inherit from the parent process python interpreter (with all existing imports, ...). If you want a brand new interpretor this not a good choice. See the diff fork/exec unix system call. – Nicolae Dascalu Aug 23 '11 at 02:46
  • `subprocess` module uses `fork/exec` on POSIX systems and `CreateProcess` on Windows. No need to use `fork` directly if you want to run a Python script. – jfs Apr 05 '14 at 11:35
  • This makes a lot of assumptions. Top level scripts operate differently than imported modules. What if it does its work in a `if "__name__" == "__main__":` clause? What about all of the other things you need to do after fork for a new process? Maybe it would work... but there are a lot of caveats here. – tdelaney Aug 19 '23 at 16:42
1

What's wrong with

import sys
from os.path import dirname, abspath

local_dir = abspath(dirname(__file__))
sys.path.append(local_dir)

import somescript

or better still wrap the functionality in a function, e.g. baz, then do this.

import sys
from os.path import dirname, abspath

local_dir = abspath(dirname(__file__))
sys.path.append(local_dir)

import somescript
somescript.baz()

There seem to be a lot of scripts starting python processes or forking, is that a requirement?

demented hedgehog
  • 7,007
  • 4
  • 42
  • 49
0
def main(argv):
    host = argv[0]
    type = argv[1]
    val = argv[2]

    ping = subprocess.Popen(['python ftp.py %s %s %s'%(host,type,val)],stdout = subprocess.PIPE,stderr = subprocess.PIPE,shell=True)
    out = ping.communicate()[0]
    output = str(out)
    print output
Sam Hasler
  • 12,344
  • 10
  • 72
  • 106
0

The subprocess call is a very literal-minded system call. it can be used for any generic process...hence does not know what to do with a Python script automatically.

Try

call ('python somescript.py')

If that doesn't work, you might want to try an absolute path, and/or check permissions on your Python script...the typical fun stuff.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jsh
  • 1,995
  • 18
  • 28
0

First, check if somescript.py is executable and starts with something along the lines of #!/usr/bin/python. If this is done, then you can use subprocess.call('./somescript.py').

Or as another answer points out, you could do subprocess.call(['python', 'somescript.py']).

Barum Rho
  • 2,743
  • 1
  • 20
  • 21
  • Just a random pointer: I've found it to be useful to use #!/usr/bin/env python so that if a module has been loaded, you are automatically running with the loaded python version. – Vorticity Aug 22 '11 at 21:56