Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have an ellipsis at the beginning of the line in a Python doctest?

Tags:

python

doctest

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?

like image 472
BjoernD Avatar asked Apr 28 '11 02:04

BjoernD


Video Answer


2 Answers

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.

like image 95
t.dubrownik Avatar answered Sep 19 '22 09:09

t.dubrownik


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
like image 33
Pedro M Duarte Avatar answered Sep 18 '22 09:09

Pedro M Duarte