Live-Forum - Die aktuellen Beiträge
Anzeige
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Parameterübergabe mit shell.excute an Python scheitert

Forumthread: Parameterübergabe mit shell.excute an Python scheitert

Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 01:23:39
Marc
Hallo zusammen,

aus VBA heraus möchte ich mit Hilfe eines Shell-Objekts Python-Code ausführen. Dafür möchte ich der Shell einen Pfad übergeben, der darauf verweist wo das entsprechende Python-Skript liegt. Ich verwende dafür einen Code, den ich vor längerer Zeit mal mit Python 3.7/3.8 verwendet hatte und der damals immer einwandfrei funktioniert hat.

Nun, mit Python 3.12 will es einfach nicht funktionieren, den Pfad zu übergeben. Ich habe bereits mehrere Stunden gegoogelt und zahlreiche Lösungsversuche unternommen, ohne Erfolg.

Sub runPhyton()


' Python aufrufen und Pfad zum Skript übergeben

Dim pfad As String, wsh As Object, oExec As Object

pfad = ThisWorkbook.Path & "\Test.py"

' Shell instanzieren

Set wsh = VBA.CreateObject("WScript.Shell")

Set oExec = wsh.Exec("C:\Users\xxxx\AppData\Local\Programs\Python\Python312\python.exe" & " " & pfad & "")

End Sub


Im Ergebnis öffnet sich zwar eine Shell aber des Skript (Test.py) wird nicht aufgerufen.

Ich hab schon unzählige Kombinationen probiert, wie man oExec instanzieren könnte, um es zum Laufen zu bekommen. Mit der Call-Variante oder Shell.run funktioniert es problemlos, nur da weiß ich dann nicht wie ich an die Rückgabewerte komme, die ich bei dieser Variante über oExec.stdout.readall abrufen kann.

Hat jemand eine genaue Idee, wie man mit shell.exec einen Dateipfad an Python 3.12 übergeben muss?

Ein Link zu einer Seite, wo die Methode Shell.exec im Detail erklärt wird, wäre auch schon hilfreich. Ich habe leider nichts gefunden.

VG
Marc

Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 05:11:29
Oberschlumpf
Hi,

ich würd es einfach so versuchen:


Sub runPhyton()
' Python aufrufen und Pfad zum Skript übergeben

Dim pfad As String

pfad = ThisWorkbook.Path & "\Test.py"

' Python aufrufen und Pfad zum Skript übergeben
CreateObject("WScript.Shell").Run "C:\Users\xxxx\AppData\Local\Programs\Python\Python312\python.exe " & Chr(34) & pfad & Chr(34), 1, True 'wichtig! hinter .exe MUSS ein Leerzeichen folgen!

End Sub


Ob es hilft, weiß ich nicht, aber ich vermute, in deinem ThisWorkbook.Path ist mindestens 1 Leerzeichen enthalten - und wenn dem so ist, wird - mit deinem bisherigen - Befehl der komplette Pfad - nicht - richtig übergeben. (und DANN ist auch nich Python 3.12 schuld, sondern wer??? du ahnst es sicher!^^ :-) )
Und deshalb übergebe zumindest ich die - notwendigen "" an den richtigen Stellen - mit CHR(34).
Es kann auch mit ""text - pfad - befehl"" funktionieren, oder mit """"text - pfad - befehl"""" - da aber ich damit oft durcheinander komme, verwende ich lieber CHR(34) :-)

Der Parameter 1, fast am Ende meiner Befehlszeile, sorgt dafür, dass das CMD-Fenster mit dem Python-Befehl sichtbar ist und den Fokus erhält.
Der Parameter TRUE, ganz am Ende meiner Befehlszeile, sorgt dafür, dass dein weiterer VBA-Code erst dann fortgeführt wird - nachdem - der Python-Befehl beendet ist.

alles wegen Parameter hier nachzulesen:
https://www.vbsedit.com/html/6f28899c-d653-4555-8a59-49640b0e32ea.asp

