有条件的setuptools entry_points

5

在setup.py中是否可以定义有条件的entry_points?我注意到可以使用extras标记来标记一个entry point,但即使没有安装该额外功能,该entry point也将可用。

setup(name='my.package',
      ...
      extras_require={
          'special': [
              'dependency1',
              'dependency2',
          ],
      },
      ...
      entry_points="""
      [custom_entrypoint]
      handlername = my.package.special:feature [special]
      """,
  )

看起来即使没有安装 special 功能(pip install my.package[special]),custom_entrypoint 也是可用的。有没有简单的方法可以让类似这样的功能正常工作?

2个回答

2
在你的“插件加载器”中(无论是通过名称还是通过枚举给定命名空间的完整可用入口点集来找到入口点),你需要执行以下操作:
import pkg_resources

# Get a reference to an EntryPoint, somehow.
plug = pkg_resources.get_entry_info('pip', 'console_scripts', 'pip')

# This is sub-optimal because it raises on the first failure.
# Can't capture a full list of failed dependencies.
# plug.require()

# Instead, we find the individual dependencies.

failed = []

for extra in sorted(plug.extras):
    if extra not in plug.dist._dep_map:
        continue  # Not actually a valid extras_require dependency?

    for requirement in i.dist._dep_map[extra]:
        try:
            pkg_resources.require(str(requirement))
        except pkg_resources.DistributionNotFound:
            failed.append((plug.name, extra, str(requirement)))

给定一个插件,您将获得一个失败依赖项列表(或在成功的情况下为未失败),其中列出了entry_point插件名称、[foo]附加标签和特定的未满足包要求。

这种操作的示例来自于web.command软件包的web versions --namespace子命令。请注意,waitress extras_require已经满足,而gevent则明确指定缺少gevent包:

Sample usage.

不幸的是,我实际上没有一个方便展示多重依赖项entry_point的示例,并且需要注意的是列出为“缺失”的软件包可能并不总是与extras_require的名称匹配。


1
入口点写在package.dist-info/entry_points.txt中。我建议在setup.py中查看系统上安装的软件包,但这可能对此处没有帮助,因为dist-info可能会在其他软件包被pip安装之前处理;即使您安装了其他软件包,这些入口点也不会自动显示,除非您使用正确的参数运行my.packagesetup.py
我建议您进行重构,以便存在一个名为my.package的软件包和另一个可安装的软件包my.package.special;后者将具有my.packagedependency1dependency2作为依赖项以及入口点。现在,如果您想安装my.package,它将不包括特殊功能;使用pip install my.package.special可以获得特殊功能。

我最终得到了类似的东西。而不是将功能移动到新包中,我将其保留在原来的包中。我不想将多个包中的功能移出到新的特殊包中,因为我将其用作实验性功能切换。相反,我创建了一个名为app.experimental的特殊包,并将其作为其他包中的extras_require包含进去。在进行iter_entry_points循环时,我检查 entrypoint 是否已满足其要求,如果没有,则忽略它(entrypoint.require()会触发pkg_resources.DistributionNotFound错误)。 - Torkel
1
@Torkel,那么请将您的解决方案发布为另一种答案并接受它 :D - Antti Haapala -- Слава Україні
2
创建整个Python包以适应“元依赖”需求是愚蠢的,因为这正是extras_require的用途。 - amcgregor

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