使用 setup.py 自定义 python 包目录布局

Customizing python package directory layout with setup.py

假设我有以下目录结构:

src/
└── python/
    └── generated/
        ├── __init__.py
        ├── a.py
        └── lib/
            ├── __init__.py
            └── b.py

我的 setup.py 需要什么样子才能创建目录布局如下的 dist:

src/
└── python/
    ├── __init__.py
    ├── a.py
    └── lib/
        ├── __init__.py
        └── b.py

目标是简单地删除 generated 文件夹。我已经尝试了 package_dir 的无穷无尽的变体,但除了原始目录结构之外什么也得不到。

首先,这是我的解决方案:

#!/usr/bin/env python

import os, shutil
from setuptools import setup
from setuptools.command.build_py import build_py

class BuildPyCommand(build_py):
  """Custom build command."""

  def run(self):
    shutil.rmtree('src.tmp', ignore_errors=True)
    os.mkdir('src.tmp')
    shutil.copytree('src/python/generated', 'src.tmp/python')
    build_py.run(self)

setup(cmdclass={ 'build_py': BuildPyCommand },
      name='Blabla',
      version='1.0',
      description='best desc ever',
      author='Me',
      packages=['python', 'python.lib'],
      package_dir={'': 'src.tmp'},
      setup_requires=['wheel']
     )

您可以使用以下方式生成您的发行版:

python setup.py build bdist_wheel

想法是执行两个步骤构建:

  • 我生成了有效的源结构
  • 我建了这个临时建筑

我用轮子交付它,因为它不需要未来的用户理解我的技巧。如果你尝试使用源分发,你会注意到你需要将生成的文件作为数据发布(不难,但很麻烦,而且,我想你会想对你的用户隐藏你的技巧)。

但是,我认为您的流程存在设计缺陷。文件src/python/generated/__init__.py,假设是一个模块<something>.generated,最终变成了你的<something>.python,这很麻烦。生成有效的 Python 结构会更简单、更健壮:src/generated/python/__init__.py。 setup.py 会变得微不足道,你的生成器也不会更复杂。

您的 setup.py 应该放在您的 src 目录中,并且应该如下所示:

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    name='Thing',
    version='1.2.3',
    packages=[
        'python',
        'python.lib',
    ],
    package_dir={
        'python': 'python/generated',
    },
)

注意 package_dir 设置。它指示 setuptools 从目录 python/generated 中获取 python 包的代码。在 built 发行版中,您将找到正确的目录结构。