强制 python 解释器重新加载代码模块

Posted

技术标签:

【中文标题】强制 python 解释器重新加载代码模块【英文标题】:Force python interpreter to reload a code module 【发布时间】:2012-09-17 19:25:44 【问题描述】:

OpenERP python 代码开发周期是编辑你的代码,重启服务器并测试它。 重新启动服务器是必要的,因为它会使您的源代码重新加载到内存中,但它会增加您工作节奏的烦人延迟。

既然python是一种动态语言,我想知道是否有办法强制正在运行的python解释器(应用服务器)动态重新加载代码模块,这样就可以在不重新启动应用服务器的情况下对其进行测试?

更新: 按照@ecatmur 建议的reload 路径,我得到了下面的代码,但它仍然不起作用:

class module(osv.osv):
    _inherit = "ir.module.module"

    def action_reload(self, cr, uid, ids, context=None):
        for obj in self.browse(cr, uid, ids, context=context):
            modulename = 'openerp.addons.' + obj.name
            tmp = __import__(modulename)
            pycfile = tmp.__file__
            modulepath = string.replace(pycfile, ".pyc", ".py")
            code=open(modulepath, 'rU').read()
            compile(code, modulename, "exec")
            execfile(modulepath)
            reload( sys.modules[modulename] )
        openerp.modules.registry.RegistryManager.delete(cr.dbname)
        openerp.modules.registry.RegistryManager.new(cr.dbname)

【问题讨论】:

【参考方案1】:

更新:从 v8 开始,Odoo 服务器提供了一个 --auto-reload 选项来执行此操作。

很好的问题,我经常想知道同样的问题。我认为您发布的代码的主要问题是它只重新加载 OpenERP 模块的 __init__.py 文件,而不是所有单个文件。 ecatmur 推荐的 reimport 模块可以解决这个问题,我还必须在重新加载所有内容之前取消注册模块的报告解析器和模型类。

我已经在Launchpad 上发布了我的module_reload 模块。它似乎适用于模型类、osv_memory 向导和报告解析器的更改。它不适用于旧式向导,可能还有其他场景不起作用。

这是重新加载模块的方法。

def button_reload(self, cr, uid, ids, context=None):
    for module_record in self.browse(cr, uid, ids, context=context):
        #Remove any report parsers registered for this module.
        module_path = 'addons/' + module_record.name
        for service_name, service in Service._services.items():
            template = getattr(service, 'tmpl', '')
            if template.startswith(module_path):
                Service.remove(service_name)

        #Remove any model classes registered for this module
        MetaModel.module_to_models[module_record.name] = []                    

        #Reload all Python modules from the OpenERP module's directory.
        modulename = 'openerp.addons.' + module_record.name
        root = __import__(modulename)
        module = getattr(root.addons, module_record.name)

        reimport(module)
    RegistryManager.delete(cr.dbname)
    RegistryManager.new(cr.dbname)
    return 

【讨论】:

赏金截止日期快到了,所以我迫不及待地等待最终的答案。我认为这是在正确的轨道上,所以我接受这个答案。 谢谢@DReispt,我会在完成代码后发布更新。 看来它正在工作,@DReispt。试试看,如果你打破它,请告诉我。我敢肯定会有问题,但如果它大部分时间都有效,它会很有用。 终于在 openerp v8 中实现了【参考方案2】:

如果你只是在做开发,那么重新加载是可以的,但如果你是在部署中,你应该避免这样的技巧,因为它们永远不会 100% 工作。总会有一些微妙之处,这些变化不会传播。例如,如果某些代码复制一个对象而不是仅使用对它的引用,那么在重新加载后它将保持不变。相反,如果引用未正确向前传播,则is 比较将在预期工作时失败,因为其中一个对象将来自“旧”未发布模块。唯一 100% 确定的触发方法是重新加载所有内容,这本质上就是服务器重启。

即使您只是在进行开发,您也偶尔会遇到错误的错误,这些错误只是不完全重新加载的副作用。如果您没有想到尝试干净重启,您可以花 长时间 时间尝试追踪幻影错误。因此,如果您最终这样做,请记住这一点。

【讨论】:

目标是加快开发周期。我想我得到的结论是我对 Python 的期望太高了,这个reload 功能不值得麻烦...... 如果有的话,使用已经过良好测试的东西,比如 ipython 的 deepreload 魔法。【参考方案3】:

ipython 有一个 deepreload 模块,文档在这里:http://ipython.org/ipython-doc/stable/api/generated/IPython.lib.deepreload.html#module-IPython.lib.deepreload

我认为它可以在 ipython REPL 之外使用。

【讨论】:

【参考方案4】:

reload 内置函数重新加载模块或包。但是在 OpenERP 的上下文中,您需要更多,因为重新加载 OpenERP 插件需要处理 XML 文件等。但我同意在 OpenERP 中使用它会很好。

【讨论】:

我的问题特别是对 python 代码的更改。对于 XML 中的更改,“模块升级”通常足够快,并且可以使更改立即可用,而无需重新启动服务器。 除此之外,除非我弄错了“模块升级”不会重新加载 Python 代码。 它没有,但我希望它会。因此我的问题。【参考方案5】:

reload 内置函数将重新加载单个模块。有多种解决方案可以递归地重新加载更新的包;见How to re import an updated package while in Python Interpreter?

部分问题是需要调整现有对象以从重新加载的模块中引用新类等; reimport 做得相当好。在 IPython 交互式控制台中,我使用了 autoreload 扩展,尽管它不是为在 IPython 之外使用而设计的。

【讨论】:

好的python指针。我还在这里找到了有趣的代码:elifulkerson.com/projects/python-dynamically-reload-module.php。它尝试过这种方式,但不幸的是它不起作用,因为 OpenERP 保留了模块的内部“注册表”。

以上是关于强制 python 解释器重新加载代码模块的主要内容,如果未能解决你的问题,请参考以下文章

重新加载已导入另一个模块的模块

Node.js:如何重新加载模块

何为模块?

内置模块

Python之reload函数

模块的导入