Hallo,
ich bin neu in der Welt der Python-Programmierung, nicht aber generell was Programmierung anbelangt. Ich kenne mich etwas in Java, C und VBA aus.
Ich habe nun in Python ein Programm geschrieben, welches Dateien auf ein GoogleDrive Laufwerk verschiebt, den entsprechenden Ordner freigibt und die Freigabelink kopiert und in eine PDF schreibt. Alles über die Google API. In der Entwicklung PyCharm funktioniert auch alles. Wenn ich aber eine ausführbare Exe erstelle (--onefile) dann greift er nicht mehr auf die json zu, wo die Zugangsdaten zur API enthalten sind. Der Link zu der JSON ist korrekt (ich habe ihn ein mal als festen Pfad und einmal als dynamischen getestet). Auch habe ich die main.exe (hat noch keinen kreativen Namen das Programm) als Administrator ausgeführt.
Ich verstehe einfach nicht, warum es in der PyCharm-Umgebung reibungslos läuft, aber als kompilierte Version nicht.
Ich habe vorher noch nie ausführbare Dateien erstellt, meistens habe ich mit Scripten gearbeitet. Vergesse ich irgendwas, muss ich irgendwas beachten?
Vielen Dank für eure Hilfe.
Problem mit ausführbarer Datei | Zugriff auf externe Datei
Aller Wahrscheinlichkeit hast du mit relativen Pfaden gearbeitet, die innerhalb von pycharm funktionieren, weil das fuer dein Projekt ein festes Arbeitsverzeichnis implizit setzt.
Der uebliche Trick besteht darin, den Pfad zu der eingebetteten Resource via der __file__-Variablen zu bauen. Ggf. gibt es da aber auch noch etwas bei deinem gewaehlten EXE-Buendler zu beachten.
Der uebliche Trick besteht darin, den Pfad zu der eingebetteten Resource via der __file__-Variablen zu bauen. Ggf. gibt es da aber auch noch etwas bei deinem gewaehlten EXE-Buendler zu beachten.
Code: Alles auswählen
import pathlib
BASE = pathlib.Path(__file__).parent # Points to the directory relative to the current module/scrip file
def main():
print(BASE / "test.json") # assumes the test.json is placed parallel to this module/script.
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Vielen lieben Dank für die schnelle Antwort.
Eigentlich nutze ich einen relativen Pfad
Ich benenne in dem Ordner Dateien auch um, das heißt, generell besteht der Zugriff. Ich nutze jedoch nicht die pathlib. Ich kann das gerne gleich mal probieren, ob e damit besser läuft.
Eigentlich nutze ich einen relativen Pfad
Code: Alles auswählen
current_directory = os.path.dirname(os.path.abspath(sys.argv[0]))
credentials_file = os.path.join(current_directory, r"_nicht_loeschen\drive.json")
An sich kein schlechtes Vorgehen, aber da es nicht zu funktionieren scheint, ist es wohl nicht so geeignet. Ein unmittelbares Problem: du hast *eine* Exe, aber das ist ja "gelogen". Stattdessen ist das eine Art selbstentpackendes Archiv. Und da kann es sein, das sys.argv[0] zwar korrekt den Pfad der EXE benennt, aber Code & Daten liegen waehrend der Ausfuehrung in einem temporaeren Verzeichnis. Da hilft aber dann __file__.
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Es hat leider nicht geklappt. Ich habe auch noch mal den festen Pfad eingepflegt, funktioniert trotzdem nicht. Ich bekomme auch keine Fehlermeldung, das die Datei nicht zu finden sei.
Folgenden Fehler erhalte ich: An error occurred: name: drive version: v3
Es geht dabei um die Funktion, den Google Service zu starten. Aus der Umgebung heraus kein Problem.
Code: Alles auswählen
def create_drive_service(credentials_file: str):
try:
with open(credentials_file, "r") as f:
credentials_info = json.load(f)
credentials = service_account.Credentials.from_service_account_info(credentials_info)
service = discovery.build("drive", "v3", credentials=credentials)
return service
except HttpError as error:
print(f"An error occurred: {error}")
return None
Es geht dabei um die Funktion, den Google Service zu starten. Aus der Umgebung heraus kein Problem.
Ich wuerde den Fehler komplett anzeigen, statt nur eine so kastrierte Version. Denn einen sinnvollen Weg, danach weiter zu machen, hast du doch nicht. So kann man naemlich nicht wirklich viel dazu finden. Wenn die Datei nicht gefunden wuerde, sollte der allerdings (denke ich) anders aussehen.
Der Fehler hat ja gar nichts damit zu tun, dass eine Datei nicht gefunden wird, sondern der Fehler tritt später auf.
Du fängst nur den HttpError, keinen IOError.
So eine Fehlerbehandlung ist im allgemeinen keine gute Idee. Denn im Fehlerfall wird die Information, wo der Fehler auftritt verheimlicht und die aufrufende Stelle bekommt statt einer schönen Exception, die sie behandeln kann nur einen Rückgabewert None.
Ein Grundsatz ist immer, dort das Exception Handling zu machen, wo man sinnvoll auf den Fehler reagieren kann, und ansonsten den Fehler einfach durchfallen lassen.
Du fängst nur den HttpError, keinen IOError.
So eine Fehlerbehandlung ist im allgemeinen keine gute Idee. Denn im Fehlerfall wird die Information, wo der Fehler auftritt verheimlicht und die aufrufende Stelle bekommt statt einer schönen Exception, die sie behandeln kann nur einen Rückgabewert None.
Ein Grundsatz ist immer, dort das Exception Handling zu machen, wo man sinnvoll auf den Fehler reagieren kann, und ansonsten den Fehler einfach durchfallen lassen.
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Für eine vernünftige Fehlerbehandlung dann lieber:Sirius3 hat geschrieben: Montag 3. April 2023, 14:49 Der Fehler hat ja gar nichts damit zu tun, dass eine Datei nicht gefunden wird, sondern der Fehler tritt später auf.
Du fängst nur den HttpError, keinen IOError.
So eine Fehlerbehandlung ist im allgemeinen keine gute Idee. Denn im Fehlerfall wird die Information, wo der Fehler auftritt verheimlicht und die aufrufende Stelle bekommt statt einer schönen Exception, die sie behandeln kann nur einen Rückgabewert None.
Ein Grundsatz ist immer, dort das Exception Handling zu machen, wo man sinnvoll auf den Fehler reagieren kann, und ansonsten den Fehler einfach durchfallen lassen.
Code: Alles auswählen
def create_drive_service(credentials_file: str):
try:
with open(credentials_file, "r") as f:
credentials_info = json.load(f)
credentials = service_account.Credentials.from_service_account_info(credentials_info)
service = discovery.build("drive", "v3", credentials=credentials)
return service
except IOError as error:
print(f"An error occurred: {error}")
return None
Code: Alles auswählen
def create_drive_service(credentials_file: str):
try:
with open(credentials_file, "r") as f:
credentials_info = json.load(f)
credentials = service_account.Credentials.from_service_account_info(credentials_info)
service = discovery.build("drive", "v3", credentials=credentials)
return service
except Exception as error:
print(f"An error occurred: {error}")
return None
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Ich weiß leider nicht wie man das macht. ChatGPT sagt mir, dass es besser sein mit dieser handhabe__deets__ hat geschrieben: Montag 3. April 2023, 15:21 Gar kein try/except. Das nimmt dir doch wertvolle Information.
ich habe also nun folgenden Code, um Fehler abzufangen:
Code: Alles auswählen
def create_drive_service(credentials_file: str):
try:
with open(credentials_file, "r") as f:
credentials_info = json.load(f)
credentials = service_account.Credentials.from_service_account_info(credentials_info)
service = build("drive", "v3", credentials=credentials)
return service
except FileNotFoundError:
print(f"Datei {credentials_file} nicht gefunden.")
return None
except json.JSONDecodeError:
print(f"Ungültiges JSON in {credentials_file}.")
return None
except HttpError as error:
print(f"HttpError Ein unerwarteter Fehler ist aufgetreten: {error.resp.status} {error.resp.reason}")
return None
except Exception as e:
print(f"ExcetionError Ein unerwarteter Fehler ist aufgetreten: {e}")
return None
Ein unerwarteter Fehler ist aufgetreten: name: drive version: v3
An error occurred: 'NoneType' object has no attribute 'files'
Lässt sich daraus ableiten, was es sein könnte?
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Ich habe es jetzt abgeändert in:
Bekomme aber immernoch keine andere Aussage außer: Ein unerwarteter Fehler ist aufgetreten: name: drive version: v3
Code: Alles auswählen
def create_drive_service(credentials_file: str):
with open(credentials_file, "r") as f:
credentials_info = json.load(f)
credentials = service_account.Credentials.from_service_account_info(credentials_info)
service = discovery.build("drive", "v3", credentials=credentials)
return service
Das passt nicht zu deinem Code.
Was machst du denn hinterher, wenn None zurückgegeben wird? Wird das sinnvoll behandelt?
Denn im Moment fängst du zwar Fehler, aber du gibst dann nur deren Info aus. Wichtige Informationen, wie zum Beispiel die Stelle, an der der Fehler aufgetreten ist, wird auf diese Weise verschluckt. Das brauchst du aber zum Debuggen.
Deshalb gilt: Kann man die Stelle des Fehlers nicht genau voraussagen oder würde das Fangen des Fehlers das Programm nicht in einem kontrollierten Zustand zurück lassen: Den Fehler nicht fangen.
Dann wird der Fehler nach oben durchgereicht, das Programm crasht und gibt einen ausführliche Traceback aus.
Zu deinem Problem mit der Datei:
1) Warum muss es eine exe-Datei sein? Das ist bei Python eher ungwöhnlich.
2) Wie wird die exe-Datei erstellt? Mit pyinstaller? Dann solltest du das hier lesen. Denn das Bünden von Dateien in pyinstaller ist nicht ohne.
Was machst du denn hinterher, wenn None zurückgegeben wird? Wird das sinnvoll behandelt?
Denn im Moment fängst du zwar Fehler, aber du gibst dann nur deren Info aus. Wichtige Informationen, wie zum Beispiel die Stelle, an der der Fehler aufgetreten ist, wird auf diese Weise verschluckt. Das brauchst du aber zum Debuggen.
Deshalb gilt: Kann man die Stelle des Fehlers nicht genau voraussagen oder würde das Fangen des Fehlers das Programm nicht in einem kontrollierten Zustand zurück lassen: Den Fehler nicht fangen.
Dann wird der Fehler nach oben durchgereicht, das Programm crasht und gibt einen ausführliche Traceback aus.
Zu deinem Problem mit der Datei:
1) Warum muss es eine exe-Datei sein? Das ist bei Python eher ungwöhnlich.
2) Wie wird die exe-Datei erstellt? Mit pyinstaller? Dann solltest du das hier lesen. Denn das Bünden von Dateien in pyinstaller ist nicht ohne.
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Vielen Dank für deine Antwort. Ich habe Tracback eingebunden und bekomme:sparrow hat geschrieben: Montag 3. April 2023, 16:56 Das passt nicht zu deinem Code.
Was machst du denn hinterher, wenn None zurückgegeben wird? Wird das sinnvoll behandelt?
Denn im Moment fängst du zwar Fehler, aber du gibst dann nur deren Info aus. Wichtige Informationen, wie zum Beispiel die Stelle, an der der Fehler aufgetreten ist, wird auf diese Weise verschluckt. Das brauchst du aber zum Debuggen.
Deshalb gilt: Kann man die Stelle des Fehlers nicht genau voraussagen oder würde das Fangen des Fehlers das Programm nicht in einem kontrollierten Zustand zurück lassen: Den Fehler nicht fangen.
Dann wird der Fehler nach oben durchgereicht, das Programm crasht und gibt einen ausführliche Traceback aus.
Zu deinem Problem mit der Datei:
1) Warum muss es eine exe-Datei sein? Das ist bei Python eher ungwöhnlich.
2) Wie wird die exe-Datei erstellt? Mit pyinstaller? Dann solltest du das hier lesen. Denn das Bünden von Dateien in pyinstaller ist nicht ohne.
Mit Traceback bekomme ich folgenden fehler:
An error occurred: name: drive version: v3
Traceback (most recent call last):
File "main.py", line 63, in create_drive_service
service = discovery.build("drive", "v3", credentials=credentials)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "googleapiclient\_helpers.py", line 130, in positional_wrapper
File "googleapiclient\discovery.py", line 287, in build
File "googleapiclient\discovery.py", line 404, in _retrieve_discovery_doc
googleapiclient.errors.UnknownApiNameOrVersion: name: drive version: v3
An error occurred: 'NoneType' object has no attribute 'files'
Press Enter to close the program.
Zu deinen Fragen:
1) Ich möchte gerne das das Programm auch von anderen schnell ausgeführt werden kann, ohne erst die PyCharm Umgebung zu öffnen. Es muss keine exe sein. Ich will nur, dass jemand anderes mit einem anderen PC, dieses Script einfach und schnell ausführen kann. Entsprechend sollte dann Python auch auf diesem Rechner installiert sein und ich kann durch eine Batch Datei, die ein cmd Befehl zum ausführen des Scripts binhaltet erstellen, als Alternative Lösung? Edit: Dazu dann das ganze Py-Projekt in einen Drive-Folder, damit von überall erreichbar.
2)Ja, mit pyinstaller. Ich werde mir den Beitrag mal anschauen. Gibt es eine einfacherer und besser Alternative zur Erstellung der exe?
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Vielen Dank für eure Antworten bis dato.Sirius3 hat geschrieben: Montag 3. April 2023, 18:25 Du hast ja immer noch die Fehlerhafte Fehlerbehandlung drin. Die Variante von 17:41Uhr war doch die richtige.
Was steht denn in `credentials_info`? Ist das für beide Umgebungen das selbe?
Das liegt daran, dass ich nicht richtig weiß, wie ich dann traceback einbinden kann um eine aussagekräftige Antwort zu erhalten. Mit der Lösung, habe ich ein wenig mehr an Infos erhalten.
In der credentials_info werden json Daten geladen:
{
"type": "service_account",
"project_id": "xxx",
"private_key_id": "xxx",
"private_key": "-----BEGIN PRIVATE KEY-----\nxxx\n-----END PRIVATE KEY-----\n",
"client_email": "xxx",
"client_id": "xxx",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "xxx"
}
Die sind in beiden Fällen gleich, da auf die selbe Datei zugegriffen wird.
Ich kenne diese Bibilothek nicht, aber wenn man sich den Code mal anschaut - https://github.com/googleapis/google-ap ... ry.py#L399 - dann beziehen die sich da auf irgendwelche Daten, die nachgeladen werden, bzw. irgendwo als Cache rumliegen sollen. Das aber nicht tun. Das kann also sehr gut ein Problem deiner Buendelung als EXE sein. Das muss geloest werden. Dazu zB mal den Debugger an der Stelle positionieren, und sich anschauen, was da genau in diesem cache passiert.
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Danke das du dir das angeschaut hast, ich versuche den Ansatz mit dem Cache nachzugehen ...__deets__ hat geschrieben: Dienstag 4. April 2023, 09:02 Ich kenne diese Bibilothek nicht, aber wenn man sich den Code mal anschaut - https://github.com/googleapis/google-ap ... ry.py#L399 - dann beziehen die sich da auf irgendwelche Daten, die nachgeladen werden, bzw. irgendwo als Cache rumliegen sollen. Das aber nicht tun. Das kann also sehr gut ein Problem deiner Buendelung als EXE sein. Das muss geloest werden. Dazu zB mal den Debugger an der Stelle positionieren, und sich anschauen, was da genau in diesem cache passiert.
-
- User
- Beiträge: 10
- Registriert: Montag 3. April 2023, 10:25
Ich habe jetzt die https://www.googleapis.com/discovery/v1 ... ve/v3/rest json heruntergeladen und lokal eingebunden. Dadurch funktioniert der Zugriff und die Verbindung wurde hergestellt. Der Hinweis mit dem Cache hat zur Lösung geführt, vielen Dank.