UPDATED
The easiest way to perform this is to pass the termination condition as a parameter to test.py
.
Otherwise, you can use printing and reading from stdout
and stdin
If you want to preserve the output and still use Popen, see below. As an example, consider a simple test.py
that calculates (in a very inefficient way) some primes:
test.py
import time
primes = [2, 3]
if __name__ == "__main__":
for p in primes:
print(p, flush=True)
i = 5
while True:
for p in primes:
if i % p == 0:
break
if i % p:
primes.append(i)
print(i, flush=True)
i += 2
time.sleep(.005)
You can read the output and choose to terminate the process when you achieve the desired output. As an example, I want to get primes up to 1000
.
import subprocess
proc = subprocess.Popen("python test.py",
stdout=subprocess.PIPE, stdin=subprocess.PIPE,
bufsize=1, universal_newlines=True,
shell=True, text=True)
must_stop = False
primes = []
while proc.poll() is None:
line = proc.stdout.readline()
if line:
new_prime = int(line)
primes.append(new_prime)
if new_prime > 1000:
print("Threshold achieved", line)
proc.terminate()
else:
print("new prime:", new_prime)
print(primes)
please notice that since there is a delay in the processing and communication, you might get one or two more primes than desired. If you want to avoid that, you'd need bi-directional communication and test.py
would be more complicated. If you want to see the output of test.py
on screen, you can print it and then somehow parse it and check if the condition is fulfilled. Other options include using os.mkfifo
(Linux only, not very difficult), which provides an easy communication path between two processes:
os.mkinfo
version
test.py
import time
import sys
primes = [2, 3]
if __name__ == "__main__":
outfile = sys.stdout
if len(sys.argv) > 1:
try:
outfile = open(sys.argv[1], "w")
except:
print("Could not open file")
for p in primes:
print(p, file=outfile, flush=True)
i = 5
while True:
for p in primes:
if i % p == 0:
break
if i % p:
primes.append(i)
print("This will be printed to screen:", i, flush=True)
print(i, file=outfile, flush=True) # this will go to the main process
i += 2
time.sleep(.005)
main file
import subprocess
import os
import tempfile
tmpdir = tempfile.mkdtemp()
filename = os.path.join(tmpdir, 'fifo') # Temporary filename
os.mkfifo(filename) # Create FIFO
proc = subprocess.Popen(["python3", "test.py", filename], shell=False)
with open(filename, 'rt', 1) as fifo:
primes = []
while proc.poll() is None:
line = fifo.readline()
if line:
new_prime = int(line)
primes.append(new_prime)
if new_prime > 1000:
print("Threshold achieved", line)
proc.terminate()
else:
print("new prime:", new_prime)
print(primes)
pass
os.remove(filename)
os.rmdir(tmpdir)