Forum: PC-Programmierung Python 3: Was kommt zurück, wenn die Dateiauswahl abgebrochen wird?


von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo

Wenn ich in Python 3 mit "name= askopenfilename()" (aus 
tkinter.filedialog)
eine Dateiauswahlbox aufrufe, sollte die mir einen Pfad auf die Datei 
als String zurückgeben. Das passiert auch so, und funktioniert.
Wenn ich nach Programmstart die Dateiauswahlbox zum ersten mal Aufrufe, 
und ohne eine Auswahl abbreche, kommt ein Leerstring zurück. Das 
passiert auch so, und funktioniert.

Soweit ok.

Wenn ich aber schon über die Dateiauswahlbox erfolgreich eine Datei 
geöffnet hatte, und nun erneut die Dateiauswahlbox aufrufe und ohne eine 
Auswahl abbreche, passiert was merkwürdiges:

print(name) gibt dann "()". Aber das ist kein String, wie in den obigen 
beiden Fällen, sondern ein Tupel.
Wenn ich den "Pfadstring" für eine Darstellung mit
"Pfad = ("Pfad: " + name)" aufbereiten möchte, kommt die Fehlermeldung,
das Python das Tupel nicht in einen String konvertieren kann.
Konvertiere ich aber name explizit per "stName = str(name)", liefert mir 
"Pfad = ("Pfad: " + stName)" den String: "Pfad: ()".

Wieso liefert mir Pfad = ("Pfad: " + stName) meistens einen String (wie 
erwartet) aber gelegentlich auch ein Tupel (was ich nicht erwarte) das 
aber so stringähnlich ist, das ich es problemlos konvertieren kann, 
ausser es steht in einem zusammengesetzten Ausdruck?

print(type(name)) zum testen eingefügt liefert übrigens in den ersten 
beiden Fällen <class 'str'> und in dem letzten fraglichen Fall <class 
'tuple'> für das was von "name= askopenfilename()" zurückkommt.

Betriebssystem hier ist Debian "squeeze".

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Nachtrag zu Beitrag #2728537:

Ich habe das Problem mit

name= askopenfilename()
name =str(name)

gelöst, indem ich name mit dem Hammer zum String umgeschmiedet habe.
Der Workaround funktioniert....

Trozdem verstehe ich nicht, was der Grund für das merkwürdige Verhalten 
ist....

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Yalu X. (yalu) (Moderator)


Lesenswert?

Das ist möglicherweise ein Bug (hab's aber nicht näher untersucht,
vielleicht ist es auch Absicht). Normalerweise liefert askopenfilename
ein String-Tuple oder einen Einzel-String zurück, je nachdem, ob die
Option multiple True ist oder nicht. Bei einem leeren Ergebnis kommt
die Funktion wohl etwas durcheinander.

Das sollte aber kein größeres Problem sein, wenn du die Abfrage des
Ergebnisses mit
1
  if name:
2
     ...

machst, da sowohl ein leerer String als auch ein leeres Tupel in einem
Booleschen Ausdruck als False gewertet wird.

Bernd Wiebus schrieb:
> Ich habe das Problem mit
>
> name= askopenfilename()
> name =str(name)
>
> gelöst, indem ich name mit dem Hammer zum String umgeschmiedet habe.
> Der Workaround funktioniert....

Sicher? Damit wird doch aus dem leeren Tupel der String '()'. Du kannst
also nicht mehr unterscheiden, ob der User Cancel gedrückt oder eine
Datei namens "()" ausgewählt hat.

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ist mit Python 2.6 genauso (die Module heißen anders, das Verhalten ist 
gleich). Siehe Anhang. Das erwähnte 'if name' funktioniert aber 
definitiv besser als Stringgefummel.

von Bernd W. (berndwiebus) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo Yalu X, hallo Tom.

Danke für Eure Antworten und Tipps.


