pyinstaller似乎找不到数据文件
编辑3:我把 __file__
替换成了 sys.argv[0]
,这样我就能知道我的脚本或可执行文件的位置。虽然这两者不完全一样,但在我的情况下运行得很好(至少在可执行版本上是这样)。现在一切都正常了,使用了一种被接受的答案中的方法来访问资源文件,所有功能都在单文件模式下正常工作!
编辑2:正如被接受的答案中的评论所示,问题出在我的脚本路径解析上;我试图使用 __file__
来获取脚本的位置,以便访问它的资源文件。但一旦打包后,这个方法就不管用了,因为 __file__
会返回来自 Python.dll
的文件名,这样几乎总是没有路径,只有文件名。因此,我必须找到其他方法来访问资源文件;目前的一个变通办法是把当前目录移动到可执行文件的路径。
顺便说一下,这意味着 ConfigParser 在访问文件时应该报告问题,而不是说某个部分缺失。
我会更新这个问题,告诉大家我是如何解决这个路径解析问题的。
我在使用 pyinstaller
时遇到了问题,因为这是我第一次使用它,肯定是我做错了什么。
所以,问题是这样的:pyinstaller
在我写的脚本上运行得很顺利,并在 dist
文件夹中生成了一些东西。好的,现在我想执行它,看看一切是否正常,但我得到了以下结果:
C:\Program Files\PyInstaller\pyinstaller-1.5.1>p_tool\dist\p_tool\p_tool.exe -?
Traceback (most recent call last):
File "<string>", line 104, in <module>
File "p_tool\build\pyi.win32\p_tool\outPYZ1.pyz/logging.config", line 76, in f
ileConfig
File "p_tool\build\pyi.win32\p_tool\outPYZ1.pyz/logging.config", line 112, in
_create_formatters
File "p_tool\build\pyi.win32\p_tool\outPYZ1.pyz/ConfigParser", line 532, in ge
t
ConfigParser.NoSectionError: No section: 'formatters'
我最初的想法是 logging.conf
文件缺失,所以我在 p_tool.spec
文件中添加了它(还有一些其他资源文件),但情况并没有好转。
Python 版本:2.6.6,运行在 WinXP 上。我使用 pyinstaller
是因为我需要将文件打包到 Solaris 工作站。
那么,有人遇到过这个问题吗?唯一相关的话题是以下问题:PyInstaller 问题,与我的问题非常接近,但可惜的是没有得到答案。
编辑3:与日志相关的细节已删除,因为与问题并不太相关。
3 个回答
这个错误信息 ConfigParser.NoSectionError: No section: 'formatters'
的意思是,问题不是文件丢失了,而是文件里缺少了一个叫做 'formatters' 的部分。
我遇到过类似的问题,但到现在为止还没找到一个优雅的解决办法。我用的“窍门”是这样的:假设我的项目放在 '~/project/project_root'
这个位置,首先在 .spec 文件中:
excluded_sources = TOC([x for x in a.pure if not x[0].startswith('project_root')])
这里的 a
是一个 Analysis
对象,基本上我把我项目里的所有文件从 PYZ
中移除了,这样就不会有任何导入从这里传递过去,日志的相对路径也不会从这里计算。之后,我从项目中创建一个 Tree
对象。
my_project_tree = Tree('~/project')
然后把这个 Tree 加入到传递给 COLLECT 的 TOC 列表中,所以:
COLLECT( exe,
a.binaries,
a.zipfiles,
a.datas,
my_project_tree,
....)
这样你就应该能把你的项目文件夹添加到 dist 文件夹里。问题是,这样你也会把项目的 pyc 文件一起分发出去,但到现在为止我还没找到更好的办法。我对有效的解决方案非常感兴趣。
首先,在读取配置文件之前,最好先打印一下配置文件的路径和它是否存在,这样你就能确认文件在哪里,Python能否找到它。
至于如何实际访问这个文件,os.path.split(__file__)
看起来差不多是对的,但我不确定在使用 pyinstaller 时它是否能正常工作。正确的打包文件的方法是把它们添加到 .spec 文件中,pyinstaller 会在编译时加载这些文件,并在运行时把它们解压到 $_MEIPASS2/ 目录下。为了在打包模式下获取 _MEIPASS2 目录,并在解压(开发)模式下使用本地目录,我使用了以下代码:
def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
# in development
>>> resource_path("logging.conf")
"/home/shish/src/my_app/logging.conf"
# in deployment
>>> resource_path("logging.conf")
"/tmp/_MEI34121/logging.conf"