Reportlab und SaveAs Dialog

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.
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

Hallo liebe Community!

Ich bin nagelneu hier im Forum um einige meiner eher speziellen Fragen loszuwerden für die ich im Netz keine Lösung finden konnte.

Ich habe mir das Toolkit Reportlab geholt um PDFs aus meinem Berechnungsprogamm erstellen zu können.
Nun ist es allerdings so, dass die PDF von Reportlab standartmäßig im Python-Verzeichnis abgelegt wird und auch einen vorgegebenen Namen hat. Das finde ich nicht besonders günstig. Schöner wäre natürlich, wenn der Anwender den Pfad und die Bezeichnung selbst wählen könnte.

Eine richtige Lösung habe ich noch nicht gefunden. Das mit dem Namen ist eher zweitrangig, aber der Speicherort wäre schon super, wenn der geändert werden könnte.
Erste Erfolge konnte ich erzielen mit dem os - Toolkit für Systemabfragen. Ich habe das Arbeitsverzeichnis einfach auf den Desktop verschoben um dort die PDF zu erstellen, aber auch das ist ein vorgegebener Pfad.

Als nächstes habe ich mit dem Filedialog von tkinter gearbeitet und versucht Pfad und Bezeichnung als Variablen abzugreifen, leider ohne erfolg.

Hat jemand Erfahrung mit reportlab oder weiß wie ich mit dem Filedialog den Pfad bzw. den Namen abgreifen kann um diesen dann programmintern zu verwenden?

Ich danke euch schon einmal vielmals. :)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bibo3000: Das ist also ein bisschen komisch beschrieben. Reportlab gibt keinen Pfad vor — wo die Datei landet und wie die heisst liegt in Deiner Verantwortung.

Was meinst Du mit „os - Toolkit für Systemabfragen“? Falls das auf `os.chdir()` rauslaufen sollte: Vergiss diese Funktion bitte gleich wieder. Wenn man anfängt das Arbeitsverzeichnis des Prozesses zu ändern, fängt man sich am Ende oft mehr Probleme ein als dieser Hack löst.

Warum hat der Dateidialog von Tkinter nicht weitergeholfen? Was hast Du gemacht und was daran hat nicht funktioniert?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Das hat ja nichts mit reportlab zu tun, das speichert dort hin, wo Du es angibst.
Du scheinst ja schon eine GUI zu benutzen, da wäre also die Frage, we Du den Filedialog benutzt hast, und was dann konkret nicht so funktioniert hat, wie Du es Dir vorgestellt hast.
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

Erst einmal vielen Dank für die Antworten!

Tut mir leid, dass meine Beschreibung etwas komisch ist. Ich versuche es mal genauer.

Ich habe eine GUI mit einem Berechnungsprogramm gebaut. Die wichtigsten Zwischenergebnisse und das Endergebnis sollen in einer PDF ausgegeben werden, die anschließend genutzt, gedruckt und abgelegt werden kann.
Für die Erzeugung der PDF habe ich mich für Reportlab entschieden. Bei der Erstellung einer PDF definiere ich den Namen. Die PDF wird aber in dem Ort erstellt in dem das Skript ausgeführt wird. In meinem Fall ist das ein Python-Ordner auf meinem Desktop. Ich habe bei Reportlab noch keine Möglichkeit gefunden den Pfad direkt zu ändern ohne mittels os.chdir() das Arbeitsverzeichnis zu ändern.

Warum hat der Filedialog von tkinter nicht geholfen?
Ich kann mit asksaveasfile() zwar einen "Speichern unter"-Dialog öffnen, aber dieser bezieht sich nicht auf die PDF die Reportlab erstellt. Soweit ich verstanden habe, kann man mit dem SaveAs-Dialog beispielsweise .txt Dokumente mit einem definierten Inhalt speichern lassen. Eventuell ist es also möglich zu sagen, dass er eine PDF mit dem Inhalt von Reportlab erstellen soll. Allerdings läuft bei der Erstellung der PDF von Reportlab ja eine Funktion ab an deren Ende eben das Erstellen der PDF im Arbeitsverzeichnis steht.

