auto-pi-to-exe >> FileNotFoundError: [WinError 3] Das System kann den angegebenen Pfad nicht finden [...]

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
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Hallo zusammen,

ich habe gerade ein kleines Skript angepasst. Das Skript funktioniert auch einwandfrei vor der Umwandlung mit auto-pi-to-exe.

Ich bekomme beim Ausführen der EXE aber folgende Fehlermeldung:

Traceback (most recent call last):
File "programm.py", line 140, in <module>
## Ermittelte CSV-Datien abarbeiten
FileNotFoundError: [WinError 3] Das System kann den angegebenen Pfad nicht finden: 'C:\\Users\\rebekka\\AppData\\Local\\Temp\\_MEI130002\\Input\\'
Ich habe vor zwei Jahren das gleiche Programm schon mal umgewandelt. Jetzt habe ich etwas am Skript geändert und wollte nochmal eine EXE erstellen. Anscheinend habe ich damals noch weitere Parameter oder Einstellungen bei der Umwandlung mitgegeben.

Leider habe ich es nicht dokumentiert.

Code: Alles auswählen

## Import

import os


## Verzeichnispfad ermitteln und festlegen

appDir = os.path.dirname(os.path.abspath(__file__))
srcPath = appDir + '\\Input\\'
desPath = appDir + '\\Output\\'
errPath = appDir + '\\Error\\'
Ziel soll im Dateisystem folgende Struktur sein:

(Verzeichnis x – Ordner soll variabel verschoben werden können)
- Input
- Output
- Error
- programm.exe

Habt ihr eine Idee was ich beim Erstellen der EXE zusätzlich angeben muss?

Über Hilfe würde ich mich sehr freuen.

Herzlichen Dank.

Grüße Becky
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich denke nicht, dass die Loesung in der Art der EXE-Generierung liegt. Der pyinstaller (der deinem auto-pi-to-exe unterliegt) buendelt ja den Interpreter + deine Skripte. Dein Vorgehen mit den Pfaden relativ zum Skript wird daduerch anfaellig dafuer, wohin die Skripte entpackt werden zur Laufzeit. Ist der Ort, den du da bekommst, denn ueberhaupt sinnvoll? Denn das sieht nicht so aus. Wo sollten die denn idealierweise liegen?
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Ich denke nicht, dass das schon einmal funktioniert hat.
Du ermittelst ja den Pfad des entpackten Skricts, wie __deets__ richtig anführt. Das hat nichts mit der Position der .exe-Datei zu tun.

Stellt sich die Frage: Die Dateien, die du dort versuchst zu öffnen, sind die Teil deines Programms - und somit in dem Archiv enthalten -, oder sollen die Dateien in dem Pfad gesucht werden, wo sich die .exe befindet?
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

https://drive.google.com/file/d/1BqqHbj ... sp=sharing

Ist ein anderes damals von mir erstelltes Programm, aber die gleiche Logik.

Ausschnitt aus dem Code:

Code: Alles auswählen

import xml.etree.ElementTree as ET
import os

## Pfade ermitteln und festlegen

appDir = os.path.dirname(os.path.abspath(__file__))
srcPath = appDir + '\\Quelle\\'
desPath = appDir + '\\Ziel\\'

## XML-Dateien ermitteln

xmlFiles = []

for file in os.listdir(srcPath):
    if os.path.isfile(srcPath + file) and '.xml' in file:
        xmlFiles.append(file)

## Ermittelte XML-Datien abarbeiten

for xmlFile in xmlFiles:
	
	usw. ...	
Hier kann ich die Datei Start mit Ordner Ziel und Quelle auch hin und her kopieren wohin ich möchte.

Es funktioniert.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich verstehe das schon, aber du machst keine Anstalten hier, die Verzeichnisse zu erstellen. Da der Code aus dem gepackten Code in *irgendein* temporaeres Verzeichnis entpackt wird, befinden sich die Pfade dann eben relativ dazu. Das heisst sie existieren nicht, und selbst wenn sie das taeten - du hast ja erstmal keine Ahnung, wo sie liegen, das temporaere Verzeichnis wird zur Laufzeit erstellt.

Du musst also anders arbeiten. Du kannst zb mit dem os.getcwd() arbeiten, das ist das Arbeitsverzeichnis, aus dem heraus du das Programm gestartet hast.
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Ich glaube wir sprechen von unterschiedlichen Dingen. Aber kein Thema, ich probiere es gerne noch einmal. :-) Vielleicht drücke ich mich auch einfach falsch aus.
__deets__ hat geschrieben: Freitag 4. Februar 2022, 12:36 Ich verstehe das schon, aber du machst keine Anstalten hier, die Verzeichnisse zu erstellen.
Die Ordner Ziel und Quelle lege ich manuell an. Das ist so auch in Ordnung für mich.

