编译pip源码-pip包解读

1.2.2自述文件

readme.md是当前模块的描述工具,通常采用markdown格式编写

funker是一个优秀的工具1.2.3demos目录

该文件夹通常包含模块的一些使用示例,以便用户快速应用模块进行开发;

1.2.4 设置.py

setup.py文件可能是一个配置文件,用于向setuptools提供一些模块相关的信息,如:模块名称、模块版本、适用的python版本、作者、github地址等;

import setuptools
with open("README.md", "r") as fh:
    long_description = fh.read()
    
setuptools.setup(
    name="fucker",  # 模块名称
    version="1.0",  # 当前版本
    author="wupeiqi",  # 作者
    author_email="wupeiqi@live.com",  # 作者邮箱
    description="一个非常NB的包",  # 模块简介
    long_description=long_description,  # 模块详细介绍,这里可以读取readme文件
    long_description_content_type="text/markdown",  # 模块详细介绍格式
    # url="https://github.com/wupeiqi/fucker",  # 模块github地址
    packages=setuptools.find_packages(),  # 自动找到项目中导入的模块
    # 模块相关的元数据
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    # 依赖模块
    install_requires=[
        'pillow',
    ],
    python_requires='>=3',
)

说明:setuptools是一个包管理工具,用于打包和安装模块;

1.2.5fucker目录

插件内容,可以在这里编译相关代码wp.py

def func():
    print("一个神奇的包")

最终文件如下所示:

fucker
├── LICENSE
├── README.md
├── demos
├── fucker
│   ├── __init__.py
│   └── wp.py
└── setup.py

1.3 包装

上述步骤编译完文件夹和代码后,需要对代码进行打包

1.3.1 安装打包工具

打包代码需要先安装setuptools和wheel,可以单独安装也可以pip安装,所以手动安装这两个工具。

由于Python3的安装自带了安装pip的功能,因此如果安装了Python3则这两个打包工具是免安装的;

注意:对于已经安装的用户,如果想要更新setuptools和wheel这两个工具,可以使用以下命令:

python -m pip install --upgrade setuptools wheel

编译pip源码-pip包解读

1.3.2 封装代码

# 在终端中进入setup所在的目录;执行如下语句
python setup.py sdist bdist_wheel

打包后路径如下

fucker
├── LICENSE
├── README.md
├── fucker
│   ├── __init__.py
│   └── wp.py
├── fucker.egg-info
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   └── top_level.txt
├── build
│   ├── bdist.macosx-10.6-intel
│   └── lib
│       └── fucker
│           ├── __init__.py
│           └── wp.py
├── demos
├── dist
│   ├── fucker-0.0.1-py3-none-any.whl
│   └── fucker-0.0.1.tar.gz
└── setup.py

打包后的文件如下,旁边有详细说明;

1.4 上传与发布

文件打包后,需要将打包后的文件上传到PyPI。 如果要上传,需要先注册一个账号。

1.5 深入学习的安装和使用2.setup.py

以上打包命令:

# 在终端中进入setup所在的目录;执行如下语句
python setup.py sdist bdist_wheel

Python已经发展很多年了,项目打包的工具也非常成熟; 你可能听说过 disutils、distutils、distutils2、setuptools 等编译pip源码,看起来很熟悉,但它们的模式化程度很高。 他们之间是什么关系? 它们之间的关系可以参见参考文档中的详细解释。 可以简单理解为上面几个不是很成熟的setuptools

2.1 设置工具

setuptools 是一个优秀、可靠的 Python 包安装和分发工具。

安装 setuptools 有两种主要形式:

2.1.1 简易安装

注:该命令不是很常用,简单理解即可;

# 通过包名,从PyPI寻找最新版本,自动下载、编译、安装
$ easy_install pkg_name
# 通过包名从指定下载页寻找链接来安装或升级包
$ easy_install -f http://pythonpaste.org/package_index.html 
# 指定线上的包地址安装
$ easy_install http://example.com/path/to/MyPackage-1.2.3.tgz
# 从本地的 .egg 文件安装
$ easy_install xxx.egg
# 在安装时你可以添加额外的参数
指定安装目录:--install-dir=DIR, -d DIR
指定用户安装:--user

编译pip源码-pip包解读

以上仅介绍了easy_install的一些常用技巧。 想了解更多可以点击官方文档:

总结一下:setuptools是官方提供的一款专业的包分发工具。 从安装来看,它的功能确实很简单。 它更大的意义在于,对于软件包分发来说非常有用,而且程序多样化程度很高。 我们仍然使用它来发布版本包。

2.2 源码包和补码包

Python包分为两种:源码包和补码包;

2.2.1 以源码形式发布