und weiteres mit diesem Google-Suchtext: createobject( wscript.shell ).run parameters

Hilfts?
Nein? Sorry, dann hab ich auch keine weitere Idee, ohne all das zu kennen, wie deine "digitale Umgebung" aussieht.

Ciao
Thorsten
Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 13:46:17
Zwenn
Hallo Marc,

Du hast nach meinem Kenntnisstand 2 bzw. 3 Möglichkeiten an die Ergebnisse des Python Scripts zu gelangen. Wie es dafür über WSH.run gestartet wird hat Thorsten bereits gezeigt und Du wusstest wohl auch schon, dass es mit run geht. Im Standard wird das Ergebnis auf dem Bildschirm ausgegeben. Hier ergeben sich die ersten beiden Möglichkeiten.

1. Umleiten der Standardausgabe in die Zwischenablage
Du leitest die Ausgabe in die Zwischenablage um und liest diese dann mit VBA aus. Diese Methode habe ich selber vor Jahren verwendet, um an Hashwerte eines Konsolenprogramms zu kommen, die für Bilddateien berechnet wurden. Deshalb poste ich nur die Kommentare und die WSH.run Zeile im Original sozusagen. Du kannst die Zeile einfach auf Dein Problem umschreiben.


'Ermittelte Datei hashen und das Ergebnis in die Zwischenablage schreiben
'Der Parameter /c hinter cmd, sorgt dafür, dass die Konsole (cmd) geschlossen wird, wenn reHash beendet wurde
'(Es gibt alternativ den Parameter /k, der die Konsole offen lässt. Achtung: Hier nicht verwenden. Das Makro bleibt dann stehen)
'Durch den vorletzten Parameter 0, führt der Windows Scripting Host die Konsole unsichtbar aus
'(1 macht sie sichtbar, aber dann zuckt der Bildschirm während des Makrolaufs sehr unruhig)
'Durch den letzten Parameter True, wartet das Makro, bis der Windows Scripting Host die Konsole wieder beendet hat
'(Achtung: Bei False würde das Makro weiterlaufen und nicht warten, bis der aktuelle Hash-Wert berechnet wurde)
'Die Angabe | clip leitet die Ausgabe der Konsole von der Standardausgabe (Bildschirm) in die Zwischenablage um
WshShell.Run "cmd /c " & ReHashPfad & " " & ReHashParameter & " " & Chr(34) & GrundPfadZuDateienBestand & VariablerPfadRest & DateiNameBearbeit & Chr(34) & " | clip", 0, True


2. Umleiten der Standardausgabe in eine Textdatei
Genau das gleiche, nur dass Du nicht | clip verwendest, sondern das Ergebnis mit >pfad\dateiname.txt in eine Textdatei schreibst, die Du ebenfalls mit VBA weiterverarbeiten kannst. So eine Umleitung mit > überschreibt eine bestehende Datei ohne Rückfrage.

3. Anpassen des Python Scripts
Du kannst alternativ auch das Python Script so anpassen, dass es sein Ergebnis nicht auf dem Bildschirm ausgibt, sondern es in eine Textdatei schreibt. Das Ergebnis ist das Gleiche wie unter 2. genannt.

Ich habe mich damals für die Zwischenablage entschieden, weil ich die Werte nur für die Weiterverarbeitung brauchte und annahm, der Weg über das Schreiben vieler kleiner Textdateien summiere sich zeitlich auch auf. Es waren millionen von Bildern, die so gehasht wurden.

Für den Zugriff auf die Zwischenablage aus VBA heraus habe ich diese Funktion von Peter Haserodt verwendet:


Public Function HoleTextVonZwischenablage() As String

' ************************************************************
' Benötigt einen Verweis auf die Microsoft Forms 2.0 Objektlibrary
' (Sollten Sie diese nicht so einfach finden, einfach eine Userform
' einfügen und dann wieder entfernen)
' Peter Haserodt 2004
' ************************************************************

