濒临崩溃!2 个 Python 开发问题,折腾了我快 7 天

2021-09-08 16:21:10 浏览数 (1)

最近,州的先生在对 MrDoc 专业版(一个基于 Django 开发的在线文档系统)进行最后的上线测试工作。

原本在开发环境下测试得好好的「一键更新」功能,在宝塔面板上通过 uWSGI 部署之后,突然不能使用了。

期间各种搜索、改代码、测试,简直快要崩溃,幸运的是,最终问题得以解决,下面回顾一下这些问题及其解决方法,方便大家借鉴和避坑。

环境

开发环境:

  • 操作系统:Windows 10
  • Python版本:3.6
  • 虚拟环境:否
  • 运行方式:runserver

测试环境:

  • 操作系统:CentOS 7
  • Python 版本:3.7.8
  • 虚拟环境:是
  • 运行方式:宝塔面板 uWSGI Nginx

功能逻辑

在 Django 内通过 subprocess.Popen() 方法,调用系统命令,拉取最新的 Git 仓库代码,然后执行 Django 的数据迁移命令,最后执行 pip 命令更新项目依赖库。

在原代码中,已经对 subprocess.Popen() 方法进行了一定的优化和处理。

首先,通过cwd参数指定命令运行的路径,通过stdinstderrstdout参数获取命令执行的输出内容,通过communicate()等待命令执行完成。

最终的脚本调用代码如下所示:

代码语言:javascript复制
Popen(
 
 [python_env, 'manage.py', 'makemigrations'],
 
    stdin=PIPE,
 
    stderr=PIPE,
 
    stdout=PIPE,
 
    cwd=settings.BASE_DIR
 
 )
 
out_2, err_2 = mig_call.communicate()
 

Git 仓库认证问题

最开始出现的是 Git 认证问题。

仓库的代码通过 https 的方式进行拉取:

代码语言:javascript复制
git clone https://git.mrdoc.pro/MrDoc/MrDocPro.git
 

正常情况下,在命令行终端输入 git 相关命令可以直接进行操作。

但是日志里面却报出了一个错误:

代码语言:javascript复制
fatal: could not read Username for 'https://git.mrdoc.pro'
 

试过使用:

代码语言:javascript复制
git config --global credential.helper store
 

这在命令行界面启动 uWSGI 时运行没问题:

代码语言:javascript复制
uwsgi --ini uwsgi.ini
 

但是一旦使用宝塔面板的「Python 项目管理器」启动,就会继续报上述错误:

最后通过修改 git 仓库地址,在地址上附带用户名和密码得以解决:

代码语言:javascript复制
git clone https://{username}:{password}@git.mrdoc.pro/MrDoc/MrDocPro.git
 

Python 解释器路径问题

因为需要执行 Django 的数据迁移命令,所以需要在脚本中调用Python

代码语言:javascript复制
python manage.py migrate
 

这在单一的 Python 环境下,也是没有任何问题的。但是在 Linux 上,在虚拟环境中,这个问题就凸现出来了。

首先很多服务器使用的 Linux 还是自带了 Python2,且默认的python命令指向的也是 Python 2,就算将其指向到 Python3。

其次,全局 Python 的第三方模块和虚拟环境内的第三方模块也不一样。

为了让代码里面执行的python命令指向正确的 Python 解释器路径,州的先生使用了 Python 内置库 sys提供的executable属性,这个属性会返回 Python 解释器的可执行二进制文件的绝对路径。

例如:

虚拟环境中:

按理来说,用 sys.executable 代替python是不会错的了,结果又报出个错误来:

代码语言:javascript复制
unable to load configuration from manage.py
 

网上搜索不到合适的问题,只得自己调试,在代码中把 sys.executable 的值打印出来,才发现 sys.executable 指向了 虚拟环境内 uWSGI 的路径。

借着这一关键信息搜索,才发现这一问题在 2014年就已经存在:

而开发者的解释是:

uwsgi 就是当前的 python 解释器,因为它链接 libpython.so。获取 sys.executable 是不可能的,因为库本身没有硬编码的二进制路径。

好吧。知道原因就好办了。虚拟环境内的 uWSGI 一般都存在于虚拟环境python的同级目录,在调用 sys.executable 之前对其返回值进行一下判断。

如果值以uwsgi结尾,就可以将其替换掉,如果是正常的Python解释器路径,就可以直接使用。

总结

当问题解决了,回想起来,好像解决方法也是很简单。

这关键在于,出现问题后,要及时定位到问题点所在。

如果不知道问题点所在,就只能盲目地找答案,而这,往往是找不到答案的。

解决问题的方法可能很简单,但是如果找不到问题点,再简单的解决方法可能也不会被自己注意到,最终就像电视剧里面的两个人,那么近又那么远,最终擦肩而过。

0 人点赞