Dynamische Laden von Klassen in Python 2.6: RuntimeWarning: Parent-Modul ‚Plugins‘ nicht gefunden, während absolute Importabwicklung

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

Frage

Ich arbeite an einem Plugin-System, wo Plugin-Module wie folgt geladen werden:

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

Der Code funktioniert, aber für jede Import-Anweisung in dem Plugin-Code erhalte ich eine Warnung wie diese:

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

Es werden keine Fehler für den Hauptprogrammcode gemeldet, und die Plug-in arbeiten.

erklären kann jemand, was das Warnmittel und was ich falsch mache. Benötige ich eine leere Plugins erstellen Modul separat und importieren Python glücklich?

War es hilfreich?

Lösung

Wenn das Verzeichnis plugins ein echtes Paket waren (enthalten __init__.py fein), könnte man leicht pkgutils verwenden, um seine Plugin-Dateien auflisten und sie laden.

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

Es kann jedoch ohne Plugin-Paket arbeiten sowieso, versuchen Sie dies:

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

Auch ist es möglich, ein Paket zu machen, dass nur zur Laufzeit vorhanden ist:

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

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

Allerdings, dass Hack, der vor allem für Spaß war!

Andere Tipps

Wenn das Plugin-Verzeichnis keine __init__.py hat, ist es kein Paket, also wenn Sie plugins.whatever erstellen, Python warnt Sie, dass so etwas nicht wirklich existieren. (Es konnte nicht von „import plugins.whatever“ egal erstellt werden, was Ihr Weg ist.)

Auch

  • spalten nicht auf /, die portabel ist. Verwenden os.path.split.
  • Verwenden Sie .split(".py") nicht ohne die Erweiterung um den Namen zu erhalten, der Buggy ist. Verwenden os.path.splitext.
  • Verwenden Sie getattr nicht mit einem String-Literal. getattr(plugin, "__init__") buchstabiert plugin.__init__.
  • Ich bin verwirrt, warum Sie eine Modulebene __init__ Funktion aufrufen. Dies scheint nicht richtig. Vielleicht möchten Sie eine „set_logger“ -Funktion oder besser, eine Klasse instanziieren, die einen Logger nimmt.
  • Do not L = L + some_other_list verwenden, um eine Liste zu erweitern, verwenden Sie die extend-Methode, die eine bessere Leistung und ist mehr idiomatische.
  • Do not Squash unbekannte Ausnahmen von except Exception. Wenn Sie etwas nicht gesund in Reaktion auf eine Ausnahme planen zu tun, Ihr Programm kann nicht vernünftig weitergehen.

Das Problem hier ist mit dem Punkt ( '') in dem Modulnamen:

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

enthalten nicht a '' nach ‚Plugins‘, oder Python werden denken, es ist ein Modulpfad.

Sie können versuchen, unter Anweisung zu Beginn der Import-Anweisungen hinzufügen.

from __future__ import absolute_import

Der Python imp Dokumentation wurde aktualisiert, da diese beantwortet wurde. Es richtet sich nun dieses Problem speziell im find_module() Methode.

  

Diese Funktion behandelt nicht hierarchische Modulnamen (Namen enthält Punkte). Um zu finden PM , das heißt, Submodul M von Paket P , sondern find_module() und load_module() zu finden und Last-Paket P , und verwenden Sie dann find_module() mit dem Pfad Argument Satz P.__path__. Wenn P selbst einen gepunkteten Namen hat, gilt dieses Rezept rekursiv.

Beachten Sie, dass P.__path__ bereits eine Liste, wenn es Versorgen find_module() . Beachten Sie auch, was die find_module() Dokumentation sagt über Pakete zu finden.

  

Wenn das Modul ein Paket ist, Datei ist None, pathname ist der Paketpfad und das letzte Element in der Beschreibung Tupel < a href = "https://docs.python.org/2/library/imp.html#imp.PKG_DIRECTORY" rel = "nofollow"> PKG_DIRECTORY .

So von der Frage des OP, das Plugin ohne die RuntimeError Warnungen zu importieren, folgen Sie den Anweisungen in der aktualisierten Python-Dokumentation:

# 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)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top