تحميل الفئة الديناميكية في Python 2.6: RunTimewarning: لم يتم العثور على الوحدة النمطية للوحدة الأم أثناء التعامل مع الاستيراد المطلق

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

سؤال

أنا أعمل على نظام إضافي حيث يتم تحميل وحدات البرنامج المساعد مثل هذا:

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 سعيدًا؟

هل كانت مفيدة؟

المحلول

إذا كان الدليل 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

لكن هذا الاختراق الذي كان في الغالب للمتعة!

نصائح أخرى

إذا كان دليل الإضافات لا يحتوي على __init__.py, ، إنها ليست حزمة ، لذلك عند إنشاء plugins.whatever, ، يحذرك بيثون من أن مثل هذا الشيء لا ينبغي أن يكون موجودًا حقًا. (لا يمكن إنشاؤه بواسطة "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. إذا لم تتمكن من التخطيط للقيام بشيء عاقل استجابةً لاستثناء ، فلا يمكن للبرنامج أن يستمر بصحبة.

المشكلة هنا هي مع النقطة ('.') في اسم الوحدة النمطية:

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

لا تشمل ". بعد "الإضافات" ، أو بيثون سيعتقد أنه مسار الوحدة النمطية.

يمكنك محاولة إضافة البيان أدناه في بداية عبارات الاستيراد.

from __future__ import absolute_import

بيثون imp تم تحديث الوثائق منذ الإجابة عليها. يعالج الآن هذه المشكلة على وجه التحديد في find_module() طريقة.

هذه الوظيفة لا تتعامل مع أسماء الوحدات النمطية الهرمية (الأسماء التي تحتوي على نقاط). من أجل العثور على مساءً, هذا هو ، الجهاز الفرعي م من الحزمة ص, ، استعمال find_module() و load_module() للعثور على الحزمة وتحميلها ص, ثم استخدم find_module() مع ال طريق تم تعيين الحجة إلى P.__path__. متى ص نفسها لها اسم منقط ، ضع هذه الوصفة بشكل متكرر.

لاحظ أن P.__path__ هي بالفعل قائمة عند تزويدها find_module(). لاحظ أيضًا ما find_module() يقول الوثائق حول العثور على الحزم.

إذا كانت الوحدة عبارة عن حزمة ، ملف هو None, اسم المسار هو مسار الحزمة والبند الأخير في وصف Tuple هو PKG_DIRECTORY.

لذلك من سؤال البروتوكول الاختياري ، لاستيراد البرنامج المساعد بدون RuntimeError تحذيرات ، اتبع الإرشادات الواردة في وثائق بيثون المحدثة:

# 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)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top