python: change sys.stdout print to custom print function - python

Im trying to understand how to create a custom print function.
(using python 2.7)
import sys
class CustomPrint():
def __init__(self):
self.old_stdout=sys.stdout #save stdout
def write(self, text):
sys.stdout = self.old_stdout #restore normal stdout and print
print 'custom Print--->' + text
sys.stdout= self # make stdout use CustomPrint on next 'print'
# this is the line that trigers the problem
# how to avoid this??
myPrint = CustomPrint()
sys.stdout = myPrint
print 'why you make 2 lines??...'
The code above prints this to console:
>>>
custom Print--->why you make 2 lines??...
custom Print--->
>>>
and i want to print only one line:
>>>
1custom Print--->why you make 2 lines??...
>>>
But cant figure out how to make this custom print work , i understand that there's some kind of recursion that triggers the second output to the console (i use self.write , to assign stdout to self.write himself !)
how can i make this work ? or is my approach just completely wrong...

It's not recursion. What happens is your write function is called twice, once with the text you expect, second time with just '\n'. Try this:
import sys
class CustomPrint():
def __init__(self):
self.old_stdout=sys.stdout
def write(self, text):
text = text.rstrip()
if len(text) == 0: return
self.old_stdout.write('custom Print--->' + text + '\n')
def flush(self):
self.old_stdout.flush()
What I do in the above code is I add the new line character to the text passed in the first call, and make sure the second call made by the print statement, the one meant to print new line, doesn't print anything.
Now try to comment out the first two lines and see what happens:
def write(self, text):
#text = text.rstrip()
#if len(text) == 0: return
self.old_stdout.write('custom Print--->' + text + '\n')

One solution may be to use a context manager if it's localised.
#!/usr/bin/env python
from __future__ import print_function
from contextlib import contextmanager
#############################
#contextmanager
def no_stdout():
import sys
old_stdout = sys.stdout
class CustomPrint():
def __init__(self, stdout):
self.old_stdout = stdout
def write(self, text):
if len(text.rstrip()):
self.old_stdout.write('custom Print--->' + text)
sys.stdout = CustomPrint(old_stdout)
try:
yield
finally:
sys.stdout = old_stdout
#############################
print("BEFORE")
with no_stdout():
print("WHY HELLO!\n")
print("DING DONG!\n")
print("AFTER")
The above produces:
BEFORE
custom Print--->WHY HELLO!
custom Print--->DING DONG!
AFTER
The code would need tidying up esp. around what the class should do WRT setting stdout back to what it was.

How about doing from __future__ import print_function. This way you will use Python3 print function instead of print statement from Python2. Then you can redefine the print function:
def print(*args, **kwargs):
__builtins__.print("Custom--->", *args, **kwargs)
There is a catch however, you will have to start using print function.

Related

External library uses print instead of return

I have a problem with an external library that I use in my script.
I execute a function from this library, but the function prints the output directly. However, I need the output to check if there is a specific string in it.
How can I ensure that the output of the function in the external library comes in a variable so that I can make the comparisons with the string?
If you really have no other choice, you could redirect stdout when you call the library. Here's a piece of code adapted from this answer :
def some_library():
print("Should probably return instead of print.")
import sys
from io import StringIO
class redirected_stdout:
def __init__(self):
self._stdout = None
self._string_io = None
def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._string_io = StringIO()
return self
def __exit__(self, type, value, traceback):
sys.stdout = self._stdout
#property
def string(self):
return self._string_io.getvalue()
with redirected_stdout() as out:
some_library()
result = out.string
print("return" in result)
# True
It would be much cleaner to modify the library, though.
You can exchange sys.stdout with your buffer temporarily, and then check the buffer.
def external_method():
print ("print something out, don't return")
class MyBuffer(object):
def __init__(self):
self.buffer = []
def write(self, *args, **kwargs):
self.buffer.append(args)
import sys
old_stdout = sys.stdout
sys.stdout = MyBuffer()
external_method()
my_buffer, sys.stdout = sys.stdout, old_stdout
print (my_buffer.buffer)

Decorator to modify output printed by a function in python

Suppose I have a function that prints five lines of text. I want to add prefix like 'asdf ' and suffix ' qwerty' for every line it prints on console. How to do this with decorator in python. Output generated can come from logging module or print statements in function that we want to decorate.
def my_decorator(func):
def wrapping_func(strlist):
for index, i in enumerate(strlist):
strlist[index] = 'wubalubadubdub' + i
return func(strlist)
return wrapping_func
#my_decorator
def fun(str_list):
for i in str_list:
print(i)
if __name__ == "__main__":
fun(['a', 'b'])
Duplicate question but anyways the above code is what you are looking for, the wrapping_func merely modifies the arguments that are given to the function i.e. adds a prefix and returns while calling the original function with the modified arguments with the my_decorator function just returning the wrapping_func.
Here is one sample code to demonstrate this problem.
Print statements output is customized, but not statements from logging module.
from contextlib import contextmanager
#contextmanager
def no_stdout():
import sys
old_stdout = sys.stdout
class CustomPrint():
def __init__(self, stdout):
self.old_stdout = stdout
def write(self, text):
if len(text.rstrip()):
self.old_stdout.write('custom Print--->'+ text)
sys.stdout = CustomPrint(old_stdout)
try:
yield
finally:
sys.stdout = old_stdout
def fun():
import logging
logger = logging.getLogger("tester")
logger.info("Test line from function")
print "BEFORE"
with no_stdout():
print "WHY HELLO!\n"
print "DING DONG!\n"
import logging
logger = logging.getLogger("test")
logger.info(" Hello world")
fun()
print "AFTER"
output:
BEFORE
custom Print--->WHY HELLO!
custom Print--->DING DONG!
2018-06-11 15:52:30,088 (42092) test INFO - Hello world
2018-06-11 15:52:30,092 (42092) tester INFO - Test line from function
AFTER
we see that logging modules output is not customized.

