3

我有一个小的 Web 框架,我们称之为 Bread,它用于构建应用程序,如 Jam、Marmalade、PeanutButter 和其他配料。Bread构建服务于这些应用程序。

鉴于以下要求,我正在尝试弄清楚如何使应用程序setup.py正常工作:

  • 这些应用程序依赖于 Bread,通过 setuptool 的 install_requires
  • 为了在开发时构建应用程序,Bread 读取一些配置,然后将资产(HTML、JS、CSS、图像等)发送到应用程序的output目录。换句话说,bread devserver 读取Jam/bread.yaml和组装Jam/output.
  • 为了构建可部署的Jam 应用程序,我想在python setup.py installJam 期间调用 Bread 来构建 Jam/output. 在生产环境中,Jam 不需要构建任何东西。
  • 我已经定义了一个自定义bdist_egg设置命令,其中 initialize_options导入 Bread,调用构建器,然后 self.distribution.data_files在调用基类之前使用适当的元组进行设置。(并不好玩。)
  • 现在,bdist_egg在 Jam 的setup.py. 我想将这个和其他样板代码移动到bread.setup中,以便我可以在 Marmalade、PeanutButter 等中重用它。
  • 潜在地,这意味着我现在在安装 Bread 之前导入 Bread 代码。这肯定会在全新安装中出现,例如构建机器上的全新 virtualenv。

这可以用 Distutils / setuptools / Distribute 完成吗?

4

1 回答 1

0

我也在Distutils-SIG中问过这个问题。那里提到setup_requireshttps://stackoverflow.com/a/12061891/6364,这给了我需要的提示:Distribution在调用之前创建一个单独的对象setup 来定义setup_requires条目。

果酱setup.py现在看起来像:

from setuptools import setup, dist

dist.Distribution(dict(setup_requires='Bread'))

from bread.setup_topping import *

setup(
    name='Jam',
    version='0.2',
    long_description=open('README.md').read(),
    **topping_setup_options
)

# Remove *.egg left by bootstrapping Bread
cleanup_bread_bootstrap()

编辑:需要更好地解释 Jam 中发生的事情setup.py

  • 最初用于在当前目录Distribution(setup_requires='Bread')easy_install 安装 Bread 及其依赖项。
  • 调用setup()触发bdist_egg以下,它使用 Bread 来构建 Jam's output。面包在当前目录中找到。
  • setup()稍后将 Jam、Bread 和所有依赖项安装在正确的位置。
  • 调用cleanup_bread_bootstrap()删除由初始Distribution.

bread/setup_topping.py看起来像:

from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
import os, fnmatch, glob, shutil

def recursive_data_files(treeroot, pattern):
    results = []
    for base, dirs, files in os.walk(treeroot):
        goodfiles = fnmatch.filter(files, pattern)
        if goodfiles:
            results.append((base, [os.path.join(base, f) for f in goodfiles]))
    return results

def make_data_files(output='output'):
    return (
        [('', ['bread.yaml'])]
        + recursive_data_files(output, '*')
    )

class bdist_egg(_bdist_egg):
    def initialize_options(self):
        bake_bread()    # build files to './output'
        self.distribution.data_files = make_data_files()
        _bdist_egg.initialize_options(self)

topping_setup_options = dict(
    cmdclass={
        'bdist_egg': bdist_egg,
    },
    install_requires=[
        'Bread',
    ],
    zip_safe=False,
)

def cleanup_bread_bootstrap(root='.'):
    for f in glob.glob(os.path.join(os.path.abspath(root), '*.egg')):
        if os.path.isdir(f):
            shutil.rmtree(f)  # Egg directory
        else:
            os.remove(f)      # Zipped Egg
于 2013-05-30T00:44:11.587 回答