环境方面:win10 64位、python 3.7、pycharm
主要涉及的第三方包:
1、aliyun-python-sdk-core-v3 2.13.3(阿里云的python核心包)。
2、pyinstaller 3.4(打包用,顺便记一下,这个也有坑,打包的时候会报一个“typeerror:expected str,bytes or os.path,not None type”,解决方法参考这里)。
好,开始说事儿...
======================================================================================
一、问题:
事情是这样子的,最近在接触python,想做个功能,每天定时给手机发一些通知短信。想着大厂靠谱,就选了阿里云的短信服务。
一系列的申请流程这些就不说了,按照阿里云上面的文档测试下来基本没什么问题,但是最后功能做好,pycharm上运行也没问题,成功发送了短信到手机上。
但是!!!!想着用pyinstaller打包成可执行的exe文件扔到服务器上,结果打包后一执行,报错了。
报的是找不到一个aliyunsdkcore\data\retry_config.json文件,具体如下:
Traceback (most recent call last):
File "daily_weather.py", line 5, in <module>
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "d:\develop\python\ds_weather\venv\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "fmt_weather.py", line 3, in <module>
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "d:\develop\python\ds_weather\venv\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "tools.py", line 6, in <module>
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "d:\develop\python\ds_weather\venv\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "aliyunsdkcore\client.py", line 44, in <module>
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "d:\develop\python\ds_weather\venv\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "aliyunsdkcore\retry\retry_policy.py", line 33, in <module>
File "aliyunsdkcore\retry\retry_condition.py", line 219, in __init__
File "aliyunsdkcore\utils\__init__.py", line 23, in _load_json_from_data_dir
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Lhy\\AppData\\Local\\Temp\\_MEI152442\\aliyunsdkcore\\data\\retry_config.json'
[12396] Failed to execute script daily_weather
看报错,是“aliyunsdkcore\utils\__init__.py”这个东东在load一个文件的时候load不到,查下该文件源码:
总结了下,就是,这里引用了外部文件,而且是通过获取当前文件绝对路径的父级路径,再拼接data文件夹和文件名的方式来获取外部文件。
实际去查一下,拼接出来的这个路径下就3个json文件,如下图:
然后,在ide运行的时候,读取的路径就是环境下的Lib/site-packages/aliyunsdkcore/data/*,所以能正常读取。
但问题就在于,pyinstaller打包的时候,并没有把这个data文件夹里面的几个文件打包进去,而且pyinstaller打包出来的可执行文件,执行的时候,会在系统的C:\Users\UserName\AppData\Local\Temp\路径下创建一个临时文件夹来放要执行的文件,这个时候上面说的那个取绝对路径的时候才会取到了报错的这个地址,报错才会报的是“C:\\Users\\Lhy\\AppData\\Local\\Temp\\_MEI132922\\aliyunsdkcore\\data\\retry_config.json”这个路径下找不到对应的文件。
二、解决:
那问题找到了,自然就有办法解决。像这种外部文件,我们在用pyinstaller打包的时候可以调整一下spec文件,手动添加进去。步骤如下:
1、生成spec配置文件
在pycharm的Terminal窗口执行:pyi-makespec -F src/daily_weather.py,在项目根目录生成daily_weather.spec文件。
2、修改spec文件,添加外部文件
如下图,在Analysis部分的datas中添加外部文件路径和打包的路径,如:
('venv/Lib/site-packages/aliyunsdkcore/data/','aliyunsdkcore/data/')
前面是源文件路径(可用相对路径,也可以用绝对路径),后面是打包后的路径
3、读取spec文件打包
命令:pyinstaller daily_weather.spec
打包成功后直接到项目的dist目录下,运行打包出来的exe文件,这个时候就能成功跑起来了。
运行的时候,我们到那个运行的临时目录下看,可以看到我们指定打包的文件已经存在了。
嗯,差不多是这样了。接触python不久,哪里理解不对的还请指正,欢迎交流。