bugfix> python > 投稿

(参考までに、integrate-mathmodはmasterにマージされました。)

私はコンパイルしていました gettext ローカライズされた(英語とフランス語、しかしおそらく将来的にはもっと)Pythonスクリプト pyinstaller --onefile palc.py 完全にコンパイルされますが、実行しようとすると、に保存されているロケールを使用しようとします。 locales ディレクトリ(パッケージを配布しないと見つからないことを意味します locales ディレクトリ)。ご想像のとおり、これは大きな欠点であり、PyInstallerのポイントをかなり台無しにします。配布するには、パッケージと一緒にディレクトリを指定して、パッケージを機能させる必要があります。ただし、これから説明します。見せてください、それでも動作しません。

主な質問は次のとおりです。

出来ますか(できれば、それほど難しくないか、大幅な書き換えが必要なもの)PyInstallerにPythonスクリプトをコンパイルさせるには gettext ロケール?

編集:私は自分の編集を試みました palc.spec 、ここに新しいバージョンがあります:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['palc.py'],
             pathex=['~/python-text-calculator'],
             binaries=[],
             datas=[('~/python-text-calculator/locales/*', 'locales')],
             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,
          [],
          exclude_binaries=True,
          name='palc',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='palc')

そして、コンパイルされたパッケージの出力は次のとおりです。

                                  Type 'help' to know the ton of Elive features available...
>>> ./palc
--------------------------------------------------------------------------
                          Language Selection
--------------------------------------------------------------------------
1 - English // Anglais
2 - Francais // French
Type: 1
Traceback (most recent call last):
  File "/Users/computer/python-text-calculator/palc.py", line 30, in <module>
    l_translations = gettext.translation('base', localedir='locales', languages=["en"])
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/gettext.py", line 514, in translation
    raise OSError(ENOENT, 'No translation file found for domain', domain)
FileNotFoundError: [Errno 2] No translation file found for domain: 'base'
[19393] Failed to execute script palc

これは以前とまったく同じ出力ですなし編集 palc.spec 。さらに、コンパイルされたパッケージをディレクトリ(私は走った ./palcpalc ディレクトリはdist)なので、ディレクトリを配布する必要があります。必要なのは、見つかったような単一のファイルですここに。

誰か助けてもらえますか?ありがとう! :D

回答 2 件
  • まず、スペックファイルが生成されたら、Pythonファイルではなくスペックファイルをpysintallerに提供します。run pyinstaller palc.spec の代わりに pyinstaller palc.py 。それ以外の場合、pyinstallerは毎回スペックファイルをリセットします。

    次に、onefileアプリケーションの正しいスペックファイルを生成するには、次を使用します。 pyi-makespec --onefile palc.py 。それはなしでスペックファイルを生成します COLLECT ステップ、そして別の EXE ステップ。

    次に、スペックファイルでカスタムPython関数を使用してビルドできます datas ロケールの場合(スペックファイルはカスタムファイル拡張子を持つ単なるPythonファイルであることを忘れないでください):

    def get_locales_data():
        locales_data = []
        for locale in os.listdir(os.path.join('./locales')):
            locales_data.append((
                os.path.join('./locales', locale, 'LC_MESSAGES/*.mo'),
                os.path.join('locales', locale, 'LC_MESSAGES')
            ))
        return locales_data
    
    

    次に、この関数の戻り値を、のデータパラメータの値として使用します。 Analysis ステップ:

    a = Analysis(['palc.py'],
                 ...
                 datas=get_locales_data(),
                 ...)
    
    

    次に、正しい場所でロケールファイルを探すようにコードを調整する必要があります(ランタイム環境に応じて:パッケージ化されているかどうか)が、答えのこの部分を開発する時間がないので、これについて議論するスレッドがあります。 ;)


    便宜上、以下はpyi-makespecで生成され、ロケールを含むように変更された正しいspecfileの例です。

    # -*- mode: python ; coding: utf-8 -*-
    import os
    block_cipher = None
    
    def get_locales_data():
        locales_data = []
        for locale in os.listdir(os.path.join('./locales')):
            locales_data.append((
                os.path.join('./locales', locale, 'LC_MESSAGES/*.mo'),
                os.path.join('locales', locale, 'LC_MESSAGES')
            ))
        return locales_data
    
    a = Analysis(['palc.py'],
                 pathex=['.'],
                 binaries=[],
                 datas=get_locales_data(),
                 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='palc',
              debug=False,
              bootloader_ignore_signals=False,
              strip=False,
              upx=True,
              upx_exclude=[],
              runtime_tmpdir=None,
              console=True )
    
    
    

  • まあ事は:
    あなたの新しい .spec ファイルが正しい場合は、バンドルに必要なファイルと、それらをバンドル内のどこに配置するかを指定します。

    それはあなたがそれらにアクセスする方法があなたに苦痛を引き起こしているものです。
    この線 l_translations = gettext.translation('base', localedir='locales', languages=["en"]) エラーコードから、ファイルがあるディレクトリをリストすることをお勧めします locales あなたが彼らがそこにいるべきだと言ったので、それは実際に理にかなっています...しかし方法 PyInstaller 作品は少し異なります。 1つのファイルとしてバンドルしているため、実際には別の場所で開かれます。 bootloader
    それを修正する方法:
    dirを指定する代わりに locales 次のように変更します。

    from os import path
    bundle_dir = getattr(sys, '_MEIPASS', path.abspath(path.dirname(__file__))) # get the bundle dir if bundled or simply the __file__ dir if not bundled
    locales_dir = path.abspath(path.join(bundle_dir, 'locales'))
    
    

    locales_dir バンドルしたディレクトリを指します PyInstaller

    P.S.
    それがエラーを引き起こす場合(そうすべきではありません)、 Analasis データセクションから datas=[('~/python-text-calculator/locales', 'locales')],

あなたの答え