'Quelle: http://www.online-excel.de/excel/singsel_vba.php?f=28

Dim oData As New DataObject
Dim strZwischenSpeicher As String 'Eingesetzt zum Test von Zwenn

'Fehlerbehandlung für meinen Anwendungsfall nicht notwendig
'On Error Resume Next ' Brutal um falsche Formate abzuwürgen, gibt dann einen Leerstring

oData.GetFromClipboard
strZwischenSpeicher = oData.GetText 'String zwischenspeichern, damit das Data Objekt freigegeben werden kann

'Test, weil nach 65.527 Zugriffen auf diese Funktion ein Speicherfehler kommt, der sich immer auf den Zugriff auf das Clipboard bezieht
Set oData = Nothing

'Übergabe des Funktionswertes aus der Zwischenspeicher-Variable an die aufrufende Routine
HoleTextVonZwischenablage = strZwischenSpeicher

End Function


Es gibt auch aus Python heraus die Möglichkeit direkt in Excel Dateien zu schreiben. Aber ich nehme an, dass funktioniert nicht mit einer geöffneten Datei und wäre für Deine Problemstellung auch unpraktikabel.

Viele Grüße,

Zwenn
Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
09.07.2024 19:20:07
Marc
@all

Tausend Dank für die ausführliche Hilfe!

Ich hab mich zwischenzeitlich mal in einem Python-Forum schlau gemacht und die Lösung des Problems ist wirklich trivial aber für einen Anfänger schwer zu erkennen. Da es dem ein oder anderen eventuell hilft, will ich die Lösung auch hier festhalten.

Das Python-Skript wurde problemlos ausgeführt, NUR die Shell (Terminal) verhält sich unterschiedlich, je nachdem mit welcher Methode man sie aufruft.

Meine Python-Testdatei enthielt einen Befehl, der die Shell dazu auffordert auf eine Eingabe zu warten. Das wurde in den meisten Foren als die einfachste Lösung genannt, um zu verhindern, dass die Shell sich wieder schließt.

Wenn man die Shell nun aus VBA heraus aufruft mit Shell.run dann wartet die Shell tatsächlich auf eine Eingabe. ABER, eine Shell, die mit shell.exec aufgerufen wird reagiert darauf nicht. Wen es interessiert, weshalb das so ist, der kann meinen Thread im Python-Forum nachlesen:

https://www.python-forum.de/viewtopic.php?t=58210

(Es kann sein, dass man die Threads nur sehen kann, wenn man eingeloggt ist.)

Beste Grüße
Marc

Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
09.07.2024 19:47:16
Oppawinni
Mal ne blöde Frage.
Das was dein Python-Script macht, hätte man das nicht mit VBA machen können?
AW: Parameterübergabe mit shell.excute an Python scheitert
09.07.2024 20:21:51
Marc
Das Testskript war ja nur da, um zunächst mal die Übergabe der Parameter zu testen. Letztlich geht es darum ein bereits existierendes Python-Skript aus VBA heraus auszuführen, dass eine relativ große Menge an Daten auswertet. Die Berechnung dauert in Python schon relativ lange und ich gehe davon aus, dass VBA damit noch mehr Zeit benötigt.
Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
09.07.2024 20:48:25
Oppawinni
Power Query und Power Pivot hast du ausgeschlossen ?
AW: Parameterübergabe mit shell.excute an Python scheitert
09.07.2024 22:06:02
Marc
In der Tat ein guter Hinweis Oppawinni!

Es erschien mir halt zunächst einfacher ein bereits bestehendes Python-Skript zu verwenden und den Output einfach nach VBA zu übernehmen, als selbst etwas zu schreiben.

Ich muss aber zugeben, dass ich von den Unwägbarkeiten in Python mittlerweile dermaßen genervt bin, dass ich gerade darüber am grübeln bin, wie ich das Ganze selbst in VBA schreibe und ja, da wäre PowerQuery oder PowerPivot vielleicht hilfreich.
Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 09:24:20
Marc
Hi Torsten,

