“Правильный” способ добавить сценарии Python к приложению не-Python

Я в настоящее время нахожусь в процессе добавления способности к пользователям расширить функциональность моего настольного приложения (C++) с помощью плагинов, заданных сценарием в Python.

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

Однако...

То, что я ищу, больше похоже на то, что делает Блендер. Блендер абсолютно настраиваем через сценарии Python, и он требует внешнего исполняемого файла Python. (Т.е. Python на самом деле не встраивается в исполняемый файл блендера вообще.) Так, естественно, можно включать любые модули, которые Вы уже имеете в своем каталоге пакетов сайта, когда Вы пишете сценарии блендера. Не то, чтобы это рекомендуется, так как это ограничило бы мобильность Вашего сценария.

Так, что я хочу знать, то, если уже существует способ иметь Ваш пирог и съесть его также. Я хочу сменную систему, которая использует:

  • Встроенный интерпретатор Python.

    Оборотная сторона подхода Блендера - то, что он вынуждает Вас иметь определенное, возможно устаревшая версия Python, установленного глобально в Вашей системе. Наличие встроенного интерпретатора позволяет мне управлять тем, какая версия Python используется.

  • Плагины брандмауэра.

    Некоторый эквивалент a virtualenv для каждого плагина; позволяя им установить все модули они нуждаются или хотят, но хранение их разделенный от возможных конфликтов в других плагинах. Возможно, zc.buildout лучший кандидат здесь, но, снова, я очень открыт для предложения. Я немного в недоумении относительно лучшего способа выполнить это.

  • Максимально безболезненный...

    Для пользователя. Я готов приложить дополнительные усилия, настолько долго так же, большая часть вышеупомянутого максимально очевидна для сменного устройства записи.


Если бы какой-либо из Вас, у людей там есть любой опыт с этим видом вещи, Ваша справка, очень ценился бы.:)


Править: В основном короткая версия того, что я хочу, является простотой virtualenv, но без связанного интерпретатора Python и способа активировать определенную "виртуальную среду" программно, как zc.buildout делает с sys.path управлением ( sys.path[0:0] = [...] прием).

Оба virtualenv и zc.buildout содержите части того, что я хочу, но никакой продукт перемещаемые сборки, которые я или сменный разработчик могу просто на молнии и отправлять на другой компьютер.

Просто управляя .pth файлами или управлением sys.path непосредственно в сценарии, выполняемом из моего приложения, получает меня на полпути там. Но это недостаточно, когда скомпилированные модули необходимы, таковы как PIL.

21
задан kurige 2 August 2010 в 23:37
поделиться

3 ответа

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

------------------------------------
| App  <--> Ext. API <--> Protocol | <--> (Socket) <--> API.py <--> Script
------------------------------------

Эта диаграмма пытается показать следующее: Ваше приложение взаимодействует с внешними процессами (например, Python), используя передачу сообщений. Это эффективно на локальной машине и может быть переносимым, поскольку вы определяете свой собственный протокол. Единственное, что вы должны предоставить своим пользователям, это библиотеку Python, которая реализует ваш пользовательский API и взаимодействует с помощью цикла передачи-получения сообщений между скриптом пользователя и вашим приложением.

Определите внешний API вашего приложения

Внешний API вашего приложения описывает все функции, с которыми должен иметь возможность взаимодействовать внешний процесс. Например, если вы хотите, чтобы ваш скрипт Python мог нарисовать красный круг в вашем приложении, ваш внешний API может включать Draw(Object, Color, Position).

Определите протокол связи

Это протокол, который внешние процессы используют для связи с вашим приложением через внешний API. Популярными вариантами для этого могут быть XML-RPC, SunRPC, JSON или ваш собственный протокол и формат данных. Выбор должен быть достаточным для вашего API. Например, если вы собираетесь передавать двоичные данные, то JSON может потребовать кодировки base64, в то время как SunRPC предполагает двоичную передачу данных.

Постройте систему обмена сообщениями вашего приложения

Это просто как бесконечный цикл, принимающий сообщения в вашем коммуникационном протоколе, обслуживающий запрос в вашем приложении и отвечающий на него через тот же сокет/канал. Например, если вы выбрали JSON, то вы получите сообщение, содержащее инструкции по выполнению Draw(Object, Color, Position). После выполнения запроса вы бы ответили на него.

Создание библиотеки обмена сообщениями для Python (или любой другой)

Это еще проще. Опять же, это цикл, посылающий и принимающий сообщения от имени пользователя библиотеки (т.е. ваших пользователей, пишущих скрипты на Python). Единственное, что должна делать эта библиотека, это предоставлять программный интерфейс к внешнему API вашего приложения и переводить запросы в ваш протокол связи, все это скрыто от ваших пользователей.

Использование Unix Sockets, например, будет чрезвычайно быстрым.

Plugin/Application Rendezvous

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

~/.myapp/plugins

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

Предположим, что ваш протокол взаимодействия определяет, что каждый скрипт будет взаимодействовать с помощью JSON через StdInput/StdOuput. Простой и эффективный подход заключается в том, чтобы указать в протоколе, что при первом запуске скрипта он посылает MAGIC_ID в стандартный выход. То есть, ваше приложение считывает первые, скажем, 8 байт и ищет определенное 64-битное значение, которое идентифицирует его как сценарий.

Дополнительно, вы должны включить в свой External API методы, позволяющие вашим скриптам идентифицировать себя. Например, сценарий должен иметь возможность сообщить приложению через External API такие вещи, как Name, Description, Capabilities, Expectations, по существу информируя приложение о том, что он собой представляет и что он будет делать.

8
ответ дан 29 November 2019 в 22:02
поделиться

Я не вижу проблемы во встраивании Python, например, с помощью Boost.Python. Вы получите все, о чем просите:

  • Он будет встроен, и это будет интерпретатор (с достаточным доступом для реализации автозавершения и тому подобного)
  • Вы можете создавать новый интерпретатор для каждого скрипта и иметь полностью разделенные среды python
  • ... и настолько прозрачные, насколько это возможно

Я имею в виду, что вам все равно придется раскрыть и реализовать API, но 1) это хорошая вещь, 2) Blender тоже это делает и 3) я действительно не могу придумать другого способа, который отвлечет вас от этой работы...

PS: У меня мало опыта с Python / Boost.Python, но я много работал с Lua / LuaBind, что вроде как то же самое

.
4
ответ дан 29 November 2019 в 22:02
поделиться

Если вы действительно хотите быть максимально безболезненным для вас и ваших пользователей, подумайте о расширении python, а не о встраивании.

  • встраивание не позволяет легко интегрироваться с другим программным обеспечением - только одна программа, встраивающая python, может одновременно использоваться скриптом python. Расширение OTOH означает, что пользователь может использовать ваше программное обеспечение везде, где работает Python;
  • Чтобы сделать материал доступным для автора сценария, вам не нужно инициализировать интерпретатор. интерпретатор будет уже инициализирован за вас, что сэкономит вам работу.
  • Вам не нужно создавать специальные встроенные переменные и поддельные модули для внедрения во встроенный интерпретатор. Просто дайте им вместо этого настоящий модуль расширения, и вы сможете инициализировать все, когда ваш модуль будет впервые импортирован.
  • Вы можете использовать distutils для распространения своего программного обеспечения.
  • Инструменты, такие как virtualenv, можно использовать как есть - вам или пользователю не нужно придумывать новые инструменты. Ваш пользователь также может использовать свою IDE / инструмент отладки / среду тестирования по своему выбору

Встраивание действительно ничего не дает вам и вашим пользователям.

4
ответ дан 29 November 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: