Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python doctest for shell scripts that test argument parsing without polluting docstring with os.popen()

Is there a way to write a python doctest string to test a script intended to be launched from the command line (terminal) that doesn't pollute the documentation examples with os.popen calls?

#!/usr/bin/env python
# filename: add
"""
Example:
>>> import os
>>> os.popen('add -n 1 2').read().strip()
'3'
"""

if __name__ == '__main__':
    from argparse import ArgumentParser
    p = ArgumentParser(description=__doc__.strip())
    p.add_argument('-n',type = int, nargs   = 2, default = 0,help  = 'Numbers to add.')
    p.add_argument('--test',action = 'store_true',help  = 'Test script.')
    a = p.parse_args()
    if a.test:
        import doctest
        doctest.testmod()
    if a.n and len(a.n)==2:
        print a.n[0]+a.n[1]

Running doctest.testmod() without using popen just causes a test failure because the script is run within a python shell instead of a bash (or DOS) shell.

The advanced python course at LLNL suggests putting scripts in files that are separate from .py modules. But then the doctest strings only test the module, without the arg parsing. And my os.popen() approach pollutes the Examples documentation. Is there a better way?

like image 677
hobs Avatar asked Apr 02 '12 09:04

hobs


People also ask

Can doctest be used to test Docstring in Python?

There are several common ways to use doctest: To check that a module's docstrings are up-to-date by verifying that all interactive examples still work as documented. To perform regression testing by verifying that interactive examples from a test file or a test object work as expected.

What is the correct way to run doctest in Python?

In a program, we can import and call the doctest module in our if __name__ == "__main__": clause at the bottom of our programming file.

What is the correct way to run all the doctest in a given file from the command line?

To run the tests, use doctest as the main program via the -m option to the interpreter. Usually no output is produced while the tests are running, so the example below includes the -v option to make the output more verbose.

Is doctest Python testing framework?

Doctest is an inbuilt test framework that comes bundled with Python by default. The doctest module searches for code fragments that resemble interactive Python sessions and runs those sessions to confirm they operate as shown. Developers commonly use doctest to test documentation.


2 Answers

Just found something looking like the answer you want: shell-doctest.

like image 108
dmitry_romanov Avatar answered Sep 25 '22 01:09

dmitry_romanov


doctest is meant to run python code, so you have to do a conversion somewhere. If you are determined to test the commandline interface directly via doctest, one possibility is to do a regexp substitution to __doc__ before you pass it to argparse, to take out the os.popen wrapper:

clean = re.sub(r"^>>> os\.popen\('(.*)'\).*", r"% \1", __doc__)
p = ArgumentParser(description=clean, ...)

(Of course there are all sorts of nicer ways to do that, depending on what you consider "nice").

That'll clean it up for the end user. If you also want it to look cleaner in the source, you can go the other way: Put commandline examples in the docstring and don't use doctest.testmodule(). Run your docstring through doctest.script_from_examples and post-process it to insert the os calls. (Then you'll have to embed it into something so you can test it with run_docstring_examples.) doctest doesn't care if the input is valid python, so you can do the following:

>>> print doctest.script_from_examples("""
Here is a commandline example I want converted:
>>> add -n 3 4
7
""")
# Here is a commandline example I want converted:
add -n 3 4
# Expected:
## 7

This will still expose the python prompt >>> in the help. If this bothers you, you may just have to process the string in both directions.

like image 27
alexis Avatar answered Sep 26 '22 01:09

alexis