Python - A way to make interactive a script execution in console - python

I'm working on a web interface for the Django migrate/makemigrations commands. I've been checking the code, an they use the Python input() to get the answers of the questions.
At the moment I have tried to use the Python subprocess library in order to answer by an external script (a Python script running a Python script).
I have generated a simple script that could be useful as a test:
sum.py
first_number = input("Welcome to the program that sum two numbers, \
please give me the first number: ")
second_number = input("Now, please give me the second number: ")
print("Congratulations, the result of the sum of %s and %s is: %s" %
(first_number, second_number, (first_number + second_number)))
And the only way that I've found to make the script runs the first script:
from subprocess import Popen, PIPE
command = ["python", "sum.py"]
p = Popen(command, stdin=PIPE, stdout=PIPE)
p.stdin.write("1\n")
p.stdin.write("2\n")
print p.communicate()[0]
I've found in internet some days ago some code to make a ping an receive like real time the stdout:
from subprocess import Popen, PIPE
command = ["ping", "192.168.1.137"]
p = Popen(command, stdout=PIPE, stdin=PIPE, )
while p.poll() is None:
print p.stdout.readline()
I've modified the code and tried to run the script:
64 bytes from 192.168.1.137: icmp_seq=7 ttl=64 time=1.655 ms
from subprocess import Popen, PIPE
command = ["python", "suma.py"]
p = Popen(command, stdout=PIPE, stdin=PIPE, )
response = "1\n"
while p.poll() is None:
print p.stdout.readline() #Obtain the message
p.stdin.write(response) #Answer the question
I've found some possibles ways with websockets and node.js like tty.js or web-console, but it could be hard of mantain since I have no much idea of the programming language.
What I find is to receive and send to an HTML page the message from stdout and get the response from the user.
I'm a bit lost, any suggestions will be appreciated.
Thanks.

Related

How can I simulate a key press in a Python subprocess?

