Issue
I am using Spyder for Python and sometime I would like to print the console into a log file (in cases where the output is quite long) and sometimes I just want to have the output at the console. For this purpose I use the following construction in my Python files:
In the beginning of the file:
import sys
# specify if the output should be printed on a separate log file or on the console
printLogToFile = False
if printLogToFile == True:
#Specify output file for the logs
sys.stdout = open('C:/Users/User 1/logfile.txt', 'w')
At the end of the file:
# Close the log file if output is printed on a log file and not on the console
if printLogToFile == True:
sys.stdout.close()
sys.stdout = sys.__stdout__
Basically, whenever my boolean variable printLogToFile
has the value False then everything is printed on the console as it should and whenever it has the value True everything is printed into the logfile. However, once I run just once the file with printLogToFile=True
this can't be reversed any longer. Even when the variable has the value False it still prints everything into the log file and not onto the console. What is even more strange is that also for other Python files, that do not have any connection to this file, the console is not printed any longer onto the console. The only way to solve this problem is to close Spyder and restart it again.
Do you have any idea why this is happening and how to avoid this? I'd appreciate every comment.
Solution
The console in Spyder is an IPython console, not a plain Python console, so I think IPython is doing something with stdout
that causes your approach to fail.
The docs for sys.__stdout__
say
It can also be used to restore the actual files to known working file objects in case they have been overwritten with a broken object. However, the preferred way to do this is to explicitly save the previous stream before replacing it, and restore the saved object.
In other words, try:
if printLogToFile:
prev_stdout = sys.stdout
sys.stdout = open('C:/Users/User 1/logfile.txt', 'w')
# code that generates the output goes here
if printLogToFile:
sys.stdout.close()
sys.stdout = prev_stdout
As an alternative, based on this answer and this answer assuming Python >= 3.7, you can use contextlib and a with
statement to selectively capture the output of some of your code. This seems to work for me in Spyder 4 and 5:
from contextlib import redirect_stdout, nullcontext
if printLogToFile:
f = open('myfile.txt', 'w')
cm = redirect_stdout(f)
else:
cm = nullcontext()
with cm:
# code that generates the output goes here
If you want to execute the whole of your Python script myscript.py
and capture everything it outputs, it's probably easier to leave your script unmodified and call it from a wrapper script:
# put this in the same folder as myscript.py
from contextlib import redirect_stdout
with redirect_stdout(open('myfile.txt', 'w')):
import myscript
If you want anything more flexible than that, it's probably time to start using logging.
Answered By - nekomatic
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.