web-dev-qa-db-ja.com

Pyinstaller --onefile exeの外部の設定ファイルをdistディレクトリに追加します

状況

WindowsでPyinstallerを使用して、プロジェクトの.exeファイルを作成しています。

--onefileオプションを使用して、きれいな結果と簡単にファイル/プログラムを配布したいと思います。

私のプログラムは、設定オプションを格納するためにconfig.iniファイルを使用しています。このファイルはユーザーがカスタマイズできます。

問題

--onefileオプションを使用するPyinstallerは、宣言されたすべての「データファイル」を単一の.exeファイルファイル内に配置します。

私はこれを見た request だが、バンドルファイルを追加するように指示する onefile内 外ではなく、.exeと同じレベルで、同じdistディレクトリにあります。

ある時点で、このファイルをコピーするために.specファイル内でshutil.copyコマンドを使用することを考えましたが、間違った方法だと思います。

誰か助けてもらえますか?感謝します:-)

16
Stefano Giraldi

Github上のリポジトリ は、私の質問に対する解決策を見つけるのに役立ちました。

shutilモジュールと.specファイルを使用して、Pyinstaller config-sample.iniオプションを使用してdistフォルダーに追加のデータファイル(私の場合は--onefileファイル)を追加しました。

Pyinstallerの.specファイルを作成する

まず、必要なオプションを指定してmakespecファイルを作成します。

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

このコマンドは、Pyinstallerで使用するexefilename.specファイルを作成します

Exefilename.specを変更して、shutil.copyfileを追加します。

これで、exefilename.specを編集して、ファイルの最後に次のコードを追加しました。

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

このコードは、コンパイルプロセスの最後に必要なデータファイルをコピーします。 shutilパッケージで利用可能なすべてのメソッドを使用できます。

PyInstallerを実行する

最後のステップはコンパイルプロセスを実行することです

pyinstaller --clean exefilename.spec

その結果、distフォルダーには、コンパイルされた.exeファイルとコピーされたデータファイルが必要です。

考慮

Pyinstallerの公式ドキュメントでは、この結果を得るオプションが見つかりませんでした。私はそれが回避策と考えることができると思います...それはうまくいきます。

7
Stefano Giraldi

私の解決策は、@ Stefano-Giraldiの優れた解決策に似ています。ディレクトリをshutil.copyfileに渡すと、アクセスが拒否されました。

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 )

これにより、_MEIフォルダーが回避され、一時フォルダーではなくdistフォルダーに必要な構成ファイルがコピーされなくなります。

お役に立てば幸いです。

0
phyatt