Seite 1 von 1
problem.next(): IOError: Bad file descriptor
Verfasst: Donnerstag 11. Februar 2010, 13:26
von ...
Hallo...
Hier kommt dann auch schon mein nächstes Problem.
Ich habe mir mit HTML mal ein paar Templates erstellt.
Platzhalter im Format: <+++Platzhaltername+++> sind dabei eingefügt.
Es besteht ein Dictionary. In den Keys sind die Platzhalternamen, und der zugehörige Wert ist dann der zugewiesene Wert.
das HTML-Dokument sieht beispielsweise so aus:
Code: Alles auswählen
<html>
<head></head>
<body>
<h1><+++Titel+++></h1>
<span style="font-size:13pt;"><+++Text+++></span>
</body>
</html>
Der code sieht so aus:
Code: Alles auswählen
import os
mydict = {'Titel':'Hallo Welt!', 'Text':'Kleines Testprogram'}
for file in os.listdir('.'):
if 'Template' in file \
and '.html' in file:
html = open(file, 'rw')
content = html.read()
for key in mydict.key():
content.replace('<+++' + key + '+++>', mydict[key])
html.write(content)
html.close()
Das Problem:
Ich bekomme einen Error: IOError: Bad file descriptor in der Zeile: html.write(content)
Woran könnte das liegen?
lg,
...
EDIT: Die Datei ist richtig geöffnet:
Ich kann mir den content mit Print einfach ausgeben lassen, und alles stimmt.
Lediglich beim Schreiben bekomme ich Probleme...
Wobei es eigenartigerweise einen unterschied macht, ob ich es so wie o.g mache, oder einfach schreibe:
Code: Alles auswählen
file = open('MyTemplate1.html', 'rw')
file.write('blub')
file.close()
Denn letzteres funktioniert einwandfrei!
--------
#Einen Teil habe ich vergessen:
#Die Templates liegen im Ordner Templates.
#Zu beginn Kopiere ich sie mit shutil.copy in das Arbeitsverzeichnis #(derzeit das Verzeichnis '.') - das in welchem auch das Script läuft.
#Allerdings: Nach dem Error ist die Datei noch nicht einmal kopiert!
Stimmt nicht: Ist doch schon da.
Verfasst: Donnerstag 11. Februar 2010, 13:42
von Hyperion
Mir fallen da zunächst ein paar Dinge auf:
1.) Wieso ein eigenes Template-Format? Es gibt zig gute Template-Engines (jinja2, mako, usw. - und zur Not auch in der Standard-Lib eine primitive).
2.) Du überschreibst das built-in file. Wieso nimmst Du nicht fname oder filename?
Mit dem "rw"-Modus kenne ich mich nicht aus. Aber darf man denn eine Datei wirklich bis zum Ende einlesen und dann noch schreiben?
Edit: In der Doku habe ich nicht gesehen, dass man zwei Modi mischen darf!
Verfasst: Donnerstag 11. Februar 2010, 13:50
von ...
http://www.python-forum.de/topic-462.html
Das rw kann ich auch weglassen, es ändert sich nichts.
Ich wollte halt die Datei lesen und schreiben...
Wieso ein eigenes Template-Format?
Du hast ja nichtmal gefragt wofür das Template.
http://pypi.python.org/pypi/pisa/3.0.32 benötigt ein Design aus HTML & CSS
Dazu kommt, das ich HTML und CSS zumindest halbwegs beherrsche...
Ebenfalls toll: Ich kann sie gleich ins Web stellen (per FTP), und muss nicht noch extra eine HTML-Seite zusätzlich erstellen.
Die meisten anderen PDF-Generatoren konnte ich nicht installieren... Gab es probleme mit dem Compilieren.
Und dieses Pakte bei dem es mit einer eigenen XML-Sprache beschrieben wird dafür zu lernen, war mir echt eigentlich zu blöd, wenn es doch dieses Lukrativ klingende Angebot gibt...
fname und filename waren mir unbekannt.
Mal sehen was die machen...
lg,
...
Verfasst: Donnerstag 11. Februar 2010, 14:03
von Hyperion
Wo in dem Thread siehst Du da so was? (Zudem ist er sehr alt - die aktuelle Referenz ist da sicher verlässlicher als solch ein Thread)
Wieso ein eigenes Template-Format?
Du hast ja nichtmal gefragt wofür das Template.
Also ist es kein eigenes Template-Format? Dann nehme ich alles zurück. Nur hat mir Dein Link dahingehend nicht geholfen, das zu erkennen
fname und filename waren mir unbekannt.
Mal sehen was die machen...
Die "machen" nichts, das sollten bessere Namen für die Dateinamen in Deinem Script sein. "file" ist ein schlechter Bezeichner, da es eine built-in Funktion desselben Namens gibt.
Verfasst: Donnerstag 11. Februar 2010, 14:20
von ...
Der Thread den ich dir Zeigte hat nichts mit rw zu tun.
Das rw macht wiegesagt bei mir keinen Unterschied zu garnichts...
Ich habe es jetzt also weggelassen.
In dem Thread wird aber Propagiert, wenn man etwas in einem Textfile (ein HTML-File ist ja im grunde ein Textfile) ändern will - ersetzen will was auch immer, müsse man den ganzen Text einlesen, die Ersetzungen/Einfügungen vornehmen, und dann wieder schreiben.
Im 2. Post wird das mit readlines erledigt.
Ich möchte aber in jeder Zeile jedes vorkommen der Platzhalter ersetzen.
Darum fand ich es simpler, alles in einen String mit Read zu lesen, und dort direkt ersetzen.
Ich habe an meinem Rechner an welchem ich schreibe leider keinen Internetzugang, aus dem grund muss ich hier immer die Scripts neu von hand schreiben.
In wirklichkeit ist das HTML-Dokument Template1.html etwa 400 Zeilen lang (inklusive CSS)
Tatsächlich verwende ich html_file als Namen, nicht file.
Ich hab gehofft, es seien Funktionen, mit denen ich bestimmen kann, das die Datei mit einem anderen Dateinamen gespeichert werden soll...
Das wäre nämlich eine feine Lösung gewesen, auf das ich nicht immer die die Templates erst kopieren muss, sondern direkt öffnen, und wo anders dann speichern...
Das Format HTML ist tatsächlich ein uraltes Format.
Im Web-Bereich dürfte es oft vorkommen, das man Templates für Websiten in HTML schreibt, und den rest mir PHP/Python/Ruby/Pearl/whatsoever ausfüllt... oder den entspechenden Code (PHP) gleich einbettet...
Dazu kommt, das pisa HTML als Templatesprache zum Designen verwendet, und dann mit diesem HTML-Dokument ein PDF schreibt.
Da ich gleichzeitig die Daten auch im Internet einstellen möchte, kommt mir das zusätzlich entgegen.
Als Alternative käme natürlich auch LaTeX in Frage.
lg,
...
Verfasst: Donnerstag 11. Februar 2010, 14:26
von /me
... hat geschrieben:Ich hab gehofft, es seien Funktionen, mit denen ich bestimmen kann, das die Datei mit einem anderen Dateinamen gespeichert werden soll...
Das wäre nämlich eine feine Lösung gewesen, auf das ich nicht immer die die Templates erst kopieren muss, sondern direkt öffnen, und wo anders dann speichern...
Entweder erklärst du dein Anliegen gerade sehr unglücklich oder du hast den naheliegendsten Ansatz übersehen. Dieser Ansatz bestände darin, direkt in Python zwei Dateien zu verwenden. Die erste Datei enthält das Template und wird nur zum Lesen geöffnet und die zweite Datei braucht nur geschrieben werden und enthält das Ergebnis nach dem Ersetzen.
Verfasst: Donnerstag 11. Februar 2010, 14:31
von Hyperion
Und dann nutze doch zusätzlich eine fertige Template-Engine! Es gibt eine sehr rudimentäre Funktionalität in der Standard-Lib (Kapitel 8.1.4. Template strings).
Verfasst: Donnerstag 11. Februar 2010, 14:34
von ...
Du meinst:
Code: Alles auswählen
for template_name in os.listdir('.' + os.sep + 'template'):
template_file = open('.' + os.sep + 'template' + template_name, 'r')
my_file = open('.' + template_name, 'w')
content = template_file.read()
template_file.close()
for key in mydict.keys():
content.replace('<+++' + key + '+++>', mydict[key]
my_file.write(content)
my_file.close()
Klingt gut!
Werde ich gleich mal ausprobieren!
lg,
...
Verfasst: Donnerstag 11. Februar 2010, 14:38
von Hyperion
Bitte noch zusätzlich wenigstens das open mit with angehen - dann sparst Du Dir das Schließen. Ganz auf Nummer sicher gehst Du dann noch mit try... except IOError.
Verfasst: Donnerstag 11. Februar 2010, 15:10
von ...
Wenn ich mit Try arbeite würg ich den Error doch ab, und wenn er mal berechtigter weise auftauchen sollte, so wäre das schade!
with hab ich nie kapiert... hab mich damit aber auch nicht groß auseinandergesetzt...
Es ist mir aber lieber genau zu wissen, wann ich eine Datei schließe, warum, und wesshalb...
btw:
Mit der letzten Version funktioniert es.
Vielen Dank dir /me für deine Idee - damit kann ich mir jetzt auch das Importen von shutil spaaren, und 9 Zeilen.
Auch dir Danke, Hyperion, für deine Mühe!
Vieleicht werden deine Vorschläge in die nächste Version einfließen.
lg,
...
Verfasst: Donnerstag 11. Februar 2010, 15:14
von Hyperion
... hat geschrieben:Wenn ich mit Try arbeite würg ich den Error doch ab, und wenn er mal berechtigter weise auftauchen sollte, so wäre das schade!
Solange Du eine konkrete Exception abfängst ist doch alles ok
with hab ich nie kapiert... hab mich damit aber auch nicht groß auseinandergesetzt...
Naja, da gibts nicht viel zu wissen denke ich mal.
Code: Alles auswählen
with open() as name:
# name enthält das file object wie gehabt
# close ist überflüssig
Es ist mir aber lieber genau zu wissen, wann ich eine Datei schließe, warum, und wesshalb...
Hm... wie Du meinst

Verfasst: Donnerstag 11. Februar 2010, 15:39
von lunar
... hat geschrieben:Es ist mir aber lieber genau zu wissen, wann ich eine Datei schließe, warum, und wesshalb...
Das weißt Du aber eben
nicht, wenn Du so vorgehst. Wenn vor dem ".close()" eine Ausnahme geworfen wird, dann wird der ".close()"-Aufruf nicht erreicht, somit ist das Schließen der Datei dem GC überlassen, und der GC ist nicht deterministisch (zumindest nicht nach Dokumentation) … die Datei wird einfach irgendwann geschlossen, oder vielleicht auch gar nicht.
Nur wenn Du "with" oder ein "try: … finally: …"-Konstrukt nutzt, weißt Du wirklich, wann eine Datei geschlossen wird.
Verfasst: Donnerstag 11. Februar 2010, 15:44
von cofi
Am "weshalb" aendert sich ebenfalls nichts, geschlossen wird, wenn es eine Ausnahme gibt oder der Block verlassen wird. Gut, bis auf die Tatsache, dass die Ressource sauber geschlossen wird im Falle von Ausnahmen.
Zu den Ausnahmen: Es heisst nicht umsonst Ausnahmebehandlung. Wenn eine auftritt weiss der Programmierer (bei den meisten) genau, was querschlaegt und kann entsprechend reagieren ohne, dass das Programm terminieren muss.
Verfasst: Donnerstag 11. Februar 2010, 16:37
von ...
Ich sehe schon: Ich hab noch viel zu lernen, junger padawan...
Also sollte ich die Exception abfangen, und dann den Fehler nur ausgeben?
Wenn ich jetzt folgendes schreibe:
Code: Alles auswählen
try:
foo = open(bar)
except IOError:
print 'ja was denn'
Wie kann ich an das was eigentlich zusammen mit dem Programmabbruch ausgegeben wird rankommen?
Also das ich den Original-Fehlertext dann ausgebe, statt nur 'ja was denn' oder einer alternativen statischen Ausgabe?
lg,
...
Verfasst: Donnerstag 11. Februar 2010, 16:41
von DasIch
Ein `raise` ohne Angabe einer Ausnahme wirft die letzte Ausnahme erneut.
Verfasst: Donnerstag 11. Februar 2010, 16:46
von Masaru
Du kannst tun und lassen was Du Dir so vorstellst für Dein Programm.
Un wenn es nach einem 3x-maligen Versuch ein subprocess call mit "format c:" und der "Y" Bestätigung ist.
Deiner Kreativität ist da keine Grenze gesetzt.
Aber nur so als Tipp

, Du bist ja ein Computer-User, hast also folglich schon einige Programme benutzt und in Aktion gesehen - ebenso deren Fehlerverhalten. Orientier Dich einfach am besten an dem, was Dir selber am besten gefallen hat.
Wenn Du 10 Personen nach "Fehlerbebandlung und -Management" fragen würdest, bekämest Du vermutlich 11 verschiedene Antworten.
>>Masasru<<
Verfasst: Donnerstag 11. Februar 2010, 16:55
von ...
Das heist, ich kann guten mutes einfach alle Fehler abfangen?
Code: Alles auswählen
while 1:
try:
print str(muh)[10]
except KeybordInterrupt:
print 'Raus hier!'
break
except:
raise
muh += 1
Das ist schön!
Ich fand die Bluescreens immer toll...
Oder diese Lösung:
http://www.geekherocomic.com/2009/06/03 ... orkaround/
Verfasst: Donnerstag 11. Februar 2010, 16:58
von Masaru
Sicher kannst Du alle Fehler abfangen.
Nur solltest Du Dir folgenden Gedanken machen: "Wenn ich alle Fehler abfange ... wie stelle ich dann fest, dass es einen Fehler gab?"
Solange Du einen Weg findest, diese Frage zu lösen ... bist Du auf dem richtigen Weg.
>>Masaru<<
Verfasst: Donnerstag 11. Februar 2010, 17:07
von ...
Das ist ne gute Frage...
Wenn ich sie einfach nur mit Raise ausgebe, gehen sie verloren.
Mal sehen, ob logging noch funktioniert, wenn ich die exceptions abfange...
Verfasst: Samstag 13. Februar 2010, 12:23
von sma
Ist die Diskussion eigentlich schon an der Stelle angekommen, wo Zeile 13 aus dem ursprünglichen Codeschnipsel nicht funktioniert? Immer daran denken: Strings in Python sind unveränderlich. Das `replace` erzeugt einen neuen String, der aber sofort wieder vergessen wird. Das kann nicht funktionieren.
Stefan