Eine von zwei Möglichkeiten habe ich mir überlegt, aber keine Lösung für gefunden:
1. Den Dialog öffnen und versuchen den vom Benutzer gewählten Speicherpfad abzugreifen und via os.chdir() den Speicherort an Reportlab zu geben (inklusive Dateinamen) oder
2. Dem Filedialog irgendwie sagen, dass das was er speichern soll die PDF von Reportlab ist ohne das Reportlab eine PDF im Arbeitsverzeichnis erstellt.

Ich hoffe jetzt ist es besser beschrieben?

Mir scheint es so, als wären beide Funktionen, Dialog und Reportlab, nicht so richtig zu verbinden.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Beim Erstellen der PDF gibts Du einen Dateinamen inklusive Pfad an. Das was Du hier beschreibst hört sich komisch bis falsch an. Wenn Du Deinen Code zeigen würdest, könnte man Dir einfacher helfen.
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

Okay, gut, dann habe ich eventuell in dem Guide von der Homepage von Reportlab was überlesen. Hier ist mein Code:

pdf_name = "Name.pdf"
pdf = Canvas(pdf_name, pagesize=A4, bottomup=1)

- Befehle für die PDF -

pdf.save()

An welcher Stelle kann ich einen Pfad vorgeben? Bzw. wie kann ich den dynamisch vom benutzer wählen lassen?
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Was passiert denn wenn du einen kompletten Pfad als "filename" übergibst?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

pdf_name ist ein Dateiname, der kann relativ sein, mit Pfadangabe, absolut, oder irgendwas das Du von einem SaveAs-Dialog bekommst.
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

Dann wird die PDF mit dem Pfad als Name erstellt. Der Name fungiert dabei leider wirklich nur als Name.
Ich habe in allen möglichen Foren, Tutorial-Seiten oder dem Guide von Reportlab leider keinen Befehl oder eine Möglichkeit gefunden die PDF woanders als im Arbeitsverzeichnis zu speichern.
Und wenn, dann ist der Pfad immer vorgegeben. Selbst mit os.chdir() ist er von mir vorgegeben. Die Änderung von einem Nutzer wäre umständlich und nicht besonders komfortabel.

@ Sirius3: Wie kann ich den Pfad vom SaveAs-Dialog bekommen? Und kann ich den dan anders verwenden als mit os.chdir()?
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Bitte poste das exakte Programm, mit dem Du getestet hast, dass Du keinen absoluten Pfad bei Canvas angeben kannst und was dann die entsprechende Fehlermeldung ist.
Und ebenso zeige hier den kompletten Code, mit dem Du versucht hast den SaveAs-Dialog zu benutzen, und was Du dort an Fehlermeldungen bekommst.

os.chdir darf man nicht benutzen, deshalb wäre es müßig, eine Frage danach zu beantworten.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Du kannst an der Stelle einen kompletten Pfad angeben. Das ist das, was ich dir als Hinweis geben wollte und was Sirius3 noch einmal ausführlich beschrieben hat.
Nur weil du die Variable falsch benannt hast (weil es kein pdf_name ist), heißt das ja nicht, dass da nicht andere Werte dran gebunden sein können.

Code: Alles auswählen

pdf_path = "/ich/bin/ein/pfad/mit/einer/datei.pdf"
pdf = Canvas(pdf_path, pagesize=A4, bottomup=1)
Wird in dem Verzeichis /ich/bin/ein/pfad/mit/einer die PDF mit dem Namen "datei.pdf" erstellen.

Und nun auf zur Dokumentation des SaveAs-Dialoges, die dir verrät, wie du den Pfad von dort zurück bekommst.
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

Ach herrje, auf die Idee mit dem Pfad vor dem Namen bin ich so noch nicht gekommen. Das habe ich so auch noch nirgends gesehen. Danke sparrow, der Code war jetzt wirklich hilfreich. Wenn Sirius das gemeint hat, dann tut es mir leid, hab ich so nicht verstanden.

