«Правильный» способ добавления сценариев Python в не-Python-приложение - PullRequest
21 голосов
/ 30 июля 2010

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

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

Однако ...

То, что я ищу, больше похоже на то, что делает Blender . Blender полностью настраивается с помощью сценариев Python, и для него требуется внешний исполняемый файл Python. (То есть python на самом деле не встроен в исполняемый файл blender.) Поэтому, естественно, вы можете включать любые модули, которые у вас уже есть, в каталог site-packages, когда вы пишете сценарии blender. Не то, чтобы это советовали, так как это ограничило бы переносимость вашего скрипта.

Итак, я хочу знать, есть ли способ получить свой пирог и съесть его тоже. Я хочу систему плагинов, которая использует:

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

    Недостатком подхода Blender является то, что он заставляет вас иметь конкретную, возможно, устаревшую версию python, установленную глобально в вашей системе. Наличие встроенного интерпретатора позволяет мне контролировать, какая версия python используется.

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

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

  • Как можно безболезненнее ...

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


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


Edit: По сути, короткая версия того, что мне нужно, - это простота virtualenv, но без встроенного интерпретатора python и способа программной активации определенной «виртуальной среды», как zc.buildout делает с помощью манипуляции sys.path (sys.path[0:0] = [...] трюк).

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

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

Ответы [ 3 ]

8 голосов
/ 03 августа 2010

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

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

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

Определение внешнего 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, например, будет чрезвычайно быстрым.

Поиск плагинов / приложений

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

~/.myapp/plugins

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

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

Кроме того, вы должны включить в методы внешнего API, которые позволяют ваши сценарииидентифицировать себя.Например, сценарий должен иметь возможность информировать приложение через такие внешние API, как Имя , Описание , Возможности , Ожидания , по существу информируя приложение, что это такое и что оно будет делать.

4 голосов
/ 03 августа 2010

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

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

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

4 голосов
/ 31 июля 2010

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

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

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

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

...