python2to3

Du hast eine Idee für ein Projekt?
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Eine weitere Änderung bei 'menu.py', ist das Arbeiten mit einer Kopie der Originaldatei, was wohl in Hyperionś ursprünglichem Code, mit der Menüoption 'save' wahrscheinlich auch so angedacht war.

Die Vorgehensweise ist die, daß bei Änderung (Daten verändern, Neue Daten hinzu, Daten löschen), eine Kopie der Originaldatei erstellt wird und mit dieser weitergearbeitet wird. Alle Änderungen sind zuerst nur in der Kopie vorhanden und erst durch den Menüpunkt 'Änderungen übernehmen', wird die Originaldatei aktualisiert und die Kopie wird anschließend gelöscht.

Jetzt sind zwar wieder ein paar Zeilchen mehr dazu gekommen, aber damit lässt es sich schon richtig gut arbeiten. :D :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
habe jetzt eine Version, die Ihr Euch anschauen könnt: https://gist.github.com/3621627

Ich hoffe mal, daß Ihr den ersten Fehler nicht gleich nach 5 Sekunden findet. :lol:
Nein ehrlich, habe mir wirklich Mühe gegeben, Euren Anforderungen gerecht zu werden. :wink:

Den Code habe ich versucht in der maximalen Zeichenbreite unterzubringen.
Wenn also manches dadurch nicht so schön aussieht ... könnt Ihr mir ja Tipps geben.
Auch habe ich versucht LC im Code zu verwenden, wo es mir möglich war.

Bestimmt lässt sich das noch weiter verbessern und hoffe, daß Ihr mir dazu Tipps gebt! :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Sodele, da ich nach 5 Sekunden nichts von Euch gehört habe, komme ich zum Ende dieses Projektes. :D

In menu.py selbst gab es noch kleinere Korrekturen.
Was ich komplett neu gemacht habe, ist ein Modul für das Erstellen und Verwalten der Einstellungen, was mir recht gut geglückt ist, :D
Ich habe dafür den Namen settingmenu.py vergeben und die Datei in der die Einstellungen gespeichert werden, heißt nicht mehr privatparam.py sondern settings.py.

Für Diejenigen, dies es noch interessiert, hier die fertige Version: https://gist.github.com/3667523

Danke, an Alle, die mir geholfen haben! :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo snafu,
Dein letzter Post, ist ja eine kleine Weile her, möchte aber wenn möglich, nochmals daran anknüpfen.
snafu hat geschrieben:Hab jetzt einfach mal die komplette Formatierungs-Funktionalität geschrieben. Aufgrund der speziellen Anforderungen, die du an die Ausgabe stellst, sind es doch ein paar Zeilen mehr geworden. Manches kann man vermutlich noch besser machen, aber ich hoffe trotzdem, den Quelltext etwas verständlicher für die Allgemeinheit hinbekommen zu haben: https://gist.github.com/3527463

Wie du siehst, habe ich den Info-Text bei den Testdatensätzen stark gekürzt, damit das schon von dir genannte Problem der Überlänge nicht auftritt. Wobei man auch hier sein Terminal-Fenster im Vollbildmodus laufen lassen sollte.

Eine Implementierung mit passendem Zeilenumbruch kommt dann in der nächsten Maus (irgendwann). ;)
Deine Funktion, funktioniert wirklich prima. Einziger Wermutstropfen, sind überlange Zeilen, die dann das Layout sprengen.

Habe Deine Funktion als Modul laufen, damit ich von verschiedenen Modulen aus, darauf zugreifen kann.

Habe den Code für die neue Anforderung etwas erweitert, bin allerdings noch am Rätseln, wie ich das umsetzen kann, bei überlangen Zeilen, einen Zeilenumbruch innerhalb der jeweiligen Spalte zu erzeugen.

Code: Alles auswählen

def window_size():
    # Fenstergröße des Terminals/Konsole ermitteln.
    # Ausgabe: Zeilen, Zeichen
    rows, columns = os.popen('stty size', 'r').read().split()
    return rows, columns