How to put all print result in a function into a variable?

I have a function in Python:
def f():
...
a lot of code
...
print "hello"
...
a lot of code
...
I want to call this function, however, the print result will be put into a variable instead print on the screen directly. How can I do this with Python?
ps:
please don't just return, sometimes I don't know where the print statement is.
Assuming that print is writing to sys.stdout, you can temporarily replace that with something like a StringIO object.
stdout = sys.stdout
sys.stdout = StringIO()
f()
x = sys.stdout.getvalue()
sys.stdout = stdout
Or, if you have a reference to the file handle that print is using, you can use that instead of sys.stdout.
If there are multiple uses of print from inside f, and you only want to capture some of them (say, only from a function g called from inside f), I'm afraid you are out of luck. The amount of introspection you would need to do would make it possible would allow you to simply re-implement the function to accumulate the desired output in a variable instead of using print.
Use a decorator like below
import sys
from StringIO import StringIO
s = StringIO()
def catch_stdout(user_method):
sys.stdout = s
def decorated(*args, **kwargs):
user_method(*args, **kwargs)
sys.stdout = sys.__stdout__
print 'printing result of all prints in one go'
s.seek(0, 0)
print s.read()
return decorated
#catch_stdout
def test():
print 'hello '
print 'world '
test()
You could also define your own context manager if you find you need to do this a lot so you can capture the output for a block of statements, eg:
import contextlib
from StringIO import StringIO
import sys
#contextlib.contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = StringIO()
yield sys.stdout, old_stdout
sys.stdout = old_stdout
Then use as follows:
def something():
print 'this is something'
# All prints that go to stdout inside this block either called
# directly or indirectly will be put into a StringIO object instead
# unless the original stdout is used directly...
with capture_print() as (res, stdout):
print 'hello',
print >> stdout, "I'm the original stdout!"
something()
print res.getvalue() + 'blah' # normal print to stdout outside with block
Gives you:
I'm the original stdout
hello this is something
blah
def f():
#code
variable = 'hello\n'
#code
variable += 'hello2\n'
#code
...
print(variable)
or
def f():
#code
variable = 'hello\n'
#code
variable += 'hello2\n'
#code
...
return(variable)
and then
print(f())

Change python's print behaviour in a context

I would like (just for debugging purposes) being able to change how the print works in a context
def printing_foo(a):
print(a)
return a
print("{")
with print_prefix(" " * 4):
list(map(printing_foo, range(4)))
print("}")
would produce:
{
0
1
2
3
}
much like you can have a local context for decimals.
or do I have to write my own context sensitive print and import and use it in all modules?
You can use a context manager to capture sys.stdout, then prefix anything print() writes to it:
from contextlib import contextmanager
import sys
class Prefixer(object):
def __init__(self, prefix, orig):
self.prefix = prefix
self.orig = orig
def write(self, text):
self.orig.write(self.prefix + text)
def __getattr__(self, attr):
return getattr(self.orig, attr)
#contextmanager
def prefix_stdout(prefix):
current_out = sys.stdout
try:
sys.stdout = Prefixer(prefix, current_out)
yield
finally:
sys.stdout = current_out
and use as:
with prefix_stdout('Prefixed: '):
print('Hello world!')
but take into account that print() calls usually write data to stdout in separate chunks; the newline at the end is a separate write.
For debugging I would recommend the logging module.

write() not called when subclassing code.InteractiveInterpreter

When subclassing code.InteractiveInterpreter I can't seem to get the write() method to run as I would expect per the documentation.
import code
class PythonInterpreter(code.InteractiveInterpreter):
def __init__(self, localVars):
self.runResult = ''
print 'init called'
code.InteractiveInterpreter.__init__(self, localVars)
def write(self, data):
print 'write called'
self.runResult = data
test = 'Hello'
interpreter = PythonInterpreter({'test':test})
interpreter.runcode('print test')
print 'Result:' + interpreter.runResult
Expected output:
init called
write called
Result: Hello
Actual output:
init called
Hello <- shouldn't print
Result:
Any thoughts?
The write method is not used by the code passed to runcode at all. You would have to redirect stdout for this to work, e.g. something like:
import code
class PythonInterpreter(code.InteractiveInterpreter):
def __init__(self, localVars):
self.runResult = ''
print 'init called'
code.InteractiveInterpreter.__init__(self, localVars)
def write(self, data):
# since sys.stdout is probably redirected,
# we can't use print
sys.__stdout__.write('write called\n')
self.runResult = data
def runcode(cd):
# redirecting stdout to our method write before calling code cd
sys.stdout = self
code.InteractiveInterpreter.runcode(self,cd)
# redirecting back to normal stdout
sys.stdout = sys.__stdout__

Categories