Convert python examples to runnable code.

Gribouillis 3 Tallied Votes 904 Views Share

A feature of the doctest module can be useful when people copy and paste their idle window in the python forum: the ability to transform an example from the python interpreter into python code without the prompts >>>, ... and the output messages. The script below permits to use this function from the command line.

TrustyTony commented: Handy +13
HiHe commented: neat +5
# script_from_examples.py
""" Script to convert python interpreter examples into python code

    Usage:
        python script_from_examples.py <file>
        
        read a file containing python interpreter examples and outputs
        the python code without the prompt. For example if <file> contains

        >>> L = range(3)
        >>> for x in L:
        ...  print x
        ... 
        0
        1
        2
        >>> 

        
        the output of the command in stdout will be the python code
        
        L = range(3)
        for x in L:
         print x
        # Expected:
        ## 0
        ## 1
        ## 2

"""
import doctest
import sys

if __name__ == "__main__":
    assert len(sys.argv) == 2
    filename = sys.argv[-1]
    print doctest.script_from_examples(open(filename).read())
TrustyTony 888 ex-Moderator Team Colleague Featured Poster

Looks like the doctest can not handle def statements from log of IDLE command prompt.

C:\py>script_from_examples.py ex2.txt
def sum(a,b):
# Expected:
##         return a+b


C:\py>type ex2.txt
>>> def sum(a,b):
        return a+b

Plain CMD Python prompt shows it differently:

>>> def sum(a,b):
...     return a+b
...
commented: indeed +14
Gribouillis 1,391 Programming Explorer Team Colleague

Looks like the doctest can not handle def statements from log of IDLE command prompt.

It is true, but I finally found a solution for idle. There is an improved idle in pypi called idlex. This idlex can be used with a normal idle shell or with an ipython shell (I had issues with the ipython shell, probably due to a version mismatch). Used with a normal shell, one can use the Paste from Shell tool to handle idle shell output !

The source code for this tool is in the file PastePyShell.py in the idlex module.

Install with

pip install idlex
Gribouillis 1,391 Programming Explorer Team Colleague

Following the previous remark, here is the new version of script_from_example.py, which should work for standard console output and also for idle output, and even ipython output (but you must install idlex first)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Sat Aug  9 21:55:07 2014
@author: Gribouillis, for the python forum at www.daniweb.com
@lisense: Public Domain
Use this code freely
"""
from __future__ import (absolute_import, division,
                        print_function, unicode_literals)
__version__ = '0.2'
import argparse
import codecs
from idlexlib.extensions.PastePyShell import PastePyShellProcessor

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="""transform a python shell example into python code

        """,
        formatter_class=argparse.RawTextHelpFormatter,)
    parser.add_argument('filename',
        action='store',
        help='file containing a python shell example (with >>> and results)',
        metavar='FILE',
        )
    parser.add_argument('-e', '--encoding',
        help='encoding (eg latin1), defaults to utf8.',
        metavar='ENCODING',
        dest='encoding',
        default='utf8')
    args = parser.parse_args()
    pc = PastePyShellProcessor()
    res = pc._paste_process(codecs.open(
        args.filename, encoding=args.encoding).read())
    for i in res.split('\n'):
        print(i)

It was tested with this text file, for python 2 and 3

>>> L = range(3)
>>> for x in L:
...  print x
... 
0
1
2
>>> def foo(x):
...     print('hello')
... 
>>> foo
<function foo at 0x7f50e99905f0>
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 argument (0 given)
>>> foo(2)
hello
>>> def sum(a,b):
        return a+b


In [1]: L = range(5)

In [2]: def foo(x):
   ...:     print x
   ...:     print 'foo'
   ...:     if x is None:
   ...:         x = "bar"
   ...:         

In [3]: foo(5)
5
foo

and produces the following

#
L = range(3)
for x in L:
 print x

#0
#1
#2
def foo(x):
    print('hello')

foo
#<function foo at 0x7f50e99905f0>
foo()
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#TypeError: foo() takes exactly 1 argument (0 given)
foo(2)
#hello
def sum(a,b):
        return a+b

L = range(5)
def foo(x):
    print x
    print 'foo'
    if x is None:
        x = "bar"

foo(5)
#5
#foo
#
# 
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.