carico Classe dinamica in Python 2.6: RuntimeWarning: modulo Parent 'plugins' non trovato durante la manipolazione di importazione assoluta
-
20-09-2019 - |
Domanda
Sto lavorando su un sistema di plugin in cui moduli plugin sono caricati in questo modo:
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
Il codice funziona, ma per ogni istruzione import nel codice del plugin Ho ricevuto un avviso simile a questo:
plugins/plugin.py:2: RuntimeWarning: Parent module 'plugins' not found while handling absolute import
import os
Non ci sono errori vengono segnalati per il codice del programma principale, e i plugin funzionano.
Qualcuno può spiegare che cosa significa l'avviso e quello che facendo male. Ho bisogno di creare un modulo plug-vuoto separatamente e importarlo per mantenere python felice?
Soluzione
Se la plugins
directory fosse un vero e proprio pacchetto (contenuta __init__.py
bene), si potrebbe facilmente utilizzare pkgutils per enumerare le sue file dei plugin e caricarli.
import pkgutil
# import our package
import plugins
list(pkgutil.iter_modules(plugins.__path__))
Tuttavia, può funzionare senza un pacchetto di plug-in in ogni caso, provate questo:
import pkgutil
list(pkgutil.iter_modules(["plugins"]))
Inoltre è possibile fare un pacchetto che esiste solo in fase di esecuzione:
import types
import sys
plugins = types.ModuleType("plugins")
plugins.__path__ = ["plugins"]
sys.modules["plugins"] = plugins
import plugins.testplugin
Comunque hack che era per lo più per divertimento!
Altri suggerimenti
Se la directory dei plugin non ha un __init__.py
, non è un pacchetto, in modo che quando si crea plugins.whatever
, Python si avverte che una cosa del genere non dovrebbe esistere veramente. (Non poteva essere creata da "import plugins.whatever
" non importa quale sia il vostro percorso è.)
Inoltre,
- Non dividere il
/
, che è portabile. Utilizzareos.path.split
. - Non utilizzare
.split(".py")
per ottenere il nome senza l'estensione, che è bacato. Utilizzareos.path.splitext
. - Non utilizzare
getattr
con una stringa letterale.getattr(plugin, "__init__")
si scriveplugin.__init__
. - Sono confuso perché si sta chiamando una funzione
__init__
a livello di modulo. Questo non mi sembra giusto. Forse si vuole una funzione "set_logger", o meglio, per creare un'istanza di una classe che prende un registratore. - Non utilizzare
L = L + some_other_list
per estendere un elenco, utilizzare il metodoextend
, che ha prestazioni migliori ed è più idiomatica. - Non schiacciare eccezioni sconosciute di
except Exception
. Se non è possibile pianificare di fare qualcosa di sano in risposta ad un'eccezione, il programma non può andare avanti in modo sano.
Il problema qui è con il punto ( '') nel nome del modulo:
imp.load_module('plugins.'+name, f, file, desc)
Non includere un '' dopo 'plugins', o Python penserà che sia un percorso del modulo.
Si può provare ad aggiungere al di sotto dichiarazione all'inizio di istruzioni di importazione.
from __future__ import absolute_import
La documentazione Python imp
è stato aggiornato dal momento che questo è stato risposto. E 'ora risolve questo problema in particolare nel metodo find_module()
.
Questa funzione non gestisce i nomi di modulo gerarchici (nomi contenenti punti). Al fine di trovare PM , cioè, modulo M del pacchetto di P , utilizzare
find_module()
eload_module()
trovare e pacchetto di carico P , e quindi utilizzarefind_module()
con il path argomento impostatoP.__path__
. Quando P per sé ha un nome puntato, applicare questa ricetta in modo ricorsivo.
Si noti che P.__path__
è già una lista quando forniscono a find_module()
. Si noti inoltre che cosa dice la documentazione find_module()
di trovare pacchetti.
Se il modulo è un pacchetto, file è
None
, percorso è il percorso del pacchetto e l'ultimo elemento del Descrizione tupla è < a href = "https://docs.python.org/2/library/imp.html#imp.PKG_DIRECTORY" rel = "nofollow">PKG_DIRECTORY
.
Quindi, dal domanda del PO, per importare il plugin senza gli avvertimenti RuntimeError
, seguire le istruzioni fornite nella documentazione Python aggiornamento:
# 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)