器→工具, 编程语言

Python包的构建与发布

钱魏Way · · 91 次浏览

PyPI简介

PyPI是一个在线存储库,用于托管和分发Python软件包。它为Python开发者提供了一个集中管理和查找第三方库的地方。PyPI上的每个包都有一个唯一的名称和版本号,用户可以通过pip(Python的包管理工具)来安装这些包。

PyPI的主要功能

  • 发布包:开发者可以将自己的Python包发布到PyPI,供其他用户安装和使用。
  • 搜索包:用户可以在PyPI网站上搜索所需的包,并查看其文档、版本历史和其他相关信息。
  • 安装包:用户可以使用pip命令从PyPI安装包。
  • 管理依赖:PyPI支持依赖管理,当安装一个包时,pip会自动安装该包所依赖的其他包。

创建自己的Python模块

编写Python模块是组织和封装代码的基本方式。模块是一个包含Python代码的文件,以.py为扩展名。

创建模块文件

模块实际上就是一个Python文件。因此,创建一个模块的第一步是创建一个.py文件。例如,创建一个名为mymodule.py的文件:

touch mymodule.py

编写代码

在mymodule.py中编写你的Python代码。这些代码可以包括函数、类、变量等。以下是一个简单的示例:

# mymodule.py

def greet(name):
    return f"Hello, {name}!"

class Calculator:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

PI = 3.14159

使用模块

你可以在其他Python文件中导入和使用这个模块。假设你有一个名为main.py的文件:

# main.py

# 导入整个模块
import mymodule

# 使用模块中的函数
print(mymodule.greet("Alice"))

# 使用模块中的类
calc = mymodule.Calculator()
print(calc.add(5, 3))

# 使用模块中的变量
print(mymodule.PI)

# 导入特定的函数、类或变量
from mymodule import greet, Calculator

print(greet("Bob"))
calc = Calculator()
print(calc.subtract(10, 4))

模块的命名空间

每个模块都有自己的命名空间,因此模块中的变量、函数和类不会与其他模块中的同名对象冲突。你可以通过模块名.对象名的方式访问模块中的对象。

模块的搜索路径

当你导入一个模块时,Python会在一系列目录中搜索该模块。搜索路径包括:

  • 当前脚本所在目录
  • PYTHONPATH环境变量中指定的目录
  • Python安装目录中的标准库

你可以通过查看sys.path列表来查看当前的搜索路径:

import sys
print(sys.path)

模块的初始化代码

在模块中,你可以编写一些初始化代码,这些代码会在模块首次被导入时执行。这通常用于设置模块的初始状态或执行一些必要的初始化操作。

# mymodule.py

print("Initializing mymodule")

def greet(name):
    return f"Hello, {name}!"

使用__name__属性

每个模块都有一个__name__属性。当模块被直接运行时,__name__的值是”__main__”,而当模块被导入时,__name__的值是模块的名称。这可以用于编写模块的测试代码,只在模块被直接运行时执行:

# mymodule.py

def greet(name):
    return f"Hello, {name}!"

if __name__ == "__main__":
    # 只有在直接运行模块时才会执行
    print(greet("World"))

通过以上步骤,你可以轻松创建并使用Python模块,从而使代码更加模块化和可重用。

最佳实践

创建Python模块时,有一些注意事项和最佳实践可以帮助你编写更高质量、更易于维护的代码。以下是一些关键点:

模块命名

  • 简洁明了:模块名应清晰地描述其功能或用途。
  • 小写字母:通常模块名使用小写字母,单词之间用下划线分隔(例如,my_module)。
  • 避免冲突:确保模块名不与Python标准库或常用第三方库冲突。

代码组织

  • 函数和类的划分:将相关功能封装在函数和类中,保持模块的职责单一。
  • 避免全局变量:尽量避免使用全局变量,以减少意外修改和依赖。
  • 适度分割代码:如果模块变得过于庞大,考虑将其拆分为多个模块或包。

文档和注释

  • 模块文档字符串:在模块开头添加文档字符串,描述模块的功能和用法。
  • 函数和类文档:为每个函数和类添加文档字符串,说明其参数、返回值和用途。
  • 注释:在代码中添加必要的注释,以解释复杂或重要的部分。

错误处理

  • 使用异常:通过抛出和捕获异常来处理错误,而不是使用返回错误码。
  • 自定义异常:对于模块特定的错误,考虑定义自定义异常类。