> Sicher? Damit wird doch aus dem leeren Tupel der String '()'. Du kannst
> also nicht mehr unterscheiden, ob der User Cancel gedrückt oder eine
> Datei namens "()" ausgewählt hat.

Ok. Hast Recht, dann funktioniert es auch für den Fall, das einer seine 
Datei "()" nennt.....

> ist mit Python 2.6 genauso (die Module heißen anders, das Verhalten ist
> gleich).

Danke. Wenn Bug, scheint er wohl so uninteressant, das sich keiner 
weiter darum gekümmert hat.

> Siehe Anhang. Das erwähnte 'if name' funktioniert aber
> definitiv besser als Stringgefummel.

Mein erster Reflex war, zu sagen, wenn einer seine Datei "()" nennt, ist 
er selber schuld....auf der anderen Seite bin ich selber schräg genug 
drauf, um genau sowas zu machen....es hat auch seinen Grund, warum mir 
das merkwürdige Verhalten beim Abbrechen der Dateiauswahlbox aufgefallen 
ist. ;O)

Ich werde das also umschreiben.
Als Anhang übrigens das Programm (PyGerbAnalyse_A6.py), soweit es bisher 
geschrieben ist.....
Ich bin dabei, das, was ich vor gut 1 1/2 Jahren in Gambas geschrieben 
habe, in Python umzuschreiben......viel können kann es aber noch nicht.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Yalu X. (yalu) (Moderator)


Lesenswert?

Statt name in einen String umzuwandeln, wie hier
1
     name= askopenfilename()
2
     name = str(name)
3
     GerberAnalyse.stPfad = name
4
     if name =="":
5
          Pfadanzeige["text"] = "Pfad: Leer"
6
          Listanzeige1.delete(0, END)
7
          Listanzeige2.delete(0, END)
8
          return()
9
     if name =="()":
10
          Pfadanzeige["text"] = "Pfad: Leer"
11
          Listanzeige1.delete(0, END)
12
          Listanzeige2.delete(0, END)
13
          return()

kannst du ihn auch direkt mit dem Tupel vergleichen:
1
     name= askopenfilename()
2
     GerberAnalyse.stPfad = name
3
     if name =="":
4
          Pfadanzeige["text"] = "Pfad: Leer"
5
          Listanzeige1.delete(0, END)
6
          Listanzeige2.delete(0, END)
7
          return()
8
     if name ==():
9
          Pfadanzeige["text"] = "Pfad: Leer"
10
          Listanzeige1.delete(0, END)
11
          Listanzeige2.delete(0, END)
12
          return()

Damit ist auch der Dateiname "()" erlaubt.

Da sich beide If-Anweisungen nur in der Bedingung unterscheiden, kannst
du sie auch zusammenfassen:
1
     name= askopenfilename()
2
     GerberAnalyse.stPfad = name
3
     if name =="" or name ==():
4
          Pfadanzeige["text"] = "Pfad: Leer"
5
          Listanzeige1.delete(0, END)
6
          Listanzeige2.delete(0, END)
7
          return()

Etwas pythonischer sieht die Bedingung so aus:
1
     name= askopenfilename()
2
     GerberAnalyse.stPfad = name
3
     if name in ["", ()]:
4
          Pfadanzeige["text"] = "Pfad: Leer"
5
          Listanzeige1.delete(0, END)
6
          Listanzeige2.delete(0, END)
7
          return()

Oder eben gleich so:
1
     name= askopenfilename()
2
     GerberAnalyse.stPfad = name
3
     if not name:
4
          Pfadanzeige["text"] = "Pfad: Leer"
5
          Listanzeige1.delete(0, END)
6
          Listanzeige2.delete(0, END)
7
          return()

Wenn du den Code in anderer Reihenfolge hinschreibst, bekommst du auch
noch das hässliche "not" vor name weg:
1
     name= askopenfilename()
2
     GerberAnalyse.stPfad = name
3
     if name:
4
          GerberAnalyse.iZeilenzahl = 0