安装源码包的过程是先解压,然后编译,最后再安装,所以是跨平台的,因为每次安装都需要编译,安装速度相对较慢二补安装包安装的形式;

源码包的本质是一个压缩包,其常见格式如下:

格式后缀

压缩

。压缩

广州塔尔

.tar.gz

兹塔尔

.tar、Z

柏油

。柏油

最常用的是.tar.gz,一般在linux下使用;

2.2.2 发布为二补包

编译pip源码-pip包解读

二补代码包省去了编译过程,可以直接解压安装,因此安装速度比源码更快。 由于不同平台编译的包不兼容,所以需要提前编译好多个平台的包。

二进制补码数据包的常见格式是:

格式后缀

。蛋

车轮

.whl

Egg格式是setuptools在2004年引入的,Wheel格式是在2012年PEP427定义的。Wheel的出现就是为了取代Egg。 它的本质是一个zip包,现在被认为是Python的二进制补码包的标准格式。

这两种格式有什么区别?

可以通过pip安装wheel包,但是需要先安装wheel模块,然后再使用pip命令。

$ pip install wheel
$ pip wheel --wheel-dir=/local/wheels pkg

** 注:** 可以直接安装 pipinstallxxx.whl

2.3 setup.py解释

在上面的打包案例中,我们可以发现最重要的是setup.py文件。

import setuptools
with open("README.md", "r") as fh:
    long_description = fh.read()
    
setuptools.setup(
    name="fucker",  # 模块名称
    version="1.0",  # 当前版本
    author="wupeiqi",  # 作者
    author_email="wupeiqi@live.com",  # 作者邮箱
    description="一个非常NB的包",  # 模块简介
    url="https://github.com/wupeiqi/fucker",  # 模块github地址
    packages=setuptools.find_packages(),  # 自动找到项目中导入的模块
)

这是上面打包文件的缩小版,下面我们将逐步扩展setup.py功能以减少更多参数;

2.3.1 节目分类信息

classifiers参数描述了包的分类信息。 有关所有支持的分类的列表,请参阅:%3Aaction=list_classifiers

# 模块相关的元数据
classifiers=[
    "Programming Language :: Python :: 3",    	 # 目标 Python 的版本
    "License :: OSI Approved :: MIT License",	 # 许可证信息
    "Operating System :: OS Independent",		 # 操作系统
    
    # 发展时期,常见的如下
    #   3 - Alpha
    #   4 - Beta
    #   5 - Production/Stable
    'Development Status :: 3 - Alpha',    # 开发状态
    # 开发的目标用户
    'Intended Audience :: Developers',
    
    # 属于什么类型
    'Topic :: Software Development :: Build Tools'
]

最常见的系统编译信息。 第一种情况,我们只写了3个。如果是个人使用的工具包,则不需要填写复杂的信息;

2.3.2 文件分发

setuptools.setup(
    name="fucker",  # 模块名称
    version="1.0",  # 当前版本
    author="wupeiqi",  # 作者
    author_email="wupeiqi@live.com",  # 作者邮箱
    description="一个非常NB的包",  # 模块简介
    url="https://github.com/wupeiqi/fucker",  # 模块github地址
    packages=setuptools.find_packages(),  # 自动找到项目中导入的模块
    
    # 安装过程中,需要安装的静态文件,如配置文件、service文件、图片等
    data_files=[
        ('', ['conf/*.conf']),
        ('/usr/lib/systemd/system/', ['bin/*.service']),
    ],
    # 希望被打包的文件
    package_data={
        '':['*.txt'],
        'bandwidth_reporter':['*.txt']
    },
    
    # 不打包某些文件
    exclude_package_data={
        'bandwidth_reporter':['*.txt']
    }
)

除了上面的参数配置之外,还可以使用一个名为MANIFEST.in的文件来控制文件的分发。 下面是一个 MANIFET.in 文件示例:

include *.txt
recursive-include examples *.txt *.py
prune examples/sample?/build

该配置指定了以下几点

MANIFEST.in需要放在与setup.py同级的顶级目录下,setuptools会手动读取该文件。

一般打包时不需要大量的文件,所以我们也会直接在setup.py文件中使用;

2.3.4 依赖包下载

