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

"Правильный" способ добавления сценариев python в приложение, отличное от python

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

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

Однако...

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

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

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

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

  • Плагины межсетевого экрана.

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

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

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


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


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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Создание системы обмена сообщениями приложений

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

Создайте библиотеку сообщений для Python (или что-то еще)

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

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

Плагин/приложение Rendezvous

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

~/.myapp/plugins

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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