Columnizer (jetzt: shcol)

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

snafu hat geschrieben:... die Terminalbreite selbst erkennen ...
Auf der Suche nach einer Möglichkeit, die Terminalgröße ohne `curses`, `stty` oder abenteuerlichem Auslesen von `env`-Variablen zu bekommen und das vielleicht auch noch in einer Console ohne X bin ich zwar sehr bald auf `ioctl` gestoßen, konnte das aber mangels C Kenntnis nicht umsetzen.
BlackJack hat mir dann geholfen, herausgekommen ist das:

Code: Alles auswählen

from ctypes import c_ushort, sizeof, Structure
from termios import TIOCGWINSZ
from fcntl import ioctl
import sys


class WinSize(Structure):
    '''To get the terminal size information via the UNIX systemcall
    'ioctl()'. This is needed cause the control sequence '\033[18t'
    only work proper in xterm-like terminals but not without running
    X-Server.

    The 'WinSize.from_file()'-method returns the result of 'ioctl()'
    and is wrapped by 'window_size()'. Use this function instead.

    Thanks to 'BlackJack' from 'python-forum.de' for this
    peace of code...! '''
    _fields_ = [
        ('rows', c_ushort),
        ('columns', c_ushort),
        ('x_pixels', c_ushort), # Unused.
        ('y_pixels', c_ushort), # Unused.
    ]

    @classmethod
    def from_file(cls, tty_file):
        result = ioctl(tty_file, TIOCGWINSZ, '\0' * sizeof(cls))
        return cls.from_buffer_copy(result)


def window_size():
    '''window_size() -> (rows, columns) '''
    size = WinSize.from_file(sys.stdout)
    return size.rows, size.columns
Vielleicht wird's Dir ja mal 'ne Hilfe sein.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Joa, man findet ja überall im Netz entsprechende Schnipsel zu dem Thema. Da hätte ich mich dann eben eingearbeitet. Ich glaube, ein aktuelles Python (3.3) hat sogar schon Funktionalität zum Ermitteln der Terminalmaße eingebaut. Aber trotzdem danke für's Posten. Das ist auf jeden Fall ein guter Start. :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

mutetella hat geschrieben:

Code: Alles auswählen

    '''
    ...
    Thanks to 'BlackJack' from 'python-forum.de' for this
    peace of code...! '''
Codefrieden? :)
Das Leben ist wie ein Tennisball.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Was bedeutet 'Codefrieden'?
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mutetella hat geschrieben:Was bedeutet 'Codefrieden'?
Na du hat doch "peace of code" geschrieben. Da peace Frieden heißt, halte ich das für eine angemessene Übersetzung.

Vielleicht meintest du ja piece, also Stück. Oder solltest du piss gemeint haben? :shock:
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

:oops: OMG! Ich möchte überhaupt nicht wissen, welche Blüten sich da noch so in meinen docstrings befinden... :?
Und dabei hab' ich mir doch jetzt fest vorgenommen, ganz viele englischsprachige Vortragsvideos etc. anzuschauen, damit ich nächstes Jahr auf der Europython in Berlin einigermaßen Land sehe...

Aber das muss ich wohl nochmals überdenken.... :mrgreen:

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mutella: Naja, das gesprochene Wort im Vortragsvideo hilft dir wenig, um zwischen "peace" vs. "piece" zu unterscheiden... ;)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@snafo: Dabei gäbe es ein so klasse Lernvideo... Aber Du hast Recht, ich sollte mir doch vorher nochmals das dazugehörige Lehrmaterial durchlesen... :)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Vielleicht ein kleines Update für Interessierte: `shcol` kann inzwischen von der Kommandozeile aus bedient werden.

Beispiel (unter Linux Mint), um alle mit "python3" beginnenden DEB-Pakete rauszusuchen und mittels `shcol` hübsch anzuordnen:

Code: Alles auswählen

$ dpkg --get-selections 'python3*' | awk '{ print $1 }' | shcol
python3                        python3-lxml
python3-apt                    python3-minimal
python3-aptdaemon              python3-oauthlib
python3-aptdaemon.gtk3widgets  python3-pkg-resources
python3-aptdaemon.pkcompat     python3-pyatspi2
python3-brlapi                 python3-pycurl
python3-cairo                  python3-software-properties
python3-crypto                 python3-speechd
python3-dbus                   python3-virtkey
python3-defer                  python3-xkit
python3-gdbm                   python3.2
python3-gi                     python3.2-minimal
python3-gi-cairo               python3.3
python3-httplib2               python3.3-minimal
python3-louis
Ich werde noch eine Option einbauen, um einzelne Spalten selektieren zu können, ohne dass `awk` oder ähnliche Tools dazwischen geschaltet werden müssen.

Hinweis: Die Kommandozeilentauglichkeit wird erst mit Version 0.2 kommen, welche noch nicht veröffentlicht worden ist. Den aktuellen Stand kann man sich aber aus dem Github-Repo laden und hat dann Version "0.2-dev". Bei einem Aufruf der "setup.py" wird unter anderem eine ausführbare Datei namens "shcol" erstellt, die (zumindest bei mir) in "/usr/local/bin" landet. Anschließend kann `shcol` dann wie ein Shell-Tool genutzt werden.

EDIT: Zeilenlänge und Spaltenabstand stehen standardmäßig auf 80 bzw 2 Zeichen. Dies lässt sich aber auch ändern.

Eine Ausgabe mit 100 Zeichen als Breite (width) und 5 Zeichen als Abstand (spacing) würde bei mir so aussehen:

Code: Alles auswählen

$ dpkg --get-selections 'python3*' | awk '{ print $1 }' | shcol -w100 -s5
python3                           python3-gdbm              python3-pycurl
python3-apt                       python3-gi                python3-software-properties
python3-aptdaemon                 python3-gi-cairo          python3-speechd
python3-aptdaemon.gtk3widgets     python3-httplib2          python3-virtkey
python3-aptdaemon.pkcompat        python3-louis             python3-xkit
python3-brlapi                    python3-lxml              python3.2
python3-cairo                     python3-minimal           python3.2-minimal
python3-crypto                    python3-oauthlib          python3.3
python3-dbus                      python3-pkg-resources     python3.3-minimal
python3-defer                     python3-pyatspi2
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Kann mal bitte jemand mit nem Windows-System testen, ob dieser Code zur Ermittlung der Terminalbreite bei ihm erwartungsgemäß funktioniert? Ich habe den quasi blind aufgrund von ein paar Google-Treffern geschrieben und habe hier leider keine Möglichkeit zum Testen unter Windows... :(
fail
User
Beiträge: 122
Registriert: Freitag 11. Januar 2013, 09:47

Läuft ohne Fehlermeldungen, aber gibt nichts aus.??

Edit: Windows 8.1 64-bit
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

fail hat geschrieben:Läuft ohne Fehlermeldungen, aber gibt nichts aus.??

Edit: Windows 8.1 64-bit
Es geht darum, dass `get_terminal_width()` ausgeführt werden soll und ob die angegebene Breite zutrifft. Am besten auch mal während der Sitzung in der Python-Shell das Terminal-Fenster breiter und schmaler machen und gucken, ob sich die Werte anpassen. Und ruhig sowohl über `cmd.exe` als auch über die PowerShell.

EDIT: Ok, vielleicht hätte ich ein paar Erläuterungen dazu schreiben sollen. Die Funktion soll z.B. so ausgeführt werden:

Code: Alles auswählen

import sys
import _termwidth

_termwidth.get_terminal_width(sys.stdout, 80)
fail
User
Beiträge: 122
Registriert: Freitag 11. Januar 2013, 09:47

Oh, sorry.

Hier die Fehlermeldungen:
test.py ist der Originalcode.
test2.py ist der

Code: Alles auswählen

import test
import sys

test.get_terminal_width(sys.stdout, 80)
IDLE:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\fail\Desktop\test2.py", line 4, in <module>
    test.get_terminal_width(sys.stdout, 80)
  File "C:\Users\fail\Desktop\test.py", line 34, in get_terminal_width
    num_handle = -(10 + tty_file.fileno())
io.UnsupportedOperation: fileno
cmd:

Code: Alles auswählen

Traceback (most recent call last):
  File "test2.py", line 4, in <module>
    test.get_terminal_width(sys.stdout, 80)
  File "C:\Users\fail\Desktop\test.py", line 35, in get_terminal_width
    handle = GetStdHandle(num_handle)
TypeError: this function takes 2 arguments (1 given)
Powershell:

Code: Alles auswählen

Traceback (most recent call last):
  File "test2.py", line 4, in <module>
    test.get_terminal_width(sys.stdout, 80)
  File "C:\Users\fail\Desktop\test.py", line 35, in get_terminal_width
    handle = GetStdHandle(num_handle)
TypeError: this function takes 2 arguments (1 given)
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@fail: Schonmal vielen, vielen Dank für deinen Einsatz. :)