from setuptools import setup, find_packages
setup(
    ...
    # 表明当前模块依赖哪些包,若环境中没有,则会从pypi中下载安装
    install_requires=['docutils>=0.3'],
    # setup.py 本身要依赖的包,这通常是为一些setuptools的插件准备的配置
    # 这里列出的包,不会自动安装。
    setup_requires=['pbr'],
    # 仅在测试时需要使用的依赖,在正常发布的代码中是没有用的。
    # 在执行python setup.py test时,可以自动安装这三个库,确保测试的正常运行。
    tests_require=[
        'pytest>=3.3.1',
        'pytest-cov>=2.5.1',
    ],
    # 用于安装setup_requires或tests_require里的软件包
    # 这些信息会写入egg的 metadata 信息中
    dependency_links=[
        "http://example2.com/p/foobar-1.0.tar.gz",
    ],
    # install_requires 在安装模块时会自动安装依赖包
    # 而 extras_require 不会,这里仅表示该模块会依赖这些包
    # 但是这些包通常不会使用到,只有当你深度使用模块时,才会用到,这里需要你手动安装
    extras_require={
        'PDF':  ["ReportLab>=1.2", "RXP"],
        'reST': ["docutils>=0.3"],
    }
)

以上是各种情况下的参数说明,最常用的是第一个install_requires。 该参数最常用的用法如下:

2.3.5 安装环境限制

有些库并不适用于所有 Python 版本。 如果一个库安装在不兼容的Python环境下,理论上在使用时不应该报错,但在安装过程中应该会失败,提示严禁安装。

这样的功能可以使用python_requires来实现。

setup(
    ...
    python_requires='>=2.7, <=3',
)

2.3.6 生成可执行分发

from setuptools import setup, find_packages
setup(
    name="mytest",
    version="1.0",
    author="wangbm",
    author_email="wongbingming@163.com",
    description="Learn to Pack Python Module",
    url="http://iswbm.com/", 
    packages=find_packages(),
    # 用来支持自动生成脚本,安装后会自动生成 /usr/bin/foo 的可执行文件
    # 该文件入口指向 foo/main.py 的main 函数
    entry_points={
        'console_scripts': [
            'foo = foo.main:main'
        ]
    },
    # 将 bin/foo.sh 和 bar.py 脚本,生成到系统 PATH中
    # 执行 python setup.py install 后
    # 会生成 如 /usr/bin/foo.sh 和 如 /usr/bin/bar.py
    scripts=['bin/foo.sh', 'bar.py']
)

编译pip源码-pip包解读

里面的脚本有sh和py后缀。 安装完成后,setuptools会完整连接到/usr/bin并添加可执行权限。

如果你想对这些文件进行一些更改,比如删除多余的后缀,你可以这样做

from setuptools.command.install_scripts import install_scripts
class InstallScripts(install_scripts):
    def run(self):
        setuptools.command.install_scripts.install_scripts.run(self)
        # Rename some script files
        for script in self.get_outputs():
            if basename.endswith(".py") or basename.endswith(".sh"):
                dest = script[:-3]
            else:
                continue
            print("moving %s to %s" % (script, dest))
            shutil.move(script, dest)
setup(
    ...
    scripts=['bin/foo.sh', 'bar.py'],
    cmdclass={
        "install_scripts": InstallScripts
    }
)

此方法类似于django使用django-adminstartprojectname。 我们猜测这是这些的包装形式。 稍后我们会阅读django的部分源码来分析这个命令的真正原理;

2.3.6 ext_modules

ext_modules 参数用于创建 C 或 C++ 扩展包。 虽然Extension实例列表,但每个Extension实例都描述了一个独立的扩展模块,扩展模块可以设置扩展包名称、头文件、源文件、链接库及其路径、宏定义和编辑参数等,如:

setup(
    # other arguments here...
    ext_modules=[
        Extension('foo',
                  glob(path.join(here, 'src', '*.c')),
                  libraries = [ 'rt' ],
                  include_dirs=[numpy.get_include()])
    ]
)

2.3.7 指定发布

setup.py 中只能指定版本,不能指定版本。 如果需要更改版本号,可以使用--release参数指定

python setup.py bdist_rpm --release=20200617

setup.py中的参数非常多,看来不依赖文档来写一个setup.py并不是那么简单。 为了方便提醒,我整理了setup函数的一些常用参数:setup.py的参数很多,参考如下:

2.3.8 构建包 2.3.9 安装包

一般情况下,我们通过上面创建的源码包或者二补包来安装模块。

但是在编译setup.py的过程中,可能不是一步就能完成的,需要多次调试。 这个时候怎么测试我写的setup.py文件是否可用呢?

这时候你可以使用这个命令,它会将你的模块安装到系统全局环境中

# 虚拟环境中,可以直接安装到虚拟环境中;
$ python setup.py install

如果你的项目还处于开发阶段,频繁安装模块也是一个麻烦。

这时候就可以使用这个命令来安装了。 该方法并不真正安装包编译pip源码,而是在系统环境中创建一个软链接,指向包实际所在的目录。 那边改了包然后就不用安装就生效了,这样就可以调试了。

# 生产环境中安装;
$ python setup.py develop

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 编译pip源码-pip包解读 https://www.wkzy.net/game/155449.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务