5
          ...
6
     else:
7
          Pfadanzeige["text"] = "Pfad: Leer"
8
          Listanzeige1.delete(0, END)
9
          Listanzeige2.delete(0, END)


Nur so am Rande :)

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Yalu X.


> Statt name in einen String umzuwandeln, wie hier
~~~~~~~~~~~~
~~~~~~~~~~~~
>
>
>
> Nur so am Rande :)

Ich habs jetzt so gemacht:
1
# Funktion Dateiauswahl Gerberfile
2
def Dateiwahl():
3
     name= askopenfilename()
4
     if name: #Nur Wahr, wenn Pfad gewählt wurde. Sonst Leerstring/Tupel
5
          GerberAnalyse.stPfad = name
6
          GerberAnalyse.iZeilenzahl = 0
7
          Pfad = ("Pfad: " + name)
8
          Pfadanzeige["text"] = Pfad
9
          Listanzeige1.delete(0, END) #Neue Datei, altes Listing...Clear 
10
          Listanzeige2.delete(0, END) #Neue Datei, alte Analyse...Clear
11
          GerberList1 = open(GerberAnalyse.stPfad, mode="rt")
12
          while True:
13
               Lesezeile = GerberList1.readline()
14
               if len(Lesezeile) ==0:
15
                    break # EOF wenn lesezeile nicht mehr kommt.
16
               Listanzeige1.insert(END, Lesezeile) #Neues Listimng
17
               Listanzeige1.yview(END) #Anzeige zum Ende
18
          GerberList1.close()
19
          return()

Bei Cancel passiert jetzt "garnichts" mehr, was ja auch die eigentliche 
Intention von Cancel ist....
Der komplette Block wird dann übersprungen und das Unterprogramm 
verlassen, ohne das was geändert wird.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Daniel -. (root)


Lesenswert?

hi,

vorab: ich habe nicht alles gelesen, aber ein Tupel könnte
sinnvoll sein, soweit man mit dem Dialog mehrere Dateien auswählen
lassen können wollte ..

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Daniel.

>
> vorab: ich habe nicht alles gelesen, aber ein Tupel könnte
> sinnvoll sein, soweit man mit dem Dialog mehrere Dateien auswählen
> lassen können wollte ..

Richtig, so ist das wohl auch gedacht. Nur war diese Option nicht 
gewählt worden.
Wenn ich nnur die Option für eine einzige Datei wähle, erwarte ich einen 
String oder halt auch einen Leerstring bei cancel.
Wenn ich die Option multiple wähle, erwarte ich halt auch ein Tupel bzw. 
Leertupel bei cancel.

Aber hier hatte ich die Option multiple nicht gewählt, und bekam zuerst 
einen Leerstring bei cancel, aber später dann ein Leertupel bei cancel.
Ich konnte immer nur eine Datei wählen, und diese einzelne Datei wurde 
auch erwartungsgemäß richtig als einzelner String übergeben.

Und das machte mich halt ratlos.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

http://www.dl0dg.de

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Ggf mußt du auch die Option für Einzelauswahl jedesmal neu setzen? 
Manche 'API' wandert auf verschlungenen Pfaden... Schon allein die 
Annahme leerer String = nix ausgewählt ist blöde wenn man auf einmal ein 
Filesystem hat wo der leere String eben gültig ist (warum auch immer).

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Läubi.


> Ggf mußt du auch die Option für Einzelauswahl jedesmal neu setzen?

???? Das ist eine Funktion, die jedesmal neu angesprungen wird, wenn der 
Dateiauswahlbutton gedrückt wird.....theoretisch erwarte ich in dem 
Falle auch immer gleiches Verhalten.


Wie meinest Du das denn?



> Manche 'API' wandert auf verschlungenen Pfaden... Schon allein die
> Annahme leerer String = nix ausgewählt ist blöde wenn man auf einmal ein
> Filesystem hat wo der leere String eben gültig ist (warum auch immer).

