You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用setuptools的find_packages仅包含指定包排除其余目录

解决方案

find_packages原生支持白名单配置,不需要通过枚举排除项、修改扫描根路径的方式绕弯,直接使用include参数即可实现「仅保留指定目录、自动排除其他所有目录」的效果,且完全不会破坏原有包导入路径。

核心用法

find_packages的完整参数签名如下,默认include=('*',)也就是匹配所有包:

find_packages(where='.', include=('*',), exclude=())

你只需要把include替换为你需要保留的包匹配规则,就会自动过滤掉所有不符合规则的目录,不需要修改where参数(默认从setup.py所在目录扫描,保证包路径和你项目实际层级一致)。

举个实际场景的例子,假设你的项目结构如下:

project_root/
├── setup.py
├── src/
│   ├── __init__.py
│   ├── feat_1/
│   │   └── __init__.py
│   └── feat_2/
│       └── __init__.py
├── tests/
│   └── __init__.py
├── temp_debug/
├── docs/
└── third_party/

如果你只需要打包src及其所有子包,排除其他所有目录,直接写:

from setuptools import setup, find_packages

setup(
    # 其余配置(name/version等)省略
    packages=find_packages(
        # 白名单规则:仅保留匹配的包
        include=[
            "src",      # 匹配src顶层包本身
            "src.*"     # 匹配src下所有层级的子包
        ]
    )
)

执行打包后,包的导入路径完全符合预期:src、src.feat_1、src.feat_2,不会出现路径丢失前缀的问题。

如果需要保留多个分散的顶层包,直接往include列表追加规则即可,比如还要保留同级的common_utils包:

find_packages(include=["src", "src.*", "common_utils", "common_utils.*"])

之前用法的问题说明

  • 单独使用exclude是黑名单模式,需要枚举所有要排除的目录,当无关目录很多时维护成本极高,不适合「仅保留少量目录」的场景。
  • 单独使用where参数会修改包扫描的根路径,setuptools会把你传入的目录当作包层级的起点,自然会丢失上层目录前缀。如果是标准的单src目录布局(所有源码都放在根目录的src文件夹下),需要配合package_dir配置才能保证路径正确,写法如下:
    setup(
        packages=find_packages(where="src"),
        package_dir={"": "src"}
    )
    
    但这种写法仅适合所有要打包的内容都集中在同一个子根目录的场景,不适合分散多目录的白名单选择需求。

匹配规则说明

include和exclude的匹配规则遵循fnmatch通配符规范:

  • *匹配任意长度字符
  • 要包含某个包下的所有子包,必须显式写包名.*规则,否则只会匹配包本身,不会递归包含子包

内容的提问来源于stack exchange,提问作者Pranjal Doshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:33:29