Question

I'd like to write a doctest like this:

"""
>>> print a.string()
          foo : a
          bar : b
         date : <I don't care about the date output>
          baz : c
"""

Is there any way to do this? I think it would make more sense to switch to unittest, but I'm curious whether it's possible to specify a range of output that shouldn't be matched for the test in doctest.

Thanks!

Was it helpful?

Solution

With doctest.ELLIPSIS, you can use ... to mean "match any string here". You can set doctest options with a doctest directive, to make it active for just one test case: one example in the online docs is:

>>> print range(20) # doctest:+ELLIPSIS
[0, 1, ..., 18, 19]

If you want a doctest option to be active throughout, you can pass it as the optionflags= argument to whatever doctest functions you use, e.g. doctest.testfile. (You can pass multiple option flags there by using the | operator to bit-or them).

OTHER TIPS

Responding to questions about "how can we ignore the whole line": yes, the fact that "..." also looks like a continuation like makes it hard to ignore the entire output. You can use "#doctest: +SKIP" if you just want to skip the example entirely, but that won't work if you are relying on its side-effects. If you really need to do this, I suppose you could monkey-patch the doctest module itself, though I wouldn't particularly recommend it:

>>> import doctest
>>> doctest.ELLIPSIS_MARKER = '-etc-'
>>> print 12 # doctest: +ELLIPSIS
-etc-

(this test passes.)

Or you could temporarily suppress stdout and/or stderr:

>>> # Suppress stdout
>>> import sys
>>> class DevNull:
...     def noop(*args, **kwargs): pass
...     close = write = flush = writelines = noop
>>> sys.stdout = DevNull()
>>> # Run a test and ignore output (but we need its side effects)
>>> print 12 # NOTE: stdout is suppressed!
>>> # Restore stdout
>>> sys.stdout = sys.__stdout__

(this test also passes.)

Ignoring the whole line is bit tricky though. Here:

"""
>>> do_your_thing() #doctest:+ELLIPSIS
...
"""

The triple dot will be interpreted as line continuation, and cause a syntax error.

If you want to ignore the whole line, you'll need something like:

"""
>>> sys.stdout.write('skip from here '); do_your_thing() #doctest:+ELLIPSIS
skip from here ...
"""

I found it easier to simply assign the unneeded return values to a variable:

>>> _ = do_something()
>>> check_something()
True

You can write tuples before and after your function (hack inspired by answer of Mark Horvath):

def foo():
    """
    >>> ();foo();() # doctest: +ELLIPSIS
    (...)
    """
    print "Hello world"
    return "Hello world"

Can I have an ellipsis at the beginning of the line in a Python doctest? explains how to create a custom output checker that uses an additional string as an ellipsis. This would let you write the following, while still used '...' elsewhere.

def foo():
  """
  >>> foo() # doctest: +ELLIPSIS
  [...] world
  """
  print "hello world"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top