失败原因【object object】_py2exe打包oss2和pycryptodome失败问题排查

7a4250a0c9b1764d1345e6bdfb2c9552.png

背景:

最近用python开发一个程序,程序需求在没有安装python的电脑上运行。对比python的打包exe工具之后我选择py2exe(py2exe官方已经不更新,由第三方人员开发维护)。

在使用过程中发现py2exe打包后出现一些文件库丢失,因此特意记录下。

简述:

py2exe是一个Python Distutils扩展,它将Python脚本转换为可执行的Windows程序,无需安装Python即可运行。

这里主要是介绍使用py2exe打包出错的排查思路,py2exe的用法请参考py2exe官网: http://www.py2exe.org/

测试环境:

系统:win10 x64
python3.6.3

依懒:

oss2==2.8.0
py2exe==0.9.3.2  # 下载地址:https://github.com/albertosottile/py2exe/releases
# pycryptodome==3.8.2 安装oss2是会自动下载安装, 安装后的目录名称是Crypto

测试代码app.py

import oss2


class OSSHandler:
    def __init__(self):
        self.endpoint = "endpoint"
        self.auth = oss2.Auth("access_key_id", "access_key_secret")
        self.bucket = oss2.Bucket(self.auth, self.endpoint, "bucket_name")

    def iterator(self):
        """
        遍历bucket文件
        :return:
        """
        for object_info in oss2.ObjectIterator(bucket=self.bucket):
            print(object_info.key)


def main():
    OSSHandler().iterator()


if __name__ == "__main__":
    main()

打包代码setup.py, 注:console要使用终端运行,否则会一闪而过

import py2exe
from distutils.core import setup

py2exe_options = {
    "dist_dir": "dist",
    "compressed": 1,
    "optimize": 2,
    "ascii": 0,
}

setup(
    name='oss',
    version='0.1.0',
    description="win tool",
    options={'py2exe': py2exe_options},
    # 注:console要使用终端运行,否则会一闪而过
    console=[{
        # windows = [{
        "script": "app.py",
    }],
    zipfile="lib/shared.lib",
    data_files=[],
)

打包命令

python setup.py py2exe

报错

运行dist文件夹app.exe得到错误, 发现找不到模块

Traceback (most recent call last):
  File "app.py", line 1, in <module>
    import oss2
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
  File "oss2__init__.pyc", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
  File "oss2models.pyc", line 10, in <module>
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
  File "oss2utils.pyc", line 30, in <module>
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
  File "CryptoCipher__init__.pyc", line 27, in <module>
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 656, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 626, in _load_backward_compatible
  File "CryptoCipher_mode_ecb.pyc", line 47, in <module>
  File "CryptoUtil_raw_api.pyc", line 300, in load_pycryptodome_raw_lib
OSError: Cannot load native module 'Crypto.Cipher._raw_ecb': Trying '_raw_ecb.cp36-win_amd64.pyd': [WinError 126] 找不到指定的模块。, Trying '_raw_ecb.pyd': [WinError 126] 找不到指定的模块。

查看distlibshared.lib文件,用解压工具可以解压查看, 发现py2exe工具没有把*.pyd文件打包进去,导致模块查找失败

ea4dfef501d94ab9706b2a7c5c69647c.png

修改

根据上面的报错信息可以看到模块调用文件位置是"CryptoUtil_raw_api.pyc", line 300

try:
    filename = basename + ext
    # 通过调试发现pycryptodome_filename函数查到不到*.pyd导致出错
    return load_lib(pycryptodome_filename(dir_comps, filename),
                    cdecl)
except OSError as exp:
    attempts.append("Trying '%s': %s" % (filename, str(exp)))

查看pycryptodome_filename函数CryptoUtil_file_system.py

util_lib, _ = os.path.split(os.path.abspath(__file__))
root_lib = os.path.join(util_lib, "..")
# 添加打印信息,查看模块加载位置
print("root_lib: ", root_lib)

return os.path.join(root_lib, *dir_comps)

添加打印信息,查看模块加载位置, 发现目录是shared.lib下面,但*.pyd没有打包进去, 所以只要让程序加载到*.pyd就可以了。

 root_lib:  D:codedistlibshared.libCryptoUtil..

修改*.pyd加载目录, 使root_lib加载目录distlib, 注意:此方法会影响未打包的oss和pycryptodome正常使用

# util_lib, _ = os.path.split(os.path.abspath(__file__))
# root_lib = os.path.join(util_lib, "..")
util_lib = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
root_lib = os.path.join(util_lib, "Crypto")
return os.path.join(root_lib, *dir_comps)

重新打包, 复制Crypto文件夹到distlib下,Libsite-packagesCrypto文件夹只需要保留*.pyd文件,其他的可以删除

发现没有报模块加载不到,而是报*.json文件加载不到

1b547c65c8fc65d15c57d61842b333b3.png

参考上面的方法, 修改Libsite-packagesaliyunsdkcoreutils_init_.py文件

# base_dir = os.path.dirname(os.path.abspath(aliyunsdkcore.__file__))
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(aliyunsdkcore.__file__))))

复制Libsite-packagesaliyunsdkcoredata到distlib下,最终目录

3feb44b53617dcbb19aace5707b67192.png

运行

至此程序就可能正常运行了

通过上面的思路,打包py2exe遇到文件加载不到时,可以通过console模式查找文件加载的目录,然后进行相应的修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值