web-dev-qa-db-fra.com

Ajouter un fichier de configuration en dehors de Pyinstaller - exefile exe dans le répertoire dist

Situation

J'utilise Pyinstaller sur Windows pour créer un fichier .exe de mon projet.

Je souhaite utiliser --onefile option pour avoir un résultat net et un fichier/programme facile à distribuer.

Mon programme utilise un config.ini fichier pour stocker les options de configuration. Ce fichier peut être personnalisé par les utilisateurs.

Problème

En utilisant --onefile option Pyinstaller a mis tous les "fichiers de données" déclarés à l'intérieur du single .exe fichier fichier.

J'ai vu cela demande mais cela donne des instructions pour ajouter un fichier de bundle à l'intérieur du onefile et non à l'extérieur, au même niveau du .exe et dans le même répertoire dist.

À un moment donné, j'ai pensé à utiliser une commande shutil.copy dans le fichier .spec pour copier ce fichier ... mais je pense que c'est dans le mauvais sens.

Est-ce que quelqu'un peut m'aider? Je l'apprécierai :-)

16
Stefano Giraldi

n référentiel sur Github m'a aidé à trouver une solution à ma question.

J'ai utilisé le module shutil et .spec fichier pour ajouter des fichiers de données supplémentaires (dans mon cas, un config-sample.ini fichier) dans le dossier dist à l'aide de Pyinstaller --onefile option.

Créer un fichier .spec pour pyinstaller

Tout d'abord, j'ai créé un fichier makespec avec les options dont j'ai besoin:

$ pyi-makespec --onefile --windowed --name exefilename scriptname.py

Cette commande crée un exefilename.spec fichier à utiliser avec Pyinstaller

Modifiez exefilename.spec en ajoutant shutil.copyfile

Maintenant, j'ai édité le exefilename.spec en ajoutant à la fin du fichier le code suivant.

import shutil
shutil.copyfile('config-sample.ini', '{0}/config-sample.ini'.format(DISTPATH))
shutil.copyfile('whateveryouwant.ext', '{0}/whateveryouwant.ext'.format(DISTPATH))

Ce code copie les fichiers de données nécessaires à la fin du processus de compilation. Vous pouvez utiliser toutes les méthodes disponibles dans le package shutil.

Exécutez PyInstaller

La dernière étape consiste à exécuter le processus de compilation

pyinstaller --clean exefilename.spec

Le résultat est que dans le dossier dist, vous devez avoir le fichier .exe compilé avec les fichiers de données copiés.

Considération

Dans la documentation officielle de Pyinstaller, je n'ai trouvé aucune option pour obtenir ce résultat. Je pense que cela pourrait être considéré comme une solution de contournement ... qui fonctionne.

7
Stefano Giraldi

Ma solution est similaire à l'excellente solution de @ Stefano-Giraldi. J'obtenais une autorisation refusée lors du passage de répertoires à shutil.copyfile.

J'ai fini par utiliser shutil.copytree:

import sys, os, shutil

site_packages = os.path.join(os.path.dirname(sys.executable), "Lib", "site-packages")
added_files = [
                (os.path.join(site_packages, 'dash_html_components'), 'dash_html_components'),
                (os.path.join(site_packages, 'dash_core_components'), 'dash_core_components'),
                (os.path.join(site_packages, 'plotly'), 'plotly'),
                (os.path.join(site_packages, 'scipy', '.libs', '*.dll'), '.')
                ]
working_dir_files = [
                ('assets', 'assets'),
                ('csv', 'csv'))
                ]

print('ADDED FILES: (will show up in sys._MEIPASS)')
print(added_files)
print('Copying files to the dist folder')

print(os.getcwd())
for tup in working_dir_files:
        print(tup)
        to_path = os.path.join(DISTPATH, tup[1])
        if os.path.exists(to_path):
                if os.path.isdir(to_path):
                        shutil.rmtree(to_path)
                else:
                        os.remove(to_path)
        if os.path.isdir(tup[0]):
                shutil.copytree(tup[0], to_path )
        else:
                shutil.copyfile(tup[0], to_path )

#### ... Rest of spec file
a = Analysis(['myapp.py'],
             pathex=['.', os.path.join(site_packages, 'scipy', '.libs')],
             binaries=[],
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='myapp',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True )

Cela évite le dossier _MEI et l'empêche de copier les fichiers de configuration que vous souhaitez dans votre dossier dist et non dans un dossier temporaire.

J'espère que cela pourra aider.

0
phyatt