erstmal ganz herzlichen Dank für die Erläuterungen!

Dein Code funktioniert natürlich, nur ist es eben die Shell.Run-Variante, die ich ja gerade nicht verwenden wollte, wie in meinem Eröffnungspost schon schrieb. Jetzt weiß ich nämlich nicht, wie ich an die Rückgabewerte komme, die die Shell ausgeben soll. Mit dem Shell.Exec-Objekt ist das relativ unkompliziert.

Ich habe natürlich auch versucht Deine Codezeile mal in die Exec-Variante zu integrieren aber dann wird wieder der Pfad nicht übergeben:

Sub getData()


' Python aufrufen und Tickersymbol übergeben

Dim pfad As String, wsh As Object, oExec As Object

pfad = ThisWorkbook.Path & "\Test.py"

' Python-Shell (Terminal) instanzieren und Pfad übergeben

Set wsh = VBA.CreateObject("WScript.Shell")
'
Set oExec = wsh.exec("C:\Users\xxxx\AppData\Local\Programs\Python\Python312\python.exe " & Chr(34) & pfad & Chr(34) & "")


Wenn Du mir sagen kannst, wie man mit Shell.Run die Rückgabewerte bekommt, dann wäre mir natürlich auch schon geholfen.

Beste Grüße
Marc
Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 09:57:33
Oberschlumpf
Hi Marc,

wie ja schon erwähnt: Ich weiß nicht, ob ich helfen kann...

Ja, richtig, du versuchst .Exec, ich zeigte eine Idee mit .Run

a) ich hatte gehofft, dass das Umschreiben meines Codes auf .Exec funktioniert = aber leider tut es das nicht
b) ich kann nicht, bzw hab gerad keine Idee, wie/wo ich .Exec verwenden könnte, weil ich .Exec nicht kenne = deshalb "nur" meine .Run-Idee
c) ich kenne mich mit Python so gar nicht aus; außer, dass ich weiß, wie es geschrieben wird^^ = deswegen schrieb ich auch: Helfen? Nein? = keine weitere Idee

d) aaaber...egal, was ich in c) schrieb: DU zeigst uns ja null, nothing, rein gar nix von dem, WAS denn deine Python-Datei tun soll^^
Somit wirds wahrsch. auch einem "Python-Wissenden" schwierig, dir helfen zu können - weil der ja auch nich weiß, WAS du überhaupt erreichen willst...

e) aufgrund von d) würde ich vorschlagen:

1. Erstell eine Python-Bsp-Datei mit Befehlen/Inhalten/was auch immer, was eben mit .Exec ausgewertet werden könnte
2. Erstell eine Excel-Bsp-Datei, in die dann das, was mit der Python-Bsp--Datei erreicht wird, eingetragen wird
Füg am besten in der Excel-Datei per Hand die Python-Einträge dort so ein, wie und wo sie von dir gewünscht sind
3. Zeig uns beide Bsp-Dateien per Upload

Ciao
Thorsten
Anzeige
AW: Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 10:00:26
Oberschlumpf
ähhh???

ich sehe gerad am Ende deines Befehls DAS HIER:
Chr(34) & "")


Wieso steht denn ganz am Ende noch mal "" ??
Der Befehl sollte doch eigtl mit dem letzten CHR(34) abgeschlossen sein, oder?
AW: Parameterübergabe mit shell.excute an Python scheitert
07.07.2024 12:20:50
Marc
Oh, danke. Du hast Recht...

Ich werde es nochmal ohne den Zusatz versuchen.
Anzeige
;

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Entdecke mehr
Finde genau, was du suchst

Die erweiterte Suchfunktion hilft dir, gezielt die besten Antworten zu finden

Suche nach den besten Antworten
Unsere beliebtesten Threads

Entdecke unsere meistgeklickten Beiträge in der Google Suche

Top 100 Threads jetzt ansehen
Anzeige