python - 为 Python 的 Cmd 类输入流使用协程
问题描述
我面临的问题是:
- 我有一个异步方法
- 调用普通的 python 代码我无法更改
- 回调一个普通的python方法
- 哪个需要使用调用异步代码
await
我有一个基于Python 的 Cmd 类构建的自定义命令解释器。我为它提供了自定义标准输入和标准输出。出于这个问题的目的,它看起来像这样:
import cmd
import sys
class CustomStream(object):
def readline(self):
return sys.stdin.readline()
def write(self, msg):
sys.stdout.write(msg)
def flush(self):
pass
class MyShell(cmd.Cmd):
def do_stuff(self, args):
print("Getting things done...")
def do_exit(self, args):
return True
stream = CustomStream()
shell = MyShell(stdin=stream, stdout=stream)
shell.use_rawinput = False
shell.cmdloop()
当Cmd
需要从用户那里读取时,它会这样做:
line = self.stdin.readline()
我想使用基于asyncio
. 我的 SSH 代码很像Simple Server 示例,它读取类似 stdin 的接口,如下所示(注意await
关键字):
line_from_client = (await self._process.stdin.readline()).rstrip('\n')
我尝试了很多东西,但我无法将 SSH 代码输入到 Cmd 对标准输入的期望中。我必须怎么做才能让我的CustomStream
对象在内部使用 asyncio/coroutines,同时提供一个老式的单线程接口MyShell
?
解决方案
解决方案是修补该cmdloop
方法以使其能够感知异步。
此代码是 Python 的 3.7.2 Cmd 类 cmdloop 函数的副本,如果您设置
raw_input
调成True
- 放在
await
readline前面
此代码的结果(aoicmd.py 可作为 gist 获得):
async def adapter_cmdloop(self, intro=None):
"""Repeatedly issue a prompt, accept input, parse an initial prefix
off the received input, and dispatch to action methods, passing them
the remainder of the line as argument.
"""
self.preloop()
#This is the same code as the Python 3.7.2 Cmd class, with the
#following changes
# - Remove dead code caused by forcing use_rawinput=False.
# - Added a readline in front of readline()
if intro is not None:
self.intro = intro
if self.intro:
self.stdout.write(str(self.intro)+"\n")
stop = None
while not stop:
if self.cmdqueue:
line = self.cmdqueue.pop(0)
else:
self.stdout.write(self.prompt)
self.stdout.flush()
line = await self.stdin.readline()
if not len(line):
line = 'EOF'
else:
line = line.rstrip('\r\n')
line = self.precmd(line)
stop = self.onecmd(line)
stop = self.postcmd(stop, line)
self.postloop()
在需要使用 Cmd 派生类的地方,例如MyShell
,创建一个MyAsyncShell
在运行时调用的新类:
#Patch the shell with async aware cmdloop
MyAsyncShell = type('MyAsyncSHell', (MyShell,), {
'cmdloop' :aiocmd.adapter_cmdloop,
'use_rawinput':False,
})
实施write
并且flush
如您所见,但您的 readline 应如下所示:
async def readline(self):
return await my_implementation_of_readline()
推荐阅读
- ffmpeg - 不显示淡入淡出的叠加层
- python - 在导入的模块中导入 Python 包,如 NumPy 或 Pandas
- angular - Angular 5 - 组件和服务之间的通信
- django - django IntegrityError (1048, "Column 'hotel_id' cannot be null")
- scala - squeryl 编写或和的正确语法是什么?
- javascript - 使用 angulrjs 验证经度和纬度的正则表达式
- excel - 直接在 Excel 中聚合 PowerQuery 表
- git - 如何在不同的分支上添加一个共同的特征
- r - 根据 Date 表示周结束的 Date 列在每周数据中创建假期虚拟变量
- php - 错误的sha1hash realexpayments?