def get_formatted_table(menupoint, HEADINGS, contents, spacing=4,
                                                numeration_width=10):
    rows, columns = window_size()
    lines = [HEADINGS] + contents
    column_widths = [max(len(item) for item in column_items)
                     for column_items in zip(*lines)]
    total_width = sum(column_widths) + (len(column_widths) - 1) * spacing
    total_width += numeration_width
    if total_width > int(columns):
        print('Layoutfehler, die Ausgabezeile ist um %s Zeichen größer, \
            \nals die Breite des Terminals/Konsole!' %
                                        (total_width - int(columns)))
    dashed_line = total_width * '-'
    blank_line = total_width * ' '
    numeration_spec = '{{:>{}}}'.format(numeration_width)
    column_specs = ['{{:{}}}'.format(width) for width in column_widths]
    line_template = numeration_spec + (spacing * ' ').join(column_specs)
    headline = line_template.format('Nummer: ', *HEADINGS)
    head_items = [dashed_line, headline, blank_line, dashed_line]
    formatted_lines = head_items[:]
    dataline = dict()
    for line_number, text_items in enumerate(contents, 1):
        needs_headings = (line_number % MAX_LINES_PER_SEGMENT == 0)
        dataline[line_number] = [text_items]
        if needs_headings:
            formatted_lines.extend(head_items)
        numeration_string = '{}: '.format(line_number)
        formatted_lines.append(line_template.format(numeration_string,
                                                    *text_items))
        formatted_lines.append(blank_line)
    formatted_lines.append(dashed_line)
    print('\n'.join(formatted_lines))
    return menupoint, dataline
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Naja, man könnte entweder überlegen, ob man das vorhandene `line_template` benutzt und bei Überlänge in einer neuen Zeile die dementsprechend nicht zu benutzenden Spalten einfach mit leeren Strings füllt und in die Spalte mit Überlänge halt den Rest des Textes packt (in einer Schleife, damit auch mehr als nur *eine* zusätzliche Zeile genutzt werden können) oder aber man geht davon aus, dass eh immer nur die letzte Spalte befüllt werden muss und berechnet daher einfach vorab den nötigen Leerraum.

Ich würde wahrscheinlich die mir persönlich schon wieder viel zu aufgeblähte Funktion in mehrere einzelne Funktionen unterteilen und etwas einigermaßen abstraktes (und damit auch wiederverwendbares) erstellen. Eventuell sogar als Klasse. Das ist mir aber momentan etwas zu aufwändig, zumal ich zur Zeit andere wichtigere Dinge im Kopf bzw auf meiner TODO-Liste habe. Kann sein, dass ich zum Wochenende was dazu baue - soll aber kein Versprechen sein.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Dies ist wirklich nicht so einfach, taste mich da Schritt für Schritt ran und habe schon 3 graue Haare mehr ... :wink:

Ein Problem ist auch, daß es sich nicht festlegen lässt, daß immer die letzte Spalte die Überlänge hat.
Könnte ja auch mal vorkommen, daß 2 oder 3 Spalten Überlängen haben.
Das wird dann schon eine recht kniffelige Sache.

Vielleicht habe ich auch schon bis zum Wochenende Codestücke fertig, die mich dem Ziel näher bringen.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Sodele, war nicht untätig und bin ein großen Schritt weitergekommen.
Ich habe snafuś Code erweitert, so daß bei überlangen Spaltenbreiten, diese Umgebrochen werden und da durch das entsprechende Format ausgegeben wird. :D
Das Problem was noch besteht, ist daß der Code nicht automatisch sich auf den jeweiligen Zeilenbedarf einstellt.
Dies habe ich im Moment, manuell auf 2 Zeilen begrenzt.

Ich poste hier mal den Code: https://gist.github.com/3727387
Dieser Code ist nur ein Provisorium!
Ich habe die Ausgabe von 'gist.github' gewählt, damit man sich auf Zeilennummern beziehen kann.
Weiter habe ich bei meinen Code '#-Infos' dazu getan und mit Leerzeilen vom übrigen Code getrennt.

Das was ich oben schon angesprochen habe, mit dem Automatismus auf den jeweiligen Zeilenbedarf, ist in der Code-Zeile 54-56 momentan manuell gelöst. Vielleicht, habt Ihr da bessere Ideen?

Über Euren Input und Tipps dazu würde ich mich freuen! :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

UPDATE!
Wie ich selbst bemerkt habe, ist mein zuletzt geposteter Code fehlerhaft.
Beim dritten Anlauf, bin ich jetzt auf dem richtigen Weg. :D

Es wird noch ein paar Tage dauern, bis ich alles komplett habe und bitte daher, von Tipps und Hilfestellung abzusehen.
Möchte es einfach selber erreichen! :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
endlich ist es soweit, daß ich Euch meine funktionierenden Code zeigen möchte. :D

snafus Code ist der echt super ist, habe ich mit ein paar weiteren Codezeilen vervollständigt.
Als erstes wird die Größe des Terminals ermittelt, welche in der weiteren Verarbeitung, eine Bezugsgröße bildet.
Es ist nun möglich, Tab-getrennte Dateien auszugeben, bei der eine oder mehr Spalten Überbreiten haben.
Ich das mit einer Datei getestet, welche ca. 20 Spalten hat. Davon habe ich dann die ersten 6 Spalten ausgewählt, bei der zwei davon Überbreite haben. Die Ausgabe im Terminal sah überzeugend aus und jede Spalte war für sich ausgerichtet.
Hier ist es ratsam, die Größe des Terminals zu maximieren.

Hier ist mal der Code, bei dem noch Kurzerläuterungen enthalten sind: https://gist.github.com/3750805

Würde mich freuen, wenn Ihr Euch den Code anschauen und mir Input darüber geben würdet, auch was sich besser machen lässt! :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Eine Kleinigkeit, mußte ich doch noch korrigieren.
Es entstand ein Layout-Fehler bei weiterer Filterung der Daten, der jetzt behoben ist.
Das betraf die Zeile 96, die an dieser Position entfällt.
Neu hinzu kam dieser Code, der nach der Zeile 76 eingefügt ist.

