如何使用setuptools打包Python项目

  • 如何使用setuptools打包Python项目

    • 一、准备
    • 二、项目结构
    • 三、简单打包
      • 3.1 文件内容
      • 3.2 打包项目
      • 3.3 安装测试
    • 四、自定义打包
      • 4.1 添加子模块
      • 4.2 只生成 whl
      • 4.3 包含/排除数据
      • 4.4 编译模块
      • 4.5 生成可执行命令

pypi 官网给出了4个打包 whl 格式的工具:Hatchling、setuptools、Flit、PDM。

初步了解了一下,还是用 setuptools 。

本文主要内容包括:pyproject.toml 的简单配置、使用 python -m build 打包、使用 cython 编译模块、生成命令等内容。

本文仅为学习经验,深入学习请参考官方文档。

一、准备

安装 setuptools 和 build

pip install --upgrade setuptools    # 65.5.0
# 安装 build 以可以运行命令: python -m build
pip install --upgrade build    # 0.9.0

二、项目结构

以名为 pypackage 的项目为例(src 结构)

pypackage/
├── LICENSE           # LICENSE
├── pyproject.toml    # 项目配置信息
├── README.md         # 自述文件
├── src               # 源码
│   └── pypackage
│       ├── __init__.py
│       └── __main.py
└── tests             # 相关的测试└── test_main.py

还有另一种结构(flat 结构)

pypackage/
├── LICENSE           # LICENSE
├── pyproject.toml    # 项目配置信息
├── README.md         # 自述文件
│── pypackage         # 名字为项目名
│   ├── __init__.py
│   └── __main.py
└── tests             # 相关的测试└── test_main.py

setuptools 具有自动检测项目代码目录的功能。另外需要说明的是,使用 src-layout 的形式时,会添加 src 下的所有目录,建议 src 下只保留一个与项目名同名的目录

三、简单打包

3.1 文件内容

src/pypackage/__init__.py

from .__main import say_hello

src/pypackage/__main.py

def say_hello(name: str):__private_say(name)def __private_say(name: str):print(f"private say: Hello, {name}!")

tests/test_main.py

TEST_RELEASE = True
if not TEST_RELEASE:import sysimport pathlibroot_dir = pathlib.Path(__file__).absolute().parent.parentsys.path.insert(0, str(root_dir.joinpath("src")))# using pytest
def test_hello():import pypackage pypackage.say_hello("yluuu")

pyproject.toml

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"[project]
name = "pypackage"
version = "0.0.1"
dependencies = ["requests","rtoml; python_version<'3.8'",
]

3.2 打包项目

默认情况会根据依赖包创建一个隔离的虚拟环境来打包,但我是离线环境,所以不能用这种方式,需要添加 --no-isolation 选项

python -m build --no-isolation

打包如果成功会提示:Successfully built pypackage-0.0.1.tar.gz and pypackage-0.0.1-py3-none-any.whl,共生成了两个文件

3.3 安装测试

使用 pip 安装 whl 文件,查看安装目录 ~/miniconda3/lib/python3.7/site-packages/pypackage

-rw-rw-r--  1 yl yl   30 10月 31 08:19 __init__.py
-rw-rw-r--  1 yl yl  124 10月 31 08:19 __main.py
drwxrwxr-x  2 yl yl 4.0K 10月 31 08:19 __pycache__

在项目根目录下直接运行 pytest 命令,测试没有问题

 ~/test/pypackage ----------------- base py | yl@jisuan01 | 08:30:28
> pytest
======================== test session starts =========================
platform linux -- Python 3.7.13, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/yl/test/pypackage
collected 1 item                                                     tests/test_main.py .                                           [100%]========================= 1 passed in 0.01s ==========================

四、自定义打包

4.1 添加子模块

setuptools 有自动发现的功能:对于常用的两种项目形式(src-layout、flat-layout),setuptools 可以自动扫描并发现代码目录。

添加文件 src/pypackage/lib1/mod1.py

def func1():return 1

添加文件 src/pypackage/lib2/mod2.py

def func2():return 2

src 及 项目下的模块均可以自动被添加

adding 'pypackage/__init__.py'
adding 'pypackage/__main.py'
adding 'pypackage/lib1/mod1.py'    # 自动添加了
adding 'pypackage/lib2/mod2.py'    # 自动添加了
adding 'pypackage-0.0.1.dist-info/LICENSE'
adding 'pypackage-0.0.1.dist-info/METADATA'
adding 'pypackage-0.0.1.dist-info/WHEEL'
adding 'pypackage-0.0.1.dist-info/top_level.txt'
adding 'pypackage-0.0.1.dist-info/RECORD'

