Estou escrevendo um aplicativo Python que usa como comando um argumento, por exemplo:
$ python myapp.py command1
Quero que o aplicativo seja extensível, ou seja, seja capaz de adicionar novos módulos que implementam novos comandos sem precisar alterar a fonte principal do aplicativo. A árvore se parece com:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Então, eu quero que o aplicativo encontre os módulos de comando disponíveis em tempo de execução e execute o apropriado.
Python define uma função __import__ , que recebe uma string para o nome de um módulo:
__import __ (nome, globais = Nenhum, locais = Nenhum, da lista = (), nível = 0)
A função importa o nome do módulo, potencialmente usando os globais e locais fornecidos para determinar como interpretar o nome em um contexto de pacote. A lista from fornece os nomes de objetos ou submódulos que devem ser importados do módulo fornecido pelo nome.
Fonte: https://docs.python.org/3/library/functions.html# import
Então, atualmente, tenho algo como:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Isso funciona muito bem, só estou me perguntando se existe uma maneira mais idiomática de realizar o que estamos fazendo com esse código.
Note que eu especificamente não quero usar ovos ou pontos de extensão. Este não é um projeto de código aberto e não espero que haja "plugins". O objetivo é simplificar o código principal do aplicativo e remover a necessidade de modificá-lo toda vez que um novo módulo de comando é adicionado.
dir(__import__)
. A lista from from deve ser uma lista de nomes para emular "from name import ...".
importlib
: stackoverflow.com/a/54956419/687896