Getting live output from asyncio subprocess

2024/10/3 6:32:25

I'm trying to use Python asyncio subprocesses to start an interactive SSH session and automatically input the password. The actual use case doesn't matter but it helps illustrate my problem. This is my code:

    proc = await asyncio.create_subprocess_exec('ssh', '[email protected]',stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.STDOUT,stdin=asyncio.subprocess.PIPE,)# This loop could be replaced by async for, I imaginewhile True:buf = await proc.stdout.read()if not buf:breakprint(f'stdout: { buf }')

I expected it to work something like asyncio streams, where I can create two tasks/subroutines/futures, one to listen to the StreamReader (in this case given by proc.stdout), the other to write to StreamWriter (proc.stdin).

However, it doesn't work as expected. The first few lines of output from the ssh command are printed directly to the terminal, until it gets to the password prompt (or host key prompt, as the case may be) and waits for manual input. I expected to be able to read the first few lines, check whether it was asking for password or the host prompt, and write to the StreamReader accordingly.

The only time it runs the line print(f'stdout: { buf }') is after I press enter, when it prints, obviously, that "stderr: b'Host key verification failed.\r\n'".

I also tried the recommended proc.communicate(), which isn't as neat as using StreamReader/Writer, but it has the same problem: Execution freezes while it waits for manual input.

How is this actually supposed to work? If it's not how I imagined, why not, and is there any way to achieve this without resorting to some sort of busy loop in a thread?

PS: I'm explaining using ssh just for clarity. I ended up using plink for what I wanted, but I want to understand how to do this with python to run arbitrary commands.

Answer

If anyone else landed here for a more generic answer to the question, see the following example:

import asyncioasync def _read_stream(stream, cb):  while True:line = await stream.readline()if line:cb(line)else:breakasync def _stream_subprocess(cmd, stdout_cb, stderr_cb):  process = await asyncio.create_subprocess_exec(*cmd,stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)await asyncio.gather(_read_stream(process.stdout, stdout_cb),_read_stream(process.stderr, stderr_cb))return await process.wait()def execute(cmd, stdout_cb, stderr_cb):  loop = asyncio.get_event_loop()rc = loop.run_until_complete(_stream_subprocess(cmd,stdout_cb,stderr_cb,))loop.close()return rcif __name__ == '__main__':  print(execute(["bash", "-c", "echo stdout && sleep 1 && echo stderr 1>&2 && sleep 1 && echo done"],lambda x: print("STDOUT: %s" % x),lambda x: print("STDERR: %s" % x),))
https://en.xdnf.cn/q/70756.html

Related Q&A

multi language support in python script

I have a large python (2.7) script that reads data from a database and generate pictures in pdf format. My pictures have strings for labels, etc... Now I want to add a multi language support for the sc…

Add date tickers to a matplotlib/python chart

I have a question that sounds simple but its driving me mad for some days. I have a historical time series closed in two lists: the first list is containing prices, lets say P = [1, 1.5, 1.3 ...] while…

Python Selenium: Cant find element by xpath when browser is headless

Im attempting to log into a website using Python Selenium using the following code:import time from contextlib import contextmanager from selenium import webdriver from selenium.webdriver.chrome.option…

Reading large file in Spark issue - python

I have spark installed in local, with python, and when running the following code:data=sc.textFile(C:\\Users\\xxxx\\Desktop\\train.csv) data.first()I get the following error:---------------------------…

pyinstaller: 2 instances of my cherrypy app exe get executed

I have a cherrypy app that Ive made an exe with pyinstaller. now when I run the exe it loads itself twice into memory. Watching the taskmanager shows the first instance load into about 1k, then a seco…

python - Dataframes with RangeIndex vs.Int64Index - Why?

EDIT: I have just found a line in my code that changes my df from a RangeIndex to a numeric Int64Index. How and why does this happen?Before this line all my df are type RangeIndex. After this line of …

Uniform Circular LBP face recognition implementation

I am trying to implement a basic face recognition system using Uniform Circular LBP (8 Points in 1 unit radius neighborhood). I am taking an image, re-sizing it to 200 x 200 pixels and then splitting …

SQLAlchemy declarative one-to-many not defined error

Im trying to figure how to define a one-to-many relationship using SQLAlchemys declarative ORM, and trying to get the example to work, but Im getting an error that my sub-class cant be found (naturally…

Convert numpy.array object to PIL image object

I have been trying to convert a numpy array to PIL image using Image.fromarray but it shows the following error. Traceback (most recent call last): File "C:\Users\Shri1008 SauravDas\AppData\Loc…

Scheduling celery tasks with large ETA

I am currently experimenting with future tasks in celery using the ETA feature and a redis broker. One of the known issues with using a redis broker has to do with the visibility timeout:If a task isn’…