Carregamento de classe dinâmica em Python 2.6: RunTimeWarning: Módulo Parent 'Plugins' Não encontrado durante o manuseio de importação absoluta

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

Pergunta

Estou trabalhando em um sistema de plug -in onde os módulos de plug -in são carregados assim:

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

O código funciona, mas para cada instrução de importação no código do plug -in, recebo um aviso como este:

plugins/plugin.py:2: RuntimeWarning: Parent module 'plugins' not found while handling absolute import
  import os

Nenhum erro é relatado para o código principal do programa e os plugins funcionam.

Alguém pode explicar o que o aviso significa e o que eu estou fazendo de errado. Preciso criar um módulo de plug -ins vazio separadamente e importá -lo para manter o Python feliz?

Foi útil?

Solução

Se o diretório plugins eram um pacote real (contido __init__.py bem), você pode usar facilmente o PKGutils para enumerar seus arquivos de plug -in e carregá -los.

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

No entanto, pode funcionar sem um pacote de plug -in de qualquer maneira, tente o seguinte:

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

Também é possível fazer um pacote que exista apenas em tempo de execução:

import types
import sys
plugins = types.ModuleType("plugins")
plugins.__path__ = ["plugins"]

sys.modules["plugins"] = plugins
import plugins.testplugin

No entanto, aquele hack que foi principalmente por diversão!

Outras dicas

Se o diretório de plugins não tiver um __init__.py, não é um pacote, então quando você cria plugins.whatever, Python adverte que isso realmente não deveria existir. (Não poderia ser criado por "import plugins.whatever"Não importa qual seja o seu caminho.)

Também,

  • Não se divida /, o que não é portável. Usar os.path.split.
  • Não use .split(".py") Para obter o nome sem a extensão, que é buggy. Usar os.path.splitext.
  • Não use getattr com uma corda literal. getattr(plugin, "__init__") está escrito plugin.__init__.
  • Estou confuso por que você está chamando de nível de módulo __init__ função. Isso não parece certo. Talvez você queira uma função "set_logger" ou melhor, para instanciar uma classe que leva um madeireiro.
  • Não use L = L + some_other_list Para estender uma lista, use o extend Método, que tem melhor desempenho e é mais idiomático.
  • Não esmaga exceções desconhecidas por except Exception. Se você não pode planejar fazer algo sã em resposta a uma exceção, seu programa não pode continuar a Santamente.

O problema aqui está com o ponto ('.') No nome do módulo:

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

Não inclua um '.' Depois de 'Plugins', ou Python pensará que é um caminho do módulo.

Você pode tentar adicionar a instrução abaixo no início das instruções de importação.

from __future__ import absolute_import

O python imp A documentação foi atualizada desde que isso foi respondido. Agora aborda esta questão especificamente no find_module() método.

Esta função não lida com nomes de módulos hierárquicos (nomes que contêm pontos). A fim de encontrar PM, isto é, submódulo M de pacote P, usar find_module() e load_module() Para encontrar e carregar pacote P, e então use find_module() com o caminho argumento definido como P.__path__. Quando P Ele próprio tem um nome pontilhado, aplique esta receita recursivamente.

Observe que P.__path__ já é uma lista ao fornecê -la para find_module(). Observe também o que o find_module() A documentação diz sobre encontrar pacotes.

Se o módulo for um pacote, Arquivo é None, Nome do caminho é o caminho do pacote e o último item no Descrição tupla é PKG_DIRECTORY.

Então, da pergunta do OP, para importar o plugin sem o RuntimeError Avisos, siga as instruções na documentação atualizada do 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top