2

我们有一个中央模块,在模块内加载时调用一个 init() 函数:

import x
import y
import z

def init():
    ....

init()

if __name__ == '__main__':
    ...

这会通过如下语句被拉入我们的每个应用程序模块:

if __name__ == '__main__':
    import central_module as b
    b.do_this()
    b.do_that()

init() 做了很多坏事,特别是建立与数据库的连接。因此,它会破坏任何单元测试,并且我编写的模块期望导入模块并显式调用任何初始化的通常行为。

我通过在顶部添加一个 INITIALIZE 变量实现了一种解决方法:

#INITIALIZE = True
INITIALIZE = False  # for DEV/test

if INITIALIZE:
    init()

但是需要我编辑该文件以运行我的测试或进行开发,然后在我准备好提交和推送时恢复更改。

出于政治原因,我对修复它没有任何吸引力,例如:

import central_module as b
...
    b.init()
    b.do_this()
    b.do_that()

有什么方法可以在模块加载时更透明地禁用该调用?问题是在导入模块时,它已经尝试连接到数据库(并且失败)。

现在我最好的想法是:我可以将 INITIALIZE 变量移动到以前的导入中,并在我的测试中导入它,将初始化设置为 FALSE,然后导入 central_module。

我将继续在政治方面(arg)工作,但想知道是否有更好的解决方法,我可以在不中断所有现有脚本的情况下禁用该初始化调用。

4

4 回答 4

3

这是我的想法,尽管它可能是邪恶的:

  1. 将模块作为文件打开并读入源代码。
  2. 用于ast.parse()将其解析为 AST。
  3. 遍历 AST,直到找到有问题的函数调用,然后修剪它。
  4. imp.new_module()评估修改后的 AST 并将其注入由sys.modules.
  5. 使用提交消息提交疯狂的黑客攻击,说根本没有必要,除非一些 twit 不知道正确的初始化,如果它咬他们的屁股。
于 2013-06-05T00:48:33.287 回答
3

对您的 hack 的一个简单更改是INITIALIZE让它来自环境变量。然后,您永远不必修改代码来运行这些测试,并且在您可以真正修复错误的 init 之前减少 hackage。

 INITIALIZE = os.environ.get('DO_TERRIBLE_INITIALIZE', False)
 if INITIALIZE:
     ....

并且值可以是任何东西,只要它的集合。

 export DO_TERRIBLE_INITIALIZE=ohgodwhy
于 2013-06-05T00:56:10.057 回答
1

如果您希望在测试和生产环境中具有不同的行为,则使用环境变量是标准的:

import os

if os.getenv("MYAPPENV") != "test":
    init()

那么开发时只需要设置MYAPPENV为“test”,加载时init()不会运行;如果该变量未在环境中设置,或者具有“test”以外的值,您将获得默认行为。而且您不必不断地重新编辑模块的源文件。

于 2013-06-05T00:54:42.457 回答
0

由于问题是特定于测试的,按照我的看法,应该调用 init,但是在其上所做的坏事(外部过程)被假代码取代。我认为你不应该避免调用 init。

于 2013-06-05T01:03:23.797 回答