本文主要研究python的依赖包管理。
Pip VS Conda
Conda和pip近似,有很多功能是重叠的。但是,它们的设计目的是不同的。
Pip是官方推荐的工具,用来从pypi(Python Package Index)安装python软件包。Pip可以以wheel或源码形式来安装。以源码形式安装时要求系统中具有兼容的编译器。
Conda是跨平台的安装包和环境管理工具,用来从Anaconda repository和Anaconda Cloud中安装conda软件包。Conda软件包是二进制的,因此不需要编译器,而且Conda软件包不仅限于Python包,也可以是C/C++ lib或R软件包。
Pip和Conda的关键区别:1. Pip只安装python软件包,而conda可以安装各种语言的依赖包;2. conda可以创建独立的环境来安装不同版本的python包或其他包,而python没有built-in的环境支持,需要借助于其他工具virtualenv或venv来创建独立的环境。pipenv,poetry和hatch封装了pip和virtualenv来实现。3. Pip只是按顺序迭代的安装依赖,不会关心这些依赖之间的版本冲突,因此,可能安装完依赖的环境存在版本冲突;而conda会关心所有依赖的所有requirements,保证安装后的环境不存在版本冲突。
Anaconda repository中包含1500个安装包,Anaconda cloud中包含几千个安装包,而pypi中存在150,000个安装包。当有些安装包只存在pypi中时,只能使用pip安装。因此,应该结合使用conda和pip。
下面是conda和pip的比较:
搭建PyPI源
本节讲解怎么使用pypiserver来搭建PyPI源。pypiserver是一个最基本的PyPI服务器实现, 可以用来上传和维护python包。生成密码文件
对PyPI源的一些操作,如上传python包等,需要密码保护,需要创建htpasswd文件来在启动pypiserver时指定用户名和密码信息。
读取htpasswd文件需要安装passlib python包。
pip install passlib
生成htpasswd文件,需要安装下面的apt软件包。
yum -y install httpd //centos
sudo apt-get install apache2-utils //ubuntu
这样,我们便可以为用户名密码创建htpasswd文件,详细信息参见文章htpasswd的使用。
htpasswd -bc /root/.pypipasswd sam passward安装和使用pypiserver
使用下面命令来安装pypiserver。可以使用pypiserver -h来查看命令的语法。
pip install pypiserver
使用下面命令来启动pypiserver,这里-P指定我们上面创建的密码文件,-p指定pypiserver启动的端口号,默认为8080,-o指定python包存放的位置,默认为~/packages。
pypi-server -P /root/.pypipasswd -p 8080 -o /usr/libs/pypi
下面是pypiserver的语法:
启动pypiserver后便可以使用浏览器来访问pypiserver。这里是安装在本地,使用默认的8080端口。将python包拷贝到目录/usr/libs/pypi中后,便可以在浏览器中查看。本地上传python包
首先,为python项目demo创建安装包,它的setup.py文件内容如下。
from setuptools import setup
setup(
name='demo',
version='0.0.1',
packages=['demo']
)
在项目根目录下执行下面命令来生成python安装包。
python setup.py sdist
命令执行后,可以在项目下的dist目录找到安装包demo-0.0.1.tar.gz。将其拷贝到pypiserver的安装包目录下,便可以在浏览器中访问。
此时,在本地环境可以使用pip或easy_install来访问python包。
# pip search -i http://localhost:8080 demo
# pip install -i http://localhost:8080 demo
# easy_install -i http://localhost:8080/simple demo远程上传python包
下面,我们将demo项目的安装包远程上传到pypiserver。
访问有密码保护的pypiserver,需要配置Distutils来指定上传操作所需要的用户名和密码。创建或者修改~/.pypirc文件, 文件需内容如下。
[distutils]
index-servers = localhost
[localhost]
repository: http://localhost:8080
username: sam
password: passward
这样,当向localhost或者地址为http://localhost:8080的PyPI源上传Python包时, 用户名sam和密码passward就会被用来验证操作权限。
python setup.py sdist upload -r localhost无密码保护的pypiserver
上面介绍了如何搭建和使用有密码保护的pypiserver。本节将介绍如何搭建无密码保护的pypiserver。将-P和-a的参数都设置为.表示对所有操作都不需要密码。
pypi-server -P . -a .
上面搭建完无密码保护的pypiserver后,可以运行下面命令来上传python包。虽然还是会提示输入密码,但只要回车确认即可。
python setup.py sdist upload -r http://localhost:8080配置默认的pypiserver地址
在客户端,如果总是需要在命令行中提供pypiserver的地址比较麻烦。pypiserver在找不到请求的package时,重定向请求到~/.pip/pip.conf或~/.pydistutils.cfg中指定的local index url。
for pip: ~/.pip/pip.conf
[global]
extra-index-url = http://localhost:8080/simple/
for easy-install: ~/.pydistutils.cfg
[easy_install]
index_url = http://localhost:8080/simple/
当在local index url中也找不到package时,在--fallback-url FALLBACK_URL指定的地址中寻找package,默认为http://pypi.python.org/simple。管理package
下面命令将会查看那些package需要更新并列出更新这些package的命令。下面输出中.表示package已经最新,u表示package需要更新,e表示pypi中找不到相应release。通过拷贝下面提供的更新命令来更新相应package或直接执行pypi-server -Ux来执行所有更新命令。
$ ./pypi-server -U
checking 106 packages for newer version
.........u.e...........e..u.............
.....e..............................e...
..........................
no releases found on pypi for PyXML, Pymacs, mercurial, setuptools
# update raven from 1.4.3 to 1.4.4
pip -q install --no-deps --extra-index-url http://pypi.python.org/simple -d /home/ralf/packages/mirror raven==1.4.4
# update greenlet from 0.3.3 to 0.3.4
pip -q install --no-deps --extra-index-url http://pypi.python.org/simple -d /home/ralf/packages/mirror greenlet==0.3.4
pypiserver可以使用不同的WSGI server来提供对package的访问。pypiserver.app具有下面的接口,返回WSGI application。root为存放package的目录,redirect_to_fallback指定package找不到时是否重定向到fallback_url。
def app(root=None,
redirect_to_fallback=True,
fallback_url="http://pypi.python.org/simple")
下面是使用gunicorn作为server的示例。
gunicorn -w4 'pypiserver:app("/home/ralf/packages")'
gunicorn -w4 'pypiserver:app(["/home/ralf/packages", "/home/ralf/experimental"])' //指定多个root