Wie ein Python REPL zu implementieren, die gut asynchrone Ausgabe behandelt?
-
22-07-2019 - |
Frage
Ich habe eine Python-basierte Anwendung, die ein paar Befehle in einer einfachen Lese-eval-print-Schleife annehmen kann. Ich verwende raw_input('> ')
den Eingang zu erhalten. Auf Unix-basierten Systemen, ich import readline
auch Dinge verhalten sich ein wenig besser zu machen. Das alles funktioniert gut.
Das Problem ist, dass es asynchrone Ereignisse kommen in, und ich möchte Ausgabe drucken, sobald sie auftreten. Leider macht diese Dinge hässlich aussehen. Der „>“ string zeigt nicht wieder nach dem Ausgang, und wenn der Benutzer auf halbem Weg durch etwas Eingabe ist, es hackt ihren Text in zwei Hälften. Es soll wohl den Benutzer Text-in-progress neu gezeichnet nach etwas gedruckt wird.
Dies scheint, wie es ein Problem gelöst sein muss. Was ist der richtige Weg, dies zu tun?
Beachten Sie auch, dass einige meiner Benutzer sind Windows-basiert.
TIA
Edit: Die akzeptierte Antwort arbeitet unter Unixy Plattformen (wenn das Readline- Modul verfügbar ist), aber wenn jemand weiß, wie man diese Arbeit unter Windows zu machen, wäre es sehr zu schätzen
Lösung
Vielleicht wie etwas, das wird es tun:
#!/usr/bin/env python2.6
from __future__ import print_function
import readline
import threading
PROMPT = '> '
def interrupt():
print() # Don't want to end up on the same line the user is typing on.
print('Interrupting cow -- moo!')
print(PROMPT, readline.get_line_buffer(), sep='', end='')
def cli():
while True:
cli = str(raw_input(PROMPT))
if __name__ == '__main__':
threading.Thread(target=cli).start()
threading.Timer(2, interrupt).start()
Ich glaube nicht, dass stdin Thread-sicher ist, so dass Sie Zeichen an die Unterbrechung Faden zu verlieren (dh der Benutzer am Ende der interrupt
erneut eingeben muß) können am Ende. Ich übertrieb die Menge an interrupt
Zeit mit dem time.sleep
Anruf. Der readline.get_line_buffer
Anruf wird nicht die Zeichen anzeigen, die verloren gehen, so dass es alle stellt sich heraus in Ordnung.
Beachten Sie, dass stdout sich nicht sicher ist, fädeln, so dass, wenn Sie mehrere Ausführungs-Threads haben unterbrechen, kann dies noch grob am Ende aussehen.
Andere Tipps
Warum schreiben Sie Ihre eigene REPL mit raw_input()
? Haben Sie bei der cmd.Cmd
Klasse aussehen? Edit: Ich habe gerade die sclapp Bibliothek, die kann auch nützlich sein.
Hinweis: die cmd.Cmd
Klasse (und sclapp) können oder auch nicht direkt Ihr ursprüngliches Ziel unterstützen; Sie kann es zu Unterklasse haben und es zu ändern, wie diese Funktion zur Verfügung zu stellen benötigt.
laufen diese:
python -m twisted.conch.stdio
Sie erhalten eine schöne, farbige, async REPL bekommen, ohne Gewinde mit . Während Sie in der Eingabeaufforderung eingeben, wird die Ereignisschleife ausgeführt wird.
Blick in den Code-Modul, es können Sie Objekte erstellen für die Interpretation Python-Code auch (schamlose Werbung) https: // github.com/iridium172/PyTerm können Sie interaktive Kommandozeilen-Programme erstellen, die roh Tastatureingaben verarbeiten (wie ^ C eine KeyboardInterrupt erhöhen).
Es ist so eine Art Nicht-Antwort, aber ich würde Blick auf IPython 's-Code sehen, wie sie es tun.
Ich glaube, Sie haben zwei grundlegende Optionen:
- Synchronisieren Sie Ihre Ausgabe (das heißt Block, bis er zurückkommt)
- Trennen Sie Ihre Eingabe und Ihren (asynchronen) -Ausgang, vielleicht in zwei getrennten Spalten.