Is there a trick to break on the print builtin with pdb? - python

Basically, the title.
I am trying to trace down where a spurious print happens in a large codebase, and I would like to break, or somehow get a stack trace whenever a print "happens." Any ideas?

For this particular case you can redirect stdout to a helper class that prints the output and its caller. You can also break on one of its methods.
Full example:
import sys
import inspect
class PrintSnooper:
def __init__(self, stdout):
self.stdout = stdout
def caller(self):
return inspect.stack()[2][3]
def write(self, s):
self.stdout.write("printed by %s: " % self.caller())
self.stdout.write(s)
self.stdout.write("\n")
def test():
print 'hello from test'
def main():
# redirect stdout to a helper class.
sys.stdout = PrintSnooper(sys.stdout)
print 'hello from main'
test()
if __name__ == '__main__':
main()
Output:
printed by main: hello from main
printed by main:
printed by test: hello from test
printed by test:
You can also just print inspect.stack() if you need more thorough information.

The only thin I can think of would be to replace sys.stdout, for example with a streamwriter as returned by codecs.getwriter('utf8'). Then you can set a breakpoint on it's write method in pdb. Or replace it's write method with debugging code.
import codecs
import sys
writer = codecs.getwriter('utf-8')(sys.stdout) # sys.stdout.detach() in python3
old_write = writer.write
def write(data):
print >>sys.stderr, 'debug:', repr(data)
# or check data + pdb.set_trace()
old_write(data)
writer.write = write
sys.stdout = writer
print 'spam', 'eggs'

Related

How to override the builtin method "print()"

I need to customize the print(), so that it does something else besides printing what I want. Is there a way to override it?
Here is A Page That Will Help You With Overriding Functions!
Here is A Way To Override print! (Making a New print)
Code:
from __future__ import print_function
try:
import __builtin__
except ImportError:
import builtins as __builtin__
def print(*args, **kwargs):
"""My custom print() function."""
__builtin__.print('your text')
return __builtin__.print(*args, **kwargs)
print()
Output:
your text
The Line __builtin__.print('your text') would Print 'Your Text', you can put other function Also Instead of Print, it would Print Your Given Text also As The Return Line Says It to, it used the built in print function!
The Second Thing That you can Do is That You Can Remove The Return Line so The Function wouldn't Print Anything To The Console
Hope This Helps
one option is to use contextlib.redirect_stdout:
from contextlib import redirect_stdout
with open('file.txt', 'a') as file, redirect_stdout(file):
print('hello')
if you need both printing and saving to a file, this may work:
from contextlib import redirect_stdout
from sys import stdout
from io import StringIO
class MyOutput(StringIO):
def __init__(self, file):
super().__init__()
self.file = file
def write(self, msg):
stdout.write(msg)
self.file.write(msg)
with open('file.txt', 'a') as file, redirect_stdout(MyOutput(file=file)):
print('hello')
You can override the print() method but you have to create class and then override the "str" dunder method (print() uses "str" implementation in backend). Here is the code.
a = 2
print(a)
class abc:
def __init__(self,x):
self.x = x
def __str__(self):
return "The value is " + str(self.x)
a = abc(2)
print(a)

override print method in current class python3

Not sure how I would accomplish overriding the print('something') function do do something else in the class I am in.
For example, I have the following code:
import app
from app.helper import ws_send
class TemplateSubJob:
def __init__(self, sessiondata, sid, payload):
self.session = sessiondata
self.sid = sid
self.payload = payload
def startme(self):
ws_send(self.sid, self.payload, 'Send some output to the user...')
ws_send(self.sid, self.payload, 'Send something else to the user...')
print('test')
return b'xlsx_bytes_output'
I want to override the function print('something') to take what is passed and do something with it.
In my case I want to create a print function that does what ws_send() is doing, except only take a string.
Something like the following:
def print(string):
ws_send(self.sid, self.payload, string)
print('now i am being sent through ws_send instead of stdout')
How can I accomplish this?
UPDATE:
The reasoning for this is so anyone who is adding code to mine, does not need to modify their code or script to use my functions. I can hijack the print function that they are already using.
You can overload the print function with the following syntax:
from __future__ import print_function
try:
# python2
import __builtin__
except ImportError:
# python3
import builtins as __builtin__
def print(*args, **kwargs):
__builtin__.print('New print function')
return __builtin__.print(*args, **kwargs)
E: Fixed bad import, as pointed out in the comment
So I'm not going to go over the why you're using a print statement in that given case, but for Python 3, within your class description
class TemplateSubJob:
def __init(self, ):
# and other methods
def __str__(self, ):
return 'String description here'
which will return the given string when someone tries to print the given object. For example, when I instantiate, I can then call the print function directly following the instantiation, which will return any strings returned by the str function above
myobject = TemplateSubJob()
print(myobject)
For redirecting print to variable(string), use this:
from io import StringIO # Python2 use: from cStringIO import StringIO
import sys
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
# blah blah lots of code ...
sys.stdout = old_stdout
# examine mystdout.getvalue()
Source: https://stackoverflow.com/a/1218951/4718434
For redirect it to file, use this:
https://stackoverflow.com/a/4675744/4718434

Custom print function yield from sub function

