本文环境是Ubuntu Server 14.04.2 LTS,内核版本3.13.0,使用的Python版本是3.7.3。
问题描述
在执行一些Python代码以及使用pip搜索安装包时报错,如下所示:
(venv) wangrui@dev-host:/data0/htdocs/dev-midata$ pip search numpy
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError("Can't connect to HTTPS URL because the SSL module is not available.")': /pypi
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError("Can't connect to HTTPS URL because the SSL module is not available.")': /pypi
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError("Can't connect to HTTPS URL because the SSL module is not available.")': /pypi
WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError("Can't connect to HTTPS URL because the SSL module is not available.")': /pypi
WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError("Can't connect to HTTPS URL because the SSL module is not available.")': /pypi
ERROR: Exception:
Traceback (most recent call last):
File "/data0/htdocs/dev-midata/venv/lib/python3.7/site-packages/pip/_vendor/urllib3/connectionpool.py", line 688, in urlopen
conn = self._get_conn(timeout=pool_timeout)
File "/data0/htdocs/dev-midata/venv/lib/python3.7/site-packages/pip/_vendor/urllib3/connectionpool.py", line 280, in _get_conn
return conn or self._new_conn()
File "/data0/htdocs/dev-midata/venv/lib/python3.7/site-packages/pip/_vendor/urllib3/connectionpool.py", line 980, in _new_conn
"Can't connect to HTTPS URL because the SSL module is not available."
pip._vendor.urllib3.exceptions.SSLError: Can't connect to HTTPS URL because the SSL module is not available.
最开始怀疑了OpenSSL版本的问题,所以将OpenSSL从1.0.1先升到了1.1.1,事后证明这个步骤可能是不需要的。实际的问题是,本机上的Python3.7版本在编译时没有包含SSL的模块,因此导致python或者pip执行过程中,无法找到SSL模块。
解决方法
解决这个问题的方式就是重新安装或者重新编译Python3.7,可以用两种方法。
方法1:通过apt安装
本机使用的apt源是阿里的镜像,默认情况下安装的python3版本是3.4,也可能你所遇到的源安装的版本不一样。这里不必纠结,如果安装源中不包含你需要的Python版本,则添加一个包含所需要版本的apt源。本文中,我们的目标是Python3.7
add-apt-repository ppa:deadsnakes/ppa
apt install python3.7
通过以上方式即可完成,完成后已经默认包含了对SSL的支持。
方法2:重新编译源代码
建议自行尝试一下这种方式,将来遇到其他问题的时候,可能还是用得上。 首先下载Python3.7的代码:
wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz
随后,解压安装包,并且编辑Modules/Setup配置文件:
tar -zxvf Python-3.7.3.tgz
cd Python-3.7.3
./configure
vi Modules/Setup
在Modules/Setup配置文件中,找到SSL相关的部分,配置为本地的OpenSSL安装路径(本文中为/usr/local/openssl/)。
# Socket module helper for SSL support; you must comment out the other
# socket line above, and possibly edit the SSL variable:
SSL=/usr/local/openssl/ #取消这一行的注释,并将原来的/usr/local/ssl改为/usr/local/openssl/
_ssl _ssl.c \ #取消这一行的注释
true-DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ #取消这一行的注释
true-L$(SSL)/lib -lssl -lcrypto #取消这一行的注释
编辑之后就可以编译和安装了。
make && make install
安装好的位置默认是在/usr/local/bin/python3.7,此时再运行代码错误消失。
附录
Ubuntu环境下的update-alternatives工具
通常我们都会在环境中具有多个不同的Python版本,比如同时具有Python2、Python3等,由于版本容易碎片化,建议尽量使用virtualenv来配置每个应用的执行环境,具体方法可参考基于HBase的数据分析方案一文。
当然,我们也希望在系统环境中,python指向的是我们希望的版本。这时,可以利用update-alternatives,它可以用来管理在系统路径下的文件链接指向。其原理就是建立系统路径下的links,来指向对应的实际可执行文件,并且对配置过的多个指向,进行管理而不是简单的覆盖或者删除。
例如,我们需要对python这个命令配置默认指向,那么可以使用:
update-alternatives --config python
在本文环境下得到的是:
There are 2 choices for the alternative python (providing /usr/bin/python).
Selection Path Priority Status
------------------------------------------------------------
0 /usr/bin/python3.7 10 auto mode
1 /usr/bin/python3.7 10 manual mode
* 2 /usr/local/bin/python3.7 2 manual mode
可以看到除了auto模式外,有两个python3.7可以供我们选择,这里我选择的是优先级较低的那个。实际上,这就是我们上文中重新编译的Python3.7,指向后我们建立了一个链接
lrwxrwxrwx 1 root root 24 Jul 8 01:42 /usr/bin/python -> /etc/alternatives/python
也就是将/usr/bin下的python指向了/etc/alternatives/python,而/etc/alternatives/python又指向了/usr/local/bin/python3.7
lrwxrwxrwx 1 root root 24 Dec 15 22:45 /etc/alternatives/python -> /usr/local/bin/python3.7
当然,要实现这样的效果,我们需要将我们希望指向的可执行文件,配置到python这个alternatives名称中。
方法如下:
update-alternatives --install /usr/bin/python python /usr/local/bin/python3.7 2
其中第一个参数(/usr/bin/python )是link的位置,第二个参数python是这个alternative的名称,第三个参数是实际执行命令,第四个参数是优先级,优先级最高的选项会被auto模式选中。 关于update-alternatives的其他管理,建议自行尝试。