8

I have the following doctest written x.doctest:

This is something:

    >>> x = 3 + 4

foo bar something else:

    >>> from __future__ import division
    >>> y = 15
    >>> z = int('24')
    >>> m = z / y
    >>> print (m)
    1.6

But when I ran python -m doctest x.doctest on python 2.7.11, the doctest didn't recognize from __future__ import division:

**********************************************************************
File "x.doctest", line 11, in x.doctest
Failed example:
    print (m)
Expected:
    1.6
Got:
    1
**********************************************************************
1 items had failures:
   1 of   6 in x.doctest
***Test Failed*** 1 failures.

Even when I shifted the future import statement to the first line:

This is something:

    >>> from __future__ import division
    >>> x = 3 + 4

foo bar something else:

    >>> y = 15
    >>> z = int('24')
    >>> m = z / y
    >>> print (m)
    1.6

The doctest still fails:

**********************************************************************
File "x.doctest", line 11, in x.doctest
Failed example:
    print (m)
Expected:
    1.6
Got:
    1
**********************************************************************
1 items had failures:
   1 of   6 in x.doctest
***Test Failed*** 1 failures.

Why is that so and how can I resolve this?

Is there a flag / option for doctest that asks ensures that from __future__ import division is recognized?

Note: I could just force the check on print (int(m)) or y = 15. and the doctest will pass but that is not that desirable.

alvas
  • 115,346
  • 109
  • 446
  • 738

2 Answers2

4

Doctests run each line in isolation through the Python compiler. This means that any compiler flags specified with a from __future__ import .. statement in the doctest itself is useless in a doctest.

However, you can add names from the real __future__ module to your doctest globals. If you don't use the from __future__ import <name> format but use import __future__ instead, you import that actual module, and can add references to the objects it defines to the doctest globs or extraglobs dictionaries:

 if __name__ == "__main__":
     import doctest
     import __future__
     doctest.testmod(extraglobs={'division': __future__.division})

The DocTestRunner will then set the right compiler flags for you when compiling individual lines from these.

Demo:

>>> import doctest
>>> import __future__
>>> import sys
>>> def foo():
...     """
...     >>> 1 / 2
...     0.5
...     """
...
>>> doctest.testmod(sys.modules['__main__'])
**********************************************************************
File "__main__", line 3, in __main__.foo
Failed example:
    1 / 2
Expected:
    0.5
Got:
    0
**********************************************************************
1 items had failures:
   1 of   1 in __main__.foo
***Test Failed*** 1 failures.
TestResults(failed=1, attempted=1)
>>> doctest.testmod(sys.modules['__main__'], extraglobs={'division': __future__.division})
TestResults(failed=0, attempted=1)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Just to confirm some facts, the `if __name__ == 'main':` trick could only work in a `x.py` file and not a `x.doctest`, is that right? – alvas Apr 05 '16 at 07:56
  • 1
    @alvas: I'm not familiar with `.doctest` files. I suspect your project loads those explicitly somewhere with a `DocFileSuite()` instance; set the globals on *that*. – Martijn Pieters Apr 05 '16 at 08:06
  • @alvas: the code that loads those files could itself do some parsing logic to add compile flags to the globals based on file contents, of course. – Martijn Pieters Apr 05 '16 at 08:06
  • Thanks Martijn for the explanation!! – alvas Apr 05 '16 at 08:07
1

You can use the option -Q for the Python interpreter. Set it to new:

python -Qnew -m doctest x.doctest

Get help on Python commandline options with:

python -h

Selected output:

-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew

More help details here.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • Thanks, do you have a link to the `-Q` documentation? Is there a way to do it with a `#doctest: ` comment within the `x.doctest` file? – alvas Feb 28 '16 at 10:22
  • 1
    Added a help link. I am not aware any `#doctest:` directives for this. On Unix.based systems, you could add a shebang to your file: `#!/usr/bin/env python -Qnew -m doctest` and execute with `./x.doctest`. – Mike Müller Feb 28 '16 at 10:38
  • `-Qnew` is a global change, though, affecting even code that wasn't supposed to be using true division. The [PEP](https://www.python.org/dev/peps/pep-0238/) that introduced true divison says `-Qnew` is only intended for educational contexts where the instructors want true division but don't want the students to have to include `from __future__ import division` in all their code. – user2357112 Apr 05 '16 at 08:08