测试代码

  • 编写测试:为模块编写单元测试,确保功能正确。可以使用unittest或pytest等测试框架。
  • 测试入口:在模块中使用if __name__ == “__main__”:块编写测试代码,方便直接运行模块时进行简单测试。

代码风格

  • 遵循PEP 8:遵循Python的代码风格指南PEP 8,保持代码一致性和可读性。
  • 使用工具:使用flake8、pylint等工具检查代码风格和质量。

依赖管理

  • 最小化依赖:尽量减少模块的外部依赖,以提高可移植性。
  • 版本控制:如果需要依赖其他包,指定明确的版本号或范围,以避免不兼容问题。

版本和发布

  • 语义化版本控制:使用语义化版本控制(如0.0)管理模块的版本。
  • 文档更新:每次更新模块时,更新相关文档和变更日志。

通过遵循这些注意事项和最佳实践,你可以创建更可靠、易于维护和可重用的Python模块。

如何打包Python模块?

Python包格式

Python的包格式主要有以下几种,它们在不同的场景下被使用,以便于包的分发、安装和管理:

源码分发包(Source Distribution,sdist)

  • 文件格式:通常是一个.tar.gz或.zip文件。
  • 内容:包含源代码、py、README、LICENSE等文件。
  • 用途:源码分发包是最传统的Python包格式,适用于需要查看或修改源代码的场景。用户在安装时需要编译源码,因此需要满足所有构建依赖。
  • 创建命令:可以使用setuptools或distutils创建:python setup.py sdist

预编译分发包(Built Distribution)

  • 文件格式:通常是.egg或.whl文件。
  • 内容:包含已经编译好的代码,适合直接安装。
  • 用途:预编译分发包适合那些包含C扩展模块的项目,因为它们可以避免用户在安装时编译源码。

.egg 文件

  • 特性:较早的预编译包格式,由setuptools引入。
  • 缺点:逐渐被.whl文件取代,因为.whl文件有更好的兼容性和功能支持。

.whl 文件(Wheel)

  • 特性:目前最流行的Python预编译包格式。
  • 优点:便于分发和安装,不需要在安装时编译源码,支持更复杂的依赖管理。
  • 创建命令:可以使用wheel库创建:
pip install wheel
python setup.py bdist_wheel

本地开发包

  • 文件格式:没有特定的文件格式,通常是一个目录结构,包含源代码和配置文件。
  • 用途:用于本地开发和测试,可以直接在开发环境中使用。
  • 安装命令:可以使用pip的-e选项进行开发模式安装:pip install -e .

包管理工具支持

不同的包管理工具支持不同的包格式。以下是常见的工具及其支持的格式:

  • pip:主要支持.whl和.tar.gz(sdist)格式。
  • setuptools:支持创建和安装.egg和.tar.gz(sdist)格式。
  • wheel:专门用于创建和安装.whl文件。

选择包格式的考虑因素

  • 兼容性:whl文件具有广泛的兼容性,适合大多数用户。
  • 构建复杂性:对于需要编译的项目,提供whl文件可以减少用户的安装难度。
  • 源码访问:如果希望用户能够查看和修改源码,提供sdist是一个好选择。

Python模块打包工具

Python模块打包工具有助于简化构建、打包和分发Python包的过程。以下是一些常用的Python模块打包工具:

Distutils

distutils是Python标准库的一部分,用于打包和分发Python软件。尽管在过去它是Python打包的主要工具,但随着更现代化工具如setuptools的出现,distutils的使用逐渐减少。尽管如此,了解distutils仍然有助于理解Python打包的基础。

基本功能

distutils提供了一些基本功能,用于构建、打包和安装Python模块和扩展。其主要功能包括:

  • 构建模块:将Python源代码转换为可分发格式。
  • 打包:创建源分发包,通常是.tar.gz或.zip格式。
  • 安装:将模块安装到Python的site-packages目录中。

使用distutils

使用distutils的关键是编写一个setup.py脚本,该脚本定义了包的元数据和安装信息。以下是一个简单的setup.py示例:

from distutils.core import setup

setup(
    name='mypackage',
    version='0.1',
    packages=['mypackage'],
    author='Your Name',
    author_email='your.email@example.com',
    description='A simple example package',
)

