Changing PYTHONHOME causes ImportError: No module named site

Changing PYTHONHOME causes ImportError: No module named site

我正在尝试通过 mod_wsgi 在 Apache 上部署 Flask 网络应用程序。我不能使用默认的 Python 环境,因为它是用 UCS-2 Unicode 而不是 UCS-4 编译的,我不能为这种情况重新编译它。因此,虚拟环境。无论如何都会使用虚拟环境,但该错误意味着我无法使用默认的 Python 安装并仅将虚拟环境的模块添加到 PYTHONPATH,否则会让我完全偶然地避免了当前的问题。

我找到了 documentation for mod_wsgi to change which Python executable to use。但是,当尝试这样做时,服务器无法正常工作。 /var/log/httpd/error_log 迅速充斥着行 ImportError: No module named site

我已经检查了在这里和其他地方可以找到的所有类似问题,但还没有成功。实验表明,据我所知,在不激活虚拟环境的情况下更改 PYTHONHOME 时会出现问题 - 以及自动部署的工作方式(通过 Fabric),据我所知我无法激活虚拟环境。


Apache 配置

我目前的应用 httpd.conf

WSGIPythonPath /path/to/dir/containing/wsgi/file/and/app:/path/to/virtualenv/lib:/path/to/virtualenv/lib/site-packages

WSGIPythonHome /path/to/virtualenv

WSGISocketPrefix /var/run/wsgi

User user

Group group

<VirtualHost *>

    ServerName servername.generic.com

    DocumentRoot /path/to/dir/containing/wsgi/file/and/app/static_dev/

    WSGIDaemonProcess appname user=user group=group threads=2

    WSGIScriptAlias / /path/to/dir/containing/wsgi/file/and/app/app.wsgi

    <Directory /path/to/dir/containing/wsgi/file/and/app>
        WSGIProcessGroup appname
        WSGIApplicationGroup %{GLOBAL}
        Require all granted
    </Directory>
</VirtualHost>

我从失败的尝试中找到的数据

我知道错误不在我的 app.wsgi 中,因为当我在最顶部添加行 raise Exception('tried to open the file') 来检查时,现有的 ImportError 一直在发生,而不是那个新 Exception.

我已通过 ldd 确认我的 mod_wsgi 版本适用于 Python 2.7。

我试过设置WSGIPythonHome /path/to/virtualenv/bin/WSGIPythonHome /path/to/virtualenv/bin/python,结果与当前状态相同。

我尝试省略 WSGIPythonHome 指令,在这种情况下,它会按原样加载 app.wsgi,但会在稍后的导入时中断,如顶部所述(我不能这样做的原因就那样做)。

我曾尝试省略 WSGIPythonPath 指令并将其留给 app.wsgi 以将内容添加到 PYTHONPATH,结果与当前状态相同。

我尝试将路径设置作为 WSGIDaemonProcess 的参数而不是 WSGIPythonPath 指令,结果与当前状态相同。

我已经确认/path/to/virtualenv/lib中有一个site.py

我已经确认没有其他正在使用的非特定于应用程序的 Apache .conf 文件(默认设置、自动模块加载等)包含字符串 "WSGI",所以我不认为这里有任何冲突。

如果我从命令行激活虚拟环境,我可以导入 site 而不会出错,只是为了测试它确实存在于环境中。但是,这还不够,因为使用的部署工具需要从对 sudo systemctl start httpd.service 的单个调用顺利启动,而这似乎并不关心当前 shell 会话的 venv。

如果在默认状态下,我 export PYTHONHOME=/path/to/virtualenv,尝试打开 Python REPL 会立即退出并显示 ImportError: No module named site

如果我激活虚拟环境然后设置 PYTHONHOME,我会得到同样的导入错误。

如果我激活虚拟环境并且不触摸 PYTHONHOMEecho $PYTHONHOME 输出一个空行,Python REPL 工作正常。在 virtualenv 中的 Python REPL 中:

(virtualenv)-bash-4.2$ python
Python 2.7.8 (default, Aug 14 2014, 13:26:38)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.prefix
'/path/to/virtualenv'
>>> sys.exec_prefix
'/path/to/virtualenv'

即使将 PYTHONHOME 设置为相同的值也不起作用。

如果我尝试 export PYTHONHOME=:/path/to/virtualenvexport PYTHONHOME=/path/to/virtualenv:,明确仅设置 prefixexec_prefix 之一,在任何一种情况下都会失败并出现相同的导入错误。

如果我激活虚拟环境并以后两种方式之一设置 PYTHONHOME,未设置的似乎默认为 / 而不是通常的默认值,但是 Python REPL 运行很好:

# Setting only exec_prefix
(virtualenv)-bash-4.2$ export PYTHONHOME=:/path/to/virtualenv
(virtualenv)-bash-4.2$ python
Python 2.7.8 (default, Aug 14 2014, 13:26:38)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.prefix
'/'
>>> sys.exec_prefix
'/path/to/virtualenv'
>>> quit()
# Setting only prefix
(.virtualenv)-bash-4.2$ export PYTHONHOME=/path/to/virtualenv:
(.virtualenv)-bash-4.2$ python
Python 2.7.8 (default, Aug 14 2014, 13:26:38)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.prefix
'/path/to/virtualenv'
>>> sys.exec_prefix
'/'

不幸的是,由于部署脚本不关心激活什么环境,所以这并不能解决问题。尝试以这种方式设置 WSGIPythonHome 没有任何区别。

我还注意到一件事:virtualenv 中的 Python 是 2.7.8。 virtualenv (usr/bin/python) 之外的 Python 运行 是 2.7.5。我不知道 - 这会以某种方式影响 PYTHONHOME 的设置吗?我希望不会 - 因为与仅在 app.wsgi 文件中设置 sys.path 相比,这似乎破坏了使用 WSGIPythonHome 到 运行 virtualenv 的全部目的,能够从不同的可执行文件开始 - 但我不能排除这种可能性,因为我一无所知。

/path/to/virtualenv/bin/python 中的 2.7.8 Python 的 sys.real_prefix/network-mounted-drive/sw/python/python-2.7.8

我将部署更改为从 /network-mounted-drive/sw/python/python-2.7.5 构建,然后进行了更多测试。结果如下:

尝试启动 httpd 会出现与之前相同的导入错误。

设置PYTHONHOME为虚拟环境的位置,然后运行ning python:

-bash-4.2$ echo $PYTHONHOME
/path/to/virtualenv
-bash-4.2$ python
ImportError: No module named site

将 PYTHONHOME 设置为虚拟环境的位置,然后显式 运行ning 虚拟环境的 python 二进制文件(激活虚拟环境然后 运行ning python给出相同的结果):

# In the directory just above the virtualenv
-bash-4.2$ ./virtualenv/bin/python
Python 2.7.5 (default, Mar 14 2016, 14:13:09)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.prefix
'/path/to/virtualenv'
>>> sys.exec_prefix
'/path/to/virtualenv'
>>> sys.real_prefix
'/network-mounted-drive/sw/python/python-2.7.5

有人知道吗?

已找到解决方案:问题似乎出在尝试使用从系统上本地 python 安装以外的东西构建的虚拟环境。

通过将 "local python install on the deployment VM doesn't have pip installed" 的问题向上推给具有安装 pip 所需权限的人来解决,因为没有尝试通过网络 python 安装的解决方法奏效。

实际使用从网络驱动器上的 Python 安装链接的虚拟环境的问题 mod_wsgi 可能无法解决,或者至少我无法在合理的数量上解决它相对于官僚解决方案的时间。