Die EXE Datei liegt auf der gleichen Ebene wie bereits im Video gezeigt.

Diese Konstellation habe ich bereits auf zig Systemen genau wie gezeigt im Einsatz. Kopieren war nie ein Problem.

Die EXE-Datei greift auf das Verzeichnis Quelle zu, abhängig vom eigenen Speicherort.

Selbst wenn ich das ursprüngliche Quellmaterial nochmal probiere in eine EXE umzuwandeln funktioniert es nicht und wirft den gleichen Fehler beim Ausführen der erstellten EXE-Datei.

Ich persönlich gehe davon aus, dass ich damals spezielle Parameter oder Verzeichnisse oder was auch immer bei der Umwandlung mitgegeben habe. Leider kann ich es nicht mehr nachvollziehen.

https://drive.google.com/file/d/1IUmRfr ... sp=sharing

Vielleicht hat sich auch an der Python Version etwas geändert, und die gleichen Befehle funktionieren nicht mehr?
Zuletzt geändert von RebekkaSilber am Freitag 4. Februar 2022, 13:16, insgesamt 2-mal geändert.
narpfel
User
Beiträge: 691
Registriert: Freitag 20. Oktober 2017, 16:10

RebekkaSilber hat geschrieben: Freitag 4. Februar 2022, 13:04 abhängig vom eigenen Speicherort.
Nein. Die Exe entpackt sich selber in ein temporäres Verzeichnis und sucht dann relativ zur Python-Datei in diesem temporären Verzeichnis nach Quelle und Ziel.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie gesagt, ich habe dein Problem schon verstanden. Das Problem hier ist, dass deine einkodierte Annahme, __file__ wuerde auf den Pfad des Programms zeigen, nicht (mehr) korrekt ist. Das liegt an der pyinstaller-version, siehe https://pyinstaller.readthedocs.io/en/s ... e%20folder. - unten steht was von Changed in 4.3.

Und so wie es jetzt ist, ist es auch richtig. Nur dein Programm nicht mehr.

Fuer deinen geschilderten Anwendungsfall ist die Loesung das von mir genannte os.getcwd(). Denn das zeigt auf den Pfad des "current working directories", welcher wie im Video gezeigt auf den Ordner, in dem die EXE und Unterordner stecken, zeigen sollte. Du musst also einfach

Code: Alles auswählen

srcPath = os.path.join(os.getcwd(), 'Quelle')
benutzen. Und generell solltest du mindestens os.path zur Pfadmanipulation, und noch besser pathlib benutzen, statt mit + und \\ rumzufuhrwerken - das ist deutlich robuster.
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Pfade sind keine Einfachen Strings, die man per + zusammenstückelt. Es ist wohl auch falsch, .xml irgendwo im Dateinamen zu suchen. Variablennamen schreibt man nach Konvention komplett klein.
Und so wie Du das beschreibst, ist diese ganze Geschichte mit __file__ eh nicht so richtig, weil Du eigentlich die Dateien vom aktuellen Arbeitsverzeichnis aus suchen willst, wie das für jeden Anwender auch nachvollziehbarer ist.
Statt `os` benutzt man `pathlib` für Pfadoperationen:

Code: Alles auswählen

import xml.etree.ElementTree as ET
from pathlib import Path

SOURCE_PATH = Path("Quelle")
DESTINATION_PATH = Path("Ziel")

def main():
    xml_files = list(SOURCE_PATH.glob("*.xml"))
    for xml_file in xml_files:
        process(xml_file)

if __name__ == "__main__":
    main()
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

__deets__ hat geschrieben: Freitag 4. Februar 2022, 13:18 Wie gesagt, ich habe dein Problem schon verstanden. Das Problem hier ist, dass deine einkodierte Annahme, __file__ wuerde auf den Pfad des Programms zeigen, nicht (mehr) korrekt ist. Das liegt an der pyinstaller-version, siehe https://pyinstaller.readthedocs.io/en/s ... e%20folder. - unten steht was von Changed in 4.3.

Und so wie es jetzt ist, ist es auch richtig. Nur dein Programm nicht mehr.

Fuer deinen geschilderten Anwendungsfall ist die Loesung das von mir genannte os.getcwd(). Denn das zeigt auf den Pfad des "current working directories", welcher wie im Video gezeigt auf den Ordner, in dem die EXE und Unterordner stecken, zeigen sollte. Du musst also einfach

Code: Alles auswählen