主要参数:

  • name:包的名称。
  • version:包的版本号。
  • packages:包含的Python包列表。
  • author:作者的名字。
  • author_email:作者的电子邮件。
  • description:简要描述包的功能。

常用命令

在项目的根目录下运行以下命令来执行不同的打包和安装操作:

  • 构建包:将模块构建为平台特定的格式。python setup.py build
  • 创建源分发包:生成一个可用于分发的源代码包。python setup.py sdist
  • 安装包:将包安装到Python环境中。python setup.py install

限制与缺点

尽管distutils在Python打包的历史中起到了重要作用,但它有一些限制:

  • 依赖管理:distutils不支持自动管理包的依赖关系。
  • 扩展性:不如setuptools那样灵活,无法方便地扩展或定制打包过程。
  • 功能有限:缺乏许多现代打包工具提供的高级功能,如Wheel格式支持、入口点管理等。

现代替代方案

由于上述限制,Python社区推荐使用setuptools和其他现代工具(如poetry、flit)来替代distutils。这些工具提供了更丰富的功能和更好的依赖管理支持。例如:

  • setuptools:是distutils的一个扩展,提供了更多的功能和灵活性。大多数现代Python项目使用setuptools。
  • wheel:与setuptools结合使用,提供一种更现代的分发格式。
  • twine:用于安全地上传包到PyPI。

未来

distutils在Python 3.10及以后版本中已被弃用,并计划在未来的Python版本中移除。社区建议开发者迁移到setuptools或其他现代打包工具。了解distutils的工作原理仍然有助于理解Python打包的基础,但不建议在新项目中使用它。

通过了解distutils,你可以更好地理解Python打包和分发的基础知识,但在实际项目中,使用更现代的工具会更有利于维护和扩展。

setuptools

setuptools是Python中最常用的打包和分发工具之一,它扩展了Python标准库中的distutils,提供了更强大的功能和更灵活的配置选项。以下是关于setuptools的详细介绍:

基本功能

setuptools的主要功能包括:

  • 依赖管理:自动管理包的依赖关系。
  • 创建和分发Wheel格式:支持创建Wheel格式的分发包,便于快速安装。
  • 包自动发现:自动发现和包括包目录。
  • 扩展模块支持:支持构建C和C++扩展模块。
  • 入口点和控制台脚本:定义包的入口点和命令行工具。

安装

如果你的Python环境中没有安装setuptools,可以通过以下命令安装:

pip install setuptools

使用setuptools

使用setuptools的核心是创建一个setup.py脚本,定义包的元数据、依赖和安装信息。以下是一个基本的setup.py示例:

from setuptools import setup, find_packages

setup(
    name='mypackage',
    version='0.1.0',
    packages=find_packages(),
    install_requires=[
        'numpy>=1.18.0',
        'requests'
    ],
    author='Your Name',
    author_email='your.email@example.com',
    description='A simple example package',
    long_description=open('README.md').read(),
    long_description_content_type='text/markdown',
    url='https://github.com/yourusername/mypackage',
    classifiers=[
        'Programming Language :: Python :: 3',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
    ],
    python_requires='>=3.6',
    entry_points={
        'console_scripts': [
            'mycommand=mypackage.module:main_function',
        ],
    },
)

关键参数

  • name:包的名称。
  • version:包的版本号。
  • packages:要包含的包列表,通常使用find_packages()自动发现。
  • install_requires:包的依赖列表。
  • entry_points:定义控制台脚本或GUI应用的入口点。
  • classifiers:用于在PyPI上分类包的信息。
  • python_requires:指定支持的Python版本。

常用命令

在项目根目录下运行以下命令来执行不同的操作:

  • 构建包:创建源分发包和Wheel分发包。python setup.py sdist bdist_wheel
  • 安装包:将包安装到Python环境中。pip install .
  • 开发模式安装:安装包的开发版本,允许在源代码目录中进行更改。pip install -e .

入口点和控制台脚本

setuptools允许定义入口点,使包可以通过命令行工具运行。使用entry_points参数可以指定控制台脚本:

entry_points={
    'console_scripts': [
        'mycommand=mypackage.module:main_function',
    ],
},

这将创建一个命令行工具mycommand,它调用mypackage.module中的main_function。

包自动发现

使用find_packages()函数可以自动发现项目中的包,而不必手动列出它们:

packages=find_packages(),

依赖管理

setuptools支持在install_requires中指定依赖包及其版本范围:

install_requires=[
    'numpy>=1.18.0',
    'requests'
],

指定该参数后,在安装包时会自定从 pypi 仓库中下载指定的依赖包安装。

此外,还支持从指定链接下载依赖,即指定 dependency_links 参数,如:

dependency_links = [
    "http://packages.example.com/snapshots/foo-1.0.tar.gz",
    "http://example2.com/p/bar-1.0.tar.gz",
]

扩展性和插件

setuptools支持编写自定义的构建命令和扩展,使其具有很高的灵活性。

包含数据文件

  • package_data:该参数是一个从包名称到 glob 模式列表的字典。如果数据文件包含在包的子目录中,则 glob 可以包括子目录名称。其格式一般为 {‘package_name’: [‘files’]},比如:package_data={‘mypkg’: [‘data/*.dat’],}。
  • include_package_data:该参数被设置为 True 时自动添加包中受版本控制的数据文件,可替代 package_data,同时,exclude_package_data 可以排除某些文件。注意当需要加入没有被版本控制的文件时,还是仍然需要使用 package_data 参数才行。
  • data_files:该参数通常用于包含不在包内的数据文件,即包的外部文件,如:配置文件,消息目录,数据文件。其指定了一系列二元组,即(目的安装目录,源文件) ,表示哪些文件被安装到哪些目录中。如果目录名是相对路径,则相对于安装前缀进行解释。
  • manifest template:manifest template 即编写in 文件,文件内容就是需要包含在分发包中的文件。一个 MANIFEST.in 文件如下:
include *.txt
recursive-include examples *.txt *.py
prune examples/sample?/build

生成脚本

有两个参数 scripts 参数或 console_scripts 可用于生成脚本。

entry_points 参数用来支持自动生成脚本,其值应该为是一个字典,从 entry_point 组名映射到一个表示 entry_point 的字符串或字符串列表,如:

setup(
    # other arguments here...
    entry_points={
        'console_scripts': [
            'foo=foo.entry:main',
            'bar=foo.entry:main',
        ],    
    }
)

scripts 参数是一个 list,安装包时在该参数中列出的文件会被安装到系统 PATH 路径下。如:

scripts=['bin/foo.sh', 'bar.py']

用如下方法可以将脚本重命名,例如去掉脚本文件的扩展名(.py、.sh):

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(
    # other arguments here...
    cmdclass={
        "install_scripts": InstallScripts
    }
)

其中,cmdclass 参数表示自定制命令。

自定义命令

Setup.py 文件有很多内置的的命令,可以使用 python setup.py –help-commands 查看。如果想要定制自己需要的命令,可以添加 cmdclass 参数,其值为一个 dict。实现自定义命名需要继承 setuptools.Command 或者 distutils.core.Command 并重写 run 方法。

from setuptools import setup, Command

class InstallCommand(Command):
    description = "Installs the foo."
    user_options = [
        ('foo=', None, 'Specify the foo to bar.'),
    ]
    def initialize_options(self):
        self.foo = None
    def finalize_options(self):
        assert self.foo in (None, 'myFoo', 'myFoo2'), 'Invalid foo!'
    def run(self):
        install_all_the_things()

setup(
    ...,
    cmdclass={
        'install': InstallCommand,
    }
)

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()])
    ]
)

zip_safe

zip_safe 参数决定包是否作为一个 zip 压缩后的 egg 文件安装,还是作为一个以 .egg 结尾的目录安装。因为有些工具不支持 zip 压缩文件,而且压缩后的包也不方便调试,所以建议将其设为 False,即 zip_safe=False。

setup.cfg 文件

setup.cfg 文件用于提供 setup.py 的默认参数,详细的书写规则可参考:https://docs.python.org/3/distutils/configfile.html

版本命名

包版本的命名格式应为如下形式:

N.N[.N]+[{a|b|c|rc}N[.N]+][.postN][.devN]

从左向右做一个简单的解释:

  • “N.N”: 必须的部分,两个 “N” 分别代表了主版本和副版本号
  • “[.N]”: 次要版本号,可以有零或多个
  • “{a|b|c|rc}”: 阶段代号,可选, a, b, c, rc 分别代表 alpha, beta, candidate 和 release candidate
  • “N[.N]”: 阶段版本号,如果提供,则至少有一位主版本号,后面可以加无限多位的副版本号
  • “.postN”: 发行后更新版本号,可选
  • “.devN”: 开发期间的发行版本号,可选

现代化和未来

随着Python打包生态系统的发展,setuptools也在不断更新,以支持新的打包标准和功能。虽然有其他现代化工具如poetry和flit,但setuptools仍然是最广泛使用的打包工具之一。

通过setuptools,你可以轻松管理Python包的构建、依赖和分发,使得包的发布和安装更加便捷和可靠。

wheel

wheel是Python中一种现代的打包格式,旨在取代旧的.egg格式。它是一个二进制分发格式,可以显著加快包的安装速度,因为它不需要在安装时进行编译。以下是关于wheel的详细介绍:

基本概念

  • Wheel格式:.whl文件是一个包含预编译代码和元数据的压缩归档文件。它是PEP 427中定义的标准。
  • 优势:与源代码分发包不同,Wheel包不需要在目标机器上编译,可以直接安装,大大加快了安装速度。

安装

wheel工具通常与setuptools一起使用,并且可以通过pip进行安装:

pip install wheel

创建Wheel包

要创建Wheel包,你需要在项目根目录下运行以下命令:

python setup.py bdist_wheel

这会在dist/目录中生成一个.whl文件。

使用Wheel包

安装Wheel包可以通过pip命令:

pip install your_package.whl

pip会自动从PyPI安装Wheel格式的包,如果没有找到Wheel格式,则会退回到源代码格式进行安装。

Wheel包的优势

  • 快速安装:由于Wheel包是预编译的,安装时不需要编译步骤,因此速度更快。
  • 跨平台支持:虽然Wheel包可以包含平台特定的代码,但也可以构建纯Python的Wheel包,使其在多个平台上兼容。
  • 兼容性:Wheel格式是Python官方推荐的分发格式,支持大多数Python工具和服务。
  • 元数据:包含丰富的元数据,可以用于依赖解析和环境管理。

Wheel包的内容

一个典型的Wheel包包含以下内容:

  • 纯Python代码:.py文件
  • 编译的扩展模块:如.so(Linux)或.pyd(Windows)文件
  • 元数据文件:如METADATA、WHEEL和RECORD文件,这些文件描述包的信息、格式版本和文件列表。

Wheel与其他工具的集成

  • setuptools:通常与setuptools结合使用,通过py配置包的信息,然后使用bdist_wheel命令生成Wheel包。
  • twine:用于将Wheel包上传到PyPI。
  • pip:用于安装Wheel包。

平台和Python版本标签

Wheel包的文件名通常包含平台和Python版本的信息,以确保在正确的环境中安装。例如:

example_package-1.0.0-py3-none-any.whl

  • example_package:包的名称。
  • 0.0:包的版本。
  • py3:支持的Python版本。
  • none:ABI(应用程序二进制接口)标签。
  • any:支持的操作系统。

未来发展

Wheel格式已经成为Python社区的标准分发格式,并且得到了广泛的支持。它与setuptools和pip等工具紧密集成,使得Python包的分发和安装更加高效和便捷。

通过使用Wheel格式,开发者可以显著加快包的安装过程,并提高用户体验,特别是对于包含C扩展模块的包,这种优势尤为明显。

flit

flit是一个轻量级的Python打包工具,旨在简化创建和发布Python包的过程。与setuptools和distutils不同,flit专注于纯Python包的管理,尤其是那些不需要复杂构建步骤的包。

特点和优势

  • 简单配置:使用toml文件进行配置,避免了复杂的setup.py脚本。
  • 快速发布:提供简单的命令来构建和上传包到PyPI。
  • 现代化设计:支持PEP 517和PEP 518标准,使其与现代Python项目管理方式兼容。
  • 自动生成Wheel包:默认创建Wheel格式的分发包,简化发布过程。

安装

flit可以通过pip安装:

pip install flit

项目配置

flit使用pyproject.toml文件来配置包的元数据和依赖项。以下是一个示例配置:

[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "your_package"
version = "0.1.0"
description = "A brief description of your package"
authors = [
    { name="Your Name", email="your.email@example.com" }
]
readme = "README.md"
requires-python = ">=3.6"
license = { text="MIT" }
dependencies = [
    "requests >=2.25",
    "numpy >=1.18"
]

[project.urls]
Homepage = "https://github.com/yourusername/your_package"

常用命令

  • 初始化项目:在项目目录中生成一个初始的toml文件。flit init
  • 构建包:创建Wheel包和源分发包。flit build
  • 发布包:将包上传到PyPI。flit publish

发布到PyPI

在发布之前,确保你的PyPI账户已经设置好,并在项目根目录下运行:

flit publish

这会自动构建和上传你的包到PyPI。你需要提供PyPI的凭证,建议使用API token。

配置文件

除了pyproject.toml,你还可以使用~/.pypirc文件来存储PyPI的认证信息,类似于twine的配置。

支持的功能

  • 依赖管理:通过dependencies字段管理包的依赖。
  • 多Python版本支持:指定requires-python字段以定义支持的Python版本范围。
  • 文档和URL:可以在配置中指定项目的文档和相关URL。

适用场景

flit非常适合以下场景:

  • 简单的纯Python项目:不需要复杂的构建过程或C扩展模块。
  • 快速原型和实验:快速创建和发布包的能力使其适合快速开发和迭代。
  • 现代Python项目:支持PEP 517/518,适用于依赖管理和现代项目结构。

与其他工具的比较

  • 与setuptools:flit更简单,适合不需要复杂构建步骤的项目。setuptools功能更强大,适合需要复杂自定义构建的项目。
  • 与poetry:flit更轻量,而poetry提供了更全面的依赖管理和虚拟环境支持。

通过使用flit,开发者可以快速、简便地管理Python包的构建和发布过程,特别适合那些不需要复杂构建步骤的纯Python项目。

Poetry

Poetry 是一个用于Python项目的依赖管理和打包工具,它提供了一种简化和现代化的方式来管理Python项目的依赖、构建和发布。与传统的工具相比,Poetry 提供了一套集成的解决方案,涵盖了项目的整个生命周期。

特点和优势

  • 依赖解析:Poetry使用一种更智能的依赖解析器,能够自动解决依赖冲突。
  • 虚拟环境管理:自动创建和管理虚拟环境,使项目环境隔离。
  • 简化配置:使用toml 文件进行配置,统一管理项目元数据和依赖。
  • 集成的命令行工具:提供了一套命令行工具,用于管理项目的依赖、构建和发布。

安装

可以通过以下命令安装 Poetry:

curl -sSL https://install.python-poetry.org | python3 -

或者使用 pip 安装:

pip install poetry

项目初始化

使用 Poetry 初始化一个新项目:

poetry new my_project

这将创建一个新的项目目录结构,包含基本的文件和目录。

配置文件

Poetry 使用 pyproject.toml 文件来配置项目的元数据和依赖:

[tool.poetry]
name = "my_project"
version = "0.1.0"
description = "A brief description of the project"
authors = ["Your Name <your.email@example.com>"]
license = "MIT"

[tool.poetry.dependencies]
python = "^3.8"
requests = "^2.25"
numpy = "^1.21"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

依赖管理

  • 添加依赖:可以使用以下命令添加依赖:poetry add requests
  • 移除依赖:使用以下命令移除依赖:poetry remove requests
  • 更新依赖:更新所有依赖到最新版本:poetry update

虚拟环境管理

Poetry 会自动创建一个虚拟环境来管理项目的依赖:

  • 激活虚拟环境:poetry shell
  • 运行命令:在虚拟环境中运行命令:poetry run python script.py

构建和发布

  • 构建项目:生成分发包(Wheel 和 sdist):poetry build
  • 发布项目:将包上传到PyPI:poetry publish

锁文件

Poetry 使用 poetry.lock 文件来记录确切的依赖版本,以确保在不同环境中安装一致的依赖版本。

适用场景

Poetry 非常适合以下场景:

  • 现代Python项目:需要一个统一的解决方案来管理依赖和打包。
  • 复杂依赖管理:项目有复杂的依赖关系,需要更智能的解析器。
  • 团队协作:确保团队成员使用一致的依赖版本。

与其他工具的比较

  • 与pip 和 setuptools:Poetry 提供了更高级的依赖管理和自动化的虚拟环境管理。
  • 与flit:Poetry 更加全面,支持依赖管理和虚拟环境,而 flit 更加轻量,主要用于打包。

通过使用 Poetry,开发者可以简化Python项目的依赖管理和打包过程,使得项目的管理更加高效和现代化。

Hatch

Hatch 是一个用于Python项目的现代化打包和环境管理工具。它旨在提供一个简单且强大的工具集,以便开发者能够更轻松地管理Python项目的生命周期,包括环境管理、依赖管理、版本控制和发布。以下是关于 Hatch 的详细介绍:

特点和优势

  • 环境管理:Hatch提供了强大的虚拟环境管理功能,可以创建、激活和管理项目的虚拟环境。
  • 多版本支持:支持多个Python版本和项目版本管理。
  • 灵活的项目配置:通过配置文件实现灵活的项目设置。
  • 插件系统:可扩展的插件系统,允许用户自定义和扩展Hatch 的功能。
  • 自动化流程:自动化常见的开发和发布任务,提高开发效率。

安装

Hatch 可以通过 pip 安装:

pip install hatch

项目初始化

使用 Hatch 初始化一个新项目:

hatch new my_project

这将创建一个新的项目目录结构,并生成必要的配置文件。

配置文件

Hatch 使用 hatch.toml 文件进行项目配置。以下是一个基本示例:

[project]
name = "my_project"
version = "0.1.0"
description = "A brief description of the project"
authors = ["Your Name <your.email@example.com>"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.envs.default]
dependencies = [
    "requests>=2.25",
    "numpy>=1.21"
]

环境管理

Hatch 提供了一套命令来管理虚拟环境:

  • 创建环境:hatch env create
  • 激活环境:hatch shell
  • 删除环境:hatch env remove

依赖管理

  • 添加依赖:在toml 中指定依赖,然后更新环境。
  • 更新依赖:更新环境中的所有依赖:hatch env update

构建和发布

  • 构建项目:生成分发包(Wheel 和 sdist):hatch build
  • 发布项目:将包上传到PyPI:hatch publish

版本管理

Hatch 支持版本控制,允许开发者轻松管理项目的版本:

  • 更新版本:hatch version <new-version>

插件系统

Hatch 具有可扩展的插件系统,用户可以编写插件以添加自定义功能。插件可以用于扩展 Hatch 的构建、测试、发布等功能。

与其他工具的比较

  • 与Poetry:Hatch 更加灵活,特别是在环境管理和插件扩展方面,而 Poetry 提供了更全面的依赖解析和锁定功能。
  • 与setuptools:Hatch 更现代化,提供了更高层次的功能集成,而 setuptools 更传统,适合需要复杂构建步骤的项目。

适用场景

Hatch 非常适合以下场景:

  • 多环境开发:需要管理多个Python版本和环境。
  • 自动化流程:需要自动化的开发和发布流程。
  • 灵活扩展:需要自定义工具功能以满足特定需求。

通过使用 Hatch,开发者可以有效地管理Python项目的环境、依赖和版本,使得项目的开发和发布流程更加现代化和高效。

Python模块打包流程

打包Python模块是将你的代码打包成一个可分发的格式,以便其他人可以轻松安装和使用。通常,这涉及创建一个源分发包和一个Wheel分发包。以下是如何打包Python模块的步骤:

准备项目结构

首先,确保你的项目有一个良好的目录结构。以下是一个基本的项目结构示例:

your_project/
    ├── your_module/
    │   ├── __init__.py
    │   └── module.py
    ├── setup.py
    ├── README.md
    └── LICENSE
  • your_module/:这是你的模块所在的目录。
  • py:使your_module成为一个包。
  • py:包含包的元数据和安装信息。
  • md:项目的描述文件。
  • LICENSE:许可证文件。

创建 setup.py

setup.py是一个Python脚本,包含包的元数据和安装信息。下面是一个简单的setup.py示例:

from setuptools import setup, find_packages

setup(
    name='your_module',
    version='0.1.0',
    packages=find_packages(),
    install_requires=[],  # 如果有依赖包,在此列出
    author='Your Name',
    author_email='your.email@example.com',
    description='A brief description of your module',
    long_description=open('README.md').read(),
    long_description_content_type='text/markdown',
    url='https://github.com/yourusername/your_module',
    classifiers=[
        'Programming Language :: Python :: 3',
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',
    ],
    python_requires='>=3.6',
)

编写 README.md

README.md是你的项目的描述文件,通常使用Markdown格式。它应该包括项目的描述、安装和使用说明。

编写 LICENSE

选择一个合适的开源许可证,并在项目根目录中添加一个LICENSE文件。例如,MIT许可证、Apache许可证等。

构建分发包

安装必要的工具:

pip install setuptools wheel

然后在项目根目录下运行以下命令来构建你的包:

python setup.py sdist bdist_wheel

这将生成源分发包(在dist/目录下的.tar.gz文件)和Wheel分发包(.whl文件)。

测试安装包

在本地环境中测试安装包,确保它可以正常工作。你可以使用以下命令安装本地构建的包:

pip install dist/your_module-0.1.0-py3-none-any.whl

如何将包发布到PyPI?

PyPI发布流程

如果你还没有PyPI账户,需要先在PyPI官网注册一个账户。确保你的电子邮件已经过验证。

上传包到PyPI

首先,安装twine工具:

pip install twine

使用twine将包上传到PyPI:

twine upload dist/*

这会提示你输入PyPI的用户名和密码(建议使用PyPI的API token作为密码以增强安全性)。

使用测试PyPI(可选)

在正式发布之前,可以先将包上传到测试PyPI进行测试。测试PyPI是一个用于测试包发布的独立实例。

首先,将包上传到测试PyPI:

twine upload --repository-url https://test.pypi.org/legacy/ dist/*

要从测试PyPI安装包,可以使用:

pip install --index-url https://test.pypi.org/simple/ your_package

版本管理

  • 确保你的包版本号是唯一的,每次发布新版本时要更新版本号。
  • 使用语义化版本控制(Semantic Versioning)来管理版本号,如0.0。

更新日志和文档

  • 维护一个更新日志,记录每个版本的更改。
  • 确保你的md和其他文档是最新的,并包含所有必要的信息。

通过这些步骤,你可以将你的Python包发布到PyPI,使得其他用户可以通过pip安装和使用你的包。发布后,确保及时更新和维护你的包,以保持其功能和安全性。

Twine简介

twine是一个用于将Python包上传到Python Package Index (PyPI) 及其镜像的工具。它提供了一种安全且可靠的方法来上传分发包,替代了旧的setup.py upload方法。

安装

twine可以通过pip安装:

pip install twine

功能与优势

  • 安全性:twine使用HTTPS来上传包,并且支持使用PyPI的API tokens,避免了在命令行中暴露PyPI密码。
  • 兼容性:支持上传Wheel格式和源代码格式的分发包。
  • 简单易用:提供简单的命令行接口,可以轻松上传包。
  • 错误检测:在上传之前检查包的完整性和格式问题。

使用方法

构建包

在使用twine上传之前,需要先构建分发包。通常使用setuptools和wheel来创建这些包:

python setup.py sdist bdist_wheel

这将在dist/目录中生成分发包。

上传包

使用twine上传包到PyPI:

twine upload dist/*

这会提示你输入PyPI的用户名和密码。建议使用API token作为密码,以提高安全性。API token可以在PyPI账户设置中生成。

上传到测试PyPI

在将包上传到正式的PyPI之前,可以先将其上传到测试PyPI进行测试:

twine upload --repository-url https://test.pypi.org/legacy/ dist/*

配置

可以在~/.pypirc文件中配置PyPI和测试PyPI的登录信息,以避免每次上传时都输入用户名和密码。以下是一个示例配置:

[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = your_pypi_api_token

[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = your_testpypi_api_token

验证包

在上传之前,twine提供了验证包的命令,确保包格式正确且没有常见问题:

twine check dist/*

处理包上传失败

如果上传失败,twine会给出详细的错误信息。常见问题包括:

  • 版本冲突:尝试上传的包版本已经存在于PyPI中。
  • 网络问题:确保网络连接正常。
  • 认证失败:检查用户名、密码或API token是否正确。

其他命令和选项

  • twine upload:上传包到PyPI或其他仓库。
  • twine check:检查包的格式和完整性。
  • twine register:已经弃用,不再需要注册包名。
  • –skip-existing:跳过已经存在的版本,避免版本冲突错误。

常见问题

  • PyPI密码安全性:建议使用API token代替密码,以提高安全性。
  • 包名和版本管理:确保包名唯一且版本号遵循语义化版本控制。

通过使用twine,开发者可以安全且高效地将Python包上传到PyPI,方便其他用户安装和使用。twine是Python包分发过程中不可或缺的工具,提供了简化和安全的上传流程。

参考链接:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注