@ Sirius3: Ohne dir zu nahe treten zu wollen, aber mit "das darf man nicht machen" kann ich nix anfangen. Ich verstehe die Dinge gerne, dass macht vieles leichter. :-) Wenn du also die Muße hast lasse ich mir das gerne erklären.
Außerdem habe ich nie gesagt ich würde einen Fehler bekommen, weder beim einen noch beim andern. Ich hab geschrieben, dass ich nicht weiß wie es gehen soll. Was den Pfad angeht wusste ich nicht, dass man diesen vor den Namen setzen kann und beim SaveAs-Dialog weiß ich nicht wie ich den Pfad abgreifen um diesen in meine Variable zu packen. Über einen Code-Schnipsel würde ich mich freuen in dem ich sehen kann wie es geht.

Was den SaveAs-Dialog angeht, den habe ich einfach mit einer kleinen Funktion aufgerufen mit filedialog.asksaveasfile().
Hier gibt es ja verschiedene Befehle, deshalb würde es mich nicht wundern, wenn ich einen falschen genommen habe. Jetzt wo ich weiß, wie das mit dem Pfad geht, kommt mir allerdings noch eine Idee...
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bibo3000: `filedialog.asksaveasfile()` ist die falsche Funktion. Lies einfach mal in der Dokumentation nach was die Funktion als Ergebnis liefert. Das ist kein Dateiname/-pfad. Dafür gibt es eine andere Funktion im gleichen Modul.

In beiden Fällen dran denken, dass der Benutzer den Dialog auch abbrechen kann ohne eine Datei ausgewählt oder angegeben zu haben.

Bezüglich `os.chdir()`: Benutze es einfach nicht. Man macht das nicht. Wenn Du's doch machst, und dadurch Probleme entstehen, erwarte keine Hilfe von Leuten die Dir gesagt haben das man das nicht benutzt. 🙄

Edit: Die `asksaveasfile()`-Funktion ist übrigens nur so semifalsch, weil `Canvas` auch ein Dateiobjekt übergeben werden kann, laut Dokumentation.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

@ blackjack: Danke für die Erklärungen!
Ein "Benutze es einfach nicht" ist genauso unbefriedigend. Das hilft einfach überhaupt nicht weiter. Wie soll man dadurch etwas lernen? Mal ein Beispiel, wenn jemand sagt "Fass nicht auf die heiße Herdplatte, dass macht man nicht" ist die Reaktion i.d.R. immer die gleiche, früher oder später verbrennt sich einer die Finger. Wenn man aber sagt "Fass nicht auf die Herdplatte, die ist heiß und du verbrennst dich und das tut arg weh" wird schon seltener draufgepatscht.

Ich bin bei weitem kein Experte im programmieren und würde mich drüber freuen von euch hier was zu lernen und das inkludiert auch zu lernen warum etwas nicht getan werden soll. ;-)
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

So, habe jetzt nochmal getüftelt und habe eine Lösung gefunden.

pdf_name = filedialog.asksaveasfilename(initialfile=standard_name,filetypes=[("PDF", "*.pdf")])
if pdf_name:
pdf = Canvas(str(pdf_name)+".pdf", pagesize=A4, bottomup=1)

Die Variable standart_name definiere ich davor.

Über die Erklärung bezüglich os.chdir() würde ich mich dennoch freuen. :)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bibo3000: Das mit der Herdplatte lässt sich ja auch einfach erklären. Globale Variablen tun nicht sofort weh, darum scheinen die ja auch so schön praktisch zu sein, aber irgendwann beissen sie einen dann doch mehr oder weniger subtil in den Allerwertesten, und dann muss man erst einmal die Fehlerursache finden, viel Spass wenn da globale Variablen beteiligt sind, und hat unnötig Arbeit das alles noch mal ohne globale Variablen umzuschreiben.

Das ist mehr „benutze Sonnencreme“ statt „fass nicht auf die Herdplatte“. Musst Du nicht machen, stört ja auch gar nicht, man wird sogar schön braun — aber wenn der Hautkrebs dann da ist…