I customized the print function to print to console and also send print lines to an object so I can pipe them to a gui using a yield function. This works fine, until my function calls a sub function and that sub function prints to console. If I import my custom print into that subfunction, it doesn't work because that print is yielding results to the subfunction, not the original outerfunction.
Is there a way to yield result from my custom print directly back to the main function and skip this inceptionesque nightmare?
from __future__ import print_function
import __builtin__
def print(*args, **kwargs):
import builtins
import io
from contextlib import redirect_stdout
builtins.print(*args, **kwargs)
with io.StringIO() as buf, redirect_stdout(buf):
builtins.print(*args, **kwargs)
output = buf.getvalue()
return output
Instead of overriding print, create an object that writes to two different files when you write to it. Something like
# I'm not sure if there are other methods you should override, but
# they would be similar.
class Delegator(io.TextIOBase):
def __init__(self, fh1, fh2):
self.fh1 = fh1
self.fh2 = fh2
def write(self, txt):
self.fh1.write(txt)
self.fh2.write(txt)
def flush(self):
self.fh1.flush()
self.fh2.flush()
sys.stdout = Delegator(sys.stdout, my_other_file)

Intercept python's `print` statement and display in GUI

I have this somewhat complicated command line function in Python (lets call it myFunction()), and I am working to integrate it in a graphical interface (using PySide/Qt).
The GUI is used to help select inputs, and display outputs. However, myFunction is designed to work as a stand-alone command line function, and it occasionnaly prints out the progress.
My question is: how can I intercept these print calls and display them in the GUI?
I know it would be possible to modify myFunction() to send processEvents() to the GUI, but I would then lose the ability to execute myFunction() in a terminal.
Ideally, I would like something similar to Ubuntu's graphical software updater, which has a small embeded terminal-looking widget displaying what apt-get would display were it executed in a terminal.
you could redirect stdout and restore after. for example:
import StringIO
import sys
# somewhere to store output
out = StringIO.StringIO()
# set stdout to our StringIO instance
sys.stdout = out
# print something (nothing will print)
print 'herp derp'
# restore stdout so we can really print (__stdout__ stores the original stdout)
sys.stdout = sys.__stdout__
# print the stored value from previous print
print out.getvalue()
Wrap it with a function that hijacks stdout:
def stdin2file(func, file):
def innerfunc(*args, **kwargs):
old = sys.stdout
sys.stdout = file
try:
return func(*args, **kwargs)
finally:
sys.stdout = old
return innerfunc
Then simply provide a file like object that supports write():
class GUIWriter:
def write(self, stuff):
#send stuff to GUI
MyFunction = stdin2file(MyFunction, GUIWriter())
The wrapper can be turned into a decorator too:
def redirect_stdin(file):
def stdin2file(func, file):
def innerfunc(*args, **kwargs):
old = sys.stdout
sys.stdout = file
try:
return func(*args, **kwargs)
finally:
sys.stdout = old
return innerfunc
return stdin2file
The use it when declaring MyFunction():
#redirect_stdin(GUIWriter())
def MyFunction(a, b, c, d):
# any calls to print will call the 'write' method of the GUIWriter
# do stuff
Here is a Python 3 pattern using contextmanager that both encapsulates the monkey-patch technique and also ensures that sys.stdout is restored in case of an exception.
from io import StringIO
import sys
from contextlib import contextmanager
#contextmanager
def capture_stdout():
"""
context manager encapsulating a pattern for capturing stdout writes
and restoring sys.stdout even upon exceptions
Examples:
>>> with capture_stdout() as get_value:
>>> print("here is a print")
>>> captured = get_value()
>>> print('Gotcha: ' + captured)
>>> with capture_stdout() as get_value:
>>> print("here is a print")
>>> raise Exception('oh no!')
>>> print('Does printing still work?')
"""
# Redirect sys.stdout
out = StringIO()
sys.stdout = out
# Yield a method clients can use to obtain the value
try:
yield out.getvalue
finally:
# Restore the normal stdout
sys.stdout = sys.__stdout__
All printing is done via sys.stdout, which is a ordinary file-like object: iirc, it requires a method write(str). As long as your replacement has that method, it's quite easy to drop in your hook:
import sys
class CaptureOutput:
def write(self, message):
log_message_to_textbox(message)
sys.stdout = CaptureOutput()
The actual contents of log_message_to_textbox are up to you.

Sensible Way to Capture Stdout for Later Replay?

As part of trying to test a legacy function's 'print to stdout' side-effect, I want to capture stdout for later replay. I use mock.
goals (fulfill as many as possible!)
stdout still prints where it normally would, but there is an additional recorder
ideally, this should be 'patched' or only occur in a context
My implementation (below) has patching that seems a bit heavy / gross. Is there a saner way to do it? cStringIO? Any better parts of mock I can use, rather that my __getattr__ hack?
class StreamCapturing(object):
def __init__(self, stream):
self.captured = []
self.stream = stream
def __getattr__(self,attr):
return getattr(self.stream,attr)
def write(self, data):
self.captured.append(data)
self.stream.write(data)
import sys
import mock
with mock.patch('sys.stdout',StreamCapturing(sys.stdout)) as ctx:
sys.stdout.write('a\n')
print 'stdout'
sys.__stdout__.write("the real one\n")
print sys.stdout.captured
sys.stdout.flush()
assert getattr(sys.stdout,'captured') is None
You don't even need to save the previous stdout python does it for you and yes use cStringIO
import sys
from cStringIO import StringIO
sys.stdout = captured = StringIO()
print "test string"
# test stuff
captured = captured.getvalue()
sys.stdout = sys.__stdout__
print "captured",captured
You do not need mock in this situation:
saved_stdout = sys.stdout
sys.stdout = StreamCapturing(saved_stdout)
print "stdout"
captured = "".join(sys.stdout.captured)
sys.stdout=saved_stdout
print "captured: ", captured

Categories

Resources