Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用固定的输入行编写Python终端应用程序?_Python_Terminal_Spyder_Curses_Ansi Escape - Fatal编程技术网

如何使用固定的输入行编写Python终端应用程序?

如何使用固定的输入行编写Python终端应用程序?,python,terminal,spyder,curses,ansi-escape,Python,Terminal,Spyder,Curses,Ansi Escape,我正在尝试编写一个终端应用程序,通过与Arduino微控制器交互。以下功能非常重要: 将传入消息打印到命令行 允许用户向串行端口输入输出消息。在打印新的传入消息时,输入应该是可能的 原则上,这应该是可能的。但当用户开始打字时,我正在努力打印收到的消息 为简单起见,我编写了以下测试脚本,每秒模拟传入消息。发出的消息只会回显到带有前缀“>”的命令行: 在Spyder IDE中,结果非常完美: 但在iterm2(Mac OS)中,输出非常混乱: 因为我想在VisualStudio代码中使用这个

我正在尝试编写一个终端应用程序,通过与Arduino微控制器交互。以下功能非常重要:

  • 将传入消息打印到命令行
  • 允许用户向串行端口输入输出消息。在打印新的传入消息时,输入应该是可能的
原则上,这应该是可能的。但当用户开始打字时,我正在努力打印收到的消息

为简单起见,我编写了以下测试脚本,每秒模拟传入消息。发出的消息只会回显到带有前缀“>”的命令行:

在Spyder IDE中,结果非常完美:

但在iterm2(Mac OS)中,输出非常混乱:

因为我想在VisualStudio代码中使用这个应用程序,所以它应该在Spyder之外工作您知道如何在iterm2中获得与Spyder相同的行为吗?

我已经考虑过或尝试过的事情:

  • 使用图书馆。这解决了我将文本打印到不同区域的问题。但我失去了无休止的滚动,因为诅咒定义了它自己的全屏窗口

  • 使用移动光标。这可能是一个可行的解决方案,但我只是不想让它发挥作用。它总是破坏用户输入的底线。我可能需要调整时间,但我仍然没有做到这一点

  • 使用不同的解释器。我已经尝试过Python和iPython,但没有成功。这可能是Spyder解释器中更微妙的设置


我已经有一段时间没有用Mac电脑与Arduino互动了。我使用了
pyserial
,它是100%可靠的。键是user
read\u until()
。我已经包括了我的包装器类以供说明。(当我没有Arduino时,还有一个模拟模式)


对!!我找到了一个解决方案:与的结合使您可以使用“一个上下文管理器,确保其中的打印语句不会破坏用户界面”来处理这个问题

以下是一个最低限度的工作示例:

#!/usr/bin/env python3
from prompt_toolkit import PromptSession
from prompt_toolkit.patch_stdout import patch_stdout
import asyncio
import time

async def echo():

    while True:
        
        print(time.time())
        await asyncio.sleep(1)

async def read():

    session = PromptSession()

    while True:
 
        with patch_stdout():
            line = await session.prompt_async("> ")
            print(line.upper())

loop = asyncio.get_event_loop()
loop.create_task(echo())
loop.create_task(read())
loop.run_forever()

我不确定这会有什么帮助。很抱歉我的问题可能有误导性,但阅读Arduino的文章不是我的问题。在我的最小示例中,我甚至生成了完全合成的消息。问题在于如何在不干扰当前未提交的用户输入的情况下显示
read_的结果,直到
import serial # pip install PySerial
from serial.tools import list_ports
import pty, os # for creating virtual serial interface
from serial import Serial
from typing import Optional


class SerialInterface:
    # define constants which control how class works
    FULLEMULATION=0
    SERIALEMULATION=1
    URLEMULATION=2
    FULLSOLUTION=3

    # define private class level variables
    __emulate:int = FULLEMULATION
    __ser:Serial
    __port:str = ""


    def __init__(self, emulate:int=FULLEMULATION, port:str="") -> None:
        self.__buffer:list = []
        self.__emulate = emulate
        self.__port = port

        #self.listports()

        # setup connection to COM/serial port
        # emulation sets up a virtual port,  but this has not been working
        if emulate == self.FULLSOLUTION:
            self.__ser = serial.Serial(port, 9600)
        elif emulate == self.SERIALEMULATION:
            master, slave = pty.openpty()
            serialport = os.ttyname(slave)

            self.__ser = serial.Serial(port=serialport, baudrate=9600, timeout=1)
        elif emulate == self.URLEMULATION:
            self.__ser = serial.serial_for_url("loop://")


    # useful to show COM/serial ports on a computer
    @staticmethod
    def listports() -> list:
        for p in serial.tools.list_ports.comports():
            print(p, p.device)
            serialport = p.device
        return serial.tools.list_ports.comports()

    def read_until(self, expected:bytes=b'\n', size:Optional[int]=None) -> bytes:
        if self.__emulate == self.FULLEMULATION:
            return self.__buffer.pop()
        else:
            return self.__ser.read_until(expected, size)

    # note it is important to have \n on end of every write to allow data to be read item by item
    def write(self, bytes:bytes=b'') -> None:
        if self.__emulate == self.FULLEMULATION:
            self.__buffer.append(bytes)
        else:
            self.__ser.write(bytes)

    def dataAvail(self) -> bool:
        if self.__emulate == self.FULLEMULATION:
            return len(self.__buffer) > 0
        else:
            return self.__ser.inWaiting() > 0

    def close(self) -> None:
        self.__ser.close()

    def mode(self) -> int:
        return self.__emulate




#!/usr/bin/env python3
from prompt_toolkit import PromptSession
from prompt_toolkit.patch_stdout import patch_stdout
import asyncio
import time

async def echo():

    while True:
        
        print(time.time())
        await asyncio.sleep(1)

async def read():

    session = PromptSession()

    while True:
 
        with patch_stdout():
            line = await session.prompt_async("> ")
            print(line.upper())

loop = asyncio.get_event_loop()
loop.create_task(echo())
loop.create_task(read())
loop.run_forever()