0

    svn下载项目到本地离线 七个披萨的博客

    2023.05.29 | admin | 191次围观

    distutils 简介

    distutils 是标准库中负责建立 Python 第三方库的安装器,使用它能够进行 Python 模块的安装和发布。distutils 对于简单的分发很有用,但功能缺少。

    setuptools 简介

    setuptools 是 distutils 增强版,不包括在标准库中。其扩展了很多功能,能够帮助开发者更好的创建和分发 Python 包。大部分 Python 用户都会使用更先进的 setuptools 模块。

    特性文件

    setup.py、MANIFEST.in、setup.cfg

    第一个安装文件

    假设我们的项目名为”setup-demo”,包名为”myapp”,目录结构如下:

    setup-demo/
     ├ setup.py        # 安装文件
     └ myapp/          # 源代码
         ├ __init__.py
         ...
    

    一个最基本的”setup.py”文件如下:

    #coding:utf8
    from setuptools import setup
    setup(
       name='MyApp',        # 项目名
       version='1.0',       # 版本号
       packages=['myapp']   # 包括在安装包内的Python包
    )
    

    setup.py命令 help

    查看所有支持的命令:

    python setup.py --help-commands
    

    build

    构建安装时所需的所有内容:

    python setup.py build
    

    install

    安装包到系统环境中。该命令会将当前项目安装到当前Python环境的”site-packages”目录下,这样其他项目就可以像导入标准库一样导入该项目的代码了。

    python setup.py install
    

    develop

    以开发方式安装包。

    如果项目在开发过程中会频繁变更,每次安装还需要先将原来的版本卸掉svn下载项目到本地离线,会很麻烦。使用”develop”开发方式安装的话,项目代码不会真的被拷贝到本地Python环境的”site-packages”目录下,而是在”site-packages”目录里创建一个指向当前项目位置的链接。这样如果当前位置的源码被改动,就会马上反映到”site-packages”里。

    python setup.py develop
    

    register、upload

    用于包的上传发布。

    python setup.py register
    # 发布源码包
    python setup.py sdist upload
    

    以下为python的打包命令:

    build_ext

    构建扩展,如用 C/C++, Cython 等编写的扩展,在调试时通常加 --inplace 参数,表示原地编译,即生成的扩展与源文件在同样的位置。

    python setup.py build_ext
    

    sdist

    构建源码分发包。该命令会在当前目录下的”dist”目录内创建一个压缩包,默认在 Windows 下为 zip 格式,Linux 下为 tag.gz 格式 ,也可以通过指定--formats参数指定压缩包格式。

    执行 sdist 命令时,默认会被打包的文件:

    该命令构建的包主要用于发布,例如上传到 pypi 上。

    python setup.py sdist
    

    bdist

    构建一个二进制的分发包。

    python setup.py bdist
    

    bdist_egg

    构建一个 egg 分发包,经常用来替代基于 bdist 生成的模式。该命令会在当前目录下的”dist”目录内创建一个”egg”文件,名为”MyApp-1.0-py2.7.egg”。文件名格式就是”项目名-版本号-Python版本.egg”。同时你会注意到,当前目录多了”build”和”MyApp.egg-info”子目录来存放打包的中间结果。

    python setup.py bdist_egg
    

    bdist_wheel

    构建一个 wheel 分发包,egg 包是过时的,whl 包是新的标准。同上面类似,只是打成的包的后缀是.whl 。

    python setup.py bdist_wheel
    

    引入非Python文件

    上例中,我们只会将”myapp”包下的源码打包,如果想引入静态文件,如JS、CSS、图片等,怎么做?

    答:在项目根目录下添加一个”MANIFEST.in”文件夹。假设我们把所有静态文件都放在”static”子目录下,现在的项目结构如下:

     setup-demo/
     ├ setup.py        # 安装文件
     ├ MANIFEST.in     # 清单文件
     └ myapp/          # 源代码
         ├ static/     # 静态文件目录
         ├ __init__.py
         ...
    

    我们在清单文件”MANIFEST.in”中,列出想要在包内引入的目录路径:

    recursive-include myapp/static *
    recursive-include myapp/xxx *
    

    recursive-include表明包含子目录。

    在”setup.py”中将include_package_data参数设为True:

    #coding:utf8
    from setuptools import setup
    setup(
       name='MyApp',        # 项目名
       version='1.0',# 版本号
       packages=['myapp'],  # 包括在安装包内的Python包
       include_package_data=True   # 启用清单文件MANIFEST.in
    )
    

    如果你想排除一部分文件,可以在”setup.py”中使用exclude_package_date参数:

    setup(
        ...
        include_package_data=True, # 启用清单文件MANIFEST.in
        exclude_package_date={'':['.gitignore']}
    )
    

    依赖管理

    我们的项目会依赖其他Python模块,如何在setup.py中管理这些依赖呢?

    答:修改”setup.py”文件svn下载项目到本地离线,加入install_requires参数:

    #coding:utf8
    from setuptools import setup
    setup(
       name='MyApp',        # 项目名
       version='1.0',# 版本号
       packages=['myapp'],  # 包括在安装包内的Python包
       include_package_data=True,   # 启用清单文件MANIFEST.in
       exclude_package_date={'':['.gitignore']},
       install_requires=[   # 依赖列表
           'Flask>=0.10',
           'Flask-SQLAlchemy>=1.5,<=2.1'
       ]
    )
    

    上面的代码中,我们声明了应用依赖Flask 0.10及以上版本,和Flask-SQLAlchemy 1.5及以上、2.1及以下版本。setuptools会先检查本地有没有符合要求的依赖包,如果没有的话,就会从PyPI中获得一个符合条件的最新的包安装到本地。

    可以通过dependency_links指定依赖包下载路径。install_requires中的包在安装时会先去PyPI下载并安装,如果包在PyPI中找不到,则会从dependency_links标识的URL中获取:

    setup(
       ...
       install_requires=[   # 依赖列表
           'Flask>=0.10',
           'Flask-SQLAlchemy>=1.5,<=2.1'
       ],
       dependency_links=[   # 依赖包下载路径
           'http://example.com/dependency.tar.gz'
       ]
    )
    

    路径应指向一个”egg”包或”tar.gz”包,也可以是个包含下载地址(一个”egg”包或”tar.gz”包)的页面。

    PS:现在python的第三方依赖一般写在requirements.txt 文件中,然后用pip工具下载。关于他们的不同,可以参考我的博客中requirements.txt VS install_requires 这一小节。

    自动搜索Python包

    packages=['myapp'] :将Python包”myapp”下的源码打包。

    之前我们在”setup.py”中指定了packages=['myapp'],说明将Python包”myapp”下的源码打包。但是如果我们的应用很大,逐一列举需要打包的源码包会很麻烦,这时就需要用到setuptools提供的find_packages()方法来自动搜索可以引入的Python包。

    packages=find_packages() :自动搜索可以引入的Python包,它默认在与 setup.py 文件同一目录下搜索各个含有 __init__.py 的目录做为要添加的包。

    #coding:utf8
    from setuptools import setup, find_packages
    setup(
       name='MyApp',              # 应用名
       version='1.0',             # 版本号
       packages=find_packages(),  # 包括在安装包内的Python包
       include_package_data=True,  # 启用清单文件MANIFEST.in
       exclude_package_date={'':['.gitignore']},
       install_requires=[         # 依赖列表
           'Flask>=0.10',
           'Flask-SQLAlchemy>=1.5,<=2.1'
       ]
    )
    

    find_packages()方法可以限定你要搜索的路径,比如使用find_packages('src')就表明只在”src”子目录下搜索所有的Python包。

    发布包

    setuptools 支持使用 setup.py upload 上传包文件到 PyPI,但只支持 HTTP 而被新的 twine 取代。

    方式一:使用setup.py upload发布

    (1)配置.pypirc配置文件。.pypirc配置文件在用户根目录下的:~/.pypirc ,也可以通过修改setup.py文件,替换register和upload命令的_get_rc_file方法来自定义文件路径(参考 .pypirc配置文件一节)

    [distutils]
    index-servers =
        pypi
        private-repository
    [pypi]
    username = __token__
    password = <PyPI token>
    [private-repository]
    repository = <private-repository URL>
    username = <private-repository username>
    password = <private-repository password>
    

    (2)接着注册项目

    python setup.py register
    

    (3)构建源码包发布:

    # 发布源码包
    python setup.py sdist upload
    # 同时发布源码包和 whl 二进制包
    python setup.py sdist bdist_wheel upload
    

    方式二:使用twine发布

    官方提供了 twine 工具专门用来与 PyPI 交互,twine支持上传任何包装格式,其包含三个子命令check, register, upload,且同样支持从.pypirc中读取配置。上传包时,直接用 upload 命令:

    # 构建包
    python setup.py sdist bdist_wheel
    # 通过-r指定上传到哪个仓库(https://stackoverflow.com/questions/57935191/twine-is-asking-for-my-password-each-time-how-to-use-the-pypirc)
    twine upload -r private-repository dist/*
    #上传到指定仓库,还可以通过-u指定用户名,-p指定密码
    twine upload --repository-url 仓库地址 -u 用户名 -p 密码 dist/*
    

    使用twine upload发布到http开头的私有库时,有可能会报证书校验失败的错误(certificate verify failed)。这种情况下,可以使用以下命令禁用SSL验证():

    export CURL_CA_BUNDLE=""
    

    参考

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论