流程

  1. pyproject.toml

    1
    2
    3
    
    [build-system]
    requires = ["setuptools"]
    build-backend = "setuptools.build_meta"
  2. 创建 setup.py 或者 setup.cfg 文件
  3. 安装 build 包

数据文件添加

提供三种方式

  1. include_package_data=True + MANIFEST.in 声明
  2. package_data= {…}
  3. exclude_package_data={…}

通过传统 distutils 方法

  • 声明需要添加 data files: include_package_data = True
  • 文件说明: 在 MANIFEST.in 文件中详细说明

MANIFEST.in 用法

参考: Including files in source distributions with MANIFEST.in 语法:

举例:

1
2
3
4
5
include keywords.tsv hello.data
exclude

graft tests
global-exclude *.py[cod]
类型命令备注
单文件匹配include pat1 pat2使用相对于 project_root 的举对路径
exclude pat1 pat2同上
文件夹内部匹配recursive-include dir-pattern pa1 pat2dir-pattern 文件夹模式,pat1 pat2 文件模式
recursive-exclude
全局匹配global-include pat1 pat2允许任意位置的文件匹配
global-exclude
文件夹贪婪匹配graft dir-pattern匹配文件夹下的所有文件
文件夹贪婪排除prune dir-pattern排除文件夹下的所有文件
MANIFEST.in 匹配命令
运算符备注
"*"类似 linux 通配符,一个或多个字符,除掉文件分隔符 os.sep
"?"单个字符
"[]"字符集合,类似 regex [] , eg: [a-z]
"**"类似"*",但是匹配任意字符,即使 os.sep
MANIFEST.in 匹配运算符

package_data 参数法

举例:

1
2
3
4
5
6
package_data={
    # If any package contains *.txt or *.rst files, include them:
    "": ["*.txt", "*.rst"],
    # And include any *.msg files found in the "hello" package, too:
    "hello": ["*.msg"],
}

参数:

  • "": 所有 package 都使用的规则
  • "package_name": 限定 package 内部的匹配规则

    • 注意:

      • 路径相对于给定的包名
  • 不包含 __init__.py 的文件夹不可以在 key 中出现

    • eg: scieye/eyes/data/keywords.tsv

      • data 下面没有 __init__.py, 其他上级目录有
    • 正确写法:

      • {"scieye": ["eyes/data/*.tsv"]}
      • {"scieye.eyes": ["data/*.tsv"]}
    • 错误写法

      • {"scieye.eyes.data": ["*.tsv"]}
      • 注: *验证可用*,无错误 (win10)

举例:

1
2
3
4
5
6
setup(
    ...
    packages=find_packages(exclude=['tests.*', 'tests']),
    package_data={'scieye': ['eyes/data/*.tsv']},
    ...
    zip_safe=False)
  • 这里 scieye/eyes/data/keywords.tsv 声明如下

    • 包名: scieye
    • 路径和文件模式: eyes/data/*.tsv

Entry Points

参考:

console_scripts 命令行工具

plugins

plugins

参考:

实现和查找方法:

  1. 通过 模块前缀

    • eg: flask-sqlalchemy, 这里的 flask 就是前缀
  2. 通过 namespace 方法

  3. 通过 entry point, (即 package metadata)

    • 参考:

    • 定义

      1
      2
      
      [project.entry-points.'myapp.plugins']
      a = 'myapp_plugin_a'
    • 发现

      1
      2
      3
      4
      5
      6
      7
      
      import sys
      if sys.version_info < (3, 10):
      from importlib_metadata import entry_points
      else:
      from importlib.metadata import entry_points
      
      discovered_plugins = entry_points(group='myapp.plugins')