Next post: Downloading all revisions from a remote subversion repo

Python printval

After reading about Python inspect, I realized that a lot of information is available to a function being called. One can even look downwards into the scope of the caller. It occurred to me that this could be useful for debugging -- as a companion to the good-old "print values to stdout and see what's wrong" technique. Here is what I call Printval -- it uses introspection to automagically print both the expression and the value. It uses the | operator for quick typing.

from printval import printval
def example():
    a = 4
    b = 5
    printval | a
    printval | 3*a*b

(
written to the console:
"a is 4"
"3*a*b is 60"
)

The entire code to make printval work (including expanding structures and classes) is only a few lines long:

import inspect, itertools
class PythonPrintVal(object):
    def _output(self, name, val):
        # expands a struct to one level.
        print('printval| ' + name + ' is ' + repr(val))
        if name == 'locals()':
            for key in val:
                if not key.startswith('_'):
                    self._output(key, val[key])
        elif ' object at 0x' in repr(val):
            for propname in dir(val):
                if not propname.startswith('_'):
                    sval = repr(val.__getattribute__(propname))
                    print(' \t\t.'+propname+'  =  '+sval)

    def __or__(self, val):
        # look in the source code for the text
        fback = inspect.currentframe().f_back
        try:
            with open(fback.f_code.co_filename, 'r') as srcfile:
                line = next(itertools.islice(srcfile, fback.f_lineno-1, fback.f_lineno))
                self._output(line.replace('printval|','',1).strip(), val)
        except (StopIteration, IOError):
            return self._output('?',val)

printval = PythonPrintVal()

Helpfully, it will enumerate through the fields of a class. And if you use printval| locals(), you get a more-nicely formatted representation of all locals in scope.

It's such a hack to be able to introspect *into the source code*. (In an earlier version, I used the syntax printval.a, so I could create chains like printval.a.b. This method doesn't require looking at source code -- the printval object knows the string 'a' from the parameter passed to __getattribute__, and retrieves its value from the scope of the caller. As a benefit this could work in compiled/frozen apps. The downside is that this doesn't allow expressions like printval|a+4)

I've since learned that other people have had similar ideas; there are modules for ScopeFormatter, Say, and Show.

I've added the source to GitHub here under the GPLv3.