使用 Py2Exe 编译的 Python 应用程序引发 UnknownTimezoneError 异常
Posted
技术标签:
【中文标题】使用 Py2Exe 编译的 Python 应用程序引发 UnknownTimezoneError 异常【英文标题】:UnknownTimezoneError Exception Raised with Python Application Compiled with Py2Exe 【发布时间】:2012-02-27 20:28:42 【问题描述】:我在分发使用 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'
我认为这是因为时区信息没有与可执行文件捆绑在一起,但我不确定如何实现。
编辑: 一个简单的解决方案是将 zoneinfo 目录从 python site-packages 目录中的 pytz 模块添加到 library.zip。
为了自动执行此操作,我遵循了 Google Transit Data Feed 项目中使用的解决方案,来自: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py
我修改后的 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()
【问题讨论】:
您还需要当前版本的 setuptools。特别是 pkg_resources。 'import pkg_resources' 不能失败。pkg_resources
到底在哪里使用?还是直接导入?
【参考方案1】:
手动压缩 zoneinfo(如 Jason S 所述)确实有助于在我的一台计算机上构建包。 但是,当我在另一台计算机上构建软件包时 - 错误又回来了! 找到原因花了我一段时间 - 所以我最好分享一下。
建议的解决方案不适用于新的 pytz 版本(至少对于 2014.7)! 挖掘为什么会发现 pytz 将 zoneinfo 文件的格式从 pyc 更改为某种二进制格式。在我看来,通过这种更改,他们“打破”了将 pytz 打包成 zip 的选项,因为 python 的内置 zipimport 机制不适用于加载二进制文件。 其实这个问题应该由 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 )
【讨论】:
这对我有用 (pytz 2014.10),但我必须从 shutil.copytree() 中删除所有忽略。 是的!有效!最奇怪的是,我的 pytz 和 py2exe 正在工作。然后我在我的程序中修改了一些东西,完全与pytz无关,突然停止工作并给出了UnkownTimeZoneError 言下之意,完全正确!那也是我的问题。而且由于(至少对我而言)py2exe 的作用以及它如何收集它的东西并不总是很明显,我什至不得不将调试打印破解到 pytz 以找出在 py2exe 的收集阶段出了什么问题。 :-) 为我工作。谢谢你:) 我还没有添加以下行: os.environ.setdefault('PYTZ_TZDATADIR', f'basePath\\pytz\\zoneinfo') 因为它仍然没有找到数据。 【参考方案2】:一个简单的解决方案是将 zoneinfo 目录从 python site-packages 目录中的 pytz 模块添加到 library.zip em>。
为了自动执行此操作,我遵循了 Google Transit Data Feed 项目使用的解决方案,来自: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py
我修改后的 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()
(由提问者回答)
【讨论】:
以上是关于使用 Py2Exe 编译的 Python 应用程序引发 UnknownTimezoneError 异常的主要内容,如果未能解决你的问题,请参考以下文章
是否有与 python 3.5 兼容的 py2exe 版本?
python编写游戏怎么打包——详解python+pygame游戏开发之使用Py2exe打包游戏为exe文件
python编写游戏怎么打包——详解python+pygame游戏开发之使用Py2exe打包游戏为exe文件