In dem Falle kann "Abbruch/cancel" NICHT über den Pfadstring übergeben 
werden, weil in letzter Konsequenz jeder gültige String auch eine 
gültige Datei sein könnte. Es gäbe daher keinen Platz für einen Abbruch 
im String und es müsste für den Zweck eine extra Variable existieren.

Andersherum.....es währe ein "verbotener" Dateinahme unter Milliarden 
von erlaubten. Vermutlich könnte ich damit leben. Vor allem, wenn es um 
Gerberdatensätze geht. ;O)

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

http://www.dl0dg.de

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Nachtrag:


> Andersherum.....es währe ein "verbotener" Dateinahme unter Milliarden
> von erlaubten. Vermutlich könnte ich damit leben. Vor allem, wenn es um
> Gerberdatensätze geht. ;O)


Ich könnte auch z.B. bei jedem Cancel eine Warnung an den User ausgeben, 
daß, falls er in Wirklichkeit eine Datei mit einem Leerstring als Name 
oder Pfad gewählt hätte, speziell diese Datei wegen ihres Namens nicht 
gelesen werden kann und er sie darum bitteschön umbenennen möge. ,O)

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
ttp://www.dl0dg.de

von Yalu X. (yalu) (Moderator)


Lesenswert?

Bernd Wiebus schrieb:
> Ich könnte auch z.B. bei jedem Cancel eine Warnung an den User ausgeben,
> daß, falls er in Wirklichkeit eine Datei mit einem Leerstring als Name
> oder Pfad gewählt hätte, speziell diese Datei wegen ihres Namens nicht
> gelesen werden kann und er sie darum bitteschön umbenennen möge. ,O)

Gibt es eigentlich ein OS, in dem der Leerstring als Dateiname erlaubt
ist? In Unix geht ja fast alles, was ein krankes Hirn sich auszudenken
in der Lage ist, aber leere Dateinamen sind auch hier nicht möglich :)

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Bernd Wiebus schrieb:
> ???? Das ist eine Funktion, die jedesmal neu angesprungen wird
Ich kenne nun die Implementierung nicht, hatte deine Beschreibung aber 
so verstanden, dass irgendwo [pre]setSingleSelection(true)[pre] aufrufen 
muss.

Bernd Wiebus schrieb:
> In dem Falle kann "Abbruch/cancel" NICHT über den
> Pfadstring übergeben  werden,
Kennt Python kein 'null' oder Objekte?

Yalu X. schrieb:
> Gibt es eigentlich ein OS, in dem der Leerstring als
> Dateiname erlaubt ist?
Keine Ahnung... zumindest wenn du im Web surfst wird der leere Pfad auf 
eine Menge von index files von den meisten Webserver gemappt.

Das war jetzt nicht so ernst gemeint, sonder war auch nur eine 
hypothetische Anmerkung, in Java kann man so einem Filedialog ein 
eigenes FileSystemView mitgeben in welchem man sich theoretisch nach 
belieben austoben kann :-)
Dort wird cancel/ausgewählte Date(en) aber auch über ein Zustandsobjekt 
behandelt.

Yalu X. schrieb:
> aber leere Dateinamen sind auch hier nicht möglich

Konnte man unter MacOS nicht irgendwie Dateien nur aus Leerzeichen 
angeben?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Läubi .. schrieb:
> Konnte man unter MacOS nicht irgendwie Dateien nur aus Leerzeichen
> angeben?

Das geht in Unix auch. Auch Tabs, Linefeeds, Carriage-Returns,
Backspaces und anderes Ungeziefer dürfen verwendet werden. Nur ein
richtig leerer Name (also mit 0 Zeichen Länge) geht halt nicht.

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Yalu.

> Gibt es eigentlich ein OS, in dem der Leerstring als Dateiname erlaubt
> ist? In Unix geht ja fast alles, was ein krankes Hirn sich auszudenken
> in der Lage ist, aber leere Dateinamen sind auch hier nicht möglich :)

