Python Konsolenausschnitte ausführen

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei Beispielen in Dokumentation ist es ja oft so, dass ein paar Zeilen aus der Interpreter-Session einfach in den Text reinkopiert werden. An sich ist das auch recht anschaulich, aber wenn man den gezeigten Code mal ausprobieren will und zu faul ist, alles abzuschreiben, wird Copy&Paste nervig, da man den Interpreter-Prompt händisch wieder rauskriegen muss.

Das folgende Skript nimmt an, dass es alle Vorkommen von `>>>` bzw. `...` am Zeilenanfang als Prompt interpretieren und daher löschen darf. Zusätzlich werden Zeilen, die mit keins von beiden anfangen, komplett gelöscht. Das hat den Vorteil, dass etwaige Rückgabewerte rausgenommen werden und man das bereinigte Ergebnis direkt via `exec` ausführen oder irgendwo zum späteren Ausführen zwischenspeichern kann.

Wer `xsel` installiert hat (also i.d.R. Linux-User), braucht eigentlich nur den gewünschten Code in die Zwischenablage zu kopieren und die Hauptfunktion des Skriptes auszuführen, da dann die Ausgabe des besagten Programms (also Clipboard-Inhalt) zum Bereinigen genommen wird. Windows-Benutzer müssen die Konsolenausgabe leider händisch übergeben - zumindest solange es keine "Paste-Funktion" für sie gibt...

Was man noch machen könnte, wären Kommandozeilen-Parameter. Aktuell wird bei einem Ausführen "von Außen" standardmäßig das "Tastatur-Clipboard" verwendet (`xsel -b`). Vielleicht nutzt der Ein oder andere aber auch lieber die mittlere Maustaste für solche Aktionen oder möchte gar nichts mit der Zwischenablage machen, sondern nur die Ausgabe sehen. Außerdem finde ich den Weg, wie ich in die Pipe von `xsel` schreibe, nicht so toll. Ich denke, das geht doch bestimmt auch ohne `echo`.

Code: Alles auswählen

from subprocess import Popen, PIPE

def _get_clipboard_contents():
    xsel = Popen(['xsel', '-b'], stdout=PIPE)
    clipboard_contents = xsel.communicate()[0]
    return clipboard_contents

def _write_to_clipboard(s):
    echo = Popen(['echo', s], stdout=PIPE)
    xsel = Popen(['xsel', '-b', '-i'], stdin=echo.stdout, stdout=PIPE)
    xsel.communicate()

def pycon2source(s=None, copy_result=True):
    s = s or _get_clipboard_contents()
    result = '\n'.join(
        line[4:] for line in s.splitlines()
        if line.startswith(('>>>', '...'))
    )
    if copy_result:
        _write_to_clipboard(result)
    return result

if __name__ == '__main__':
    print pycon2source()
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Da man den Prompt veraendern kann, sollte man den Prompt-Stripper als Funktion uebergeben koennen.

Code: Alles auswählen

def strip_std_prompt(s):
    if s.startswith(('>>>', '...')):
        return s[4:]
    else
        return s

def pycon2source(s=None, copy_result=True, strip=strip_std_prompt):
    s = s or _get_clipboard_contents()
    result = '\n'.join(strip(line) for line in s.splitlines())
    if copy_result:
        _write_to_clipboard(result)
    return result
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das ist eigentlich unnötig, da man die möglichen Prompts auch als Tupel für die Funktion übergeben könnte, wobei der Standard-Prompt der Default-Wert wäre. Außerdem unterschlägt deine Funktion das Feature, dass Konsolenausgaben rausgelöscht werden, da man natürlich nur die Eingaben ausführen möchte. ;)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ok, das "Feature" hatte ich uebersehen, aber das liesse sich fixen ;) Das ist uebrigens genau das schoene bei so einer strip-Funktion, da du das dem Anwender ueberlaesst.

Der Punkt ist allerdings, dass es mit einem Tupel der Prompts nicht getan ist, da du dich auf die Laenge 3 beschraenkst.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Okay, dann gibt man den Prompt eben korrekt mit den trennenden Leerzeichen an und in der Hauptfunktion schneide ich halt exakt diese Länge ab. Ich sehe für den Benutzer keinen Vorteil, wenn er die Funktion selber schreiben soll.
crs
User
Beiträge: 42
Registriert: Dienstag 14. Juli 2009, 13:24

snafu hat geschrieben:Bei Beispielen in Dokumentation ist es ja oft so, dass ein paar Zeilen aus der Interpreter-Session einfach in den Text reinkopiert werden. An sich ist das auch recht anschaulich, aber wenn man den gezeigten Code mal ausprobieren will und zu faul ist, alles abzuschreiben, wird Copy&Paste nervig, da man den Interpreter-Prompt händisch wieder rauskriegen muss.
mit dem column-edit feature/mode von emacs/vim geht sowas eigentlich relativ komfortabel ;)

oder natuerlich

Code: Alles auswählen

sed 's/>*//' foo.py
8)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Du willst jedes > aus einem Python-Skript entfernen? Das ist wohl ein Scherz, oder? Aus ``a < b`` wird ``a b`` etc.
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

derdon hat geschrieben:Du willst jedes > aus einem Python-Skript entfernen? Das ist wohl ein Scherz, oder? Aus ``a < b`` wird ``a b`` etc.
Nein, aber aus `a > b` wird `a b` :D

SCNR
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

:oops:
crs
User
Beiträge: 42
Registriert: Dienstag 14. Juli 2009, 13:24

hm, habt ihr das getestet?

Code: Alles auswählen

?: echo "a > b" | sed 's/>*//'
a > b
?: echo "> a > b" | sed 's/>*//'
a > b
?: echo ">>>> a > b" | sed 's/>*//'
a > b
?: sed --version
GNU sed version 4.2.1
mag aber sein das man noch ein '^' vor die regex setzen sollte o.ae... der smiley sollte auch andeuten das ich eher die emacs/vim variante bevorzugen wuerde.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Hab vergessen, dass sed zeilenbasiert arbeitet.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der sed-Ausdruck kommt ziemlich schlecht an das vorgegebene Ziel. Er lasst die Dreier-Punkte, das Leerzeichen zwischen Prompt und Eingabe und die jeweilige Ausgabe einfach so bestehen. Davon hat man nicht wirklich was bei mehrzeiligem Code. Ich werde mich aber nun in die sed-Syntax einlesen, um zu sehen, ob das vielleicht tatsächlich halbwegs verständlich damit geht. Mit `xsel` könnte man ja dann viel direkter die Daten reinschicken und bei Bedarf wieder in die Zwischenablage packen. Vielleicht hat ja auch jemand ne Lösung mit Perl?
Antworten