0

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_number\n")
#I should wait here for maximum 15 seconds
p.stdin.write("verification_code\n")
print("Done")
#First, Done is printed, console says program finished but then subprocess methods are executed
Roland Smith
  • 42,427
  • 3
  • 64
  • 94
hvsniddin
  • 3
  • 4

1 Answers1

0

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 (git@github.com: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 (git@github.com: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+2\n")
4
>>> proc.stdin.flush()
>>> 3
>>> proc.stdin.write("3*9\n")
4
>>> proc.stdin.flush()
>>> 27
>>> proc.stdin.reconfigure(line_buffering=True)
>>> proc.stdin.write("3*12\n")
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.
Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • In my actual project, there are 3 inputs, but all of them gets not very long texts(maximum 15 characters). And can you give an example for your answer please? If `Popen` doesn't work, I can use other methods you can suggest – hvsniddin Aug 19 '22 at 12:54
  • @HusniddinRavshanov See updated answer. – Roland Smith Aug 19 '22 at 13:50
  • `subprocess` methods are being executed after the program is finished (console says `[Prgoram finished]` and the subprocess starts) so other (`print()` `time.wait()`) methods are executed first despite their position. So can I wait between each `stdint` method? There is the case I have to wait for some time to get a code – hvsniddin Aug 19 '22 at 15:44
  • @hvsniddin There are no inherent reasons why you should not be able to wait between writes. Can you update your question with your actual code? – Roland Smith Aug 19 '22 at 15:48
  • Done, check it. – hvsniddin Aug 19 '22 at 15:58
  • @hvsniddin That the output from the subprocess appears after the main program ends could also have to do with buffering or the settings of the terminal it is run on. – Roland Smith Aug 19 '22 at 16:14
  • I don't know why. would I actually be able to wait between two inputs, if it didn't happen? Btw, I'm running it with pydroid3 (Android app) – hvsniddin Aug 19 '22 at 16:31
  • If you are running Python on a platform like Android where it is not that common, it might be wise to mention that in the question. (I've added it to the tags.) Unfortunately I have zero experience with pydroid3, so I cannot help you with this. It could be that the Android OS imposes restrictions on starting new processes. – Roland Smith Aug 19 '22 at 16:54
  • I took all of them in a function and tried to use `time.sleep()` between the two writes and it worked! Thank you for your help :) – hvsniddin Aug 19 '22 at 17:04