根本问题是(通过它自己的模块)ipython
玩奇怪的把戏,因此,当通过它的内省“所谓的模块”时,它不存在——所以 doctest 不会递归到它。__main__
FakeModule
doctest
__dict__
Foo
这是一个解决方案:
class Foo():
"""
>>> 3+2
5
"""
if __name__ in ("__main__", "__console__"):
import doctest, inspect, sys
m = sys.modules['__main__']
m.__test__ = dict((n,v) for (n,v) in globals().items()
if inspect.isclass(v))
doctest.testmod(verbose=True)
这确实会根据要求产生:
$ ipython dot.py
Trying:
3+2
Expecting:
5
ok
1 items had no tests:
__main__
1 items passed all tests:
1 tests in __main__.__test__.Foo
1 tests in 2 items.
1 passed and 0 failed.
Test passed.
Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12)
[[ snip snip ]]
In [1]:
只是设置 global__test__
不起作用,再次因为将其设置为您所想的全局__main__
并实际上并没有将它放在由__dict__
恢复的实际对象中m = sys.modules['__main__']
,而后者正是doctest
内部使用的表达式(实际上它使用sys.modules.get
,但这里不需要额外的预防措施,因为我们知道它__main__
存在于sys.modules
......它只是不是你期望的对象!-)。
此外,m.__test__ = globals()
由于不同的原因,直接设置也不起作用:doctest
检查其中的值__test__
是否是字符串、函数、类或模块,并且如果没有一些选择,您不能保证globals()
会满足该条件(实际上不会) . 在这里,我只选择类,如果您还想要函数或诸如此类的东西,则可以在调用中的 genexpor
的子句中使用 an 。if
dict
python manage.py shell
但_一个类似的方法应该有帮助(无论你的 Django shell 是使用 ipython,可用时的默认值,还是纯 Python):__test__
在你获得的对象中适当地设置为sys.modules['__main__']
(或者__console__
,如果这是你传递给 doctest.testmod 的内容,我猜测)应该可以工作,因为它模仿了 doctest 将在内部执行的操作以定位您的测试字符串。
最后,对设计、建筑、简单、透明和“黑魔法”的哲学反思……:
所有这些努力基本上都是为了打败 ipython(也许是 Django,尽管它可能只是将那部分委托给 ipython)为您的“方便”而代表您所做的“黑魔法”......任何时候两个框架(或更多;-)各自独立地做着自己品牌的黑魔法,互操作性可能突然需要大量的努力并变得很方便;-)。
我并不是说在没有黑魔法、内省、假模块等的情况下(由 ipython、django 和/或 doctest 中的任何一个或多个)可以提供同样的便利;这些框架中的每一个的设计者和维护者都是出色的工程师,我希望他们已经彻底完成了他们的功课,并且只执行了最少量的黑魔法,这对于提供他们认为需要的用户便利是必不可少的。然而,即使在这种情况下,只要你想做一些超出框架作者设想的事情,“黑魔法”就会突然从方便的梦想变成调试的噩梦。
好吧,在这种情况下,也许不是一场噩梦,但我确实注意到这个问题已经开放了一段时间,即使有赏金的诱惑,它也没有得到很多答案——尽管你现在确实有两个答案可供选择来自,我使用__test__
doctest 的特殊功能,@codeape 使用 Ironpython 的特殊__IP.magic_run
功能。我更喜欢我的,因为它不依赖于任何内部或未记录的内容——它__test__
是 doctest 的一个记录特征,同时__IP
,随着这两个隐约可见的前导下划线,向我尖叫“深层内部结构,不要碰”;-)... 如果它在下一个版本中中断,我一点也不感到惊讶。尽管如此,品味问题——这个答案可以说被认为更“方便”。
但是,这正是我的观点:在放弃简单性、透明度和/或避免内部/未记录/不稳定的功能方面,便利可能会付出巨大的代价;所以,作为对我们所有人的一个教训,我们可以逃脱的最少的黑魔法和c(即使以放弃这里和那里的便利为代价),从长远来看,我们都会更快乐(并且我们会让其他需要在未来利用我们当前努力的开发人员更快乐)。