Reputation: 1655
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!
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
).
Upvotes: 1
Views: 560
Reputation: 1655
code.InteractiveConsole.interact
does exactly what is asked.
Upvotes: 1
Reputation: 2656
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):
Upvotes: 0