web-dev-qa-db-ja.com

Python 2.6:RuntimeWarning:絶対インポートの処理中に親モジュール 'プラグイン'が見つかりません

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

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幸せを保つために、空のプラグインモジュールを個別に作成してインポートする必要がありますか?

23
pehrs

ディレクトリpluginsが実際のパッケージ(含まれている__init__.py fine)、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

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

14
u0b34a0f6ae

プラグインディレクトリに___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_によって未知の例外を押しつぶさないでください。例外に応じて何か正気なことをする計画ができない場合、プログラムは正気に進むことができません。
16
Mike Graham

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

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

'。'を含めないでください'plugins'の後、またはPythonは、モジュールパスであると見なします。

7
Ferry Boender

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

from __future__ import absolute_import
2
Vitz

Python imp ドキュメントは、これが回答されてから更新されました。この問題は、特に find_module() メソッド。

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

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

モジュールがパッケージの場合、fileNonepathnameはパッケージパスであり、descriptionタプルの最後の項目です。 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)
0
Mark Mikofski