在Windows 98上通过网络访问py2exe程序时出现ImportErrors

2 投票
1 回答
613 浏览
提问于 2025-04-15 17:40

我正在一台服务器上运行一个用py2exe编译的Python程序,这个程序在多台客户端机器上运行(每台机器都映射到一个网络驱动器,比如说W:)。

对于Windows XP及以后的机器,到目前为止,我没有遇到任何问题,Python可以顺利找到W:\python23.dll(是的,我使用的是Python 2.3.5,以便兼容Windows 98等)。然后它会使用W:\zlib.pyd来解压W:\library.zip,这个压缩包里包含了所有的.pyc文件,比如os等模块,然后这些模块被导入,程序就可以正常运行了。

我遇到的问题是在一些Windows 98 SE机器上(注意:并不是所有Windows 98 SE机器都有这个问题,有些机器似乎没有任何问题)。问题是,程序从W:运行,W:\python23.dll应该是能找到的(因为我收到了Python的导入错误,我们需要能够执行Python的导入语句),但是有几个地方不工作:

1) 如果W:\library.zip里只有一份.pyc文件,我会收到 ZipImportError: can't decompress data; zlib not available(这说不通,因为W:\zlib.pyd是可用的,并且在同一网络上的XP及更高版本的机器上运行良好)。

2) 如果.pyc文件实际上是通过py2exe打包到python可执行文件里的,或者放在与.exe相同的目录下,或者放在一个命名的子目录中并将其设置为PYTHONPATH变量的一部分(例如W:\pylib),我会收到ImportError: no module named os(os是第一个被导入的模块,在sys和其他模块之前)。

想想看,如果在导入os之前sys.path不可用的话,会不会导致这个问题?我会尝试调整这些导入的顺序,但我的问题依然存在:为什么这是一个偶发性的问题,在某些网络上工作而在其他网络上不工作?我该如何强制Python找到那些打包在我运行的可执行文件里的文件?我可以立即访问正常工作的Windows 98 SE机器,但我每天早上在客户店开门前才能接触到不工作的那台机器。

提前谢谢!


编辑:好的,进展很大。通过使用PY2EXE_VERBOSE进行调试,特定W98SE机器上出现的问题是,它在查找导入时没有使用正确的路径语法。首先,它似乎没有读取PYTHONPATH环境变量(可能有一个我不知道的py2exe特定的变量,比如PY2EXE_VERBOSE)。

其次,它只在一个地方查找,然后就放弃了(如果文件打包在EXE里,它就只查找那里。如果没有,它就查找library.zip)。

编辑2:事实上,根据这个链接,Python解释器中的sys.path和Py2exe可执行文件中的sys.path是有区别的。具体来说,sys.path只包含一个条目:共享代码档案的完整路径名。真是无奈。没有后备方案?连当前工作目录都没有?我想尝试将W:\添加到PATH,但py2exe并不遵循任何标准来定位系统库,所以这也不行。

现在有趣的部分来了。它尝试从以下路径加载atexit、os等模块:

W:\\library.zip\<module>.<ext>

注意library.zip后面是单斜杠,而驱动器字母后面是双斜杠(如果这是有意为之并且应该工作,请有人纠正我)。看起来如果这是一个字符串字面量,由于斜杠没有加倍,它被视为一个(无效的)转义序列,原始字符被打印出来(导致W:\library.zipos.pyd, W:\library.zipos.dll, ...而不是带斜杠的);如果它不是字符串字面量,双斜杠可能不会自动进行规范化(应该是这样),所以双斜杠会让模块加载器困惑。就像我说的,我不能简单地set PYTHONPATH=W:\\library.zip\\,因为它会忽略这个变量。

在我的程序开始时使用sys.path.append可能是值得一试,但硬编码模块路径是绝对的最后手段,特别是因为这个问题只在一个过时的操作系统的配置中出现。

有什么想法吗?我有一个想法,就是对sys.path进行规范化……可惜我需要os模块来做到这一点。另一个想法是将os.getenv('PATH')os.getenv('PYTHONPATH')添加到sys.path……同样,我需要os模块。site模块也无法初始化,所以我不能使用.pth文件。

我最近在程序开始时尝试了以下代码:

for pth in sys.path:
    fErr.write(pth)
    fErr.write(' to ')
    pth.replace('\\\\','\\') # Fix Windows 98 pathing issues
    fErr.write(pth)
    fErr.write('\n')

但它无法加载linecache.pyc,或者其他任何东西;看起来它实际上无法执行那些命令。有没有办法使用内置功能而不需要linecache来动态修改sys.path?还是我只能硬编码正确的sys.path?

1 个回答

2

这不是直接的答案,但可能会对你有点帮助。你知道Python中的-v选项吗?可以输入python -h来了解更多信息。需要注意的是,对于用py2exe打包的脚本,PYTHONVERBOSE环境变量的对应项是PY2EXE_VERBOSE,这个信息几乎没有地方提到,除了作者的这篇帖子。显然,它可以取1或2的值,基本上就像-v-vv,不过这和PYTHONVERBOSE的工作方式稍有不同。

关于你的sys.path想法也要注意:你是否已经导入了sys模块,对能否导入os没有影响。也就是说,Python的路径(在sys.path中可见)总是可用的,因为它反映了解释器的一个内部特性,无论你是否导入了sys模块,这个特性都是存在的。

像其他一些模块一样,sys是内置的,所以即使你的应用几乎完全不能用,它也应该始终可以导入。如果有帮助的话,你可以使用sys.builtin_module_names来查看你所用Python版本的内置模块。如果解释器能运行,这些信息就会可用,因此以下代码可能是你能写的最简单的程序,用来查看你有什么:

import sys
print sys.builtin_module_names

另外,我建议不要尝试一些复杂的操作,比如把.pyc文件打包到.exe里。你已经在支持Win98方面遇到不少困难,如果我是你,我会选择最简单的方法来完成工作,然后再去做更有趣的事情。如果你能正常安装Python并从源代码运行,绝对应该考虑这样做!:)

编辑:根据darvids0n的评论,添加了关于PY2EXE_VERBOSE信息的链接。

撰写回答