How can I write 2 input to python subprocess

Question:

I am trying to use subprocess library.

The file that I am trying to run with subprocess:

a = input()
print(a)

Here is what I tried:

import subprocess

p = subprocess.Popen(['python', 'registration.py'], encoding="Utf8")
p.communicate(input="11")

It worked very well. Then I tried to use multiple inputs:

a=input()
print(a)
b=input()
print(b)

I used 2 p.communicate(input='something') but got an error in the second one:
ValueError: I/O operation on closed file.

I surfed the Internet and found that communicate only works once.

My question is, is there a way to give 2 inputs to subprocess in my case?

Here is the full code

import subprocess
from subprocess import PIPE

p = subprocess.Popen(['python', '-i', 'registration.py'], stdin=PIPE, text=True)

p.stdin.reconfigure(line_buffering=True)
p.stdin.write("phone_numbern")
#I should wait here for maximum 15 seconds
p.stdin.write("verification_coden")
print("Done")
#First, Done is printed, console says program finished but then subprocess methods are executed
Asked By: hvsniddin

||

Answers:

If you create the Popen object with stdin=subprocess.PIPE, it has a stdin attribute that you can write to.

However, the subrocess documentation warns that this can lead to deadlocks:

due to any of the other OS pipe buffers filling up and blocking the child process.

If you write small amounts of data and if the subprocess reads its standard input regularly, it should be fine.

An example:

> python
Python 3.9.13 (main, May 31 2022, 12:56:40) 
[Clang 13.0.0 ([email protected]:llvm/llvm-project.git llvmorg-13.0.0-0-gd7b669b3a on freebsd13
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess as sp
>>> proc = sp.Popen(['python', '-i'], stdin=sp.PIPE, text=True)
>>> Python 3.9.13 (main, May 31 2022, 12:56:40) 
[Clang 13.0.0 ([email protected]:llvm/llvm-project.git llvmorg-13.0.0-0-gd7b669b3a on freebsd13
Type "help", "copyright", "credits" or "license" for more information.
>>> proc.stdin.write("1+2n")
4
>>> proc.stdin.flush()
>>> 3
>>> proc.stdin.write("3*9n")
4
>>> proc.stdin.flush()
>>> 27
>>> proc.stdin.reconfigure(line_buffering=True)
>>> proc.stdin.write("3*12n")
5
>>> 36
>>> proc.kill()
>>> 

Of note:

  • Multiple programs need to be told to be interactive if their standard input is not a terminal. Hence the use of the '-i' flag.
  • Use text=True to make your life easier.
  • Note that if line_buffering is not activated for a standard input of the subprocess, you have to flush the stream for the process to receive the data.
  • Therefore it is probably best to reconfigure the stdin stream of the Popen object and set line_buffering to True.
Answered By: Roland Smith