24

私はプラグインモジュールが次のようにロードされるプラグインシステムに取り組んでいます:

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

コードは機能しますが、プラグインコードのインポートステートメントごとに、次のような警告が表示されます。

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

メインプログラムコードのエラーは報告されず、プラグインは機能します。

誰かが警告の意味と私が間違っていることを説明できますか?Pythonを満足させるために、空のプラグインモジュールを個別に作成し、インポートする必要がありますか?

4

5 に答える 5

16

プラグインディレクトリにがない場合__init__.py、それはパッケージではないため、を作成するときにplugins.whatever、Pythonはそのようなものは実際には存在してはならないことを警告します。import plugins.whatever(パスが何であれ、""で作成することはできませんでした。)

また、

  • に分割しないでください/。これは移植性がありません。を使用しos.path.splitます。
  • .split(".py")バグのある拡張子なしで名前を取得するために使用しないでください。を使用しos.path.splitextます。
  • getattr文字列リテラルと一緒に使用しないでください。getattr(plugin, "__init__")スペルト小麦plugin.__init__です。
  • __init__モジュールレベルの関数を呼び出す理由がわかりません。これは正しくないようです。おそらく、ロガーを取るクラスをインスタンス化するために、「set_logger」関数以上が必要です。
  • L = L + some_other_listリストを拡張するために使用しないでくださいextend。パフォーマンスが高く、慣用的な方法を使用してください。
  • によって未知の例外を押しつぶさないでくださいexcept Exception。例外に応じて何か正気なことをする計画ができない場合、プログラムは正気に進むことができません。
于 2010-02-15T18:16:31.680 に答える
14

ディレクトリpluginsが実際のパッケージ(正常に含まれて__init__.pyいる)の場合、pkgutilsを使用してプラグインファイルを簡単に列挙し、それらをロードできます。

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

ただし、プラグインパッケージがなくても機能する可能性があるため、次のことを試してください。

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

また、実行時にのみ存在するパッケージを作成することもできます。

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

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

しかし、それは主に楽しみのためだったそのハック!

于 2010-02-15T18:54:37.803 に答える
7

ここでの問題は、モジュール名のドット('。')にあります。

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

'。'を含めないでください。「プラグイン」の後、またはPythonはそれがモジュールパスであると見なします。

于 2014-10-18T08:08:08.590 に答える
2

importステートメントの先頭に以下のステートメントを追加してみてください。

from __future__ import absolute_import
于 2018-12-07T10:22:33.950 に答える
0

これが回答されてから、 Pythonのimpドキュメントが更新されました。これで、特にfind_module()メソッドでこの問題に対処できるようになりました。

この関数は、階層モジュール名(ドットを含む名前)を処理しません。PM、つまりパッケージPのサブモジュールM見つけるには、とを使用してパッケージPを見つけてロードし、path引数をに設定して使用します。P自体に点線の名前がある場合は、このレシピを再帰的に適用します。find_module()load_module()find_module()P.__path__

P.__path__に提供するときは、すでにリストになっていることに注意してくださいfind_module()find_module()また、パッケージの検索についてドキュメントに記載されている内容にも注意してください。

モジュールがパッケージの場合、ファイルNoneパス名はパッケージパスであり、説明タプルの最後の項目はですPKG_DIRECTORY

したがって、OPの質問から、警告なしでプラグインをインポートするRuntimeErrorには、更新された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)
于 2016-09-22T09:42:00.660 に答える