比较现实可靠的python模块的安装部署方法


每一个pythoner都知识pip install,安装python模块实现是方便。

当一个应用扩展十几二十个python模块时,网上最流行的方法是这样的:


1、pip freeze > requirements.txt将包依赖信息保存在requirements.txt文件中。

requirements.txt文件的内容大概是这样的:

blinker==1.3
Flask==0.10.1
Flask-Babel==0.9
Flask-Login==0.2.11
Flask-Mail==0.9.1
Flask-OpenID==1.2.4
Flask-Redis==0.0.6
Flask-RESTful==0.3.2
Flask-Session==0.1.1
Flask-WTF==0.11
flup==1.0.2

2、然后在部署时,首先请出virtualenv这尊大神,使用:

> virtualenv myenv

建立一个python的隔离环境

3、然后在命令行执行 myenv\scripts\activate进入该隔离环境.

4、最后

pip install -r requirements.txt

这样万事大吉,一个安装部署大体就完成了。


但在天朝这事情貌似没这么简单,pip安装的文件是从位于国外的pypi.python.org下载的,因此就比较悲剧了,上述上方法几乎难以有效运行。

从pypi安装速度超慢,不稳定,timeout是经常的。

而上述安装部署方法,还有一个问题,就是某些python模块是需要编译的,如果用户环境编译环境没有安装配置合适,安装模块也是比较容易失败的。

另外由于有一些python模块会升级,可能会带来不兼容,因而可能导致一些意想不到的问题。

又由于升级等原因,找不到对应的模块导致安装失败。


总之问题比较多,我希望安装部署是这样的:

1、能从本地文件夹进行安装,而不是在线安装。

2、应用总是依赖我开发时的模块,而不是最新的。

3、能在创建隔离环境后自动安装所有依赖模块。

4、避免进行安装时编译。


因此,当你的软件需要交付给不同的用户时,我目前使用的比较现实的python模块的安装部署方法是样,简单说一下思路:

1、将你所有需要依赖的python模块复制到install\libs,将编译过的模块按平台归类收集到一个文件夹中,如install\libs\windows\64bit。

2、接着自己建立virtualenv 的创建启动脚本,就是运行以下python代码,生成一个install\create.py的脚本文件。

import virtualenv, textwrap
output = virtualenv.create_bootstrap_script(textwrap.dedent("""
import os, subprocess
def after_install(options, home_dir):
    #在此处写你自己的脚本,主要就是复制文件和安装模块的命令
    #此处的home-dir就是你创建的虚拟环境
    #以下的是我写一些代码供参考
    if sys.platform == 'win32':
        bin_path = 'Scripts'
    else:
        bin_path = 'bin'
    #安装需要编译的python模块,按平台进行复制
    # 针对一些需要编译的模块,此处采用的是直接复制二进制包的方式
    import platform,shutil
    bits,ostype=platform.architecture()
    ostype=platform.system()
    libs_path=os.path.join(os.path.dirname(__file__),"libs",ostype,bits)
    def copyFiles(sourceDir,  targetDir):
        for file in os.listdir(sourceDir):
            sourceFile = os.path.join(sourceDir,  file)
            targetFile = os.path.join(targetDir,  file)
            if os.path.isfile(sourceFile):
                if os.path.splitext(sourceFile)[1]==".whl":
                    subprocess.call([join(home_dir,bin_path, 'pip'),'install',sourceFile])
                else:
                    if not os.path.exists(targetDir):
                        os.makedirs(targetDir)
                    if not os.path.exists(targetFile) or(os.path.exists(targetFile) and (os.path.getsize(targetFile) != os.path.getsize(sourceFile))):
                        open(targetFile, "wb").write(open(sourceFile, "rb").read())
            if os.path.isdir(sourceFile):
                copyFiles(sourceFile, targetFile)


    for file in os.listdir(libs_path):
        fullname=os.path.join(libs_path,file)
        if os.path.isdir(fullname):
            print "installing %s......" % file ,
            try:
                copyFiles(fullname,join(home_dir,'Lib',"site-packages"))
                print "OK!"
            except Exception,E:
                print "ERROR:%s" % E.message

    #不需要编译的python模块,直接调用pip install xxxx.tar.gz,
    libs=[
        "Werkzeug-0.10.1.tar.gz",
        "Jinja2-2.7.3.tar.gz",#模板引擎
        "Flask-0.10.1.tar.gz",#Flask
        "SQLAlchemy-0.9.9.tar.gz",#ORM
        "Flask-SQLAlchemy-2.0.tar.gz",#ORM
        "WTForms-2.0.2.tar.gz",#表单库
        "Flask-WTF-0.11.tar.gz",#表单库
    ]

    #开始依次安装
    for lib in libs:
        lib_file=os.path.join(os.path.dirname(__file__),'libs',lib)
        subprocess.call([join(home_dir,bin_path, 'pip'),'install','--no-cache-dir','--no-deps','--disable-pip-version-check',lib_file])

"""))

f = open('create.py', 'w').write(output)

上面的代码会生成一个create.py的文件,然后你这个文件中找到after_install方法,自己修改。

基本思路就是从pypi.python.org下载对应的.tar.gz或.whl安装包,然后调用pip install xxxxxxxxx.tar.gz进行安装。


2、然后在命令行使用生成的create.py来创建隔离环境,如:

> python create.py myeny


按照上述方法,安装时就可以脱离pypi通过本地文件进行安装,相比较而言,更稳定些。




评论关闭