146

イメージとアイコンを含める PyInstaller を使用して、1 ファイルの EXE を構築しようとしています。私は一生それを使うことができません--onefile

私が--onedirそれを行うと、すべてが非常にうまく機能します。を使用する--onefileと、参照されている追加ファイルが見つかりません (コンパイルされた EXE を実行している場合)。2 つのイメージだけでなく、DLL と他のすべてが正常に検出されます。

EXEの実行時に生成されたtemp-dir(\Temp\_MEI95642\たとえば)を調べたところ、ファイルは実際にそこにあります。その一時ディレクトリにEXEをドロップすると、それらが見つかります。非常に当惑します。

これは私が.specファイルに追加したものです

a.datas += [('images/icon.ico', 'D:\\[workspace]\\App\\src\\images\\icon.ico',  'DATA'),
('images/loaderani.gif','D:\\[workspace]\\App\\src\\images\\loaderani.gif','DATA')]     

サブフォルダーにも入れないようにしましたが、違いはありませんでした。

編集: PyInstaller の更新により、新しい回答を正しいものとしてマークしました。

4

14 に答える 14

205

新しいバージョンのPyInstallerはenv変数を設定しなくなったため、Shishの優れた答えは機能しません。これで、パスは次のように設定されsys._MEIPASSます。

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)
于 2012-12-09T19:08:32.747 に答える
58

pyinstaller は、データを一時フォルダーに解凍し、このディレクトリ パスを_MEIPASS2環境変数に格納します。パック モードで dirを取得し、_MEIPASS2展開 (開発) モードでローカル ディレクトリを使用するには、次のようにします。

def resource_path(relative):
    return os.path.join(
        os.environ.get(
            "_MEIPASS2",
            os.path.abspath(".")
        ),
        relative
    )

出力:

# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"

# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"
于 2011-10-06T13:36:18.447 に答える
46

アプリケーションが PyInstalled でない (つまり、設定されていない) 場合、他のすべての回答は現在の作業ディレクトリsys._MEIPASSを使用します。スクリプトがあるディレクトリ以外のディレクトリからアプリケーションを実行できないため、これは間違っています。

より良い解決策:

import sys
import os

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)
于 2017-06-04T10:07:27.420 に答える
8

提案どおりにすべてのパス コードを書き直す代わりに、作業ディレクトリを変更しました。

if getattr(sys, 'frozen', False):
    os.chdir(sys._MEIPASS)

この 2 行をコードの先頭に追加するだけで、残りはそのままにしておくことができます。

于 2016-04-06T16:09:18.147 に答える
4

Maxからの優れた回答と、画像や音声などの追加データ ファイルの追加に関するこの投稿と、私自身の調査/テストを使用して、そのようなファイルを追加する最も簡単な方法を見つけました。

実際の例を見たい場合は、私のリポジトリがGitHub にあります。

注: これは、pyinstallerで--onefileorコマンドを使用してコンパイルするためのものです。-F

私の環境は以下の通りです。


2ステップで問題を解決

この問題を解決するには、アプリケーションに「バンドル」する必要がある余分なファイルがあることを Pyinstaller に具体的に伝える必要があります。

また、「相対」パスを使用する必要もあります。これにより、アプリケーションが Python スクリプトまたは Frozen EXE として実行されているときに適切に実行できるようになります。

そうは言っても、相対パスを持つことができる関数が必要です。Max Posted関数を使用すると、相対パスを簡単に解決できます。

def img_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)

上記の関数をこのように使用して、アプリがスクリプトまたは凍結された EXE として実行されているときにアプリケーション アイコンが表示されるようにします。

icon_path = img_resource_path("app/img/app_icon.ico")
root.wm_iconbitmap(icon_path)

次のステップは、アプリケーションの実行時に追加ファイルが一時ディレクトリに作成されるように、コンパイル時に追加ファイルを見つける場所を Pyinstaller に指示する必要があることです。

ドキュメントに示されているように、この問題を 2 つの方法で解決できますが、個人的には自分の .spec ファイルを管理する方が好きなので、その方法で行います。

まず、すでに .spec ファイルが必要です。私の場合、追加の引数を指定して実行することで、必要なものを作成できました。ここでpyinstaller追加の引数を見つけることができます。このため、私のスペック ファイルはあなたのものとは少し異なるように見えるかもしれませんが、重要な部分を説明した後、参考のためにすべてを投稿します。

