在setup.py中使用依赖项的代码

3
我有一个小型web框架,我们称之为Bread,用于构建像Jam、Marmalade、PeanutButter和其他配料这样的应用程序。Bread既可以构建这些应用程序,也可以提供它们。
我正在尝试弄清楚如何使这些应用程序的setup.py能够正常工作,满足以下要求:
  • 这些应用程序依赖于Bread,通过setuptool's install_requires
  • 在开发时构建应用程序时,Bread会读取一些配置,然后将资产(HTML、JS、CSS、图像等)发出到应用程序的output目录。换句话说,bread devserver读取Jam/bread.yaml并在Jam/output中组装资产,然后通过Flask提供应用程序服务(但这与其他无关)。
  • 为了构建一个可部署的Jam应用程序,我想在Jam的python setup.py install期间调用Bread来构建Jam/output。在生产环境中,Jam不需要构建任何内容。
  • 我定义了一个自定义的bdist_egg设置命令,其中initialize_options导入Bread,调用构建器,然后使用适当的元组设置self.distribution.data_files,最后调用基类。(而且那真的很有趣。)
  • 现在,bdist_egg在Jam的setup.py中定义。我想将此和其他样板代码移动到bread.setup中,以便我可以在Marmalade、PeanutButter等中重用它。
  • 潜在地,这意味着我现在正在导入Bread代码,在Bread被安装之前。这肯定会在干净的安装中出现,例如在构建机器上的新虚拟环境中。
这可以使用Distutils / setuptools / Distribute完成吗?
1个回答

0

我也在Distutils-SIG中提出了这个问题。 那里提到了setup_requires,这让我想起了https://dev59.com/SGfWa4cB1Zd3GeqPh4hh#12061891,它给了我需要的提示:在调用setup之前创建一个单独的Distribution对象,该对象定义了setup_requires条目。

Jam的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的output。Bread在当前目录中找到。
  • setup()稍后会将Jam、Bread和所有依赖项 正确地安装在指定位置。
  • 调用cleanup_bread_bootstrap()删除了最初Distribution 在当前目录中生成的所有Eggs。

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

副作用无处不在。哎呀。 - offby1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接