chargement dynamique des classes en Python 2.6: RuntimeWarning: Module parent « plugins » introuvable lors de la manipulation importation absolue

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

Question

Je travaille sur un système de plug-in où les modules de plug-ins sont chargés comme ceci:

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

Le code fonctionne, mais pour chaque déclaration d'importation dans le code du plugin i obtenir un avertissement comme ceci:

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

Aucune erreur ne sont signalées pour le code principal du programme, et les plug-ins fonctionnent.

Quelqu'un peut-il expliquer ce que les moyens d'avertissement et ce que je fais mal. Ai-je besoin de créer un module plugins vide séparément et importer pour garder python heureux?

Était-ce utile?

La solution

Si le plugins de répertoire était un vrai paquet (contenu __init__.py fine), vous pouvez facilement utiliser pkgutils d'énumérer ses fichiers de plugin et de les charger.

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

Cependant, il peut fonctionner sans un paquet de plug-in de toute façon, essayez ceci:

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

En outre, il est possible de faire un paquet qui existe seulement à l'exécution:

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

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

Cependant, ce hack qui était la plupart du temps pour le plaisir!

Autres conseils

Si le répertoire plugins ne dispose pas d'un __init__.py, ce n'est pas un paquet, donc quand vous créez plugins.whatever, Python vous avertit qu'une telle chose ne devrait pas exister vraiment. (Il ne peut être créé par « import plugins.whatever » peu importe ce que votre chemin est.)

En outre,

  • Ne pas couper sur /, qui est non portable. Utilisez os.path.split.
  • Ne pas utiliser .split(".py") pour obtenir le nom sans l'extension, qui est buggy. Utilisez os.path.splitext.
  • Ne pas utiliser getattr avec une chaîne littérale. getattr(plugin, "__init__") est orthographié plugin.__init__.
  • Je suis confus pourquoi vous appelez un module de niveau fonction __init__. Cela ne semble pas juste. Peut-être que vous voulez une fonction « set_logger » ou mieux, pour instancier une classe qui prend un enregistreur.
  • Ne pas utiliser L = L + some_other_list d'étendre la liste, utilisez la méthode extend, qui a de meilleures performances et plus idiomatiques.
  • Ne pas écraser par des exceptions except Exception inconnus. Si vous ne pouvez pas l'intention de faire quelque chose de sain d'esprit en réponse à une exception, votre programme ne peut pas continuer sanely.

Le problème est ici avec le point ( '') au nom du module:

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

Ne pas inclure « » après 'plugins', ou Python pensera qu'il est un chemin de module.

Vous pouvez essayer d'ajouter ci-dessous déclaration au début des déclarations d'importation.

from __future__ import absolute_import

Le Python imp la documentation a été mis à jour depuis cela a été répondu. Il aborde maintenant cette question spécifiquement dans la méthode find_module() .

  

Cette fonction ne gère pas les noms de modules hiérarchiques (noms contenant des points). Pour trouver PM , qui est, sous-module M du paquet P , utilisez find_module() et load_module() pour trouver et paquet de charge P , et puis utilisez find_module() avec chemin argumentation à P.__path__. Lorsque P a lui-même un nom en pointillé, appliquez cette recette récursive.

Notez que P.__path__ est déjà une liste en fournissant à find_module() . A noter également que le find_module() la documentation dit de trouver des paquets.

  

Si le module est un package, fichier est None, chemin est le chemin de l'emballage et le dernier élément dans la Description tuple est < a href = "https://docs.python.org/2/library/imp.html#imp.PKG_DIRECTORY" rel = "nofollow"> PKG_DIRECTORY .

de la question de l'OP, d'importer le plug-in sans les avertissements RuntimeError, suivez les instructions de la documentation Python mise à jour:

# 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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top