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 Steelson,

Un lien utilie ?

VBA_Python

Cdlt.

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 :

  1. excel- web,
  2. excel - SAP (via autoit),
  3. excel - arduino,
  4. excel - mysql,
  5. excel - PuTTY,
  6. etc.

@ Kwns

voici un exemple assez simple ...

  1. j'ai pris le parti de réécrire le code complet à partir d'excel (il y a une ligne en variable)
  2. il faut adapter PythonExe à ta config,
  3. et dans mon exemple j'utilise aussi notepad++ pour afficher le résultat ici (mais ce n'est pas indispensable !
  4. 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
239python.zip (19.56 Ko)

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.

image

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 :

  1. Tu es bien sous windows ?
  2. untitled0.py est bien écrit tel que tu le souhaitais ?
  3. Tu as bien modifié le chemin Shell "C:\.....................\pythonw.exe untitled0.py" pour pythonw.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 !!
  4. 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

https://docs.microsoft.com/fr-fr/office/vba/language/concepts/getting-started/64-bit-visual-basic-for-applications-overview


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).

http://www.python-simple.com/python-langage/unicode.php

https://docs.python.org/fr/3.9/howto/unicode.html

Rechercher des sujets similaires à "executer script python vba"