Executer un script Python sur VBA ?
Hello.
J'ai un code VBA qui me donne une liste d'identifiants. A la main, je rentre cette liste d'identifiants sur mon script Python afin d'en tirer des listes de données sous forme .csv.
Exemple : Mon code VBA me donne : Pierre, Mathilde, Paul, Georges
Mon script Python qui contient une liste à modifier en tant que ["Pierre", "Mathilde", "Paul", "Georges"] me fournit Notes_Pierre.csv, Notes_Mathilde.csv, Notes_Paul.csv, Notes_Georges.csv
Est ce qu'il y a un moyen pour faire en sorte qu'un code VBA modifie directement mon script Python et l'exécute sans que j'ai à le faire moi ?
Un truc du style "ma liste VBA est copiée sous la forme ["ID_1","ID_2", etc.] dans mon script Python ; le script est executé".
Merci d'avance !
Est ce qu'il y a un moyen pour faire en sorte qu'un code VBA modifie directement mon script Python et l'exécute sans que j'ai à le faire moi ?
Un truc du style "ma liste VBA est copiée sous la forme ["ID_1","ID_2", etc.] dans mon script Python ; le script est executé".
Bonjour,
voilà un sujet intéressant
le script python étant un fichier texte il est possible de l'écrire via VBA
pour le lancer, il faut utiliser
Shell
#If VBA7 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#Else
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If
Sub lancer()
mypy = "C:\xxxxx\yyyyy.py"
x = Shell("C:\xxxxxxxxxxxxxxxx\python.exe" & " " & mypy, vbNormalFocus)
If x = 0 Then
MsgBox "Impossible de lancer Python !", vbOKOnly
End If
End Sub
Bonjour Jean-Eric,
Intéressant ... mais je refuse souvent (toujours) de travailler avec des ajouts, je préfère garder mon excel pur (en dehors de PowerQ mais c'est parce qu'il était intégré dans les nouvelles versions d'excel).
Par contre, j'aime bien travailler sur les passerelles :
- excel- web,
- excel - SAP (via autoit),
- excel - arduino,
- excel - mysql,
- excel - PuTTY,
- etc.
@ Kwns
voici un exemple assez simple ...
- j'ai pris le parti de réécrire le code complet à partir d'excel (il y a une ligne en variable)
- il faut adapter
PythonExe
à ta config, - et dans mon exemple j'utilise aussi notepad++ pour afficher le résultat ici (mais ce n'est pas indispensable !
- attention / achtung / be careful : le fichier .py doit être écrit en unicode !
edit : le lancement de python est un peu capricieux, mais l'écriture du script en unicode fonctionne très bien => correction apportée ci-dessous
Est ce qu'il y a un moyen pour faire en sorte qu'un code VBA modifie directement mon script Python et l'exécute sans que j'ai à le faire moi ?
Juste une précision ... j'ai répondu ci-dessus à cette demande, mais ton titre se référerait à un autre processus : il s'agit bien ici d'écrire et lancer un script à partir de VBA, car il est possible d'importer des fonctions Python dans VBA.
Ce script semble plus stable ... avec ajout de ChDir
Je confirme aussi qu'il faut utiliser pythonw.exe
et non python.exe
#If VBA7 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#Else
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If
Sub process()
Application.Calculate
ecrire
lancerpy
Application.Wait (Now + TimeValue("00:00:02"))
lancertxt
End Sub
Sub ecrire()
Close #1
Open ThisWorkbook.Path & "\ExemplePython.py" For Output As #1
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Print #1, Encode_UTF8(Cells(i, 1).Value)
Next
Close #1
End Sub
Sub lancerpy()
ChDir ActiveWorkbook.Path
Shell "C:\Users\Michel\AppData\Local\Programs\Python\Python38-32\pythonw.exe ExemplePython.py"
End Sub
Sub lancertxt()
mytxt = ThisWorkbook.Path & "\ExemplePython.txt"
Shell "C:\Program Files (x86)\Notepad++\notepad++.exe " & mytxt
End Sub
Sub test()
End Sub
Hello Steelson,
Déjà merci beaucoup. J'ai testé ton fichier .zip, tout fonctionne nickel. Je décortique et reviens vers toi avec toutes mes questions !
Donc si j'ai bien compris, plutôt que de modifier une ligne spécifique dans mon code, l'alternative c'est de créer une Sheet Excel avec tout mon code C/C, et d'executer ta macro qui va tout réécrire dans un fichier Python, puis l'exécuter
Donc j'ai essayé de faire un simple
pint("hello")
et selon moi ça donnerait ceci :
#If VBA7 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#Else
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If
Sub process()
Application.Calculate
ecrire
lancerpy
End Sub
Sub ecrire()
Close #1
Open ThisWorkbook.Path & "\untitled0.py" For Output As #1
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Print #1, Encode_UTF8(Cells(i, 1).Value)
Next
Close #1
End Sub
Sub lancerpy()
ChDir ActiveWorkbook.Path
Shell "C:\Users\Michel\AppData\...\pythonw.exe untitled0.py"
End Sub
Et quand j'exécute, j'obtiens bien que mon code untitled0.py s'est transformé en print("hello"), pourtant je n'ai pas l'impression que mon code Python s'est exécuté. Je ne vois aucun hello dans le kernel.
Qu'ai je mal fait ?
Merci !
C'est toujours possible de ne modifier qu'une seule ligne, pour cela il faut ouvrir le fichier texte en VBA, lire ligne à ligne, faire un replace, réécrire et fermer. Ce n'est pas très complexe, je vais le faire pour mon cas de figure !
Pour le reste :
- Tu es bien sous
windows
? untitled0.py
est bien écrit tel que tu le souhaitais ?- Tu as bien modifié le chemin
Shell "C:\.....................\pythonw.exe untitled0.py"
pourpythonw.exe
? je suppose que oui si tu as pu faire tourner le fichier excel et que tu as bien obtenu un fichier texte avec la bonne date et la bonne heure de lancement du code VBA, mais j'ai eu du mal à le trouver !! - Quand tu lances manuellement
untitled0.py
est-ce qu'il te donne la réponse que tu attends ?
Après, pour les sorties dans le kernel, je ne connais pas assez python pour te guider. Néanmoins, essaie sur ton application sans changer les noms, juste en lançant ton appli, pour voir si les .csv ont bien été générés.
Rectification, ton code marche du feu de Dieu !
Je n'ai pas pu encore tester avec des fichiers csv plus lourds avec mon code initial, mais avec un petit code trouvé sur internet :
entetes = [
u'Colonne1',
u'Colonne2',
u'Colonne3',
u'Colonne4',
u'Colonne5'
]
valeurs = [
[u'Valeur1', u'Valeur2', u'Valeur3', u'Valeur4', u'Valeur5'],
[u'Valeur6', u'Valeur7', u'Valeur8', u'Valeur9', u'Valeur10'],
[u'Valeur11', u'Valeur12', u'Valeur13', u'Valeur14', u'Valeur15']
]
f = open('MonFichier.csv', 'w')
ligneEntete = ";".join(entetes) + "\n"
f.write(ligneEntete)
for valeur in valeurs:
ligne = ";".join(valeur) + "\n"
f.write(ligne)
f.close()
ça génère le csv.
En revanche, tu peux me faire une explication rapide du code si ça ne te dérange pas, stp ?
#If VBA7 Then
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#Else
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If
Cette partie ci sert à quoi ?
Sub ecrire()
Close #1
Open ThisWorkbook.Path & "\untitled0.py" For Output As #1
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Print #1, Encode_UTF8(Cells(i, 1).Value)
Next
Close #1
End Sub
Là j'ai bien compris que ça parcourait tout mon Excel de façon à copier coller les lignes une par une dans mon fichier Python. Mais ce que j'ai du mal à comprendre c'est les Close #1, le For Output As #1 et le Encode_UTF8. Si j'ai bien compris pour le Encode_UTF8 ça permet d'écrire en unicode mais, qu'est ce qui doit être en unicode ?
Et encore si j'ai bien, compris, l'unicode c'est une chaine de caractères qui se définit par u"mon texte" ?
Merci énormément.
En revanche, tu peux me faire une explication rapide du code si ça ne te dérange pas, stp ?
#If VBA7 Then Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _ (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long #Else Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _ (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long #End If
Cette partie ci sert à quoi ?
ceci permet de déclarer la fonction qui sert à lancer une appli par shell, utilisé 2 fois ici :
Shell "C:\Users\Michel\AppData\Local\Programs\Python\Python38-32\pythonw.exe ExemplePython.py"
et
Shell "C:\Program Files (x86)\Notepad++\notepad++.exe " & mytxt
mais pour assurer la compatibilité avec les versions 32/64bits on utilise
#If VBA7 Then
Declare PtrSafe Sub...
#Else
Declare Sub...
#EndIf
Sub ecrire() Close #1 Open ThisWorkbook.Path & "\untitled0.py" For Output As #1 For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row Print #1, Encode_UTF8(Cells(i, 1).Value) Next Close #1 End Sub
Là j'ai bien compris que ça parcourait tout mon Excel de façon à copier coller les lignes une par une dans mon fichier Python. Mais ce que j'ai du mal à comprendre c'est les Close #1, le For Output As #1 et le Encode_UTF8. Si j'ai bien compris pour le Encode_UTF8 ça permet d'écrire en unicode mais, qu'est ce qui doit être en unicode ?
1 correspond ici au numéro de fichier. Un même numéro ne peut être réutilisé tant que le fichier qu'il référence n'est pas fermé.C'est pourquoi je le ferme avant tout ! Pour remédier à ce problème et obtenir un numéro de fichier toujours valide, la fonction Freefile peut être utilisée.
Sub ecrire()
int = FreeFile
Open ThisWorkbook.Path & "\untitled0.py" For Output As #int
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Print #int, Encode_UTF8(Cells(i, 1).Value)
Next
Close #int
End Sub
Ce qui doit être en unicode ? Tous les caractères dont l'asci est sup à 127. Exemple û de août (249) ... c'est là que je m'en suis rendu compte ! Python a hurlé ...
Dans ton cas, tu n'as pas besoin de la fontion de transformation unicode
j = FreeFile
Open ThisWorkbook.Path & "\GenCSV.py" For Output As #1
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Print #j, Cells(i, 1).Value
Next
Close #j
ChDir ActiveWorkbook.Path
Shell "C:\Users\Michel\AppData\Local\Programs\Python\Python38-32\pythonw.exe GenCSV.py"
End Sub
Et encore si j'ai bien, compris, l'unicode c'est une chaine de caractères qui se définit par u"mon texte" ?
exact
- x = 'é' : type str, et la longueur est de 2 (2 octets xc3 et xa9 qui sont en fait la représentation en UTF-8 de ce caractère unicode U+00E9)
- x=u'é' : type unicode, et la longueur est de 1 (1 seul caractère \xe9).