fbpixel
Étiquettes :

Il est possible de convertir un script Python en ficher exécutable (EXE) à l’aide de la librairie PyInstaller. Une fois votre code Python testé et validé, vous pouvez le partager sous forme d’application de bureau exécutable de n’importe quel ordinateur. Ceci est d’autant plus pratique pour les interface graphique (IHM) comme ce moniteur série développer sous Python

Structure du projet

Pour commencer, il nous faut bien structurer notre projet. Pour cela nous utilisons l’arborescence suivante

app/
│
├── resources
|   ├── logo.ico
|   ├── logo.png
|   ├── style.txt
├── app.py
├── LICENSE
├── README.md
├── requirements.txt
├── setup.py
└── tests.py
  • app.py contient le code principal
  • logo.ico sera le fichier icône utilisé après la compilation
  • logo.png est utilsé dans le logiciel
  • style.txt contient la définition du style CSS

Dans ce tutoriel, nous allons créer une simple interface à ‘aide de PySide (vous pouvez aussi utiliser PyQt) contenant un bouton qui va modifier les messages dans la barre de debug.

#!/usr/bin/python
# -*-coding:Utf-8 -*
"""
Created on Thu Nov 17 16:59:13 2022

@author: X.Wiedmer

Dummy app
Define a simple app to test PyInstaller
"""
import sys,os
#from PyQt5.QtWidgets import *
#from PyQt5.QtCore import *
#from PyQt5.QtGui import *
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
pyqtSignal=Signal #translate pyqt to Pyside



# Generic app container     
def resource_path(relative_path):
	""" Get absolute path to resource, works for dev and for PyInstaller """
	try:
		# PyInstaller creates a temp folder and stores path in _MEIPASS
		base_path = sys._MEIPASS
	except Exception:
		base_path = os.path.abspath(".")

	return os.path.join(base_path, relative_path)


"""
App configuration
"""
__title__="DummyApp"
__version__="v0.1"	
style_path = resource_path("resources\\style.txt")
__icon__=resource_path("resources/logo.png")

class AcApp(QMainWindow):

	def __init__(self,title='DummyApp',mainFrame=QFrame):
		super().__init__()
		self.title=title
		self.mainFrame=mainFrame()
		self.initUI()

	def initUI(self):        
		#mainframe
		self.setCentralWidget(self.mainFrame)
		centralLayout=QHBoxLayout(self.mainFrame)
		
		#widgets
		self.button = QPushButton("Start")
		self.button.clicked.connect(self.clicked)
		centralLayout.addWidget(self.button)
	   
		#General configuration
		self.setWindowTitle(self.title)
		self.setGeometry(300, 300, 400, 200)
		self.setWindowIcon(QIcon(__icon__))
	   
		#Debug bar
		self.statusBar()
		self.statusBar().showMessage('Display debug messages')
	   
		self.show()

	def debugMsg(self,val):
		self.statusBar().showMessage(val)
	
	def clicked(self):
		if self.button.text() == "Start":
			self.debugMsg("Process started")
			self.button.setText("Stop") 
		else:
			self.debugMsg("Process stopped")
			self.button.setText("Start")    
  
def main():
	app = QApplication(sys.argv)
	app.setQuitOnLastWindowClosed(True)
	app.setStyleSheet(open(style_path).read()); #set style according to file 
	ex = AcApp(__title__+__version__)
	app.quit()
	sys.exit(app.exec_())
   
if __name__ == '__main__':
	main()

python-dummy-app Créer un exécutable EXE à partir d'un script Python

N.B.: Si vous souhaitez que des fichiers, comme l’icône, soit bien inclus dans le .EXE, il vous faudra spécifier le chemin absolu dans le script Python.

Afin de générer automatiquement les chemins absolus, vous pouvez utiliser la fonction suivante

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)
	
style_path = resource_path("resources\\ac_style.txt")

Installation du paquet PyInstaller

Pour compiler le projet nous utilisons la librairie PyInstaller, qui permet de créer un fichier exécutable contenant toutes les dépendances nécessaires à l’exécution du code.

Avant d’installer pyinstaller, vérifiez que C:\Users\ADMIN\AppData\Local\Programs\Python\Python38\Scripts est ajouté dans le Path des variables d’environnement.

python -m pip install pyinstaller==5.6.2

N.B.: la version 5.7.0 est sortie mais affiche une erreur de permission

Configuration du fichier install_bat

Nous créons un fichier install_app.bat qui va automatiser le process de compilation. Dans ce fichier, nous spécifions le type de compilation (onefile, noconsole) les librairies (PySide2) et les dossiers à inclure dans l’exécutable (resources)

python -m PyInstaller --noconfirm --log-level=WARN ^
    --onefile --noconsole ^
    --hidden-import=PySide2 ^
    --hidden-import=shiboken2 ^
    --add-data  ./resources;resources ^
    --icon=./resources/logo_araignee.ico ^
    app.py
python-pyinstaller Créer un exécutable EXE à partir d'un script Python

PyInstaller va créer les dossiers build, dist et un fichier app.spec

Le fichier app.spec contient les spécifications de la compilation et le dossier dist le fichier EXE

python-pyinstaller-result Créer un exécutable EXE à partir d'un script Python

Vous pouvez à présent partager ce fichier exécutable à n’importe qui (utilisant le même OS) sans installation particulière de sa part.

Limitations

PyInstaller ne permet pas à partir d’une même machine de compiler pour différents OS. Pour créer une application Windows, vous devez utilisez PyInstaller sur une machine Windows. Il faudra donc le faire pour Linux ou MacOS.

PyInstaller ne contient pas exactement toutes les dépendances. En effet, certaines dépendances sont contenues dans l’OS. Il est donc possible que certaines personnes ne puissent pas faire tourner votre logiciel.

Il est possible de faire une compilation croisée pour différents OS en utilisant un docker.

Sources