Reputation: 298
Let's say I wrote following function. Now the problem is that another function uses the voronoi.out file as input. What I do not know is how to close this stdin after sp.Popen has finished. When I don't do it, qvoronoi program is "hanging" till the end of my script and next function cannot read this voronoi.out file.
def voronoi(self):
''' This function calls qvoronoi program to create
file with vertices.'''
self.inp=open(self.out_name, 'r') #Redirect input and output for qvoronoi script
self.out=open('voronoi.out', 'w')
sp.Popen(['./qvoronoi', 'p', 'FN'], stdin=self.inp, stdout=self.out) #Execute qvoronoi
self.out.close() #Safely close output file
Upvotes: 3
Views: 5916
Reputation: 38462
It's possible to close the child process' stdin before it starts:
from sys import stdin
import subprocess
subprocess.run(cmd, preexec_fn=stdin.close)
This won't close stdin, but it will ensure stdin is an empty file, plus it will work on Windows(R):
subprocess.run(cmd, stdin=subprocess.DEVNULL)
Both of these solutions lack the race condition present in other answers. Many commands check stdin at startup and alter their behavior, so to close stdin just after start can produce unpredictable results.
Upvotes: 2
Reputation: 77337
The primary problem is that you don't wait for the program to exit. qvoronio is still using the file when your function exits so others may be blocked. And since you don't wait, qvoronio remains in a "zombie" state when done executing, which may look like its hung. Also, you put the temporary inp/outp file handles on your self object, when really, you want to close them right away.
More zealous pythonistas like to use context managers to make sure files are closed properly, and may do something like this:
def voronoi(self):
with open(self.out_name, 'r') as inp:
with open('voronoi.out', 'w') as outp:
qvoronio = sp.Popen(['./qvoronoi', 'p', 'FN'], stdin=inp, stdout=oup)
qvoronio.wait()
Notice that the wait is done after the context managers exit. You've closed the files in the parent after handing them to the child.
I typically do:
def voronoi(self):
qvoronio = sp.Popen(['./qvoronoi', 'p', 'FN'], stdin=open(self.out_name, 'r'),
stdout=open('voronoi.out', 'w'))
qvoronio.wait()
and suffer the wrath of the purists. My way works fine for cpython, but may jam you up in other variants.
Upvotes: 3