Python Forum
class that Redirects text from stdio to file
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
class that Redirects text from stdio to file
#1
Hello,

Here's a Class to redirect stdio to a file.

I wrote a class that toggles stdio from within a script.
see the __name__ clause for usage
save the code as 'ToggleStdio.py'


import sys

class ToggleStdio:
   def __init__(self, filename=None):
       self.savestdout = None
       self.stdio_redirected = False
       if filename:
           self.savefile = filename

   def toggle_stdout(self):
       if self.stdio_redirected:
           sys.stdout = self.savestdout
           self.savestdout = None
           self.stdio_redirected = False
       else:
           self.savestdout = sys.stdout
           sys.stdout = open(self.savefile, 'w')
           self.stdio_redirected = True

if __name__ == '__main__':
   ts = ToggleStdio('mystdio.txt')
   ts.toggle_stdout()
   print('This should go to file')
   ts.toggle_stdout()
   print('This should go to screen')
   ts.toggle_stdout()
   print('added to file')
   print('more added to file')
   ts.toggle_stdout()
   print('more on screen')
Usage:

import ToggleStdio

# instantiate the class
ts = ToggleStdio(filename='xxxx.txt')  

ts.toggle_stdout()   # toggles between screen and file may be called once at beginning of a block of code, and once at end

                               # Can be used for more than one block of code, but be aware, nesting may cause unpredictable results.

Larz60+
#2
What are your thoughts on making it a context manager so that it can be used in a with block? Also, you don't necessarily need to store the previous stdout yourself, unless you want to support really unusual use cases.
#3
Also, you can probably make it much smaller if you want.  Something like...
import sys

class ToggleIO:
	def __init__(self, orig, other):
		self.current = orig
		self.other = other
		self.toggled = False
	
	def toggle(self):
		self.current, self.other = self.other, self.current
		sys.stdout = self.current
		return self.current # unneeded?
		
if __name__ == '__main__':
	with open('output.txt', 'w') as log:
		io = ToggleIO(sys.stdout, log)
		io.toggle()
		print("this should go to log")
		io.toggle()
		print("this should go to console")
#4
Here's what I meant about using a context manager:
import sys

class ToggleIO:
    "begins without redirecting; use as context manager or call toggle() to enable"
    def __init__(self, other, original=sys.stdout):
        self.current = self.original = original
        self.other = other
    
    def toggle(self):
        self.current, self.other = self.other, self.current
        sys.stdout = self.current
        return self.current # unneeded?

    def __enter__(self):
        sys.stdout = self.current = self.other
        self.other = self.original
        return self

    def __exit__(self, *args):
        sys.stdout = self.original
        
if __name__ == '__main__':
    with open('output-1.txt', 'w') as log, ToggleIO(log) as io:
        print("[output-1] using io automatically")
        io.toggle()
        print("[console] explicitly turned off") 

    print("[console] outside of context block")

    with open('output-2.txt', 'w') as log, ToggleIO(log):
        print("[output-2] this is nice if we never want to toggle within the block")

    print("[console] again leaving a context manager")

    with open("output-3.txt", 'w') as log:
        io = ToggleIO(log)
        print("[console] io not enabled yet")
        io.toggle()
        print("[output-3] explicitly enabled")
        io.toggle()
        print("[console] and disabled")

    #note that if we toggled in the block above, and forgot to untoggle, we'd have problems
output:

$ python testit.py 
[console] explicitly turned off
[console] outside of context block
[console] again leaving a context manager
[console] io not enabled yet
[console] and disabled
$ cat output-1.txt 
[output-1] using io automatically
$ cat output-2.txt 
[output-2] this is nice if we never want to toggle within the block
$ cat output-3.txt 
[output-3] explicitly enabled
Note that doing this without a context manager is dangerous, since if someone has an exception while using it, and someone else catches that exception, there could be bad state. Also obviously there are threading issues, and I haven't considered carefully the implications of nesting here.

I did do something similar to this once before, years ago. I didn't reference that code here, though I might go check it out later to see if it was very different. I have also considered doing this when I want to indent all output, since that should be relatively nestable (though threading issues and the like would still be present).
#5
Hello,

Have at it guys - I wrote this in about 10 minutes because I needed it fast (tracking something like Application Experience (oh wow! don't ya just love it!) in microshaft winblows ).
I'd love to see a context manager.

Larz60+

Hello micsyldel,

Love it, I 'll put it in my toolbox.

Larz60+

Hello nilamo,

I have also replaced my simple version with your's.

Larz60+
#6
i like this category :) ... i find examples are very helpful to learning  :D
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020