Multi-line string output in Python doctest

Viewed 2347

I have a Python3 function that returns a multi-line string. I want to test it with doctest, but can't get it to work. I've tried using the +NORMALIZE_WHITESPACE directive without success.

def dummy():
    """Dummy test function

    >>> dummy()  # doctest: +NORMALIZE_WHITESPACE
    '''Hello Mum
    Hello Dad'''
    """
    return """Hello Mum
    Hello Dad"""

if __name__ == "__main__":
    import doctest
    doctest.testmod()

The above code fails with this error:

File "c:/foo.py", line 5, in __main__.dummy
Failed example:
    dummy()  # doctest: +NORMALIZE_WHITESPACE
Expected:
    '''Hello Mum
    Hello Dad'''
Got:
    'Hello Mum\n    Hello Dad'

I have tried changing the doctest line to include a literal \n as follows:

>>> dummy()  # doctest: +NORMALIZE_WHITESPACE
'Hello Mum\n    Hello Dad'

But this fails with an almost identical error:

Failed example:
    dummy()  # doctest: +NORMALIZE_WHITESPACE
Expected:
    'Hello Mum
    Hello Dad'
Got:
    'Hello Mum\n    Hello Dad'

How can I test a multi-line string output with doctest?

2 Answers

As mentioned in my comment, a work around so you don't need \n literals in the doctest string is to print the output and then match on that, e.g.

def dummy():
    """Dummy test function

    >>> a = dummy()
    >>> print(a)
    Hello Mum
    Hello Dad

    """
    return """Hello Mum
Hello Dad"""

if __name__ == "__main__":
    import doctest
    doctest.testmod()

The problem is that the \n is being interpreted as a newline in the docstring, but doctest needs a literal backslash in there.

The doctest help says (emphasis mine):

If you continue a line via backslashing in an interactive session, or for any other reason use a backslash, you should use a raw docstring, which will preserve your backslashes exactly as you type them

So what they suggest is the following (note the r before the """):

def dummy():
    r"""Dummy test function

    >>> dummy()
    'Hello Mum\n    Hello Dad'
    """
    return """Hello Mum
    Hello Dad"""

if __name__ == "__main__":
    import doctest
    doctest.testmod()

It would also work without the leading r if you were to use a \\n instead of \n, but it's probably better to stick with the r version that's copy-pasteable from a python REPL.

Related