更多请参考: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html

4.2 只生成 whl

添加选项 --wheel 即可

python -m build --no-isolation --wheel

4.3 包含/排除数据

如 添加 keep.parquet 排除 exclude.txt

pypackage/
├── ...
│── src
│   └── pypackage
│       ├── __init__.py
│       ├── __main.py
│       └── data
│           ├── keep.parquet
│           └── exclude.txt
└── ...

pyproject.toml 添加

[tool.setuptools]
include-package-data = true[tool.setuptools.package-data]
pypackage = ["data/*.parquet"][tool.setuptools.exclude-package-data]
pypackage = ["data/*.txt"]

其实 include-package-data 默认就是 true 的

打包记录

adding 'pypackage/__init__.py'
adding 'pypackage/__main.py'
adding 'pypackage/data/keep.parquet'    # 这里
adding 'pypackage/lib1/mod1.py'
adding 'pypackage/lib2/mod2.py'
adding 'pypackage-0.0.1.dist-info/LICENSE'
adding 'pypackage-0.0.1.dist-info/METADATA'
adding 'pypackage-0.0.1.dist-info/WHEEL'
adding 'pypackage-0.0.1.dist-info/top_level.txt'
adding 'pypackage-0.0.1.dist-info/RECORD'

更多请参考: https://setuptools.pypa.io/en/latest/userguide/datafiles.html

4.4 编译模块

使用 cython

pip install cython --upgrade

创建 setup.py

# 方式一:按 setuptools 文档,使用 Extension 类,使用 cython 编译时无法设置 language_level TODO 待解决
# from setuptools import setup, Extension# setup(
#     ext_modules=[
#         Extension(
#             name="pypackage.lib1.mod1",
#             sources=["src/pypackage/lib1/mod1.pyx"],
#         )
#     ]
# )# 方式二:直接调用 cython,可以设置 language_level
# 备注: 子模块尽量添加 __init__.py 以确保编译后的库文件可以正常打包到子模块中。
from setuptools import setup
from Cython.Build import cythonizesetup(ext_modules=cythonize(module_list=["src/pypackage/lib1/mod1.pyx"], language_level=3)
)

另外在 pyproject.toml 中排除 c 文件打包

[tool.setuptools.exclude-package-data]
pypackage = ["info/*.txt"]
"pypackage.lib1" = ["*.c"]

src/pypackage/lib1/mod1.py 重命名为 src/pypackage/lib1/mod1.pyx,并在 src/pypackage/lib1 下添加 __init__.py 文件

然后使用 python -m build 时会自动调用 setup.py 生成库文件并打包

单独编译模块时运行 python setup.py build_ext

备注:测试过程中的坑,都在上面的注释里了

adding 'pypackage/__init__.py'
adding 'pypackage/__main.py'
adding 'pypackage/info/keep.parquet'
adding 'pypackage/lib1/__init__.py'
adding 'pypackage/lib1/mod1.cpython-37m-x86_64-linux-gnu.so'
adding 'pypackage/lib2/mod2.py'
adding 'pypackage-0.0.1.dist-info/LICENSE'
adding 'pypackage-0.0.1.dist-info/METADATA'
adding 'pypackage-0.0.1.dist-info/WHEEL'
adding 'pypackage-0.0.1.dist-info/top_level.txt'
adding 'pypackage-0.0.1.dist-info/RECORD'

4.5 生成可执行命令

__main.py 中添加以下内容作为可执行命令的入口

def hello():__private_say("pypackage")

