Carga de clases dinámica en Python 2.6:Advertencia de tiempo de ejecución:No se encontraron los 'complementos' del módulo principal al manejar la importación absoluta

StackOverflow https://stackoverflow.com/questions/2267984

Pregunta

Estoy trabajando en un sistema de complementos 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 declaració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 qué significa la advertencia y qué estoy haciendo mal?¿Necesito crear un módulo de complementos vacío por separado e importarlo para mantener contento a Python?

¿Fue útil?

Solución

Si el directorio plugins fuera un verdadero paquete (contenida fina __init__.py), se puede utilizar fácilmente pkgutils enumerar sus archivos de plugin y cargarlos.

import pkgutil
# import our package
import plugins
list(pkgutil.iter_modules(plugins.__path__))

Sin embargo, puede trabajar sin un paquete de plug-in de todos modos, intente lo siguiente:

import pkgutil
list(pkgutil.iter_modules(["plugins"]))

También es posible hacer un paquete que sólo 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, eso truco que era todo para la diversión!

Otros consejos

Si el directorio de plugins no tiene un __init__.py, no es un paquete, por lo que cuando se crea plugins.whatever, Python advierte de que tal cosa no debe existir realmente. (No se ha podido crear por "import plugins.whatever" no importa lo que su trayectoria es.)

Además,

  • No divida en /, que es no portables. Utilice os.path.split.
  • No utilice .split(".py") para obtener el nombre sin la extensión, que está libre de errores. Utilice os.path.splitext.
  • No utilice getattr con una cadena literal. getattr(plugin, "__init__") se escribe plugin.__init__.
  • Estoy confundido por qué está llamando una función __init__ de nivel de módulo. Esto no parece estar bien. Tal vez usted quiere una función "set_logger" o mejor, para crear instancias de una clase que lleva un registrador.
  • No utilice L = L + some_other_list para extender una lista, utilice el método extend, que tiene un mejor rendimiento y es más idiomática.
  • No aplastar excepciones desconocidas por except Exception. Si no se puede planificar para hacer algo cuerdo en respuesta a una excepción, su programa no puede continuar con cordura.

El problema aquí es con el punto ( '') en el nombre del módulo:

imp.load_module('plugins.'+name, f, file, desc)

No incluya una ''. después de 'plugins', o Python pensará que es una ruta del módulo.

Se puede tratar de añadir a continuación declaración al comienzo de las declaraciones de importación.

from __future__ import absolute_import

La pitón imp La documentación se ha actualizado desde que se respondió esto.Ahora aborda esta cuestión específicamente en el find_module() método.

Esta función no maneja nombres de módulos jerárquicos (nombres que contienen puntos).Para encontrar PM, es decir, submódulo METRO del paquete PAG, usar find_module() y load_module() para buscar y cargar el paquete PAG, y luego usar find_module() con el camino argumento establecido en P.__path__.Cuando PAG tiene un nombre con puntos, aplique esta receta de forma recursiva.

Tenga en cuenta que P.__path__ ya es una lista al suministrarla a find_module().Tenga en cuenta también lo que find_module() La documentación dice sobre la búsqueda de paquetes.

Si el módulo es un paquete, archivo es None, nombre de ruta es la ruta del paquete y el último elemento del descripción tupla es PKG_DIRECTORY.

Entonces, según la pregunta del OP, importar el complemento sin el RuntimeError advertencias, 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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top