Подтвердить что ты не робот

Альтернативные реализации точек ввода/вывода python/setuptools (расширения) на других языках/приложениях

Хотя этот вопрос имеет бэкэнд на python, вопрос не связан с самим python, а скорее о механизмах расширения и порядке регистрации/поиска для плагинов.

В python концепция entrypoints была введена setuptools и привязана к метаданным установленных дистрибутивов python (называемых пакетами в других системах упаковки).

По моему мнению, одна из функций, предоставляемых входами, - это позволить приложению определять место, где другие могут вставлять вещи, поэтому любое приложение, желающее использовать точку входа, может получить список зарегистрированных классов/функций там. Возьмем пример:

  • Foo определяет точку входа "entrypoint1" и ищет плагины, зарегистрированные под этим именем.
  • Бар регистрирует вызываемый (Bar.callable) в точке входа "entrypoint1" .
  • Любой python script затем может перечислить Bar.callable как один из зарегистрированных вызовов для "entrypoint1" .

С помощью setuptools приложения регистрируют точки входа во время установки, и информация хранится в метаданных, связанных с упаковкой под названием .egginfo(которые обычно содержат информацию о имени распространения, его зависимостях и некоторых других метаданных о упаковке).

У меня такое ощущение, что метаданные упаковки не являются подходящим местом для хранения такой информации, поскольку я не понимаю, почему эта информация привязана к упаковке.

Мне интересно узнать о таких функциях entrypoints/extensions/plugins на других языках, и особенно если концепция привязана к метаданным и упаковке или нет. И вот вопрос...

Есть ли у вас примеры, на которые я должен обратить внимание? Не могли бы вы объяснить, почему выбор дизайна был сделан таким образом?

Вы можете увидеть различные способы решения этой проблемы? Вы знаете, как эта проблема уже решена в разных инструментах? Каковы недостатки и преимущества текущей реализации python над другими?


Что я нашел до сих пор

Я нашел в разных проектах, способ создания и распространения "плагинов", которые особенно заботятся о том, "как мы делаем плагины".

Например, libpeas (структура плагина gobject) определяет набор способов расширения поведения по умолчанию путем указания плагинов. Хотя это интересно, меня просто интересует "регистрация и обнаружение" (и, в конечном итоге, загрузка) его части.

Вот некоторые из моих выводов:

Libpeas определяет собственный файл метаданных (*.plugin), в котором хранится информация о типе вызываемого (на разных языках возможно наличие разных плагинов), Основная информация здесь - это имя загружаемого модуля.

Maven имеет проектный документ, содержащий информацию о том, как там управляется материал. Maven управляет плагинами с их зависимостями и метаданными, поэтому кажется интересным местом для поиска того, как они реализовали вещи.

Как указано в их документации, плагины maven используют аннотации (@goal) для классов, которые затем используются, чтобы найти все плагины, зарегистрированные с определенным @goal. Хотя этот подход возможен в статических языках, он не находится в интерпретируемых языках, так как мы знаем только, какие все возможные классы/вызовы в одной заданной точке времени могут меняться.

Mercurial использует центральный файл конфигурации (~/.hgrc), содержащий отображение имени плагина в путь, который он может найти.


Еще несколько мыслей

Хотя это не ответ на этот вопрос, интересно также, как внедряются точки входа setuptools и как они сравниваются с точки зрения производительности с помощью меркуриальных.

Когда вы запрашиваете определенную точку входа с помощью setuptools, все метаданные читаются во время выполнения, и список создается таким образом. Это означает, что это чтение может занять некоторое время, если у вас много дистрибутивов python на вашем пути. Mercurial с другой стороны жестко кодирует эту информацию в один файл, а это означает, что вы должны указать полный путь к вашему вызываемому, а затем зарегистрированные вызовы не "обнаруживаются", а "читаются" непосредственно из файла конфигурации. Это позволяет получить более тонкую конфигурацию на том, что должно быть доступно, а что не должно быть и кажется быстрее.

С другой стороны, поскольку путь python можно изменить во время выполнения, это означает, что вызываемые вызовы, предоставленные таким образом, должны быть проверены на пути, чтобы знать, должны ли они быть возвращены или нет во всех ситуациях.


Почему точки входа в настоящее время привязаны к упаковке

Также интересно понять, почему точки входа привязаны к упаковке в setuptools. Основная причина заключается в том, что представляется полезным, что дистрибутивы python могут регистрировать часть себя как расширение точки входа во время установки: тогда установка также позволяет регистрировать точки входа: нет необходимости в дополнительном этапе регистрации.

Хотя это работает довольно хорошо в большинстве случаев (когда на самом деле устанавливаются дистрибутивы python), это происходит не тогда, когда они не установлены или просто не упакованы. Другими словами, из того, что я понимаю, вы не можете зарегистрировать точку входа во время выполнения без файла .egg-info.

4b9b3361

Ответ 1

как одна из возможных идей, вы можете взглянуть на концепцию OSGi, которая используется для управления системой плагинов Eclipse. Это может быть излишним для вашего конкретного случая, но, безусловно, источником вдохновения.

Ответ 2

Как вы начали говорить о реализации/обработке языка программирования, может быть стоит отметить, что недавно gcc получил возможности плагина.

Ответ 3

В python существует "PYTHONPATH", который является переменной среды, которая определяет место, откуда "импорт" будет смотреть на фрагменты кода.

Если у вас есть

 PYTHONPATH=/home/user/tests

все поддиры в

 /home/user/tests 

имеют свои собственные

 __init__.py 

в котором перечислены модули, которые можно найти там.

Например: в

 /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.

Надеюсь, это поможет.