然后在 pypackage.toml 中添加名为 pypackage-hello 的命令(在命令行中可直接运行 pypackage-hello

[project.scripts]
pypackage-hello = "pypackage.__main:hello"

完成。重新打包安装后效果如下:

> pypackage-hello
private say: Hello, pypackage!

【新】使用setuptools打包Python项目相关推荐

  1. pyinstaller精简打包python项目完整流程,含常见问题解决方案

    最近写了一个python爬虫小项目,想打包成一个exe文件,放在其他电脑上使用.但是没想到一个20B的py文件打包过程却十分艰辛.先后经历了打包失败无法运行,打包成功但是运行十分缓慢,打包了一大堆不需 ...

  2. python setup.py build_打包Python项目为rpm时遇到python setup.py build报错的问题

    问题描述 使用rpmbuild打包python项目,执行报错 rpmbuild -bb autoinstall.spec hrwxr-xr-x XXX/XXX     0 2018-12-19 13: ...

  3. 使用pyinstaller打包python_使用pyinstaller打包Python项目,python

    00 前言 上一篇文章写的是使用百度aip实现一个图片转文字的小工具( https://blog.csdn.net/George_Clancy/article/details/105551872 ), ...

  4. 2021-01-22 使用 Docker 打包 Python 项目

    使用 Docker 打包 Python 项目 1. 获取 Python 的镜像文件 项目的封装可以建立在已有镜像的基础上,在 Ubuntu 中可通过 docker pull python:3.6.8- ...

  5. docker打包Python项目

    docker打包Python项目 Step1: 配置运行环境文档 项目结构如下 docker_test ├── Dockerfile ├── (myapps) │ └── BPNN.py └── re ...

  6. Python编程:twine模块打包python项目上传pypi

    注册账号(重要) https://pypi.org 可以配置到$HOME/.pypirc文件中,就不用多次输入了 [pypi] username = <username> password ...

  7. 船新的100个Python项目,看了再学毕竟快乐总是一闪而过

    Github上面有很多有趣的python项目,包括软件.库.教程.资源等.这次收集了其中比较受欢迎的100个,供大家参考.(内容比较多,建议收藏了再看!) 资料来源:https://github.co ...

  8. python程序打包多个py文件_不使用setup.py,打包 Python 项目

    我编写了许多开源项目,并允许其他人通过PyPI访问这些项目.为此,我需要从这些项目构建一个源代码分发版(sdist)和一个可选的wheel包,并将二者上传到PyPI.最后,这个sdist和wheel包 ...

  9. 新浪云python示例_新浪SAE部署python项目

    SAE实际上就是个多节点的虚拟主机,跟云主机差不多,只不过SAE的节点比一般的云主机要多,把网站程序布署在SAE上比自己用独立的服务器稳定性和性能要高很多.将自己用python开发的博客项目放在SAE ...

最新文章

  1. 记一次大规模数据迁移和加密
  2. React基础——快速搭建开发环境
  3. Jmeter工具笔记-Jmeter+influxdb+grafanas设置性能监控过程
  4. 《机器学习》 —— 第一章:绪论 学习笔记
  5. 前端学习(2159):vuecli脚手架的配置和安装
  6. Cloud一分钟 | 马云发表致股东的公开信;5G算什么?中国已着手研究6G相关工作...
  7. .net mvc ajax 用html()怎么出来正个页面呀,如何使用jquery或ajax为MVC项目更新c#/ asp.net中的razor部分视图...
  8. 发条js调试工具_【转载】移动端js调试工具:eruda
  9. Mysql密码忘记怎么办?重置密码完整教程
  10. 提取文本手机号 易语言代码
  11. 动态添加SqlParameter
  12. Excel绘制折线图--更新中。。。
  13. 没有更改计算机日期权限,修改电脑时间_修改电脑时间没有权限
  14. 盘点那些年,被Oracle收购的公司
  15. 简答实现登录注册(需要导入JQ库)
  16. C++在终端、文件中就地覆盖输出的方法
  17. vc++ 编程 经典电子书
  18. crm day03 创建市场活动
  19. python valueerror object2_Python使用json.loads 报错 ValueError: No JSON object could be decoded的解决方法...
  20. 超宽带定位中的TOA/TDOA两种最常用算法介绍

热门文章

  1. Apache年度报告出炉,大数据项目依然最活跃
  2. 2022世界传感器大会 | 龙芯中科发布龙芯2K0500多功能SoC芯片及解决方案
  3. 架构师之路046 服务端开发的总结
  4. 惠普HP CM1312nfi 彩色激光打印机如何添加网络打印机
  5. 解决办法:360压缩解压出现空白文件创建失败,但压缩包文件无损坏显示有十几个文件
  6. 【java并发编程】无锁并发框架disruptor
  7. ghost后分区丢失如何恢复数据-分区表医生!
  8. 2022年团体程序设计天梯赛-总决赛
  9. oracle分页改写为mysql_mysql和oracle分页
  10. MediaPlayer代码分析(1)-初始化和设置数据的过程