Code: Alles auswählen

    for line_number, text_items in enumerate(contents, 1):
        for i in range(len(text_items)):
            text_items[i] = text_items[i].replace('\n', '')
            text_items[i] = text_items[i].replace(' ', '')
        dataline[line_number] = [text_items]
Dies lässt sich bestimmt noch besser machen, zumindest erfüllt es vorerst die Funktion.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Deine `True`-`False`-Wörterbuchgebilde lassen sich vereinfachen:

Code: Alles auswählen

# schlecht
total_width = {True: columns, False: total_width}[total_width > columns]

# besser
total_width = min(columns, total_width)

# schlecht
normal_width = {True: normal_width, False: round(normal_width / len(xtra_width) + 0.5)}[len(xtra_width) == 1]

# besser
if len(xtra_width) != 1:
    normal_width = round(normal_width / len(xtra_width) + 0.5)
Und das, was du im letzten Post dazugeschrieben hast, lässt sich auch so ausdrücken:

Code: Alles auswählen

text_items = [item.replace('\n', '').replace(' ', '') for item in text_items]
Ich wette aber, dass man dies noch anders lösen kann. Wahrscheinlich mittels `item.strip()`. Aber dazu müsste ich mir den Quelltext genauer ansehen, wozu mir momentan einfach die Zeit/Motivation fehlt. Fraglich ist ja auch, wieso etwas namens `items` überhaupt Whitespace (vermutlich) am Ende drin hat...

EDIT: Und der Ausdruck von Zeile 86-93 ist echt der Knüller. Oh Mann. :mrgreen:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo snafu,
Dein Input, dieser hilft mir weiter, die Dinge einfacher zu gestalten! :wink:

Mach Dir keinen Kopf über Zeit und Motivation, Du hast mir sehr geholfen, Danke dafür!

Nachtrag:
snafu, Deine letzte Zeile ist mir erst im Nachhinein aufgefallen ... :mrgreen: ... keine Frage, diese Codezeilen sind verbesserungswürdig, daher kommt auch das fehlerhafte Zeilenformat beim Filtern.
Habe den Zeilenumbruch durch Leerzeichen ersetzt.
Versuche den Code noch weiter zu vereinfachen. :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Sodele, habe diesen Bereich nochmals überarbeitet.

Code: Alles auswählen

    for line_number, text_items in enumerate(contents, 1):
        for i in xtra_width:
            rang = i[0]
            true_width = len(text_items[rang])
            if true_width > normal_width:
                start_width = (sum(column_widths[:rang])
                                + numeration_width + ((rang) * spacing))
                        lines = round((true_width / normal_width) + 0.5)
                        text_items[rang] = ('{}'.format(''.join([
                        (text_items[rang][normal_width * i:
                                            normal_width * (i + 1)])
                        + {True: (total_width - normal_width) * ' ',
                        False: (normal_width * (i + 1) - true_width)
                                                * ' '}[i + 1 < lines]
                        for i in range(lines)])))
        needs_headings = (line_number % MAX_LINES_PER_SEGMENT == 0)
        if needs_headings:
            formatted_lines.extend(head_items)
        numeration_string = '{}: '.format(line_number)
        formatted_lines.append(line_template.format(numeration_string,
                                                    *text_items))
        formatted_lines.append(blank_line)
        text_items = [item.replace('  ', '') for item in text_items]
        dataline[line_number] = [text_items]
    formatted_lines.append(dashed_line)
    print('\n'.join(formatted_lines))
Jetzt läuft von der funktionalen Seite alles rund. :D
Wie ich Euch kenne, habt ihr dafür bestimmt bessere Vorschläge.

Was mich jetzt aber grundsätzlich interessiert, ist ob dieser Bereich des Codes mit den Einrückungen so gut ist, daß man die einzelnen Bereiche besser erkennt

Code: Alles auswählen

                text_items[rang] = ('{}'.format(''.join([
                        (text_items[rang][normal_width * i:
                                            normal_width * (i + 1)])
                        + {True: (total_width - normal_width) * ' ',
                        False: (normal_width * (i + 1) - true_width)
                                                * ' '}[i + 1 < lines]
                        for i in range(lines)])))
oder ob man dies hier besser einheitlich, links ausrichtet so wie hier?

Code: Alles auswählen

                text_items[rang] = ('{}'.format(''.join([
                        (text_items[rang][normal_width * i:
                        normal_width * (i + 1)])
                        + {True: (total_width - normal_width) * ' ',
                        False: (normal_width * (i + 1) - true_width)
                        * ' '}[i + 1 < lines]
                        for i in range(lines)])))
Zuletzt geändert von Nobuddy am Samstag 22. September 2012, 12:53, insgesamt 2-mal geändert.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Weder noch. Der Abschnitt ist komplex genug fuer mindestens eine Funktion.

Ich will mir das nicht en detail durchlesen, aber nur weil man 100 Sachen in 1 Ausdruck erledigen kann, sollte man es noch lange nicht tun.
Antworten