簡體   English   中英

其他語言/應用程序中 python/setuptools 入口點(擴展)的替代實現

[英]Alternative implementations of python/setuptools entry points (extensions) in other languages/applications

雖然這個問題有一個 python 后端,但這個問題與 python 本身無關,而是與擴展機制以及如何注冊/查找插件有關。

在 python 中,入口點的概念是由 setuptools 引入的,並且與已安裝的 python 發行版(在其他打包系統中稱為包)的元數據相關聯。

據我了解,入口點提供的功能之一是允許應用程序定義其他人可以放置東西的地方,因此任何想要使用入口點的應用程序都可以在那里獲得注冊類/函數的列表。 舉個例子:

  • Foo 定義了入口點“entrypoint1”並查找以該名稱注冊的插件。
  • Bar 在“entrypoint1”入口點上注冊一個可調用( Bar.callable )。
  • 然后,任何 python 腳本都可以將Bar.callable列為“entrypoint1”的已注冊可調用對象之一。

使用 setuptools,應用程序在安裝時注冊入口點,並將信息存儲在與打包相關的元數據中,稱為 .egginfo(通常包含有關分發名稱、其依賴項以及有關打包的更多元數據的信息)。

我覺得打包元數據不是存儲此類信息的正確位置,因為我不明白為什么這些信息與打包相關聯。

我很想知道其他語言中的此類入口點/擴展/插件功能,特別是如果該概念與元數據和包裝相關聯。 所以問題是……

你有我應該看的例子嗎? 你能解釋一下為什么設計選擇是這樣的嗎?

你能看到處理這個問題的不同方法嗎? 你知道這個問題是如何用不同的工具解決的嗎? 當前的 python 實施與其他實施相比有哪些缺點和優點?


到目前為止我發現了什么

我在不同的項目中發現了一種創建和分發“插件”的方法,它們特別關注“我們如何制作插件”。

例如, libpeas (gobject 插件框架)定義了一組通過指定插件來擴展默認行為的方法。 雖然這很有趣,但我只是對其中的“注冊和查找”(並最終加載)部分感興趣。

以下是我迄今為止的一些發現:

Libpeas 定義了自己的元數據文件(*.plugin),它存儲有關可調用類型的信息(可能有不同語言的不同插件)。 這里的主要信息是要加載的模塊的名稱。

Maven 有一個設計文檔,其中包含有關如何在那里管理東西的信息。 Maven 管理插件及其依賴項和元數據,因此它似乎是一個有趣的地方,可以查看它們是如何實現的

如其文檔中所述, maven 插件在類上使用注釋@goal ),然后用於查找使用特定@goal注冊的所有插件。 雖然這種方法在 static 語言中是可行的,但它不適用於解釋語言,因為我們只知道在某個給定時間點所有可能的類/可調用對象是什么,這可能會發生變化。

Mercurial 使用中央配置文件( ~/.hgrc ),其中包含插件名稱到可以找到的路徑的映射。


還有一些想法

雖然這不是這個問題的答案,但值得注意的是 setuptools 入口點是如何實現的,以及它們在性能方面如何與 mercurial 進行比較。

當您使用 setuptools 請求特定入口點時, 會在運行時讀取所有元數據並以這種方式構建一個列表 這意味着如果您的路徑上有很多 python 發行版,則此閱讀可能需要一些時間。 另一方面,Mercurial 將此信息硬編碼到一個文件中,這意味着您必須在那里指定可調用對象的完整路徑,然后注冊的可調用對象不是“發現”而是直接從配置文件中“讀取”。 這允許對哪些應該可用、哪些不應該可用以及看起來更快的更細粒度的配置。

另一方面,由於 python 路徑可以在運行時更改,這意味着必須根據路徑檢查以這種方式提供的可調用對象,以便了解是否應在所有情況下返回它們。


為什么入口點目前與包裝相關聯

理解為什么入口點與 setuptools 中的打包相關聯也很有趣。 主要原因是 python 發行版可以在安裝時將自己的一部分注冊為擴展入口點似乎很有用:然后安裝意味着也注冊入口點:不需要額外的注冊步驟。

雖然這在大多數情況下都非常有效(當實際安裝 python 發行版時)它在未安裝或根本未打包時不起作用。 換句話說,據我了解,如果沒有 .egg-info 文件,您將無法在運行時注冊入口點。

作為一種可能的想法,您可以查看OSGi概念,該概念用於Eclipse的插件系統管理。 對於您的具體情況來說,這可能是矯枉過正,但絕對是靈感的來源。

當您開始談論編程語言實現/處理時,可能值得注意的是,最近gcc 也獲得了插件功能

我想回答關於“如何在不打包或安裝模塊的情況下注冊 python 入口點”的問題。 我認為這是您的想法和發現所暗示的,並且實際上是讓我發瘋了很長時間的原因。

至於 rest,雖然是一個非常有趣的話題,但我認為這個問題太寬泛而無法完全回答(我實際上很驚訝它由於寬泛而沒有關閉)而且我一直很難找到它,直到我已經能夠自己回答這部分。

如何在不打包也不安裝模塊的情況下注冊 python 入口點

對於將 python 模塊或 bare.py 文件放置在可導入路徑(通常是 ./src、./lib 或平面工作目錄)中的普通從業者來說,不需要 package 任何東西來注冊入口點。

在您的示例中,只需將文件放在.../bar.dist-info/entry_points.txt 下的同一可導入目錄中,其內容如下

# bar.dist-info/entry_points.txt
[entrypoint1]
bar = Bar.callable

以便可以通過以下方式檢索任意可調用對象

import importlib.metadata
importlib.metadata.entry_points()["entrypoint1"]

這樣,一切實際上都獨立於 setuptools 或任何其他打包工具。

這是相當無證的,我只是在痛苦地調試 setuptools 的 pkg_resources 的導入后才發現它。 我還沒有深入了解 entry_points.txt 的放置要求,但似乎任何任意 *.{egg,dist}-info/ 文件夾都會將其刪除,只要它位於 python 路徑中即可。

與您的想法相關,由於 python 可導入路徑可以通過 PYTHONPATH、PYTHONHOME、PYTHONUSERSITE 和其他站點內部功能篡改,我認為這種行為非常方便,以便僅注冊 Python 導入機制范圍內的入口點。 恕我直言,比制作需要運行時檢查記錄的單個文件更好。

備擇方案?

進一步閱讀https://docs.python.org/3/library/importlib.html#setting-up-an-importer讓我想到應該可以通過importlib.machinery入口查找器注冊入口點,但我沒有沒玩過。 如果您從瘋狂的非文件源(如https://github.com/nvbn/import_from_github_com )加載模塊,這可能是實現它的唯一方法

示范應用

pytest允許您通過“pytest11”入口點標識符注冊插件。 例如,插件編寫者應該這樣宣布自己,以便pytest --fixtures將列出他們打包的夾具。

然而,作為 pytest 最終用戶,您不需要通過該入口點注冊任何掛鈎、固定裝置或任何東西。 它們將從您本地記錄的 conftest.py 文件中加載,如果開發實際的本地插件,您可以使用PYTEST_PLUGINS環境變量注冊它們。

因此,pytest“應用程序”為您提供了等效的機制來注冊任意功能,無論您是插件開發人員、插件用戶還是只是編寫本地黑客。 入口點只是“正確安裝”插件的注冊機制。

對於任何需要注冊插件的應用程序,我相信這應該是通往 go 的方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM