Estoy escribiendo una aplicación Python que toma como comando como argumento, por ejemplo:
$ python myapp.py command1
Quiero que la aplicación sea extensible, es decir, que pueda agregar nuevos módulos que implementen nuevos comandos sin tener que cambiar la fuente principal de la aplicación. El árbol se parece a:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Entonces, quiero que la aplicación encuentre los módulos de comando disponibles en tiempo de ejecución y ejecute el apropiado.
Python define una función __import__ , que toma una cadena para el nombre de un módulo:
__importar __ (nombre, globales = Ninguno, locales = Ninguno, de la lista = (), nivel = 0)
La función importa el nombre del módulo, potencialmente usando los globales y locales dados para determinar cómo interpretar el nombre en un contexto de paquete. La lista de origen proporciona los nombres de los objetos o submódulos que deben importarse del módulo dado por su nombre.
Fuente: https://docs.python.org/3/library/functions.html# import
Así que actualmente tengo 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()
Esto funciona bien, solo me pregunto si es posible que haya una forma más idiomática de lograr lo que estamos haciendo con este código.
Tenga en cuenta que específicamente no quiero usar huevos o puntos de extensión. Este no es un proyecto de código abierto y no espero que haya "complementos". El objetivo es simplificar el código de la aplicación principal y eliminar la necesidad de modificarlo cada vez que se agrega un nuevo módulo de comando.
dir(__import__)
. La lista from from debe ser una lista de nombres para emular "from name import ...".
importlib
: stackoverflow.com/a/54956419/687896