Explique os pontos de entrada do Python?

181

Eu li a documentação sobre pontos de entrada de ovos em Pylons e nas páginas Peak, e ainda não entendi direito. Alguém poderia me explicar?

Brad Wright
fonte

Respostas:

168

Um "ponto de entrada" geralmente é uma função (ou outro objeto que pode ser chamado de função) que um desenvolvedor ou usuário do seu pacote Python pode querer usar, embora um objeto que não possa ser chamado também possa ser fornecido como um ponto de entrada (como corretamente apontado nos comentários!).

O tipo de ponto de entrada mais popular é o ponto de entrada console_scripts , que aponta para uma função que você deseja disponibilizar como ferramenta de linha de comando para quem instala seu pacote. Isso vai para o seu setup.py como:

entry_points={
    'console_scripts': [
        'cursive = cursive.tools.cmd:cursive_command',
    ],
},

Eu tenho um pacote que acabei de implantar chamado "cursive.tools" e queria que ele disponibilizasse um comando "cursivo" que alguém pudesse executar a partir da linha de comando, como:

$ cursive --help
usage: cursive ...

A maneira de fazer isso é definir uma função, como talvez uma função "cursive_command" em cursive / tools / cmd.py que se parece com:

def cursive_command():
    args = sys.argv[1:]
    if len(args) < 1:
        print "usage: ..."

e assim por diante; deve assumir que foi chamado na linha de comando, analisar os argumentos que o usuário forneceu e ... bem, fazer o que o comando foi projetado para fazer.

Instale o pacote docutils para um ótimo exemplo de uso do ponto de entrada: ele instalará algo como meia dúzia de comandos úteis para converter a documentação do Python para outros formatos.

Brandon Rhodes
fonte
3
o docutils atual ' setup.pynão contém entry_pointsnada.
22613 Matthew
2
Essa é uma excelente resposta, pois demonstra o poder de vários projetos que compartilham um único nome de grupo entry_point, que é "console_scripts". Compare esta resposta com a resposta mais geral de Petri. Você verá que o setuptools deve estar usando esse mecanismo pkg_resources para obter os console_scripts e, em seguida, criar um wrapper de shell em torno deles. Inspirador? Use estes. Eles são bons para mais do que apenas console_scripts.
117815 Bruno Bronosky
188

Os EntryPoints fornecem um mecanismo persistente de registro de nomes de objetos com base no sistema de arquivos e um mecanismo de importação direta de objetos com base em nomes (implementado pelo setuptools pacote ).

Eles associam nomes de objetos Python a identificadores de forma livre. Portanto, qualquer outro código que utilize a mesma instalação do Python e saiba o identificador pode acessar um objeto com o nome associado, independentemente de onde o objeto estiver definido. Os nomes associados podem ser quaisquer nomes existentes em um módulo Python ; por exemplo, nome de uma classe, função ou variável. O mecanismo do ponto de entrada não se importa com o que o nome se refere, desde que seja importável.

Como exemplo, vamos usar (o nome de) uma função e um módulo python imaginário com um nome totalmente qualificado 'myns.mypkg.mymodule':

def the_function():
   "function whose name is 'the_function', in 'mymodule' module"
   print "hello from the_function"

Os pontos de entrada são registrados por meio de uma declaração de pontos de entrada em setup.py. Para registrar a função_ no ponto de entrada chamado 'my_ep_func':

    entry_points = {
        'my_ep_group_id': [
            'my_ep_func = myns.mypkg.mymodule:the_function'
        ]
    },

Como o exemplo mostra, os pontos de entrada são agrupados; há uma API correspondente para procurar todos os pontos de entrada pertencentes a um grupo (exemplo abaixo).

Após a instalação de um pacote (ou seja, executando 'python setup.py install'), a declaração acima é analisada pelo setuptools. Em seguida, ele grava as informações analisadas em um arquivo especial. Depois disso, o API pkg_resources (parte do setuptools) pode ser usada para procurar o ponto de entrada e acessar o (s) objeto (s) com o (s) nome (s) associado (s):

import pkg_resources

named_objects = {}
for ep in pkg_resources.iter_entry_points(group='my_ep_group_id'):
   named_objects.update({ep.name: ep.load()})

Aqui, o setuptools lê as informações do ponto de entrada que foram gravadas em arquivos especiais. Ele localizou o ponto de entrada, importou o módulo (myns.mypkg.mymodule) e recuperou a função_ definida lá, ao chamar pkg_resources.load ().

Supondo que não houvesse outros registros de ponto de entrada para o mesmo ID de grupo, chamar a função the_ seria então simples:

>>> named_objects['my_ep_func']()
hello from the_function

Assim, embora talvez seja um pouco difícil de entender a princípio, o mecanismo do ponto de entrada é realmente bastante simples de usar. Ele fornece uma ferramenta útil para o desenvolvimento de software Python conectável.

Petri
fonte
4
Onde o nome 'my_ep_func' é usado em todo esse processo? Não parece ser usado para nada pelo iterador pkg_resources.
Kamil Kisiel
2
@KamilKisiel: no exemplo usado para ilustração aqui, o nome do ponto de entrada não é realmente usado para nada, nem precisa ser; se o nome do ponto de entrada é ou não usado para qualquer coisa depende do aplicativo. O nome está disponível simplesmente como o atributo name da instância do ponto de entrada.
Petri
3
Eu acho que descartar o ep.name e tornar nomeado_objetos uma lista em vez de um dicionário foi confuso, então editei a resposta. É isso que a resposta mostra onde obter o nome e se deve ser 'the_function' ou 'my_ep_func'. Caso contrário, o leitor teria que encontrar documentação adicional em outro lugar. Esta é uma resposta EXCELENTE e a explicação mais curta e clara dos pontos de entrada que eu já vi!
de Bruno Bronosky
3
Eu criei um projeto no github que demonstra esse conceito. github.com/RichardBronosky/entrypoint_demo
Bruno Bronosky;
1
Esta é uma explicação muito clara dos pontos de entrada, que você fornece para a explicação detalhada. O EntryPointslink está obsoleto, embora a explicação seja muito clara.
Rahul Nair
18

Do ponto de vista abstrato, os pontos de entrada são usados ​​para criar um registro em todo o sistema de chamadas de código Python que implementam determinadas interfaces. Existem APIs em pkg_resources para ver quais pontos de entrada são anunciados por um determinado pacote, bem como APIs para determinar quais pacotes anunciam um determinado ponto de entrada.

Os pontos de entrada são úteis para permitir que um pacote use plug-ins que estão em outro pacote. Por exemplo, o projeto Colar de Ian Bicking usa pontos de entrada extensivamente. Nesse caso, você pode escrever um pacote que anuncia sua fábrica de aplicativos WSGI usando o ponto de entrada paste.app_factory.

Outro uso para pontos de entrada é enumerar todos os pacotes no sistema que fornecem alguma funcionalidade de plug-in. A estrutura da web TurboGears usa o python.templating.enginesponto de entrada para procurar bibliotecas de modelos instaladas e disponíveis.

Rick Copeland
fonte