Problem bei der Fehlersuche: Viele Leute die programmieren können, werden dabei nicht wirklich direkt helfen (wollen), weil das durch globale Variablen unnötig erschwert wird. Insbesondere wenn ich weiss es wurde mal deutlich kommuniziert BENUTZE KEINE GLOBALEN VARIABLEN, ist der erste und einzige Rat: Schreib das ohne globale Variablen um, dann verschwindet entweder schon der Fehler, oder er ist einfach oder zumindest deutlich einfacher zu finden.

Edit: `asksavefilename()` liefert bereits eine Zeichenkette. Die mit `str()` ”umzuwandeln” macht keinen Sinn.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
bb1898
User
Beiträge: 199
Registriert: Mittwoch 12. Juli 2006, 14:28

Bei der Vorstellung, dass das ganze Programm, während es läuft, sein Arbeitsverzeichnis wechselt, würde ich noch deutlich mehr Bauchschmerzen bekommen als bei selbst definierten globalen Variablen. Auch wenn ich gerade auf die Schnelle in der offiziellen Dokumentation keine Warnhinweise bei os.chdir() gefunden habe. Die setzt an dieser Stelle wohl genügend Wissen voraus.
Bibo3000
User
Beiträge: 30
Registriert: Mittwoch 5. Oktober 2022, 14:01

@blackjack:
Vielen Dank für die Erläuterung! Globale Variablen versuche ich tatsächlich immer zu vermeiden, wenn es geht. Das es globalen Variablen schnell zu unauffindbaren Fehlern kommen kann, war mir schnell klar. Die Variablen im oberen Code sind auch nicht global, falls du dich darauf beziehst. Der Code-Schnipsel steht in einer Funktion. Trotzdem danke. :)

So ein Schnipsel wäre, um ehrlich zu sein, genau die Hilfe gewesen die ich mir erhofft hatte. Dahingehend nochmal einen großen Dank an sparrow, dass hat mich wirklich weiter gebracht.
Ihr wisst alle tausend mal besser als ich wie man programmiert und das Vorgehen kann ich am besten im Code selber erkennen. Eine Erklärung dazu warum so und nicht anders hilft dabei zusätzlich fürs Verständnis, erinnert euch mal an die Schulzeit. Deshalb auch meine endlose Fragerei nach dem Grund os.chdir() nicht zu benutzen. Das es problematisch ist habe ich jetzt verstanden, aber es ist unbefriedigend nicht den Grund zu wissen. Was kann denn passieren?

Das asksaveasfilename eine Zeichenkette liefert weiß ich. Ich war mir nur nicht sicher ob ich ohne umwandlung direkt die Endung ranhängen kann. Werde es mal probieren.

In diesem Sinne aber auch trotzdem nochmal ein großes Dankeschön an alle.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

os.chdir beeinflusst eine globale Variable. Das sogenannte Arbeitsverzeichnis. Die hast du nicht angelegt, das ist Teil der System-Runtime. Aber es ist immer noch eine globale Variable, und wenn du verstanden hast, warum globale Variables schlecht sind (deine Aussage), dann sollte das doch selbsterklaerend sein, warum os.chdir schlecht ist, oder nicht?
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Was kann denn passieren?
Nichts bis das allerschlimmste.

Globale Variablen machen den Zustand eines Programms schwer bis nicht nachvollziehbar, weil eben ein oder mehrere Variablen global sind und damit sich jederzeit irgendwo im Programm ändern könnten -> will man nicht.

Es gibt Randfälle, wo der Einsatz von `global` sinnvoll sein kann. Wenn du mal zu so einem Randfall kommen solltest kannst du i.d.R. bereits so gut in Python programmieren, dass du selber weißt, dass das ein Randfall ist und `global` bzw. einen globale Variable der richtige Weg ist. Aber in > 99% der Fälle ist es nicht nötig.

Gruß, noisefloor
Antworten