30 mars 2022

[Dynamo += Python] Installation automatisé de Package CPython3

 





Installer des packages CPython3 directement depuis un script Dynamo 💡

#DynamoBIM #Revit #CPython3 #pip #modules #AutodeskExpertElite #AutodeskCommunity 


if this article is not in your language, use the Google Translate widget (bottom of page for Mobile version) 


L'installation manuelle de Package pour le moteur CPython3 se fait en suivant ce guide :

Cependant, il est possible d'automatiser tout cela directement depuis Dynamo (très utile si vous voulez déployer sur votre réseau les mêmes packages).

Le script Python prend en entrée une liste de noms de packages (attention à la case).
Vous retrouverez la liste des packages ainsi que le nom à passer dans la commande pip sur ce site :

Exemple avec numpy

exemple de nom à copier-coller dans la liste en entrée

le code Python
Credit Ekko Nap pour l'idée et le code d'origine

- Edit 11/05/2024 : MAJ du code pour l'édition du fichier pth et ajout d'un dictionnaire en sortie


# More info here
# https://github-wiki-see.page/m/DynamoDS/Dynamo/wiki/Customizing-Dynamo%27s-Python-3-installation
import sys
import clr
import System
import re
print('\n'.join(sys.path))
pyEngineName = sys.implementation.name 

clr.AddReference("System.Windows.Forms")
import System.Windows.Forms
from System.Windows.Forms import MessageBox, MessageBoxButtons, MessageBoxIcon

from System.Reflection import Assembly
dynamo = Assembly.Load('DynamoCore')
dynamo_version = str(dynamo.GetName().Version)
dynamo_version = tuple(int(x) for x in dynamo_version.split("."))
print('dynamo_version', dynamo_version)
init_setup = False
if pyEngineName != "ironpython" and dynamo_version > (2,8,0,0):
    clr.AddReference('Python.Included')
    import Python.Included as pyInc
    path_py3_lib = pyInc.Installer.EmbeddedPythonHome
    import platform, os, subprocess, importlib.util
    from System import Environment
    from System.Net import WebClient
    #
    # get paths
    assert os.path.isdir(path_py3_lib)
    pipDirPath = os.path.join(path_py3_lib, 'Scripts')
    pipfilePath = pipDirPath + "\\pip"
    get_pip_path = os.path.join(path_py3_lib, 'get-pip.py')
    site_packagepath = os.path.join(path_py3_lib, 'Lib\site-packages')
    lib_path = os.path.join(path_py3_lib, 'Lib')
    #
    if not os.path.isfile(get_pip_path):
        client = WebClient()
        client.DownloadFile('https://bootstrap.pypa.io/get-pip.py', get_pip_path)
    filepy_pth = f'python{sys.version_info.major}{sys.version_info.minor}._pth'
    pthFilePath = os.path.join(path_py3_lib, filepy_pth)
    assert os.path.isfile(pthFilePath), "Error file {} not found".format(pthFilePath)
    # start update pthFilePath
    with open(pthFilePath, 'r+') as f:
        lines = f.readlines()
        for idx, line in enumerate(lines):
            if re.match(r'#import site', line) is not None:
                lines[idx] = re.sub(r'#', '', line)
                f.writelines(lines)
                break
        # add site-packages
        if re.search(r'./Lib/site-packages', lines[-1]) is None:
            f.write("\n./Lib/site-packages")
        
    # end update pthFilePath
    # install pip
    if not os.path.isdir(pipDirPath):
        #print(f'installing pip in local Python environment: {path_py3_lib}')
        print('installing pip in local Python environment: {}'.format(path_py3_lib))
        subprocess.Popen(["python", get_pip_path])
        # try to update pip
        try:
            #subprocess.run(['python', '-m', pipfilePath, 'install', '--upgrade pip'],  cwd = path_py3_lib)
            subprocess.Popen(["python", '-m', pipfilePath, 'install', '--upgrade pip'],  cwd = path_py3_lib)
        except Exception as ex:
            print(str(ex))
        init_setup = True
        MessageBox.Show("Initialization in Progress...\nWhen installation finished, close Dynamo and relaunch this script to install packages", "Initialization In Progress...", MessageBoxButtons.OK, MessageBoxIcon.Warning)
        raise Exception("close Dynamo and relaunch this script to install packages")
    else: 
        print('pip was already installed for this local Python environment')
        init_setup = False
    # install packages
    installPackages = IN[0]
    dict_result = {"out":[], "error_warning" : []}
    if installPackages and not init_setup:
        sys.path.append(site_packagepath)
        sys.path.append(lib_path)
        for packageName in installPackages:
            spec = importlib.util.find_spec( packageName )
            if spec is None: 
                try:
                    result = subprocess.run([pipfilePath, "install", '--target='+ site_packagepath, packageName], capture_output=True, cwd = path_py3_lib)
                    #print('{} succesfully installed'.format(packageName))
                    dict_result["out"].append(result.stdout.decode('utf-8'))
                    dict_result["error_warning"].append(result.stderr.decode('utf-8'))
                except Exception as ex:
                    #print(f'error while installing {packageName}')
                    dict_result["error_warning"].append('error while installing {} , {}'.format(packageName, ex))
            else:
                #print(f"package {packageName} is already installed")
                dict_result["out"].append("package {} is already installed".format(packageName))
                
        # check result
        if False:
            import numpy as np
            import pandas as pd
        MessageBox.Show("Installation et Configuration Python terminé avec succès!", "Installation Python", MessageBoxButtons.OK, MessageBoxIcon.Information)
        OUT = dict_result, None
    
elif pyEngineName == "ironpython" and dynamo_version > (2,8,0,0):
    MessageBox.Show("Basculer ce noeud sur le moteur CPython3 puis relancer le script!", "Installation Python", MessageBoxButtons.OK, MessageBoxIcon.Warning)
    
else:
    MessageBox.Show("Installation et Configuration Python terminé avec succès!", "Installation Python", MessageBoxButtons.OK, MessageBoxIcon.Information)


Résultat











0 commentaires:

Enregistrer un commentaire