从GAE Datastore导入python module的可行方案
November 16th, 2010
Micolog支持插件机制已经有一段时间了,但是,每次添加删除插件都需要在客户端使用Google Launcher重新上传整个micolog,感觉不是很方便。为了解决这个问题,准备在下一个版本中实现插件的动态加载,更新和删除。
当前,可能的方案之一,就是将插件实现的代码(py文件)和资源(Html,图片等)都使用GAE Datastore来存储。
于是,今天试验了一下,初步验证了,该方案的可行性。
这个方案的关键点在于python module的动态加载。
查阅了一下资料,根据官方文档显示,我们可以自定义模块导入的方法,其中使用的技术叫做 Import Hooks (http://www.python.org/dev/peps/pep-0302/).
为此我们必须创建一个类,实现 find_module 和 load_module方法,然后将这个类加入到sys.path_hooks
以下是实现代码(实现了将文本导入为模块的功能)
#------------------------------------------------------------------------------- # Name: gaedbimporter # Purpose: # # Author: Xuming # # Created: 16-11-2010 #------------------------------------------------------------------------------- #!/usr/bin/env python import sys, marshal, imp, new class gaedbimporter(object): def __init__(self, item, *args, **kw): if item != "gaedb": raise ImportError def is_package(self,fullname): return True def get_code(self,fullname): return compile(self.get_source(fullname), "db:%s" % fullname, "exec") def get_source(self,fullname): return '''def test(): print 'test' ''' def find_module(self, fullname, path=None): if fullname=='dbtest': return self else: return None def load_module(self, fullname): print "load_module:", fullname ispkg=True code=self.get_code(fullname) #ispkg, code = self._get_code(fullname) mod = sys.modules.setdefault(fullname, imp.new_module(fullname)) mod.__file__ = "<%s>" % self.__class__.__name__ mod.__loader__ = self if ispkg: mod.__path__ = [] #print mod.__dict__ exec code in mod.__dict__ return mod @classmethod def install(cls): sys.path_hooks.append(gaedbimporter) sys.path_importer_cache.clear() # probably not necessary sys.path.insert(0, "gaedb") if __name__ == "__main__": gaedbimporter.install() from dbtest import * test()
更进一步,我们可以将模块编译后存储在GAE DataStore中,来提高加载的速度。以上只是验证代码,但通过一些附加的代码,相信很容易就可以实现Python Module的动态加载功能了。