14

pytzを利用するアプリケーションの配布に問題があります。Py2Exeを使用して、Python ソースから実行可能ファイルを作成しています。

私が抱えている問題の簡単な例として、pytz_test.py:

import pytz

tz_au = pytz.timezone("Australia/Sydney")
print tz_au

そしてsetup.pyで:

from distutils.core import setup
import py2exe

setup(console=['pytz_test.py'], options={"py2exe" : { 'packages': ['pytz'], } })

次に、setup.py を実行します。

python setup.py py2exe

実行可能ファイルをコンパイルします。作成したpytz_test.exeを実行すると、次のようになります。

Traceback (most recent call last):
  File "pytz_test.py", line 3, in <module>
    tz_au = pytz.timezone("Australia/Sydney")
  File "pytz\__init__.pyc", line 185, in timezone
pytz.exceptions.UnknownTimeZoneError: 'Australia/Sydney'

タイムゾーン情報が実行可能ファイルにバンドルされていないためだと思いますが、それを実現する方法がわかりません。

編集:簡単な解決策は、python site-packages ディレクトリのpytzモジュールから、zoneinfoディレクトリをlibrary.zipに追加することです。

これを自動的に行うために、Google Transit Data Feed使用 したプロジェクトのソリューションに従いました。

変更したsetup.pyは次のようになります。

from distutils.core import setup
import glob
import py2exe

options = {
    "py2exe" : { 
        "compressed": 1, 
        "optimize": 2,
        'packages': ['pytz'], 
     } 
}

setup(console=['pytz_test.py'], options=options)

import pytz
import os 
import zipfile
zipfile_path = os.path.join("dist/" 'library.zip')
z = zipfile.ZipFile(zipfile_path, 'a')
zoneinfo_dir = os.path.join(os.path.dirname(pytz.__file__), 'zoneinfo')
disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__))
for absdir, directories, filenames in os.walk(zoneinfo_dir):
    assert absdir.startswith(disk_basedir), (absdir, disk_basedir)
    zip_dir = absdir[len(disk_basedir):]
    for f in filenames:
      z.write(os.path.join(absdir, f), os.path.join(zip_dir, f))

z.close()
4

2 に答える 2

3

zoneinfo を手動で圧縮すると (Jason S が説明したように)、実際に私のコンピューターの 1 つでパッケージをビルドするのに役立ちました。しかし、別のコンピューターでパッケージをビルドすると、エラーが再発しました。理由を見つけるのに時間がかかったので、共有したいと思います。

提案されたソリューションは、新しい pytz バージョン (少なくとも 2014.7) では機能しません! pytz が zoneinfo ファイルの形式を pyc から何らかのバイナリ形式に変更したことが明らかになった理由を掘り下げます。私には、Pythonの組み込みのzipimportメカニズムがバイナリファイルのロードには機能しないため、この変更により、pytzをzipにパックするオプションが「壊れた」ように見えます。実際、この問題は pytz で修正する必要がありますが、今のところ別の解決策を見つけました。

  • pytz ディレクトリ全体を dist ディレクトリに直接コピーするだけです
  • プログラム内で、メイン実行可能ファイルのパスを python の検索パスに追加します

実際には、これはsetup.py内で pytz-zipping を次のように置き換えることを意味します

import pytz, os, shutil
srcDir = os.path.dirname( pytz.__file__ )
dstDir = os.path.join( 'dist', 'pytz' )
shutil.copytree( srcDir, dstDir, ignore = shutil.ignore_patterns('*.py') )

pytz を「packages」オプションから「excludes」に移動します。

options = {
    "py2exe" : { 
        "compressed": 1, 
        "optimize": 2,
        "packages": [],
        "excludes": ['pytz']
     } 
}

プログラムのメイン エントリに (pytz をインポートする前に実行されるようにするため)、次のようなものを追加する必要があります。

import os, sys
basePath = os.path.dirname( os.path.abspath( sys.argv[0] ) )
sys.path.insert( 0, basePath )
于 2014-10-27T13:18:33.733 に答える
3

簡単な解決策は、python site-packages ディレクトリのpytzモジュールから、zoneinfoディレクトリをlibrary.zipに追加することです。

これを自動的に行うために、Google Transit Data Feedが使用 したプロジェクトのソリューションに従いました。

変更したsetup.pyは次のようになります。

from distutils.core import setup
import glob
import py2exe

options = {
    "py2exe" : { 
        "compressed": 1, 
        "optimize": 2,
        'packages': ['pytz'], 
     } 
}

setup(console=['pytz_test.py'], options=options)

import pytz
import os 
import zipfile
zipfile_path = os.path.join("dist/" 'library.zip')
z = zipfile.ZipFile(zipfile_path, 'a')
zoneinfo_dir = os.path.join(os.path.dirname(pytz.__file__), 'zoneinfo')
disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__))
for absdir, directories, filenames in os.walk(zoneinfo_dir):
    assert absdir.startswith(disk_basedir), (absdir, disk_basedir)
    zip_dir = absdir[len(disk_basedir):]
    for f in filenames:
      z.write(os.path.join(absdir, f), os.path.join(zip_dir, f))

z.close()

(質問者さんからの回答)

于 2014-08-02T18:05:33.503 に答える