Question

I was wondering if this is possible in python:

# module1
def test():
    print('hey')

# module2
import module1

module1.test() # prints to stdout

Without modifying module1 is there any way to wrap this in module2 so that I can capture the print('hey') inside a variable? Apart from running module1 as a script?

Was it helpful?

Solution 3

Yes, you can. You need to take control of sys.stdout. Something like this:

import sys

stdout_ = sys.stdout #Keep track of the previous value.
sys.stdout = open('myoutputfile.txt', 'w') # Something here that provides a write method.
# calls to print, ie import module1
sys.stdout = stdout_ # restore the previous stdout.

OTHER TIPS

I don't want to be responsible for modifying sys.stdout and then restoring it to its previous values. The above answers don't have any finally: clause, which can be dangerous integrating this into other important code.

https://docs.python.org/3/library/contextlib.html

import contextlib, io

f = io.StringIO()
with contextlib.redirect_stdout(f):
    module1.test()
output = f.getvalue()

You probably want the variable output which is <class 'str'> with the redirected stdout.

Note: this code is lifted from the official docs with trivial modifications (but tested). Another version of this answer was already given to a mostly duplicated question here: https://stackoverflow.com/a/22434594/1092940

I leave the answer here because it is a much better solution than the others here IMO.

Yes, all you need is to redirect the stdout to a memory buffer that complies with the interface of stdout, you can do it with StringIO. This works for me in 2.7:

import sys
import cStringIO

stdout_ = sys.stdout #Keep track of the previous value.
stream = cStringIO.StringIO()
sys.stdout = stream
print "hello" # Here you can do whatever you want, import module1, call test
sys.stdout = stdout_ # restore the previous stdout.
variable = stream.getvalue()  # This will get the "hello" string inside the variable

For Python 3:

# redirect sys.stdout to a buffer
import sys, io
stdout = sys.stdout
sys.stdout = io.StringIO()

# call module that calls print()
import module1
module1.test()

# get output and restore sys.stdout
output = sys.stdout.getvalue()
sys.stdout = stdout

print(output)

There's No need to use another module, just class object with write attribute, with one input, which you can save in another variable. for ecample

CLASS:

class ExClass:
    def __init__(self):
        self.st = ''
    def write(self, o): #here o is the output that goes to stdout
        self.st += str(o)

MAIN Program:

import sys
stdout_ = sys.stdout
var = ExClass()
sys.stdout = var

print("Hello") # these will not be pronted 
print("Hello2") # instead will be written in var.st

sys.stdout = stdout_

print(var.st) 

output will be

Hello
Hello2

Sending ftplib debug output to the logging module

Based on the approach taken by jimmy kumar ahalpara answer, I was able to capture ftplib's debug output into logging. ftplib was around before the logging module and uses print to emit debug messages.

I'd tried reassigning the print function to a logging method but I couldn't get that to work. The code below works for me.

I should think this will work with other modules as well but there would not be any granularity between different module's output as it's capturing everything sent to stdout to the same logger.

# convenience class to redirect stdout to logging
class SendToLog:

    def __init__(self, logging_method):

        self.logger = logging
_method
    def write(self, o):

        if str(o).strip():  #  ignore empty lines
            self.logger(str(o))


import logging
import sys

# code to initialise logging output and handlers ...
# ...

# get logger for ftplib and redirect it's print output to our log
ftp_logger = logging.getLogger('ftplib')
# note: logging's debug method is passed to the class, the instance then calls this method
sys.stdout = SendToLog(ftp_logger.debug)

# code to do stuff with ftplib ...
# remember to set ftplib's debug level > 0 or there will be no output
# FTP.set_debuglevel(1)
# ...

# important to finalise logging and restore stdout
logging.shutdown()
sys.stdout = sys.__stdout__

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top