added_filesは本質的にタプルを含むリストです。私の場合、単一の画像のみを追加したいのですが、複数の ico、png、または jpg を使用して追加でき('app/img/*.ico', 'app/img')ますadded_files = [ (), (), ()]

タプルの最初の部分では、追加するファイルまたはファイルの種類と、それらを見つける場所を定義します。これを CTRL+C と考えてください

タプルの 2 番目の部分は、Pyinstaller に、パス 'app/img/' を作成し、.exe を実行したときに作成される一時ディレクトリに関連するディレクトリにファイルを配置するように指示します。これを CTRL+V と考えてください。

の下a = Analysis([main...に を設定datas=added_filesしました。元々はそうdatas=[]でしたが、インポートのリストをインポートしたいので、カスタム インポートを渡します。

EXE の特定のアイコンが必要でない限り、これを行う必要はありません。spec ファイルの下部で、Pyinstaller にオプションで exe のアプリケーション アイコンを設定するように指示していますicon='app\\img\\app_icon.ico'

added_files = [
    ('app/img/app_icon.ico','app/img/')
]
a = Analysis(['main.py'],
             pathex=['D:\\Github Repos\\Processes-Killer\\Process Killer'],
             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='Process Killer',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True , uac_admin=True, icon='app\\img\\app_icon.ico')

EXE へのコンパイル

私はとても怠け者です。必要以上にタイピングするのは好きではありません。クリックするだけの .bat ファイルを作成しました。これを行う必要はありません。このコードは、コマンド プロンプト シェルで問題なく実行されます。

.spec ファイルにはすべてのコンパイル設定と引数 (別名オプション) が含まれているため、その .spec ファイルを Pyinstaller に渡すだけです。

pyinstaller.exe "Process Killer.spec"
于 2020-05-03T04:26:59.773 に答える
3

受け入れられた回答へのわずかな変更。

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)

    return os.path.join(os.path.abspath("."), relative_path)
于 2015-08-17T10:31:08.330 に答える
0

既存の回答がわかりにくく、問題がどこにあるのかを突き止めるのに長い時間がかかりました。これが私が見つけたすべての編集です。

アプリを実行すると、エラーが発生しますFailed to execute script foo(foo.pyメイン ファイルの場合)。--noconsoleこれをトラブルシューティングするには、PyInstaller を(または編集main.specして変更console=False=>で)実行しないでくださいconsole=True。これで、コマンドラインから実行可能ファイルを実行すると、失敗が表示されます。

最初に確認することは、余分なファイルが正しくパッケージ化されていることです。('x', 'x')フォルダーを含めたい場合のように、タプルを追加する必要がありますx

クラッシュした後は、[OK] をクリックしないでください。Windows を使用している場合は、Search Everythingを使用できます。ファイルの 1 つを探します (例: sword.png)。ファイルを解凍した一時パスを見つける必要があります (例: C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png)。このディレクトリを参照して、すべてが含まれていることを確認できます。この方法で見つからない場合は、main.exe.manifest(Windows) またはpython35.dll(Python 3.5 を使用している場合) などを探してください。

インストーラーにすべてが含まれている場合、次に考えられる問題はファイル I/O です。Python コードは、一時ディレクトリではなく、実行可能ファイルのディレクトリでファイルを探します。

それを修正するために、この質問の答えはどれでも機能します。個人的には、それらすべての混合が機能することがわかりました。メインのエントリポイントファイルで最初に条件付きでディレクトリを変更すると、他のすべてがそのまま機能します。

if hasattr(sys, '_MEIPASS'): os.chdir(sys._MEIPASS)

于 2016-12-18T19:56:58.633 に答える
0

私は最大の解決策に基づいてこれを使用します

def getPath(filename):
    import os
    import sys
    from os import chdir
    from os.path import join
    from os.path import dirname
    from os import environ
    
    if hasattr(sys, '_MEIPASS'):
        # PyInstaller >= 1.6
        chdir(sys._MEIPASS)
        filename = join(sys._MEIPASS, filename)
    elif '_MEIPASS2' in environ:
        # PyInstaller < 1.6 (tested on 1.5 only)
        chdir(environ['_MEIPASS2'])
        filename = join(environ['_MEIPASS2'], filename)
    else:
        chdir(dirname(sys.argv[0]))
        filename = join(dirname(sys.argv[0]), filename)
        
    return filename
于 2020-09-21T17:35:38.980 に答える