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

如何构建含自动生成Python文件的Python包?

Python包自动编译YAML并打包的解决方案

核心逻辑

通过扩展setuptools的构建命令,在包构建或源码安装阶段自动执行YAML到Python的编译步骤,将生成文件纳入最终包中,同时确保编译工具仅作为构建依赖,不影响用户运行环境。

步骤1:更新pyproject.toml配置

首先补充构建依赖,把编译需要的kaitaistruct加入构建系统依赖列表:

[build-system]
requires = ["setuptools", "kaitaistruct"]
build-backend = "setuptools.build_meta"

[project]
name = "<package>"
version = "xyz"
description = "<description>"
authors = [ <authors> ]
dependencies = [
    "kaitaistruct",
]

# 可选:指定要包含的生成文件,确保打包时不会遗漏
[tool.setuptools.package-data]
"<project>" = ["generated/*.py"]

步骤2:编写自定义构建脚本(setup.py)

创建setup.py,重写setuptools的build_py命令,让它在复制Python文件前先完成YAML编译:

from setuptools import setup
from setuptools.command.build_py import build_py
import os
from kaitaistruct import compile

class CustomBuildPy(build_py):
    def run(self):
        # 定义路径
        pkg_root = self.package_dir["<project>"]
        specs_dir = os.path.join(pkg_root, "specs")
        generated_dir = os.path.join(pkg_root, "generated")
        
        # 创建生成目录(不存在则自动创建)
        os.makedirs(generated_dir, exist_ok=True)
        
        # 遍历并编译所有.ksc文件
        for fname in os.listdir(specs_dir):
            if fname.endswith(".ksc"):
                spec_path = os.path.join(specs_dir, fname)
                output_fname = f"{os.path.splitext(fname)[0]}.py"
                output_path = os.path.join(generated_dir, output_fname)
                compile(spec_path, output_path)
        
        # 执行原build_py的文件复制逻辑
        super().run()

setup(
    cmdclass={
        'build_py': CustomBuildPy,
    }
)

步骤3:支持可编辑模式(可选)

如果需要pip install -e .的可编辑安装也能自动编译,扩展develop命令:

# 在setup.py中添加以下内容
from setuptools.command.develop import develop

class CustomDevelop(develop):
    def run(self):
        # 编译逻辑和之前一致
        specs_dir = os.path.join("<project>", "specs")
        generated_dir = os.path.join("<project>", "generated")
        os.makedirs(generated_dir, exist_ok=True)
        
        for fname in os.listdir(specs_dir):
            if fname.endswith(".ksc"):
                spec_path = os.path.join(specs_dir, fname)
                output_fname = f"{os.path.splitext(fname)[0]}.py"
                output_path = os.path.join(generated_dir, output_fname)
                compile(spec_path, output_path)
        
        super().run()

# 更新setup的cmdclass
setup(
    cmdclass={
        'build_py': CustomBuildPy,
        'develop': CustomDevelop,
    }
)

同时在pyproject.toml中添加文件监听,方便修改YAML后重新编译:

[tool.setuptools.editable_watch_files]
"<project>/specs/*.ksc" = ["<project>/generated/"]

各场景验证

  • PyPI安装:上传到PyPI的wheel已包含所有生成文件,用户直接安装即可使用,无需编译。
  • 本地构建wheel:执行python -m build . --wheel时,会自动编译YAML并将生成文件打包进wheel。
  • 源码安装:执行pip install .时,构建系统会先编译YAML,再完成安装。
  • 可编辑模式:执行pip install -e .时自动编译,修改.ksc文件后重新执行该命令即可更新生成文件。

额外注意事项

  • 不要将generated目录提交到仓库,在.gitignore添加:/<project>/generated/
  • 编译工具kaitaistruct仅作为构建依赖,用户通过PyPI安装wheel时不会安装它;源码安装时会临时安装,安装完成后可手动移除。

内容的提问来源于stack exchange,提问作者e-rk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:15:38