srcPath = os.path.join(os.getcwd(), 'Quelle')
benutzen. Und generell solltest du mindestens os.path zur Pfadmanipulation, und noch besser pathlib benutzen, statt mit + und \\ rumzufuhrwerken - das ist deutlich robuster.
Vielen Dank für den Hinweis.

Wie verhält sich

Code: Alles auswählen

srcPath = os.path.join(os.getcwd(), 'Quelle')
dann?

Muss ich dann Quelle, Ziel und die EXE im Arbeitsverzeichnis liegen haben?
Kann ich das Arbeitsverzeichnis dynamisch ändern beim Ausführen der py-Datei?
Wie verhält es sich dann bei der Erstellung der EXE?

Mein Ziel ist ja, dass ich davor nicht wissen muss, wo der Anwender das "Hauptverzeichnis" mit Quelle, Ziel und EXE ausführt.
Trotzdem soll er immer relativ auf das Verzeichnis Quelle und Ziel zugreifen.
Maßgebend soll weiter die EXE sein und nicht wo das Ganze entpackt wird, z.B. 'C:\\Users\\rebekka\\AppData\\Local\\Temp\\_MEI130002'.

Bei meiner bisherigen Lösung habe ich die EXE irgendwo hin kopiert, die zwei Ordner manuell erstellt und gut war es.

Ich freue mich über Tipps.
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Vielen Dank.
Sirius3 hat geschrieben: Freitag 4. Februar 2022, 13:22

Code: Alles auswählen

import xml.etree.ElementTree as ET
from pathlib import Path

SOURCE_PATH = Path("Quelle")
DESTINATION_PATH = Path("Ziel")

def main():
    xml_files = list(SOURCE_PATH.glob("*.xml"))
    for xml_file in xml_files:
        process(xml_file)

if __name__ == "__main__":
    main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

RebekkaSilber hat geschrieben: Freitag 4. Februar 2022, 14:03 Mein Ziel ist ja, dass ich davor nicht wissen muss, wo der Anwender das "Hauptverzeichnis" mit Quelle, Ziel und EXE ausführt.
Trotzdem soll er immer relativ auf das Verzeichnis Quelle und Ziel zugreifen.
Maßgebend soll weiter die EXE sein und nicht wo das Ganze entpackt wird, z.B. 'C:\\Users\\rebekka\\AppData\\Local\\Temp\\_MEI130002'.

Bei meiner bisherigen Lösung habe ich die EXE irgendwo hin kopiert, die zwei Ordner manuell erstellt und gut war es.
Das ist genau das, was da passiert: wenn man eine Exe per Doppelklick ausfuehrt, dann ist das CWD da, wo sie liegt. Man kann das beeinflussen auf verschiedenen Wegen, aber erstmal ohne alles sollte es genauso funktionieren.

Sirius3 code ist in der Beziehung ebenfalls equivalent, weil ein Path-Objekt mit relativem Pfad (Also ohne Laufwerk etc bei windows) immer aufgeloest wird relativ zu dem CWD. Ist mir persoenlich zu implizit, aber kann man so machen.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Das Arbeitsverzeichnis (current working dir), das du mit os.getcwd bekommst, ist das Verzeichnis, das aktuell dein Arbeitsverzeichnis ist. Das _kann_ das Verzeichnis sein, in dem die .exe liegt - muss aber nicht.

Wenn das Programm in c:\ein_verzechnis\ liegt und du das auf der Konsole aufrufst, während dein aktuelles Current Working Dir c:\ ist, dann wird os.getcwd() c:\ zurück liefern.

Wenn du das Programm als one-file-exe packst und wissen willst, wo diese .exe liegt, unabhänig davon, was gerade das Arbeitsverzeichnis ist, dann kannst du sys.executable verwenden.
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Vielen Dank für eure Tipps und Geduld.

Ich habe gerade folgendes getestet:

Code: Alles auswählen

import os
import sys

print(os.getcwd())
print(sys.executable)
Ergebnis:
C:\Users\rebekka\OneDrive - rebekka silber\MyCode
C:\Python\Python39\python.exe
Leider liegt aber meine Datei weder in dem einen noch in dem anderen Verzeichnis. Ich kann auch später nicht voraussagen, von welchem Verzeichnis aus der Anwender die Datei ausführt.

Wie kann ich herausfinden in welchem Verzeichnis die programm.py liegt oder später die EXE?

Im gleichen Verzeichnis liegt auch das Input und Output Verzeichnis.

Ich möchte es einfach wie bisher verschieben oder kopieren können und es soll lauffähig sein.

