Найти - Пользователи
Полная версия: Разное имя класса при импорте из модулей
Начало » Python для новичков » Разное имя класса при импорте из модулей
1
VaMpir
Доброго времени суток всем
Не знаю, в эту ветку или лучше в django, но все же:
Есть проект на джанго, в котором делаю автозагрузку плагинов из каталога. Структура каталогов такая:
mycms/
—- __init__.py
—- plugins
——– __init__.py
——– test.py
——– base.py
—- plugin_manager.py

в plugin_manager.py есть класс PluginManager, в __init__() которого я перебираю файлы из каталога plugins, пропуская __init__.py и base.py (в нем находится базовый класс для плагинов - baseplugin), после чего импортирую модули при помощи __import__()

После загрузки всех модулей, перебираю классы в каждом модуле и, если класс имеет базовым baseplugin, то добавляю его в список. Проблема в том, что проверка базового класса через issubclass(obj, plugins.base.baseplugin) не выполняется, т.к. baseplugin имеет полный путь <class ‘mycms.plugins.base.baseplugin’>, а базовый класс класса obj (проверяемого) - <class ‘plugins.base.baseplugin’>

Сам plugin_manager импортируется из urls.py в корне.

Можно ли как-то изменить импорт import plugins.base в plugin_manager, чтобы имя базового класса было не mycms.plugins.base.baseplugin, а plugins.base.baseplugin ?

plugin_manager.py
#-*- coding: utf-8 -*-
import os
import inspect
import sys
import plugins.base

plugin_dir = "plugins"

class PluginManager(object):
__plugins__ = []

def __init__(self):
modules = []
print "Load plugins..."

#загрузка модулей
for fname in os.listdir(plugin_dir):
if fname.endswith('.py'):
module_name = fname[:-3]
if module_name != "base" and module_name != "__init__" :
package_obj = __import__(plugin_dir+'.'+module_name)
modules.append(module_name)

#перебор классов модуля
for modulename in modules:
module_obj = getattr(package_obj, modulename)

for elem in dir(module_obj):
if elem == "baseplugin":
continue
if elem.startswith("__"):
continue

obj = getattr(module_obj, elem)
print plugins.base.baseplugin
if inspect.isclass(obj):
print obj
if issubclass(obj, plugins.base.baseplugin): # <------- здесь не проходит проверка
a = obj()
else:
print "--- Skipping ", elem, "class, not a plugin"

plug_man = PluginManager()
base.py
#-*- coding: utf-8 -*-
class baseplugin(object):
def __init__(self):
self.__name__ = __name__
pass

def load(self):
print ' -', self.__class__.__name__, 'loaded'
pass

def unload(self):
print ' -', self.__class__.__name__, 'unloaded'
pass
test.py
#-*- coding: utf-8 -*-
from base import baseplugin
class TestClass(baseplugin):
def load(self):
super(self.__class__, self).load()
pass
def unload(self):
super(self.__class__, self).unload()
pass
Андрей Светлов
Полагаю, вам потребовалось подкрутить еще и sys.path. Вас это не насторожило?

Не сочтите за рекламу: http://asvetlov.blogspot.com/2010/05/blog-post.html и последующие части — описание того, как работает импорт
VaMpir
Андрей Светлов
Статью прочитал, но все равно не могу исправить код нормально. Вся проблема в том, что есть plugin_manager.py запустить из консоли, то все работает нормально, т.е полное имя класса из base.py совпадает внутри plugin_manager.py и test.py, т.е. после

import plugins.base
print plugins.base

Результат: <class ‘plugins.base.baseplugin’>.

Если же запускается из django, точнее, импортируется в urls.py корня проекта (from plugin_manager import PluginManager), то полное имя класса в plugin_manager.py становится mycms.plugins.base.baseplugin. Подозреваю, что он импортирует base.py по цепочке от корня, т.е. /mycms/. Как можно заставить импортировать в первую очередь непосредственно из plugins, игнорируя корень?

Пробовал менять sys.path, но результата не получал:
sys.path.insert(0, ‘.’)
sys.path.insert(0, ‘/home/username/src/mycms’)
sys.path.insert(0, ‘/home/username/src/mycms/plugins’),
в любом случае результат неизменен.
Андрей Светлов
Наоборот. Если используете для работы с плагинами __import__ — пишите путь от корня проекта. Т.е. чтобы было __import__('mycms.plugins.' + module_name)
VaMpir
Андрей Светлов
Не получается. Если пишу путь от корня, то не импортирует:

package_obj = __import__('mycms.'+plugin_dir+'.'+module_name)
print package_obj

Результат:
<module ‘maxcms’ from ‘/home/username/src/mycms/__init__.pyc’>
VaMpir
Все, смог решить задачу. Сначала импортирую как:
package_obj = __import__('mycms.'+plugin_dir+'.'+module_name)
modules.append(module_name)

потом перебираю плагины:
for modulename in modules:
module_obj = getattr(package_obj.plugins, modulename)
Андрей Светлов
package_obj — это пакет верхнего уровня. Т.е. mycms в вашем случае.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB