1

I want to find (or make) a python script that reads a different python script line by line and prints the commands executed and the output right there after.

Suppose you have a python script, testfile.py as such:

print("Hello world")

for i in range(3):
    print(f"i is: {i}")

Now, I want a different python script that parses the testfile.py and outputs the following:

print("Hello world")
## Hello world
for i in range(3):
    print(f"i is: {i}")
## i is: 0
## i is: 1
## i is: 2

Any suggestions on existing software or new code on how to achieve this is greatly appreciated!


Attempts / concept code:

Running ipython from python:

One of the first thoughts were to run ipython from python using subprocess:

import subprocess
import re
try:
    proc = subprocess.Popen(args=["ipython", "-i"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
    # Delimiter to know when to stop reading
    OUTPUT_DELIMITER = ":::EOL:::"
    # Variable to contain the entire interaction:
    output_string = ""
    # Open testfile.py
    with open("testfile.py") as file_:
        for line in file_:
            # Read command
            cmd = line.rstrip()
            # Add the command to the output string
            output_string += cmd + "\n"
            proc.stdin.write(f"{cmd}\n")
            # Print the delimiter so we know when to end:
            proc.stdin.write('print("{}")\n'.format(OUTPUT_DELIMITER))
            proc.stdin.flush()
            # Start reading output from ipython
            while True:
                thisoutput = proc.stdout.readline()
                thisoutput = thisoutput.rstrip()
                # Now check if it's the delimiter
                if thisoutput.find(OUTPUT_DELIMITER) >= 0:
                    break
                output_string += thisoutput + "\n"

except Exception as e:
    proc.stdout.close()
    proc.stdin.close()
    raise
proc.stdout.close()
proc.stdin.close()
print("-" * 4 + "START OUTPUT" + "-" * 4)
print(output_string)
print("-" * 4 + "END OUTPUT" + "-" * 4)

In this approach, the problem becomes indented blocks, like the for loop. Ideally something like this would work using just plain python (and not ipython).

4
  • Pretty much related: stackoverflow.com/questions/52130639/… Commented Sep 23, 2018 at 13:33
  • Why? What is the end goal? What benefit will this REPL/interpreter-mimicking-script have? Commented Sep 23, 2018 at 13:34
  • @DeepSpace The end goal is nicely typesetting python scripts. This would be the first step. Commented Sep 23, 2018 at 13:34
  • I figured it out by using the python [code.InteractiveConsole.interact](https://docs.python.org/3/library/code.html#code.InteractiveConsole.interact) method. Commented Apr 2, 2020 at 11:39

2 Answers 2

1

code.InteractiveConsole.interact does exactly what is asked.

Sign up to request clarification or add additional context in comments.

Comments

0

This is not exactly what you wanted, but it's close. trace module does something very similar.

so.py:

print("Hello world")
for i in range(3):
    print(f"i is: {i}")
python -m trace --trace so.py

 --- modulename: so, funcname: <module>
so.py(1): print("Hello world")
Hello world
so.py(3): for i in range(3):
so.py(4):     print(f"i is: {i}")
i is: 0
so.py(3): for i in range(3):
so.py(4):     print(f"i is: {i}")
i is: 1
so.py(3): for i in range(3):
so.py(4):     print(f"i is: {i}")
i is: 2
so.py(3): for i in range(3):

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.