Wenn Du schon so anfängst, müsstest Du auch berücksichtigen, das 
irgendjemand mal ein Operationssystem schreiben könnte, in dem ein 
Leerstring
als Dateiname möglich und sogar sinnvoll ist. ;O)

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Läubi.

> Bernd Wiebus schrieb:
>> ???? Das ist eine Funktion, die jedesmal neu angesprungen wird
> Ich kenne nun die Implementierung nicht, hatte deine Beschreibung aber
> so verstanden, dass irgendwo [pre]setSingleSelection(true)[pre] aufrufen
> muss.

...Du bringst mich auf eine Idee. Genau das habe ich explizit NICHT 
gemacht. Aber vieleicht sollte ich das ja mal machen.

Ich werde es ausprobieren.

>
> Bernd Wiebus schrieb:
>> In dem Falle kann "Abbruch/cancel" NICHT über den
>> Pfadstring übergeben  werden,
> Kennt Python kein 'null' oder Objekte?

So wie ich das aber Verstanden habe, ist "Null" ein spezieller Typ und 
eben kein String mehr.

Vieleicht sollte ich mir das noch einmal genau durchlesen.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Ich habe es ausprobiert.
1
# Funktion Dateiauswahl Gerberfile
2
def Dateiwahl():
3
     name= askopenfilename(multiple = False) #Hier wird ausdrücklich auf EIN File festgenagelt.
4
     GerberAnalyse.stPfad = name
5
     GerberAnalyse.iZeilenzahl = 0
6
     Pfad = ("Pfad: " + name)
7
     Pfadanzeige["text"] = Pfad
8
     Listanzeige1.delete(0, END) #Neue Datei, altes Listing...Clear 
9
     Listanzeige2.delete(0, END) #Neue Datei, alte Analyse...Clear
10
     GerberList1 = open(GerberAnalyse.stPfad, mode="rt")
11
     while True:
12
          Lesezeile = GerberList1.readline()
13
          if len(Lesezeile) ==0:
14
               break # EOF wenn lesezeile nicht mehr kommt.
15
          Listanzeige1.insert(END, Lesezeile) #Neues Listimng
16
          Listanzeige1.yview(END) #Anzeige zum Ende
17
     GerberList1.close()
18
     return()


Einmal "Datei wählen" direkt nach dem Start aufgerufen und cecancelt.
Dann eine lesbare Datei aufgerufen.
Dann nochmalEinmal "Datei wählen" aufgerufen und cecancelt.

Fehlermeldungen in der Shell:
1
Exception in Tkinter callback
2
Traceback (most recent call last):
3
  File "/usr/lib/python3.1/tkinter/__init__.py", line 1402, in __call__
4
    return self.func(*args)
5
  File "/home/wiebus/python/PyGerbAnalyse_A8-2.py", line 841, in Dateiwahl
6
    GerberList1 = open(GerberAnalyse.stPfad, mode="rt")
7
IOError: [Errno 2] No such file or directory: ''
8
Exception in Tkinter callback
9
Traceback (most recent call last):
10
  File "/usr/lib/python3.1/tkinter/__init__.py", line 1402, in __call__
11
    return self.func(*args)
12
  File "/home/wiebus/python/PyGerbAnalyse_A8-2.py", line 837, in Dateiwahl
13
    Pfad = ("Pfad: " + name)
14
TypeError: Can't convert 'tuple' object to str implicitly

"IOError: [Errno 2] No such file or directory: '' "ist das erste 
canceln. Hier kommt der Leerstring zurück, und
"TypeError: Can't convert 'tuple' object to str implicitly " ist das 
zweite canceln, wo dann das Leertupel zurückkommt.

Das explizite Angeben, das nur ein File geöffnet werden soll, hat also 
keinen Einfluss auf dieses Verhalten.


Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.