argparse type=argparse.FileType("w") stdout oder nicht?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab sowas:

Code: Alles auswählen

    parser.add_argument("outfile", nargs="?",
        type=argparse.FileType("w"),
        default=sys.stdout,
        help="If given: write output in a new file else: Display it."
    )
Aber wie kann ich dann im Programm prüfen, ob es nun eine normale Datei ist, oder stdout?
self.outfile.name == "<stdout>" ist irgendwie blöd...

EDIT: Gleich noch eine zweite Frage: Hab auch ein infile. Wie kann ich verhindern, das infile==outfile ist?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Warum willst Du das überhaupt prüfen? Letzteres kann zum Beispiel durchaus nützlich sein wenn man eine named Pipe hat über die man Daten empfangen und Ergebnisse zurückschreiben möchte.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich würde mich wohl in beiden Fällen lieber auf die Funktionalität der Shell verlassen. Sowohl Unix-basierte Shells als auch die PowerShell unter Windows können auf recht bequeme Art und Weise Datenströme umleiten. Zumal der Benutzer damit nicht das spezifische Verhalten eines Programms erlernen muss, sondern einfach die gewohnten Mechanismen anwenden kann.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hier ist der Problematische Teil:

Code: Alles auswählen

        to_stdout = self.outfile.name == "<stdout>" # FIXME
        if not to_stdout:
            print "Create file %r..." % self.outfile.name

        assert self.infile.name != self.outfile.name # FIXME

        for line in self.infile:
            ...
            self.outfile.write(line)

        if not to_stdout:
            self.outfile.close()
Gesamte Skript hier: https://github.com/jedie/PyDragon32/blo ... r_trace.py

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Wenn `stdout` dazu verwendet werden kann Ausgabedaten zu produzieren die für sich alleine stehen können/müssen, dann gehören andere Ausgaben normalerweise nach `stderr`. Dann braucht man da nicht weiter testen ob man das nun ausgeben kann oder nicht.

Den Test auf infile != outfile würde ich aus bereits gesagten Gründen gar nicht machen, denn das kann ein Benutzer durchaus absichtlich so haben wollen.

Warum das Schliessen der Standardausgabe am Programmende verhindern? Da kann ja danach nichts mehr ausgegeben werden, sonst hat ein Benutzer der die Shellumleitung benutzt, Daten in der Datei, die er ohne Umleitung aber mit Nennung eines Dateinamens dort nicht hätte. Das wäre IMHO ein überraschendes Verhalten was ich vermeiden würde.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Danke für deine Anmerkungen...
BlackJack hat geschrieben:@jens: Wenn `stdout` dazu verwendet werden kann Ausgabedaten zu produzieren die für sich alleine stehen können/müssen, dann gehören andere Ausgaben normalerweise nach `stderr`. Dann braucht man da nicht weiter testen ob man das nun ausgeben kann oder nicht.
Das wäre eine Möglichkeit. Wobei es halt nicht wirklich Fehler sind...
BlackJack hat geschrieben:Den Test auf infile != outfile würde ich aus bereits gesagten Gründen gar nicht machen, denn das kann ein Benutzer durchaus absichtlich so haben wollen.
Das geht aber nicht, weil ich doch über die infile iteriere um in das outfile zu schreiben ;)
Erst die ganze Datei ein den Speicher laden, möchte ich nicht, die kann schnell mal mehrere hunderte MBs groß werden.
BlackJack hat geschrieben:Warum das Schliessen der Standardausgabe am Programmende verhindern?
Ja, wenn es stdout ist, macht das Schließen keinen Sinn bzw. führt zu einem Fehlverhalten... Aber wenn es eine richtige Datei ist, sollte man sie doch nach dem beschreiben besser explizit schließen...


Irgendwie eröffnet sich mir noch keine richtige Lösung :?
Vielleicht besser erst garnicht bei outfile auf argparse.FileType setzten?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Es sind keine Fehler aber halt auch keine Daten die zur generierten Datei gehören. Es ist übliches Verhalten das Werkzeuge die Daten die sie auch in Dateien schreiben könn(t)en und Ausgaben für den Benutzer auf diese Art trennen, eben damit der Benutzer ausserhalb des Programms die erzeugten Dateiinhalte umleiten kann ohne auch die anderen Ausgaben da drin zu haben. Oder anders ausgedrückt ``tool -o filename`` und ``tool > filename`` sollten sowohl im Terminal als auch in der Datei die gleichen Inhalte produzieren. Was man durch die Aufteilung auf `stdout` und `stderr` einfach und zuverlässig erreichen kann. Darum machen das viele Programme so.

Und das mit infile == outfile geht durchaus, das habe ich doch schon beschrieben: Zum Beispiel wenn man für beides eine named pipe angibt. Dann ist der Ausgabestrom etwas anderes als der Eingabestrom, aber es ist für das Programm die selbe Datei. Das gleiche gilt für Dateien wie PTYs. Ich glaube Du siehst den Dateibegriff hier zu eng.

Wieso kann man die Datei am Ende des Programms nicht schliessen? Danach sollten darauf doch keine Ausgaben mehr erfolgen, und Ausgaben für den Benutzer die nichts mit dem Dateiinhalt zu tun haben, sollten ja wie gesagt sowieso nach `stderr` gehen.

Ansonsten würde ich den Test wohl nicht auf den Dateinamen machen, sondern prüfen ob `sys.stdout` das gleiche Objekt ist.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab es nun mit stderr gemacht. Allerdings wird das ein wenig Haarig, wenn man Statusausgaben jede Sekunde dazwischen packt, z.B.:

Code: Alles auswählen

                sys.stderr.write(
                    "In %i lines (%i/sec.) are %i unique address calls..." % (
                        line_no, (line_no - last_line_no), len(unique_addr)
                    )
                )
Man muß dann ein wenig jonglieren, damit nicht versehentlich die letzte Zeile nach outfile durch das \r zumindes im Terminal "überschrieben" werden...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@jens:
Mit `os.isatty(sys.stdout.fileno())` kannst Du prüfen, ob STDOUT ein Terminal ist. Ist es kein Terminal, kannst Du Dir mit `os.ctermid` den Pfad des Terminals holen, öffnen und dort die Statusausgaben reinschreiben. STDIN, -OUT und -ERR können zu allem Möglichem verbogen sein (auch andere Terminals).
Antworten