Tengo una aplicación, escrita en Python, que es utilizada por un público bastante técnico (científicos).
Estoy buscando una buena manera de hacer que la aplicación sea extensible por los usuarios, es decir, una arquitectura de scripting / plugin.
Estoy buscando algo extremadamente ligero . La mayoría de los scripts, o complementos, no serán desarrollados y distribuidos por un tercero e instalados, sino que serán creados por un usuario en unos minutos para automatizar una tarea repetitiva, agregar soporte para un formato de archivo, Por lo tanto, los complementos deben tener el código mínimo absoluto y no requieren 'instalación' aparte de copiarlos en una carpeta (por lo que algo como los puntos de entrada de las herramientas de configuración o la arquitectura del complemento de Zope parece demasiado).
¿Hay algún sistema como este ya disponible, o algún proyecto que implemente un esquema similar al que debería buscar ideas / inspiración?
imp
módulo está en desuso a favor deimportlib
comenzar desde Python 3.4imp.load_module
.module_example.py
:loader.py
:Ciertamente es "mínimo", no tiene absolutamente ninguna comprobación de errores, probablemente innumerables problemas de seguridad, no es muy flexible, pero debería mostrarle cuán simple puede ser un sistema de complementos en Python ...
Es probable que desee ver en la imp módulo también, aunque se puede hacer mucho con solo
__import__
,os.listdir
y algunos de manipulación de cadenas.fuente
def call_plugin(name, *args)
adef call_plugin(name, *args, **kwargs)
, y luegoplugin.plugin_main(*args)
aplugin.plugin_main(*args, **kwargs)
imp
está en desuso a favor deimportlib
Eche un vistazo a esta descripción general sobre los marcos / bibliotecas de complementos existentes , es un buen punto de partida. Me gusta bastante yapsy , pero depende de su caso de uso.
fuente
Si bien esa pregunta es realmente interesante, creo que es bastante difícil de responder, sin más detalles. ¿Qué tipo de aplicación es esta? ¿Tiene una GUI? ¿Es una herramienta de línea de comandos? ¿Un conjunto de guiones? Un programa con un punto de entrada único, etc.
Dada la poca información que tengo, responderé de manera muy genérica.
¿Qué medios tienes para agregar complementos?
En una práctica de código / diseño puro, tendrá que determinar claramente qué comportamiento / acciones específicas desea que amplíen sus usuarios. Identifique el punto de entrada común / un conjunto de funcionalidades que siempre se anularán y determine los grupos dentro de estas acciones. Una vez hecho esto, debería ser fácil extender su aplicación,
Ejemplo usando ganchos , inspirados en MediaWiki (PHP, pero ¿el lenguaje realmente importa?):
Otro ejemplo, inspirado en mercurial. Aquí, las extensiones solo agregan comandos al ejecutable de la línea de comandos hg , extendiendo el comportamiento.
Para ambos enfoques, es posible que necesite una inicialización y finalización comunes para su extensión. Puede usar una interfaz común que toda su extensión tendrá que implementar (se adapta mejor con un segundo enfoque; mercurial usa un reposetup (ui, repo) que se llama para todas las extensiones), o usar un enfoque de tipo gancho, con un ganchos.conjunto de gancho.
Pero, de nuevo, si desea respuestas más útiles, tendrá que limitar su pregunta;)
fuente
El marco de plugins simple de Marty Allchin es la base que uso para mis propias necesidades. Realmente recomiendo echarle un vistazo, creo que es realmente un buen comienzo si quieres algo simple y fácilmente pirateable. Puede encontrarlo también como fragmentos de Django .
fuente
Soy un biólogo retirado que se ocupó de micrograqphs digitales y se encontró con que tenía que escribir un paquete de procesamiento y análisis de imágenes (no técnicamente una biblioteca) para ejecutarlo en una máquina SGi. Escribí el código en C y usé Tcl para el lenguaje de script. La GUI, tal como estaba, se realizó utilizando Tk. Los comandos que aparecían en Tcl eran de la forma "extensionName commandName arg0 arg1 ... param0 param1 ...", es decir, palabras y números simples separados por espacios. Cuando Tcl vio la subcadena "extensionName", el control se pasó al paquete C. Eso a su vez ejecutó el comando a través de un lexer / parser (hecho en lex / yacc) y luego llamó a las rutinas C según sea necesario.
Los comandos para operar el paquete se podían ejecutar uno por uno a través de una ventana en la GUI, pero los trabajos por lotes se realizaban editando archivos de texto que eran scripts Tcl válidos; elegiría la plantilla que realizaba el tipo de operación a nivel de archivo que deseaba hacer y luego editaría una copia para contener el directorio real y los nombres de archivo más los comandos del paquete. Funcionó a las mil maravillas. Hasta ...
1) El mundo recurrió a las PC y 2) las secuencias de comandos se hicieron más largas de aproximadamente 500 líneas, cuando las capacidades organizativas dudosas de Tcl comenzaron a convertirse en un verdadero inconveniente. El tiempo pasó ...
Me retiré, Python se inventó y parecía el sucesor perfecto de Tcl. Ahora, nunca he hecho el puerto, porque nunca he enfrentado los desafíos de compilar (bastante grandes) programas C en una PC, extender Python con un paquete C y hacer GUI en Python / Gt? / Tk? /? ?. Sin embargo, la vieja idea de tener scripts de plantillas editables todavía parece viable. Además, no debería ser una carga demasiado pesada ingresar los comandos del paquete en una forma nativa de Python, por ejemplo:
packageName.command (arg0, arg1, ..., param0, param1, ...)
Algunos puntos extra, parens y comas, pero esos no son showstoppers.
Recuerdo haber visto que alguien ha hecho versiones de lex y yacc en Python (prueba: http://www.dabeaz.com/ply/ ), por lo que si todavía son necesarias, están disponibles.
El punto de esta divagación es que me ha parecido que Python ES EL front-end "ligero" deseado por los científicos. Tengo curiosidad por saber por qué piensas que no es así, y lo digo en serio.
agregado más tarde: la aplicación gedit anticipa que se agregarán complementos y su sitio tiene la explicación más clara de un procedimiento de complemento simple que he encontrado en unos minutos de mirar alrededor. Tratar:
https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld
Todavía me gustaría entender mejor tu pregunta. No tengo claro si usted 1) quiere que los científicos puedan usar su aplicación (Python) de manera bastante simple de varias maneras o 2) quiere permitir que los científicos agreguen nuevas capacidades a su aplicación. La opción n. ° 1 es la situación que enfrentamos con las imágenes y que nos llevó a utilizar secuencias de comandos genéricas que modificamos para adaptarlas a las necesidades del momento. ¿Es la Opción # 2 la que lo lleva a la idea de los complementos, o es algún aspecto de su aplicación que hace que la emisión de comandos sea impracticable?
fuente
Cuando busqué decoradores de Python, encontré un fragmento de código simple pero útil. Puede que no se ajuste a tus necesidades pero es muy inspirador.
Sistema de registro de plugin Scipy Advanced Python #
Uso:
fuente
WordProcessor.plugin
no devuelve nada (None
), por lo que importar laCleanMdashesExtension
clase más tarde solo importaNone
. Si las clases de complementos son útiles por sí mismas, cree el.plugin
método de clasereturn plugin
.Disfruté de la agradable discusión sobre diferentes arquitecturas de complementos dada por el Dr. Andre Roberge en Pycon 2009. Da una buena visión general de las diferentes formas de implementar complementos, comenzando por algo realmente simple.
Está disponible como un podcast (segunda parte después de una explicación de parches de mono) acompañado de una serie de seis entradas de blog .
Recomiendo escucharlo rápidamente antes de tomar una decisión.
fuente
Llegué aquí buscando una arquitectura mínima de complementos, y encontré muchas cosas que me parecieron excesivas. Por lo tanto, he implementado complementos de Python súper simples . Para usarlo, crea uno o más directorios y suelta un
__init__.py
archivo especial en cada uno. La importación de esos directorios hará que todos los demás archivos de Python se carguen como submódulos, y sus nombres se colocarán en la__all__
lista. Entonces depende de usted validar / inicializar / registrar esos módulos. Hay un ejemplo en el archivo README.fuente
En realidad, setuptools funciona con un "directorio de complementos", como el siguiente ejemplo tomado de la documentación del proyecto: http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins
Ejemplo de uso:
A la larga, setuptools es una opción mucho más segura ya que puede cargar complementos sin conflictos ni requisitos faltantes.
Otro beneficio es que los complementos pueden ampliarse utilizando el mismo mecanismo, sin que las aplicaciones originales tengan que preocuparse por ello.
fuente
Como otro enfoque para el sistema de complementos, puede marcar el proyecto Extenderme .
Por ejemplo, definamos una clase simple y su extensión
Y trata de usarlo:
Y muestra lo que se esconde detrás de la escena:
La biblioteca extend_me manipula el proceso de creación de clases a través de metaclases, por lo tanto, en el ejemplo anterior, cuando creamos una nueva instancia de
MyCoolClass
tenemos una nueva clase que es subclase de ambosMyCoolClassExtension
y queMyCoolClass
tiene funcionalidad de ambos, gracias a la herencia múltiple de PythonPara un mejor control sobre la creación de clases, hay pocas metaclases definidas en esta biblioteca:
ExtensibleType
- permite una extensibilidad simple mediante subclasesExtensibleByHashType
- similar a ExtensibleType, pero con capacidad para construir versiones especializadas de clase, permitiendo la extensión global de la clase base y la extensión de versiones especializadas de clase¡Esta lib se usa en OpenERP Proxy Project y parece estar funcionando lo suficientemente bien!
Para un ejemplo real de uso, busque en la extensión 'field_datetime' del proxy OpenERP :
Record
Aquí hay un objeto extensible.RecordDateTime
Es extensión.Para habilitar la extensión, solo importe el módulo que contiene la clase de extensión y (en el caso anterior) todos los
Record
objetos creados después de que tenga la clase de extensión en las clases base, teniendo así toda su funcionalidad.La principal ventaja de esta biblioteca es que, el código que opera objetos extensibles, no necesita saber acerca de la extensión y las extensiones podrían cambiar todo en objetos extensibles.
fuente
my_cool_obj = MyCoolClassExtension1()
lugar demy_cool_obj = MyCoolClass()
__new__
método anulado , por lo que busca automáticamente todas las subclases y crea una nueva clase, es decir, una subclase de todas ellas, y devuelve una nueva instancia de esta clase creada. Por lo tanto, la aplicación original no necesita conocer todas las extensiones. Este enfoque es útil cuando se construye una biblioteca, para permitir que el usuario final modifique o extienda su comportamiento fácilmente. en el ejemplo anterior, MyCoolClass se puede definir en la biblioteca y utilizar, y MyCoolClassExtension puede ser definido por el usuario final.setuptools tiene un EntryPoint :
AFAIK este paquete siempre está disponible si usa pip o virtualenv.
fuente
Ampliando la respuesta de @ edomaur, puedo sugerir que eche un vistazo a simple_plugins (conector descarado), que es un marco de complemento simple inspirado en el trabajo de Marty Alchin .
Un breve ejemplo de uso basado en el archivo README del proyecto:
fuente
He pasado tiempo leyendo este hilo mientras buscaba un marco de plugin en Python de vez en cuando. He usado algunos pero había defectos con ellos. Esto es lo que se me ocurrió para su escrutinio en 2017, un sistema de administración de complementos sin interfaz y libremente acoplado: cárgueme más tarde . Aquí hay tutoriales sobre cómo usarlo.
fuente
Puedes usar pluginlib .
Los complementos son fáciles de crear y se pueden cargar desde otros paquetes, rutas de archivos o puntos de entrada.
Cree una clase principal de complemento, definiendo los métodos necesarios:
Cree un complemento heredando una clase padre:
Cargue los complementos:
fuente
foo
, es posible que tenga un módulo llamadofoo.parents
donde defina las clases principales. Entonces sus complementos, importaríanfoo.parents
. Eso funciona bien para la mayoría de los casos de uso. Debido a que 'foo' también se importa, para evitar la posibilidad de importaciones circulares, muchos proyectos dejan la raíz del módulo vacía y usan un__main__.py
archivo o puntos de entrada para iniciar la aplicación.He pasado mucho tiempo tratando de encontrar un pequeño sistema de complementos para Python, que se ajuste a mis necesidades. Pero luego pensé, si ya existe una herencia, que es natural y flexible, ¿por qué no usarla?
El único problema con el uso de la herencia para complementos es que no sabes cuáles son las clases de complementos más específicas (las más bajas en el árbol de herencia).
Pero esto podría resolverse con metaclase, que realiza un seguimiento de la herencia de la clase base, y posiblemente podría construir una clase, que hereda de los complementos más específicos ('Root extendido' en la figura a continuación)
Así que llegué con una solución codificando una metaclase de este tipo:
Entonces, cuando tiene una base raíz, hecha con metaclase, y tiene un árbol de complementos que hereda de ella, puede obtener automáticamente la clase, que hereda de los complementos más específicos simplemente subclasificando:
La base de código es bastante pequeña (~ 30 líneas de código puro) y tan flexible como lo permite la herencia.
Si está interesado, participe @ https://github.com/thodnev/pluginlib
fuente
También puede echar un vistazo a Groundwork .
La idea es crear aplicaciones alrededor de componentes reutilizables, llamados patrones y complementos. Los complementos son clases que se derivan de
GwBasePattern
. Aquí hay un ejemplo básico:También hay patrones más avanzados para manejar, por ejemplo, interfaces de línea de comandos, señalización u objetos compartidos.
Groundwork encuentra sus complementos al vincularlos mediante programación a una aplicación como se muestra arriba o automáticamente a través de
setuptools
. Los paquetes de Python que contienen complementos deben declararlos utilizando un punto de entrada especialgroundwork.plugin
.Aquí están los documentos .
Descargo de responsabilidad : soy uno de los autores de Groundwork.
fuente
En nuestro producto sanitario actual, tenemos una arquitectura de complemento implementada con clase de interfaz. Nuestra pila tecnológica es Django sobre Python para API y Nuxtjs sobre nodejs para frontend.
Tenemos una aplicación de administrador de complementos escrita para nuestro producto que es básicamente un paquete pip y npm en cumplimiento con Django y Nuxtjs.
Para el desarrollo de nuevos complementos (pip y npm) creamos el administrador de complementos como dependencia.
En el paquete Pip: con la ayuda de setup.py puede agregar el punto de entrada del complemento para hacer algo con el administrador de complementos (registro, iniciaciones, etc.) https://setuptools.readthedocs.io/en/latest/setuptools .html # automatic-script-creation
En el paquete npm: Similar a pip, hay ganchos en los scripts npm para manejar la instalación. https://docs.npmjs.com/misc/scripts
Nuestro caso de uso:
El equipo de desarrollo de plugins ahora está separado del equipo central de desarrollo. El alcance del desarrollo de complementos es para integrarse con aplicaciones de terceros que se definen en cualquiera de las categorías del producto. Las interfaces del complemento se clasifican por ejemplo, por ejemplo: - El administrador de complementos de fax, teléfono, correo electrónico ... etc. se puede mejorar a nuevas categorías.
En su caso: tal vez pueda tener un plugin escrito y reutilizarlo para hacer cosas.
Si los desarrolladores de complementos tienen que usar reutilizar objetos centrales, ese objeto puede usarse haciendo un nivel de abstracción dentro del administrador de complementos para que cualquier complemento pueda heredar esos métodos.
Solo compartiendo cómo implementamos en nuestro producto espero que dé una pequeña idea.
fuente