贯穿IPython的文档测试和伪游戏机(Running doctests through iPyth

2019-08-02 16:55发布

我有一个很基本的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.

Answer 1:

以下工作:

$ 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]:


Answer 2:

问题的根源是, 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()将满足该条件(其实也不会)。 在这里我只选择课程,如果你也想的功能或诸如此类的东西,你可以使用一个orif在内的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,我们可以逃脱(即使在这里放弃便利的埃普西隆价格和那里),更快乐我们都会从长远来看,(和越幸福,我们会让那些需要利用我们的未来目前的努力)其他开发商。



文章来源: Running doctests through iPython and pseudo-consoles