Jan Weidner
Jan Weidner

Reputation: 589

Doctest of verbose function

I sometimes run into the following problem. I have a function, which returns something I am interested in and prints something I do not care about. E.g.

def f(x):
  print('Some complicated printing stuff')
  important_result = 42
  return important_result

I want to write a doctest, which checks, that it indeed returns the correct result. But whose code is not obfuscated by the complicated printing stuff. Something along the following lines would be cool:

def f(x): 
    """
    >>> f(0)
    ...
    42
    """
    print('Some complicated printing stuff')
    important_result = 42
    return important_result

Is there an elegant way to acomplish this?

Upvotes: 1

Views: 1557

Answers (3)

brewmanz
brewmanz

Reputation: 1221

One option is to print to stderr instead of to stdout e.g.

print('Some complicated printing stuff', file=sys.stderr)

Printing to stderr will not be checked by doctest

Upvotes: 0

joe_maya
joe_maya

Reputation: 195

To get some feedback, I ended up printing the result of doctest.testmod()

Upvotes: 0

Nabeel Ahmed
Nabeel Ahmed

Reputation: 19252

Given that, your question has tag 'doctest' - I am assuming you want to run doctest for your function (enlighten me in the comment section, for any presumption or trivia) - as the text is ambiguous.


doctest basically works by looking for text in the form of Python interactive session. This text can be written in the docstring (like you have in the second code block/sample) or in a separate file.

  1. using docstrings - all you have to do is specify few (or at-least one) examples of function i.e. passing the required parameters and the expected result, exactly in the same format as of Python interactive session. A good practice is to run your function in the interactive session and copy paste it in the docstring of the function.

To run the doctest, first specify the following code (for your mentioned code example, you just have to type the exact lines):

if __name__ = "__main__":
    import doctest
    doctest.testmod()
  1. Line 1 - run the following code, only if the module (your *.py file) is run as script i.e. not imported, etc. (a more detailed answer here)
  2. Line 2 - importing the doctest module.
  3. Line 3 - looks for any interactive session style text in the docstring and runs it.

Once you have the above code included in your module (*.py file), just run in as a script:

python yourmodule.py

OR, You can run the doctest directly (without the above 3 lines of code):

pyhton -m doctest yourmodule.py
  1. using a separate file - add the following line in your file:

    if __name__ = "__main__"    
         import doctest
         doctest.testfile("somefile.txt")
    

it will identify and execute any interactive Python text in the file. By default the testfile() will look for 'somefile.txt' in the same directory where the module (.py file) is located (using options we can look for files in other locations).


Coming back to your question

I want to write a doctest, which checks, that it indeed returns the correct result. But whose code is not obfuscated by the complicated printing stuff. Something along the following lines would be cool:

NO (directly not possible) - Scenarios for doctest are set/written by specifying examples in form of Python interactive sessions in your docstring - exactly the i.e. as mentioned above a good practice is to run your function with various inputs in the interactive session and copy paste those lines in the docstring - and all the print statements will definitely be there, and part of the out for doctest to mark test as passed.


Indirect ways:

  1. use an optional parameter in function, for example printing - the overhead 'd be you'll need to make changes to the function i.e. moving the print statements under if.

     def f(x, printing=True): 
            """
            f(0, printing=False)
            ...
            42
            """
            if printing:
                print('Some complicated printing stuff')
            important_result = 42
            return important_result 

  1. pass the None argument to print function - beware, it'll be passed to all the print calls in the module i.e. the whole *.py file.

    def f(x): 
        """
        f(0)
        ...
        42
        """
        print('Some complicated printing stuff')
        important_result = 42
        return important_result
    if name == 'main': 
        import doctest
        print = lambda *args, **kwargs: None
        doctest.testmod()

Source: jonrsharpe's answer

Upvotes: 1

Related Questions