resueltos - programacion orientada a objetos python pdf
Carga dinámica de clases en Python 2.6: RuntimeWarning: no se encuentran los ''complementos'' del módulo principal mientras se maneja la importación absoluta (4)
Estoy trabajando en un sistema de complemento donde los módulos de complementos se cargan así:
def load_plugins():
plugins=glob.glob("plugins/*.py")
instances=[]
for p in plugins:
try:
name=p.split("/")[-1]
name=name.split(".py")[0]
log.debug("Possible plugin: %s", name)
f, file, desc=imp.find_module(name, ["plugins"])
plugin=imp.load_module(''plugins.''+name, f, file, desc)
getattr(plugin, "__init__")(log)
instances=instances+plugin.get_instances()
except Exception as e:
log.info("Failed to load plugin: "+str(p))
log.info("Error: %s " % (e))
log.info(traceback.format_exc(e))
return instances
El código funciona, pero para cada instrucción de importación en el código del complemento recibo una advertencia como esta:
plugins/plugin.py:2: RuntimeWarning: Parent module ''plugins'' not found while handling absolute import
import os
No se informan errores para el código del programa principal, y los complementos funcionan.
¿Alguien puede explicar lo que significa la advertencia y lo que estoy haciendo mal? ¿Debo crear un módulo de complementos vacío por separado e importarlo para mantener a python satisfecho?
El problema aquí es con el punto (''.'') En el nombre del módulo:
imp.load_module(''plugins.''+name, f, file, desc)
No incluya un ''.'' después de ''complementos'', o Python pensará que es una ruta de módulo.
La documentación Python imp
se ha actualizado desde que se respondió. Ahora aborda este problema específicamente en el método find_module()
.
Esta función no maneja nombres de módulos jerárquicos (nombres que contienen puntos). Para encontrar PM , es decir, el submódulo M del paquete P , use
find_module()
y imp.load_module para buscar y cargar el paquete P , y luego usefind_module()
con el argumento de ruta establecido enP.__path__
. Cuando P mismo tiene un nombre punteado, aplique esta receta recursivamente.
Tenga en cuenta que P.__path__
ya es una lista al suministrarlo a find_module()
. También tenga en cuenta lo que dice la documentación de find_module()
sobre la búsqueda de paquetes.
Si el módulo es un paquete, el archivo es
None
, pathname es la ruta del paquete y el último elemento en la descripción tuple esPKG_DIRECTORY
.
Entonces, de la pregunta del OP, para importar el complemento sin las advertencias de RuntimeError
, siga las instrucciones en la documentación actualizada de Python:
# first find and load the package assuming it is in
# the current working directory, ''.''
f, file, desc = imp.find_module(''plugins'', [''.''])
pkg = imp.load_module(''plugins'', f, file, desc)
# then find the named plugin module using pkg.__path__
# and load the module using the dotted name
f, file, desc = imp.find_module(name, pkg.__path__)
plugin = imp.load_module(''plugins.'' + name, f, file, desc)
Si el directorio de complementos no tiene un __init__.py
, no es un paquete, así que cuando creas plugins.whatever
, Python te advierte que tal cosa no debería existir realmente. (No podría ser creado por " import plugins.whatever
" sin importar cuál sea tu ruta).
También,
- No se divida en
/
, lo que no es portátil. Useos.path.split
. - No use
.split(".py")
para obtener el nombre sin la extensión, que tiene errores. Useos.path.splitext
. - No use
getattr
con un literal de cadena.getattr(plugin, "__init__")
se escribeplugin.__init__
. - Estoy confundido por qué está llamando a una función
__init__
nivel de__init__
. Esto no parece correcto. Quizás desee una función "set_logger" o mejor, para instanciar una clase que tenga un registrador. - No use
L = L + some_other_list
para extender una lista, use el métodoextend
, que tiene un mejor rendimiento y es más idiomático. - No squash excepciones desconocidas por excepción
except Exception
. Si no puede planear hacer algo sensato en respuesta a una excepción, su programa no puede seguir sano.
Si los plugins
del directorio eran un paquete real (contenía __init__.py
fine), podría usar pkgutils fácilmente para enumerar sus archivos de complementos y cargarlos.
import pkgutil
# import our package
import plugins
list(pkgutil.iter_modules(plugins.__path__))
Sin embargo, puede funcionar sin un paquete de complemento de todos modos, intente esto:
import pkgutil
list(pkgutil.iter_modules(["plugins"]))
También es posible crear un paquete que solo existe en tiempo de ejecución:
import types
import sys
plugins = types.ModuleType("plugins")
plugins.__path__ = ["plugins"]
sys.modules["plugins"] = plugins
import plugins.testplugin
Sin embargo, ese truco fue principalmente por diversión.