Search code examples
pythonstringio

How to get all previous print in Python


I'm currently using some functions to store all print in Python

And it get all print AFTER the function has finished

Here is a sample snippet

import io
import sys
import time
import traceback

def return_std(func):
    def wrapper(*args, **kwargs):
        old_stdout = sys.stdout
        sys.stdout = buffer = io.StringIO()
        try:
            func(*args, **kwargs)
        except:
            print(traceback.format_exc())
        finally:
            sys.stdout = old_stdout
            body = buffer.getvalue()
            buffer.close()
        return body
    return wrapper

@return_std
def some_useful_function():
    print('so this line is executed at ' + time.strftime('%X'))
    time.sleep(5)

print('program execute at ' + time.strftime('%X'))
std_of_some_useful_function = some_useful_function()
print(std_of_some_useful_function)
print('but we can not know if it succeeded or failed before ' + time.strftime('%X'))

output

program execute at 11:11:11
so this line is executed at 11:11:11

but we can not know if it succeeded or failed before 11:11:16

This way captures all print and error in some_useful_function, and stores it as the function return. But print will not show BEFORE this function has finished

How should I modify the wrapper return_std, so I can see the output at 11:11:11 instantly (like it was really printed), and get all previous print stored at 11:11:16


Solution

  • You can create a subclass of io.StringIO and override the write() method so that it writes to a saved version of sys.stdout aswell as writing to it's internal buffer

    class SavedStdOut(io.StringIO):
    
        def __init__(self, stdout):
            super().__init__()
            self.stdout = stdout
    
        def write(self, s: str):
            self.stdout.write(s)
            return super().write(s)
    

    The class then writes to the passed file and saves the written data

    foo = SavedStdOut(sys.stdout)
    foo.write('Hello\n')  # Hello
    print('Buffer:', foo.getvalue())  # Buffer: Hello
    

    A complete example

    import io
    import sys
    import time
    import traceback
    
    
    class SavedStdOut(io.StringIO):
    
        def __init__(self, stdout):
            super().__init__()
            self.stdout = stdout
    
        def write(self, s: str):
            self.stdout.write(s)
            return super().write(s)
    
    
    def return_std(func):
        def wrapper(*args, **kwargs):
            sys.stdout = buffer = SavedStdOut(sys.stdout)
            try:
                func(*args, **kwargs)
            except:
                print(traceback.format_exc())
            finally:
                sys.stdout = buffer.stdout
                body = buffer.getvalue()
                buffer.close()
            return body
        return wrapper
    
    
    @return_std
    def some_useful_function():
        print('so this line is executed at ' + time.strftime('%X'))
        time.sleep(5)
    
    
    print('program execute at ' + time.strftime('%X'))
    std_of_some_useful_function = some_useful_function()
    print('saved stdout:', std_of_some_useful_function)
    print('but we can not know if it succeeded or failed before ' + time.strftime('%X'))
    

    Output:

    program execute at 03:52:01
    so this line is executed at 03:52:01  # Printed as soon as print() is called
    saved stdout: so this line is executed at 03:52:01
    
    but we can not know if it succeeded or failed before 03:52:06