2

Is it possible to set up my debugger in such a way that it breaks when the debugged application produces the next console output?

My application is printing a strange string and I need to figure out where is it coming from. Searching the source code found too many possible candidates, the string is very generic.

user7610
  • 25,267
  • 15
  • 124
  • 150

2 Answers2

3

In case you're using Python 3, simply define a custom print function that calls the original function through __builtins__ and set your breakpoint in that custom function. It will be called instead of the original one by your code without modifying anything else:

def print(*args, **kwargs):
    # set debugger breakpoint here
    __builtins__.print(*args, **kwargs)

# your code below can use print() normally

And when you're done with debugging, simply remove or comment that overriding function again.

Byte Commander
  • 6,506
  • 6
  • 44
  • 71
  • @GingerPlusPlus Your edit was incorrect, there is no `builtins` object, only `__builtins__` as I wrote it in my answer. I rolled it back. – Byte Commander Mar 26 '16 at 11:14
  • I didn't know there is built-in `__builtins__` module in Py3, thanks. However, there is also importable `builtins` module. – GingerPlusPlus Mar 26 '16 at 13:45
  • [Python: What's the difference between `__builtin__` and `__builtins__`?](http://stackoverflow.com/questions/11181519/python-whats-the-difference-between-builtin-and-builtins) – GingerPlusPlus Mar 26 '16 at 13:48
  • @GingerPlusPlus Ah, okay. I did not know about that module. But your edit did not contain an import statement. – Byte Commander Mar 29 '16 at 06:32
2

In Python 2.x, you can kind of intercept a print statement by replacing sys.stdout with an object that satisfies the interface of a file (think duck typing). A simple start:

import inspect
import sys

class OutputHook(object):
    def __init__(self, stdout):
        self._stdout = stdout

    def write(self, text):
        frame = inspect.currentframe(1)
        try:
            class_name = frame.f_locals['self'].__class__.__name__ + "."
        except KeyError:
            class_name = ""
        self._stdout.write("writing to sys.stdout at "
                           "{}{}() in line {}:\n{}\n".format(
                               class_name,
                               frame.f_code.co_name,
                               frame.f_lineno,
                               repr(text)))

def test():
    print "BBB"

class Test:
    def bla(self):
        print "Hello"

sys.stdout = OutputHook(sys.stdout)

print "aaa"
test()
Test().bla()

You will get as output:

writing to sys.stdout at <module>() in line 33:
'aaa'
writing to sys.stdout at <module>() in line 33:
'\n'
writing to sys.stdout at test() in line 25:
'BBB'
writing to sys.stdout at test() in line 25:
'\n'
writing to sys.stdout at Test.bla() in line 29:
'Hello'
writing to sys.stdout at Test.bla() in line 29:
'\n'

You could add a check if the written text is your pattern and start the debugger, or just break, for example:

if text.startwith("funny"):
    pdb.set_trace()
hochl
  • 12,524
  • 10
  • 53
  • 87