Python doctests are cool. Let me start with a simple example:
def foo():
"""
>>> foo()
hello world
"""
print "hello world"
Now let's assume some part is somewhat varying, e.g., because it is a time value or a random number. In general, doctests allow me to specify a wildcard saying using the +ELLIPSIS option.
This works fine when for instance "world" is a varying string:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
hello ...
"""
print "hello world"
In my case however, the variable string is at the beginning of the line:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
... world
"""
print "hello world"
which is bad, because the 3 dots in the beginning are interpreted as line continuation characters and not as ellipsis for the output. Therefore, this test fails:
Failed example:
foo() # doctest: +ELLIPSIS
world
Expected nothing
Got:
hello world
So, I could now rewrite my could to have the variable part somewhere else, but is there any way to teach doctest that the 3 dots at the beginning of a line are an ellipsis?
Here's a quick and dirty hack for you:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
[...] world
"""
print "hello world"
if __name__ == "__main__":
import doctest
OC = doctest.OutputChecker
class AEOutputChecker(OC):
def check_output(self, want, got, optionflags):
from re import sub
if optionflags & doctest.ELLIPSIS:
want = sub(r'\[\.\.\.\]', '...', want)
return OC.check_output(self, want, got, optionflags)
doctest.OutputChecker = AEOutputChecker
doctest.testmod()
This still understands the normal ( ... ) ellipsis, but it adds a new one ( [...] ) that doesn't raise the line start ambiguity.
It would be seriously hard for doctest to guess whether there is a line continuation pending or whether its a line start ellipsis - it can be done, in theory, if you subclass DocTestParser to do that work but it probably won't be fun.
In complex situations you should probably roll your own DocTestRunner that would use the new OutputChecker and use that instead of the normal testmod but this should do in simple scenarios.
You can update the ELLIPSIS_MARKER
for your test so that ...
does not get confused with the line continuation dots:
def foo():
"""
>>> import doctest
>>> doctest.ELLIPSIS_MARKER = '-ignore-'
>>> foo()
hello world
>>> foo() # doctest: +ELLIPSIS
-ignore- world
"""
print "hello world"
if __name__ == "__main__":
import doctest
doctest.testmod()
Disclaimer: the example above works when doctests are run as
$ py.test --doctest-module foo.py
or
$ python foo.py
However, for reasons I don't understand it does not work when running doctests via
$ python -m doctest foo.py
Here is a somewhat simpler way to do this:
Just print a dummy string before the line that begins with the unknown output.
Like this:
def foo():
"""
>>> print 'ignore'; foo() # doctest: +ELLIPSIS
ignore... world
"""
print "hello world"