Kannst bitte mal die neue Version von `_termwidth.py` testen? Am besten nochmal so ausführlich, wie du es gerade schon getan hast. Übrigens kannst du jetzt einfach ``_termwidth.test()`` (ggf an deinen Modulnamen anpassen) aufrufen.

Achso, noch was: Welche Python-Version verwendest du?
fail
User
Beiträge: 122
Registriert: Freitag 11. Januar 2013, 09:47

Python 3.3.2
fail
User
Beiträge: 122
Registriert: Freitag 11. Januar 2013, 09:47

Gute Nachrichten.
Mit cmd und Powershell funktionert es.
Im IDLE:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\fail\Desktop\termwidth.py", line 71, in <module>
    print(test())
  File "C:\Users\fail\Desktop\termwidth.py", line 68, in test
    fd = sys.__stdout__.fileno()
AttributeError: 'NoneType' object has no attribute 'fileno'
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@fail: Naja, das Skript nutzt jetzt auch einfach eine Builtin-Funktion zur Ermittlung der Terminalgröße, die seit Python 3.3 neu hinzugekommen ist. Daher hatte ich auch nach der Python-Version gefragt.

Bitte ersetze mal den `if hasattr...`-Teil (ziemlich am Anfang) durch ein `if False:`, damit er zu Testzwecken wieder die "ctypes"-Variante nutzt. Die Tests in IDLE können weg bleiben. Das scheint ohne größere Verrenkungen nicht zu funktionieren. Schon mein (versuchter) Workaround mit `sys.__stdout__` ist IMHO keine wirklich saubere Lösung.
fail
User
Beiträge: 122
Registriert: Freitag 11. Januar 2013, 09:47

Auch so funktionert es in der cmd und Powershell.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Super. Nochmals herzlichen Dank. Ich gehe dann mal davon aus, dass ich den kompletten Code zur automatischen Ermittlung der Terminalbreite für das Projekt comitten kann. Ich arbeite nur noch an ein paar Feinheiten...
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

shcol 0.2-dev geht langsam aber sicher in Richtung Zielgerade. Ich habe auf der Github-Seite mal die Readme-Datei überarbeitet, damit ein größerer Fokus auf die neuen Highlevel-Funktionen (z.B. ``print_filenames()``) gelegt wird. In Kürze folgt noch eine Vorstellung der Kommandozeilen-Funktionalität des Tools. Nach Installation der Entwicklungsversion kann man sich dies bereits mittels ``shcol --help`` gerne ansehen. :)

Achso, und könnte jemand von den Mods den Thread ins Showcase-Forum verschieben? Danke.
Antworten