The scenario is, I have a Python script which part of it is to execute an external program using the code below:
subprocess.run(["someExternalProgram", "some options"], shell=True)
And when the external program finishes, it requires user to "press any key to exit".
Since this is just a step in my script, it would be good for me to just exit on behalf of the user.
Is it possible to achieve this and if so, how?
from subprocess import Popen, PIPE
p = Popen(["someExternalProgram", "some options"], stdin=PIPE, shell=True)
p.communicate(input=b'\n')
If you want to capture the output and error log
from subprocess import Popen, PIPE
p = Popen(["someExternalProgram", "some options"], stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
output, error = p.communicate(input=b'\n')
remember that the input has to be a bytes object

Controlling shell stdin from python

I have a custom input method and I have a python module to communicate with it. I'm trying to control the shell with it so everything from local stdout is printed on the remote device and everything sent from the remote device goes into local stdin, so that remote device can control the input given to the program, like if there was an input function inside the program the remote device can answer to that too (like in ssh).
I used python subprocess to control the stdin and stdout:
#! /usr/bin/python
from subprocess import Popen, PIPE
import thread
from mymodule import remote_read, remote_write
def talk2proc(dap):
while True:
try:
remote_write(dap.stdout.read())
incmd = remote_read()
dap.stdin.write(incmd)
except Exception as e:
print (e)
break
while True:
cmd = remote_read()
if cmd != 'quit':
p = Popen(['bash', '-c', '"%s"'%cmd], stdout=PIPE, stdin=PIPE, stderr=PIPE)
thread.start_new_thread(talk2proc, (p,))
p.wait()
else:
break
But it doesn't work, what should I do?
p.s.
is there a difference for windows?
I had this problem, I used this for STDIN
from subprocess import call
call(['some_app', 'param'], STDIN=open("a.txt", "rb"))
a.txt
:q
This I used for a git wrapper, this will enter the data line wise whenever there is an interrupt in some_app that is expecting and user input
There is a difference for Windows. This line won't work in Windows:
p = Popen(['bash', '-c', '"%s"'%cmd], stdout=PIPE, stdin=PIPE, stderr=PIPE)
because the equivalent of 'bash' is 'cmd.exe'.

Is there a viable way to make a semi-interactive command line in python [duplicate]

I'm working on a GUI front end in Python 2.6 and usually it's fairly simple: you use subprocess.call() or subprocess.Popen() to issue the command and wait for it to finish or react to an error. What do you do if you have a program that stops and waits for user interaction? For example, the program might stop and ask the user for an ID and password or how to handle an error?
c:\> parrot
Military Macaw - OK
Sun Conure - OK
African Grey - OK
Norwegian Blue - Customer complaint!
(r) he's Resting, (h) [Hit cage] he moved, (p) he's Pining for the fjords
So far everything I've read tells you how to read all output from a program only after it's finished, not how to deal with output while the program is still running. I can't install new modules (this is for a LiveCD) and I'll be dealing with user input more than once.
Check out the subprocess manual. You have options with subprocess to be able to redirect the stdin, stdout, and stderr of the process you're calling to your own.
from subprocess import Popen, PIPE, STDOUT
p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
grep_stdout = p.communicate(input='one\ntwo\nthree\nfour\nfive\nsix\n')[0]
print grep_stdout
You can also interact with a process line by line. Given this as prog.py:
import sys
print 'what is your name?'
sys.stdout.flush()
name = raw_input()
print 'your name is ' + name
sys.stdout.flush()
You can interact with it line by line via:
>>> from subprocess import Popen, PIPE, STDOUT
>>> p = Popen(['python', 'prog.py'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
>>> p.stdout.readline().rstrip()
'what is your name'
>>> p.communicate('mike')[0].rstrip()
'your name is mike'
EDIT: In python3, it needs to be 'mike'.encode().

Why does subprocess hang when reading from stdout [duplicate]

This question already has answers here:
process.stdout.readline() hangs. How to use it properly?
(3 answers)
Closed 6 years ago.
I have a script called 'my_script.py' with the following contents:
my_input = ''
while my_input != 'quit':
my_input = raw_input()
print(my_input)
Then in the console, the following commands:
from subprocess import *
p1 = Popen(['python', 'my_script.py'], stdin=PIPE)
p1.stdin.write('some words\n')
prints "some words", but if instead I write
from subprocess import *
p2 = Popen(['python', 'my_script.py'], stdin=PIPE, stdout=PIPE)
p2.stdin.write('some words\n')
p2.stdout.readline()
the shell will hang and I have to terminate it manually. How can I get this to work if I want to be able to access the stdout of the script? I'm using python2.7
Edit: To clarify my question, the above snippet will run properly for other executables that have an I/O loop (the particular one I'm working with is the stockfish chess engine). Is there a way I can modify my_script.py such that the above snippet will run properly? Using
Popen(['python3', 'my_script.py'], ...)
will work, but is it not possible using Python 2.7?
It could happen due to deadlock in readline.
You need to use communicate method to read asynchronously.
Example:
def run_shell_command(cmd, params):
cmdline = [cmd]
p = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
raise RuntimeError("%r failed, status code %s stdout %r stderr %r" % (
cmd, p.returncode, stdout, stderr))
return stdout.strip() # This is the stdout from the shell command
To execute command in background you can use following example:
def run_shell_remote_command_background(cmd):
cmdline = [cmd]
cmdline = cmdline + params.split(' ')
subprocess.Popen(['cmdline'])

Communicate with python subprocess while it is running

I running a subprocess that run a software in "command" mode. (This software is Nuke by The Foundy, in case you know that software)
When in command mode, this software is waiting for user input. This mode allow to create compositing scripts without any UI.
I have done this bit of code that start the process, find when the application is done starting then I try to send the process some commands, but the stdin doesn't seem to be sending the commands properly.
Here the sample code I did to test this process.
import subprocess
appPath = '/Applications/Nuke6.3v3/Nuke6.3v3.app/Nuke6.3v3' readyForCommand = False
commandAndArgs = [appPath, '-V', '-t']
commandAndArgs = ' '.join(commandAndArgs)
process = subprocess.Popen(commandAndArgs,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True, )
while True:
if readyForCommand:
print 'trying to send command to nuke...'
process.stdin.write('import nuke')
process.stdin.write('print nuke')
process.stdin.write('quit()')
print 'done sending commands'
readyForCommand = False
else:
print 'Reading stdout ...'
outLine = process.stdout.readline().rstrip()
if outLine:
print 'stdout:', outLine
if outLine.endswith('getenv.tcl'):
print 'setting ready for command'
readyForCommand = True
if outLine == '' and process.poll() != None:
print 'in break!'
break
print('return code: %d' % process.returncode)
when I run nuke in a shell and send the same commands here is what I get:
sylvain.berger core/$ nuke -V -t
[...]
Loading /Applications/Nuke6.3v3/Nuke6.3v3.app/Contents/MacOS/plugins/getenv.tcl
>>> import nuke
>>> print nuke
<module 'nuke' from '/Applications/Nuke6.3v3/Nuke6.3v3.app/Contents/MacOS/plugins/nuke/__init__.pyc'>
>>> quit()
sylvain.berger core/$
Any idea why the stdin is not sending the commands properly?
Thanks
your code will send the text
import nukeprint nukequit()
with no newline, thus the python instance will not try to execute anything, everything is just sitting in a buffer waiting for a newline
The subprocess module is not intended for interactive communication with a process. At best, you can give it a single pre-computed standard input string and then read its stdout and stderr:
p = Popen(..., stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, err = p.communicate(predefined_stdin)
If you actually need interaction, consider using pexpect.

Categories