Eu tenho um aplicativo, escrito em Python, que é usado por um público bastante técnico (cientistas).
Estou procurando uma boa maneira de tornar o aplicativo extensível pelos usuários, ou seja, uma arquitetura de script / plugin.
Estou procurando por algo extremamente leve . A maioria dos scripts ou plug-ins não será desenvolvida e distribuída por terceiros e instalada, mas será criada por um usuário em alguns minutos para automatizar uma tarefa repetida, adicionar suporte para um formato de arquivo, etc. Portanto, os plug-ins devem ter o código mínimo padrão absoluto e não requerem 'instalação' além de copiar para uma pasta (algo como setuptools pontos de entrada ou a arquitetura de plugins do Zope parece demais).
Existe algum sistema como este já existente, ou algum projeto que implemente um esquema semelhante ao qual eu deveria procurar idéias / inspiração?
imp
módulo está a ser preterida em favorimportlib
da partir de python 3.4imp.load_module
.module_example.py
:loader.py
:Certamente é "mínimo", não tem absolutamente nenhuma verificação de erro, provavelmente inúmeros problemas de segurança, não é muito flexível - mas deve mostrar como um sistema de plug-in no Python pode ser simples.
Você provavelmente também deseja examinar o módulo imp , embora possa fazer muito com apenas
__import__
,os.listdir
e alguma manipulação de string.fonte
def call_plugin(name, *args)
paradef call_plugin(name, *args, **kwargs)
, em seguida,plugin.plugin_main(*args)
paraplugin.plugin_main(*args, **kwargs)
imp
é preterido em favor deimportlib
Dê uma olhada nesta visão geral sobre estruturas / bibliotecas de plugins existentes , é um bom ponto de partida. Eu gosto bastante de yapsy , mas isso depende do seu caso de uso.
fonte
Embora essa pergunta seja realmente interessante, acho que é bastante difícil responder, sem mais detalhes. Que tipo de aplicação é essa? Possui uma GUI? É uma ferramenta de linha de comando? Um conjunto de scripts? Um programa com um ponto de entrada exclusivo, etc ...
Dada a pouca informação que tenho, responderei de uma maneira muito genérica.
Quais meios você tem para adicionar plugins?
Em uma prática pura de código / design, você precisará determinar claramente que comportamento / ações específicas deseja que seus usuários estendam. Identifique o ponto de entrada comum / um conjunto de funcionalidades que sempre serão substituídas e determine grupos dentro dessas ações. Feito isso, será fácil estender seu aplicativo,
Exemplo de uso de hooks , inspirado no MediaWiki (PHP, mas a linguagem realmente importa?):
Outro exemplo, inspirado em mercurial. Aqui, as extensões adicionam apenas comandos ao executável da linha de comando hg , estendendo o comportamento.
Para ambas as abordagens, pode ser necessário inicializar e finalizar comummente sua extensão. Você pode usar uma interface comum que toda a sua extensão precisará implementar (se encaixa melhor na segunda abordagem; o mercurial usa um reposetup (ui, repo) chamado para toda a extensão) ou usar uma abordagem do tipo gancho, com um hooks.setup hook.
Mas, novamente, se você quiser respostas mais úteis, terá que refinar sua pergunta;)
fonte
A estrutura simples de plug-ins de Marty Allchin é a base que eu uso para minhas próprias necessidades. Eu realmente recomendo dar uma olhada, acho que é realmente um bom começo se você quiser algo simples e fácil de hackear. Você pode encontrá-lo também como um Django Snippets .
fonte
Eu sou um biólogo aposentado que lidou com micrografos digitais e teve que escrever um pacote de processamento e análise de imagens (não tecnicamente uma biblioteca) para rodar em uma máquina SGi. Eu escrevi o código em C e usei Tcl para a linguagem de script. A GUI, como era, foi feita usando Tk. Os comandos que apareceram no Tcl tinham o formato "extensionName commandName arg0 arg1 ... param0 param1 ...", ou seja, palavras e números simples separados por espaço. Quando Tcl viu a substring "extensionName", o controle foi passado para o pacote C. Por sua vez, ele executou o comando através de um lexer / analisador (feito em lex / yacc) e, em seguida, chamou rotinas C, conforme necessário.
Os comandos para operar o pacote podiam ser executados um a um por meio de uma janela na GUI, mas os trabalhos em lotes eram executados editando arquivos de texto que eram scripts Tcl válidos; você escolheria o modelo que executava o tipo de operação em nível de arquivo que desejava executar e, em seguida, editaria uma cópia para conter o diretório e os nomes dos arquivos reais, além dos comandos do pacote. Funcionou como um encanto. Até ...
1) O mundo voltou-se para os PCs e 2) os scripts ultrapassaram as 500 linhas, quando os duvidosos recursos organizacionais do Tcl começaram a se tornar um verdadeiro inconveniente. Tempo passou ...
Eu me aposentei, o Python foi inventado e parecia o sucessor perfeito do Tcl. Agora, nunca fiz a porta, porque nunca enfrentei os desafios de compilar (muito grandes) programas C em um PC, estendendo o Python com um pacote C e fazendo GUIs em Python / Gt? / Tk? /? ? No entanto, a velha idéia de ter scripts de modelo editável ainda parece viável. Além disso, não deve ser muito difícil inserir comandos de pacote em um formato nativo de Python, por exemplo:
packageName.command (arg0, arg1, ..., param0, param1, ...)
Alguns pontos extras, parênteses e vírgulas, mas esses não são limitadores de exibição.
Lembro-me de ver que alguém fez versões do lex e do yacc no Python (tente: http://www.dabeaz.com/ply/ ); portanto, se elas ainda são necessárias, elas estão por aí.
O ponto desta divagação é que me pareceu que o próprio Python é o front-end "leve" desejado, utilizável pelos cientistas. Estou curioso para saber por que você acha que não é, e quero dizer isso seriamente.
adicionado mais tarde: O aplicativo gedit antecipa a inclusão de plug-ins e o site deles tem a explicação mais clara de um procedimento simples de plug-in que encontrei em alguns minutos olhando ao redor. Experimentar:
https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld
Ainda gostaria de entender melhor sua pergunta. Não estou claro se você 1) deseja que os cientistas possam usar seu aplicativo (Python) de maneira bastante simples de várias maneiras ou 2) deseja permitir que os cientistas adicionem novos recursos ao seu aplicativo. A escolha 1 é a situação que enfrentamos com as imagens e que nos levou a usar scripts genéricos que modificamos para atender à necessidade do momento. É a opção 2 que leva à idéia de plug-ins ou é algum aspecto do seu aplicativo que inviabiliza a emissão de comandos?
fonte
Ao pesquisar por Decoradores Python, encontrei um trecho de código simples, mas útil. Pode não se encaixar nas suas necessidades, mas muito inspirador.
Sistema de Registro Scipy Advanced Python # Plugin
Uso:
fonte
WordProcessor.plugin
não retorna nada (None
); portanto, importar aCleanMdashesExtension
classe posteriormente apenas importaNone
. Se as classes de plug-in são úteis por si só, crie o.plugin
método de classereturn plugin
.Gostei da agradável discussão sobre as diferentes arquiteturas de plugins, oferecida pelo Dr. Andre Roberge no Pycon 2009. Ele fornece uma boa visão geral das diferentes maneiras de implementar plugins, começando por algo realmente simples.
Está disponível como um podcast (segunda parte após uma explicação sobre o uso de patches), acompanhado por uma série de seis entradas no blog .
Eu recomendo ouvi-lo rapidamente antes de tomar uma decisão.
fonte
Cheguei aqui procurando uma arquitetura mínima de plugins e encontrei muitas coisas que pareciam um exagero para mim. Então, eu implementei plugins Python super simples . Para usá-lo, você cria um ou mais diretórios e solta um
__init__.py
arquivo especial em cada um. A importação desses diretórios fará com que todos os outros arquivos Python sejam carregados como sub-módulos, e seus nomes serão colocados na__all__
lista. Cabe a você validar / inicializar / registrar esses módulos. Há um exemplo no arquivo README.fonte
Na verdade, o setuptools funciona com um "diretório de plug-ins", como o exemplo a seguir, retirado da documentação do projeto: http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins
Exemplo de uso:
A longo prazo, o setuptools é uma opção muito mais segura, pois pode carregar plug-ins sem conflitos ou sem requisitos.
Outro benefício é que os próprios plug-ins podem ser estendidos usando o mesmo mecanismo, sem que os aplicativos originais tenham que se preocupar com isso.
fonte
Como uma outra abordagem ao sistema de plug-ins, você pode verificar o projeto Estender-me .
Por exemplo, vamos definir classe simples e sua extensão
E tente usá-lo:
E mostre o que está oculto nos bastidores:
A biblioteca extend_me manipula o processo de criação de classe por meio de metaclasses, assim no exemplo acima, ao criar uma nova instância,
MyCoolClass
obtemos uma instância de nova classe que é subclasse de ambosMyCoolClassExtension
e queMyCoolClass
possui funcionalidade de ambos, graças à herança múltipla do PythonPara melhor controle sobre a criação de classes, existem poucas metaclasses definidas nesta lib:
ExtensibleType
- permite extensibilidade simples subclassificandoExtensibleByHashType
- semelhante ao ExtensibleType, mas com capacidade de criar versões especializadas de classe, permitindo a extensão global da classe base e a extensão de versões especializadas da classeEssa lib é usada no OpenERP Proxy Project e parece estar funcionando suficientemente bem!
Para um exemplo real de uso, consulte a extensão 'field_datetime' do OpenERP Proxy :
Record
aqui está um objeto extesível.RecordDateTime
é extensão.Para habilitar a extensão, apenas importe o módulo que contém a classe de extensão e (no caso acima) todos os
Record
objetos criados depois dela terão classe de extensão nas classes base, possuindo assim toda a sua funcionalidade.A principal vantagem dessa biblioteca é que, o código que opera objetos extensíveis, não precisa saber sobre extensão e as extensões podem mudar tudo em objetos extensíveis.
fonte
my_cool_obj = MyCoolClassExtension1()
, em vez demy_cool_obj = MyCoolClass()
__new__
método, portanto, encontra automaticamente todas as subclasses e constrói uma nova classe, que é a subclasse de todas elas, e retorna uma nova instância dessa classe criada. Portanto, o aplicativo original não precisa conhecer todas as extensões. Essa abordagem é útil ao criar a biblioteca, para permitir que o usuário final modifique ou estenda seu comportamento facilmente. no exemplo acima, MyCoolClass pode ser definido na biblioteca e usado por ele, e MyCoolClassExtension pode ser definido pelo usuário final.O setuptools possui um EntryPoint :
AFAIK, este pacote estará sempre disponível se você usar pip ou virtualenv.
fonte
Expandindo a resposta do @ edomaur, posso sugerir dar uma olhada em simple_plugins (plug descarado), que é uma estrutura de plug-ins simples inspirada no trabalho de Marty Alchin .
Um pequeno exemplo de uso baseado no README do projeto:
fonte
Passei um tempo lendo este tópico enquanto procurava uma estrutura de plugins no Python de vez em quando. Eu usei alguns, mas havia deficiências com eles. Aqui está o que eu proponho para o seu escrutínio em 2017, um sistema de gerenciamento de plug-ins gratuito e sem interface: Carregue-me mais tarde . Aqui estão os tutoriais sobre como usá-lo.
fonte
Você pode usar o pluginlib .
Os plugins são fáceis de criar e podem ser carregados de outros pacotes, caminhos de arquivos ou pontos de entrada.
Crie uma classe pai do plug-in, definindo quaisquer métodos necessários:
Crie um plugin herdando uma classe pai:
Carregue os plugins:
fonte
foo
, você pode ter um módulo chamadofoo.parents
onde você define as classes pai. Então seus plugins importariamfoo.parents
. Isso funciona bem para a maioria dos casos de uso. Como o próprio 'foo' também é importado, para evitar a possibilidade de importações circulares, muitos projetos deixam a raiz do módulo vazia e usam um__main__.py
arquivo ou pontos de entrada para iniciar o aplicativo.Passei muito tempo tentando encontrar um pequeno sistema de plugins para Python, que atendesse às minhas necessidades. Mas então pensei: se já existe uma herança, natural e flexível, por que não usá-la?
O único problema com o uso de herança para plug-ins é que você não sabe quais são as classes de plug-in mais específicas (a mais baixa na árvore de herança).
Mas isso pode ser resolvido com a metaclasse, que monitora a herança da classe base, e possivelmente pode criar a classe, que herda dos plugins mais específicos ('Root extended' na figura abaixo)
Então, eu vim com uma solução codificando essa metaclasse:
Portanto, quando você tem uma base Root, feita com metaclasse e possui uma árvore de plugins que herdam dela, você pode obter automaticamente a classe, que herda dos plugins mais específicos, apenas subclassificando:
A base de código é bem pequena (~ 30 linhas de código puro) e tão flexível quanto a herança permite.
Se você estiver interessado, envolva-se em https://github.com/thodnev/pluginlib
fonte
Você também pode dar uma olhada no Groundwork .
A idéia é criar aplicativos em torno de componentes reutilizáveis, chamados padrões e plugins. Plugins são classes que derivam
GwBasePattern
. Aqui está um exemplo básico:Existem também padrões mais avançados para lidar, por exemplo, com interfaces de linha de comando, sinalização ou objetos compartilhados.
O Groundwork encontra seus plugins vinculando-os programaticamente a um aplicativo, como mostrado acima, ou automaticamente via
setuptools
. Pacotes Python contendo plug-ins devem declará-los usando um ponto de entrada especialgroundwork.plugin
.Aqui estão os documentos .
Disclaimer : Eu sou um dos autores de Groundwork.
fonte
Em nosso produto de assistência médica atual, temos uma arquitetura de plug-in implementada com a classe de interface. Nossa pilha tecnológica é o Django no topo do Python para API e o Nuxtjs no topo do nodejs para o front-end.
Temos um aplicativo gerenciador de plugins criado para o nosso produto, que é basicamente o pacote pip e npm em conformidade com o Django e o Nuxtjs.
Para o desenvolvimento de novos plugins (pip e npm), criamos o gerenciador de plugins como dependência.
No pacote Pip: com a ajuda do setup.py, você pode adicionar o ponto de entrada do plug-in para fazer algo com o gerenciador de plug-ins (registro, iniciações, ... etc.) Https://setuptools.readthedocs.io/en/latest/setuptools .html # criação de script automática
No pacote npm: Semelhante ao pip, existem ganchos nos scripts npm para lidar com a instalação. https://docs.npmjs.com/misc/scripts
Nosso caso:
A equipe de desenvolvimento de plug-ins está separada da equipe de desenvolvimento principal agora. O escopo do desenvolvimento de plug-ins é a integração com aplicativos de terceiros definidos em qualquer uma das categorias do produto. As interfaces de plugins são categorizadas, por exemplo: - Fax, telefone, email ... etc, o gerenciador de plugins pode ser aprimorado para novas categorias.
No seu caso: talvez você possa ter um plug-in escrito e reutilizar o mesmo para fazer coisas.
Se os desenvolvedores de plug-ins precisarem usar objetos principais de reutilização, esse objeto poderá ser usado executando um nível de abstração no gerenciador de plug-ins, para que qualquer plug-in possa herdar esses métodos.
Compartilhar apenas como implementamos nosso produto, espero que dê uma pequena idéia.
fonte