在Windows 98上通过网络访问py2exe程序时出现ImportErrors
我正在一台服务器上运行一个用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 个回答
这不是直接的答案,但可能会对你有点帮助。你知道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信息的链接。