Pathlib ist grundsätzlich sehr interessant, leider sehe ich aber hier keinen Ansatz, wie ich ermitteln kann, wie das Verzeichnis der ausgeführten Datei lautet. Dieses benötige ich, da sich im gleichen Verzeichnis das Input und das Output Verzeichnis befinden.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Die Ausgabe halte ich für unmöglich, wenn du eine One-File-Exe ausführst.
Wenn du das Programm ausführen, wenn es noch keine .exe ist, dann kann es zu der Ausgabe kommen.

__deets__ hat einen Link auf die Dokumentation gepostet. Die Seite solltest du lesen. Wenn du unterscheiden willst, ob das Programm gerade eine .exe ist oder nicht, musst du schauen ob sie "freeze" ist.
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Du hast Recht sparrow.

Die Ausgabe
C:\Users\rebekka\OneDrive - rebekka silber\MyCode
C:\Python\Python39\python.exe
kommt, wenn ich die py-Datei ausführe.

Ich habe den Link von __deets__ gelesen. Ob ich es 100 % verstanden habe, kann ich aber nicht sagen.

Folgende Erkenntnisse habe ich jetzt:

Code: Alles auswählen

import os
from pathlib import Path

print('Option 1:')
print((Path.cwd() / __file__))

print('Option 2:')
print(__file__)

print('Option 3:')
print(Path(__file__).parent.resolve())

print('Option 3 liefert das gleiche Ergebnis wie:')
print(os.path.dirname(os.path.abspath(__file__)))
Liefert das Ergebnis:
Option 1:
c:\Users\rebekka\OneDrive - rebekka silber\MyCode\MeinPfad\test.py

Option 2:
c:\Users\rebekka\OneDrive - rebekka silber\MyCode\MeinPfad\test.py

Option 3:
c:\Users\rebekka\OneDrive - rebekka silber\MyCode\MeinPfad

Option 3 liefert das gleiche Ergebnis wie:
c:\Users\rebekka\OneDrive - rebekka silber\MyCode\MeinPfad
Leider habe ich dann aber nur einen Befehl gegen einen anderen getauscht.


---

Verständnisfrage:

Liefert

Code: Alles auswählen

os.path.dirname(sys.executable)
mir bei einem one-klick-file das Verzeichnis zurück wo das one-klick-file liegt (z.B. c:\Users\rebekka\OneDrive - rebekka silber\MyCode\MeinPfad)
oder das Verzeichnis wo es zur Ausführung entpackt wurde (c:\\Users\\rebekka\\AppData\\Local\\Temp\\_MEI130002)?

Liebe Grüße
Becky
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Probier es doch aus?
Mal ganz abgesehen davon, dass ich das eigentlich schon ziemlich treffen geschrieben habe, finde ich.

Du brauchst eine Funktion, die folgendes tut:
- Wenn das Programm als exe gepackt ist (das kann man an "frozen" erkennen)
-- dann benutze sys.executable um an den Pfad der One-File-Exe zu kommen und gibt dessen parent-Directory als Pfad zurück
- wenn nicht:
-- benutze __file__ und lass dir dessen parent-Directory zurück geben.

Dann hast du beide Fälle abgedeckt.
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Folgendes habe ich gerade probiert:

Code: Alles auswählen

if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
    base_path = Path(sys._MEIPASS)
else:
    base_path = Path(__file__).parent

work_path = Path.cwd() / base_path

srcPath = os.path.join(work_path, 'Input')
desPath = os.path.join(work_path, 'Output')
errPath = os.path.join(work_path, 'Error')
Der Fehler ist der identische, wenn ich es als EXE gepackt habe.
FileNotFoundError: [WinError 3] Das System kann den angegebenen Pfad nicht finden: 'C:\\Users\\rebekka\\AppData\\Local\\Temp\\_MEI279362\\Input'
Über Lösungsansätze würde ich mich freuen.

Vielen Dank.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Du rätst Code. So funktioniert Programmieren nicht.

Ich habe dir doch eine Blaupause geschrieben. Wo benutzt du sys.executable, wie ich geschrieben habe?
Du hast jetzt zwar den Code von der Seite kopiert. Aber der passt nicht zu deinem Problem.

Ich dachte du hast die Scripte geschrieben und weißt, wie man grundsätzlich in Python programmiert?
RebekkaSilber
User
Beiträge: 9
Registriert: Freitag 4. Februar 2022, 09:53

Vielen Dank an alle.

Die für mich funktionierende Lösung:

Code: Alles auswählen

if getattr(sys, 'frozen', False):
    app_dir = os.path.dirname(sys.executable)
else:
    app_dir = os.path.dirname(__file__)
Gerne kann der Thread geschlossen werden.
Antworten