Интересный пример использования сегодня: мне нужно перенести модуль в нашу кодовую базу после изменений кода.Старый mynamespace.Document
исчезнет, и я хочу обеспечить плавную миграцию, заменив этот пакет на объект кода, который будет динамически импортировать правильный путь и мигрировать соответствующие объекты.
Короче:
# instanciate a dynamic package, but do not load
# statically submodules
mynamespace.Document = SomeObject()
assert 'submodule' not in mynamespace.Document.__dict__
# and later on, when importing it, the submodule
# is built if not already available in __dict__
from namespace.Document.submodule import klass
c = klass()
Несколько замечаний:
- Я говорю не только о переносе кода .Простого огромного
sed
в некотором смысле было бы достаточно, чтобы изменить код, чтобы перенести некоторые операции импорта, и мне не понадобился бы динамический модуль.Я говорю об объектах.Веб-сайт, содержащий некоторые живые / хранимые объекты, нуждается в миграции.Эти объекты будут загружены при условии, что mynamespace.Document.submodule.klass
существует, и это является причиной динамического модуля.Мне нужно предоставить сайту что-то для загрузки. - Мы не можем или не хотим изменять способ, которым объекты не выбираются / загружаются.Для простоты, давайте просто скажем, что мы хотим убедиться, что идиома
from mynamespace.Document.submodule import klass
должна работать.Я не могу использовать вместо этого from mynamespace import Document as container; klass = getattr(getattr(container, 'submodule'), 'klass')
То, что я пробовал:
import sys
from types import ModuleType
class VerboseModule(ModuleType):
def __init__(self, name, doc=None):
super(VerboseModule, self).__init__(name, doc)
sys.modules[name] = self
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.__name__)
def __getattribute__(self, name):
if name not in ('__name__', '__repr__', '__class__'):
print "fetching attribute %s for %s" % (name, self)
return super(VerboseModule, self).__getattribute__(name)
class DynamicModule(VerboseModule):
"""
This module generates a dummy class when asked for a component
"""
def __getattr__(self, name):
class Dummy(object):
pass
Dummy.__name__ = name
Dummy.__module__ = self
setattr(self, name, Dummy)
return Dummy
class DynamicPackage(VerboseModule):
"""
This package should generate dummy modules
"""
def __getattr__(self, name):
mod = DynamicModule("%s.%s" % (self.__name__, name))
setattr(self, name, mod)
return mod
DynamicModule("foobar")
# (the import prints:)
# fetching attribute __path__ for <DynamicModule foobar>
# fetching attribute DynamicModuleWorks for <DynamicModule foobar>
# fetching attribute DynamicModuleWorks for <DynamicModule foobar>
from foobar import DynamicModuleWorks
print DynamicModuleWorks
DynamicPackage('document')
# fetching attribute __path__ for <DynamicPackage document>
from document.submodule import ButDynamicPackageDoesNotWork
# Traceback (most recent call last):
# File "dynamicmodule.py", line 40, in <module>
# from document.submodule import ButDynamicPackageDoesNotWork
#ImportError: No module named submodule
Как видите, динамический пакет не работает.Я не понимаю, что происходит, потому что document
даже не запрашивают атрибут ButDynamicPackageDoesNotWork
.
Может кто-нибудь уточнить, что происходит;и если / как я могу это исправить?