python / setuptools入口点(扩展)在其他语言/应用程序中的替代实现

虽然这个问题有一个python后端,但问题不是绑定到python本身,而是关于扩展机制以及如何注册/查找插件。

在python中,入口点的概念是由setuptools引入的,并且与已安装的python发行版的元数据(称为其他包装系统中的包)有关。

就我的理解而言,入口点提供的function之一是允许应用程序定义其他人可以放入的地方,所以任何想要使用入口点的应用程序都可以获得注册类/函数列表。 举个例子:

  • Foo定义入口点“entrypoint1”并查找以这个名字注册的插件。
  • Bar在“entrypoint1”入口点上注册一个可调用的( Bar.callable )。
  • 任何python脚本都可以将Bar.callable列为“entrypoint1”的注册可调用对象之一。

使用setuptools,应用程序在安装时注册入口点,信息存储在与打包有关的元数据中,称为.egginfo(通常包含有关分发名称,依赖关系以及一些关于打包的元数据的信息)。

我觉得打包元数据不适合存储这种信息,因为我不明白为什么这些信息与打包有关。

我很好奇听到其他语言的入口点/扩展/插件function,特别是如果这个概念与元数据和打包相关联。 所以问题是…

你有我应该看的例子吗? 你能解释为什么deviseselect是这样做的吗?

你能看到不同的方法来处理这个问题吗? 你知道这个问题在不同的工具中已经被解决了吗? 目前的python实现有什么缺点和优势?


到目前为止,我发现了什么

我在不同的项目中发现了一种创build和分发“插件”的方法,这些插件特别关注“我们如何制作插件”。

例如, libpeas (gobject插件框架)定义了一组通过指定插件来扩展默认行为的方法。 虽然这很有趣,但我只是对“注册和发现”(并最终加载)部分内容感兴趣。

以下是我迄今为止的一些发现:

Libpeas定义了自己的元数据文件 (* .plugin),它存储了关于可调用types的信息(可以在不同的语言中使用不同的插件)。 这里的主要信息是要加载的模块的名称。

Maven有一个devise文档,其中包含有关如何pipe理东西的信息。 Maven使用它们的依赖和元数据来pipe理插件,所以看起来像是一个有趣的地方来寻找他们如何实现的东西 。

正如在他们的文档中指出的, Maven插件在类上使用注释 ( @goal ),然后用它来查找所有使用特定@goal注册的插件。 虽然这种方法在静态语言中是可能的,但它不在解释型语言中,因为我们只知道在一个给定时间点可能的类/可调用对象是什么,这些可能会改变。

Mercurial使用一个中央configuration文件 ( ~/.hgrc ),包含插件名称到可以find的path的映射。


一些更多的想法

虽然这不是对这个问题的答案,但是也注意到setuptools入口点是如何实现的,以及它们在性能方面如何与mercurial的进行比较。

当你用setuptools要求一个特定的入口点时, 所有的元数据都会在运行时被读取,并且列表就是以这种方式构build的 。 这意味着如果你的path上有很多python发行版,这个阅读可能需要一些时间。 另一方面,Mercurial把这些信息硬编码到一个单独的文件中,这意味着你必须在那里指定你的可调用的完整path,然后直接从configuration文件中“发现”但是“已读”。 这允许更细粒度的configuration应该是可用的,什么不应该和似乎更快。

另一方面,由于pythonpath可以在运行时改变,这意味着以这种方式提供的可调用对象将不得不根据path进行检查,以便知道它们是否应该被返回或者不是在所有情况下。


为什么入口点目前与包装有关

了解为什么入口点与setuptools中的包装相关联也是很有趣的。 主要原因是python发行版可以在安装时注册自己的一部分作为扩展入口点:安装意味着注册入口点:不需要额外的注册步骤。

虽然这在大多数情况下(当实际安装python发行版时)工作得很好,但是当它们没有安装或者没有被打包的时候,它不会。 换句话说,据我所知,你不能在运行时注册一个入口点,没有.egg-info文件。

作为可能的想法之一,您可以看看OSGi的概念,即用于Eclipse的插件系统pipe理。 对于你的具体情况可能会过度,但绝对是灵感的来源。

当您开始谈论编程语言实现/处理时,可能值得注意的是最近gcc也获得了插件function 。

在Python中,有一个“PYTHONPATH”,它是一个环境variables,它定义了一个地方,从“import”看代码段。

如果你有一个

  PYTHONPATH=/home/user/tests 

所有的分支

  /home/user/tests 

有自己的

  __init__.py 

文件,列出可以在那里find的模块。

例如:在

  /home/user/tests/__init__.py 

你有

  __all__ = ["computeSomething", "computeSomthingElse"] 

指的是现有的文件:

  /home/user/tests/computeSomething.py /home/user/tests/computeSomethingElse.py 

那么,在Python中,你可以立即

  import computeSomethingElse 

要么

  from computeSomethingElse import myObjectFromSomethingElse. 

我希望这有帮助。