-1

What I am trying to do is better explained here: Sending to the stdin of a program in python3

I am trying to send arguments to a program while it is open e.g:

rec.py

import sys
import time

while True:
   print(sys.argv)
   time.sleep(1)

send.py

import subprocess

program = Popen(['python.exe', 'rec.py', 'testArg'])
a = input('input: ')
a.communicate(b)

I want to be able to run send.py and type in my input. Say my input was 'cat', I would want the output to look like this when I run send.py

['rec.py', 'testArg']
['rec.py', 'testArg']
['rec.py', 'testArg']
cat <------- My input
['rec.py', 'testArg', 'cat']
['rec.py', 'testArg', 'cat']
['rec.py', 'testArg', 'cat']
['rec.py', 'testArg', 'cat']

ect..

Am I using the subprocess.Popen.communicate() incorrectly or is it something else?

Please help!

-Thanks

Community
  • 1
  • 1
Nic
  • 1,549
  • 2
  • 13
  • 13
  • 1
    `a` is a `str` in your case (the type returned by `input()` function). It has no `.communicate()` attribute. Don't type the code from memory. Create a minimal but complete code example and post the code that you actually have tried to run [as is]. [mcve] – jfs May 31 '16 at 08:05

2 Answers2

1

You can't change the command-line arguments after the program has started i.e., sys.argv can be changed only from the inside (normally) of the process itself.

Popen.communicate(input=data) can send data to the child process via its standard input (if you pass stdin=PIPE to Popen()). .communicate() waits for the process to exit before returning and therefore it can be used to send all the input at once.

To send the input incrementally, use process.stdin directly:

#!/usr/bin/env python3
import sys
import time
from subprocess import Popen, PIPE

with Popen([sys.executable, 'child.py'], 
           stdin=PIPE, # redirect process' stdin
           bufsize=1, # line-buffered
           universal_newlines=True # text mode
           ) as process:
    for i in range(10):
        time.sleep(.5)
        print(i, file=process.stdin, flush=True)

where child.py:

#!/usr/bin/env python3
import sys

for line in sys.stdin: # read from the standard input line-by-line
    i = int(line)
    print(i * i) # square

A better option is to import the module and use its functions instead. See Call python script with input with in a python script using subprocess

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • When i run the first program i get the error, print(i, file=process.stdin, flush=True) OSError: [Errno 22] Invalid argument – Nic May 31 '16 at 10:57
  • @Nic: the code works as is (I've tested it). If it doesn't work for you then create a new (separate) question where you should mention the exact Python version, your OS, how do you run the script? (in IDE/console, what is the current directory? (do you see `child.py` in there?), the exact filenames that you use, etc), and the complete traceback. Make sure that you've copied the code exactly as it is in the answer. – jfs May 31 '16 at 11:03
  • I have made a knew question addressing what I want to do more in detail. Its here: http://stackoverflow.com/questions/37560427/sending-to-the-stdin-of-a-program-in-python3 – Nic Jun 01 '16 at 05:52
  • @Nic I don't see how it reproduces OSError. – jfs Jun 01 '16 at 10:22
0

That's not the way interprocess-communication works. You are mixing command line arguments with the standard input pipe.

This will work:

rec.py:

import sys
import time
arguments = list(sys.argv)

while True:
    print(arguments)
    arguments.append(next(sys.stdin))

send.py

import subprocess
program = subprocess.Popen(['python.exe', 'rec.py', 'testArg'], stdin=subprocess.PIPE)
a = input('input: ')
program.stdin.write(a + '\n')
Daniel
  • 42,087
  • 4
  • 55
  • 81
  • It won't work due to the buffering. Try: `print(a, file=program.stdin, flush=True)` instead (pass `universal_newlines=True`, to enable the text mode) – jfs May 31 '16 at 08:07
  • When I run the code, I get the error: print(a, file=program.stdin, flush=True) TypeError: a bytes-like object is required, not 'str' (thats with @J.F.Sebastian print code), with the sefault, I also get the error program.stdin.write(a + '\n') TypeError: a bytes-like object is required, not 'str' – Nic May 31 '16 at 09:01
  • @Nic: pass `universal_newlines=True` as it said explicitly in my comment. – jfs May 31 '16 at 10:06
  • Could you rust write your response as an answer @J.F.Sebastian It would be much more helpful if you could do that – Nic May 31 '16 at 10:39