我有一个很基本的doctestable文件:
class Foo():
"""
>>> 3+2
5
"""
if __name__ in ("__main__", "__console__"):
import doctest
doctest.testmod(verbose=True)
其中预期时通过蟒蛇直接运行工作。
然而,在IPython中,我得到
1 items had no tests:
__main__
0 tests in 1 items.
0 passed and 0 failed.
Test passed.
由于这是一个Django项目的一部分,将需要通过修改后的命令,它使用code.InteractiveConsole访问所有适当的变量,并且使得manage.py设置,我也可以运行它,其结果之一是__name__
得到设置为“ __console__
”。
通过上面的代码中,我得到了相同的结果与IPython中。 我试图改变最后一行是:
this = __import__(__name__)
doctest.testmod(this, verbose=True)
我得到一个ImportError __console__
,这是有道理的,我想。 这对Python或IPython都没有影响。
所以,我希望能够通过所有这三种方法,尤其是InteractiveConsole一个成功运行文档测试,因为我期望需要Django的小马魔术很快就会。
只是为了澄清,这是我期待:
Trying:
3+2
Expecting:
5
ok
1 items had no tests:
__main__
1 items passed all tests:
1 tests in __main__.Foo
1 tests in 2 items.
1 passed and 0 failed.
Test passed.
以下工作:
$ ipython
...
In [1]: %run file.py
Trying:
3+2
Expecting:
5
ok
1 items had no tests:
__main__
1 items passed all tests:
1 tests in __main__.Foo
1 tests in 2 items.
1 passed and 0 failed.
Test passed.
In [2]:
我不知道为什么ipython file.py
不起作用。 但上面的至少一种变通方法。
编辑:
我发现,为什么它不工作的原因。 这是很简单的:
- 如果没有指定模块测试
doctest.testmod()
它假设你要测试的__main__
模块。 - 当IPython的执行传递给它的命令行上的文件时,
__main__
模块的IPython的__main__
,不是你的模块。 因此,文档测试试图在IPython中的条目脚本来执行文档测试。
下面的作品,但感觉有点不可思议:
if __name__ == '__main__':
import doctest
import the_current_module
doctest.testmod(the_current_module)
所以基本上模块导入本身(这是“感觉有点怪”的一部分)。 但是,它的工作原理。 东西我不喜欢生根粉。 这种方法是每一个模块需要包括源自己的名字。
编辑2:
下面的脚本, ipython_doctest
,使得IPython的表现你想要的方式:
#! /usr/bin/env bash
echo "__IP.magic_run(\"$1\")" > __ipython_run.py
ipython __ipython_run.py
该脚本创建一个python脚本将执行%run argname
在IPython中。
例:
$ ./ipython_doctest file.py
Trying:
3+2
Expecting:
5
ok
1 items had no tests:
__main__
1 items passed all tests:
1 tests in __main__.Foo
1 tests in 2 items.
1 passed and 0 failed.
Test passed.
Python 2.5 (r25:51908, Mar 7 2008, 03:27:42)
Type "copyright", "credits" or "license" for more information.
IPython 0.9.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.
In [1]:
问题的根源是, ipython
扮演着怪异的招数与__main__
(通过自身FakeModule
模块),这样,通过时间doctest
是反思的是“涉嫌模块”通过其__dict__
, Foo
不存在-这样的doctest不会递归到它。
这里有一个解决方案:
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]:
只要设置全局__test__
不起作用,因为再设置它作为一个全球性的你在想什么作为__main__
实际上并没有将它放在__dict__
是得到由回收的实际对象的m = sys.modules['__main__']
,而后者恰好是表达doctest
是内部使用(实际上它使用sys.modules.get
,但因为我们知道,额外的预防措施是没有必要在这里__main__
中存在sys.modules
......它只是不是对象你希望它是 - !)。
此外,只设置m.__test__ = globals()
直接不起作用或者,出于不同的原因: doctest
检查在值__test__
是字符串,函数,类,或模块,并且在没有一些选择你不能保证globals()
将满足该条件(其实也不会)。 在这里我只选择课程,如果你也想的功能或诸如此类的东西,你可以使用一个or
中if
在内的genexp条款dict
电话。
我不知道你究竟是如何运行的Django的外壳,是能够执行脚本(我相信python manage.py shell
不接受参数,你必须做别的东西,我无法猜测到底是什么! - ),但类似的方法应该帮助(不管是你的Django外壳使用IPython中,如果可用默认,或普通的Python):适当设置__test__
的对象,你获得的sys.modules['__main__']
(或__console__
,如果这就是你,然后传递到doctest.testmod,我猜)应该工作,因为它模仿什么文档测试将被内部做找到测试字符串。
而且,为了得出结论,设计,建筑,简单,透明,以及“黑魔法”的哲学反思...:
所有这些努力基本上是打败了“黑魔法”是IPython的(也许Django的,虽然它可以简单地委托该部分IPython的)所需的内容代表您正在为您的“方便” ......任何时间,在这两个框架(或更多;-)独立做每一个自有品牌的黑魔法,互操作性可能会突然需要大量的努力和成为什么,但方便;-)。
我不是说,同样的便利可能已经提供(通过任何一种或多种IPython中,Django和/或文档测试的),而黑魔法,自省,假模块等; 设计师和每一个这些框架的维护是一流的工程师,我希望他们已经彻底做好功课,只有执行的是不可或缺的,提供用户便利性,他们决定量,他们需要的黑魔法的最小量。 然而,即使在这种情况下,“黑魔法”突然从方便到调试的噩梦梦想,只要你想要做的事,甚至轻微外什么框架的作者曾设想变成。
好吧,也许在这种情况下,并不完全是噩梦,但我确实注意到这个问题,已经开了一段时间,甚至与赏金它并没有得到很多答案的诱惑还没有 - 虽然你现在要做的有两个答案来接从矿山使用__test__
文档测试的特点,@ codeape的使用特有的__IP.magic_run
IronPython的特征。 我喜欢我的,因为它不依赖于任何内部或无证- __test__
IS文档测试的记录功能,同时__IP
,与这两个若隐若现的前导下划线,尖叫“深内部,请勿触摸”我;-) ..如果它打破下一个点释放,我也不会感到惊讶。 尽管如此,物质的味道 - 这答案可能无疑被认为是更“方便”。
不过,这正是我的观点:方便可能会在一个巨大的价格放弃简单性,透明性,和/或内部/无证/不稳定的特点回避; 因此,对于我们所有的课,至少魔法&C,我们可以逃脱(即使在这里放弃便利的埃普西隆价格和那里),更快乐我们都会从长远来看,(和越幸福,我们会让那些需要利用我们的未来目前的努力)其他开发商。