IPython Qt Console and printf

The recent 0.11 release of IPython includes a Qt-based console which offers an improved experience compared to running IPython in a terminal. In particular, the console feels like a terminal but offers multi-line editing, syntax highlighting, graphical tooltips, and inline plot figures.

But when I tried to run an existing script in the new IPython Qt Console, the usual overly verbose set of diagnostic messages did not appear! The symtoms were:

  • Regular print statements in Python worked fine.
  • printf statements in C-code wrapped with Boost.Python did not appear.

Read on to see a solution.

This seemed quite odd until I read more about the architecture of IPython Qt Console. In particular, IPython Qt Console is a two-process architecture whereby a background IPython process executes code and frontend client handles all user input and output. So our printf statements were being sent to stdout in the background process and therefore never appear in the Qt Console window.

Somebody must have experienced this before, but a few quick Google searched turned up nothing. How would Cython handle this? In particular, we could use Cython to compile a simple Python print statement. So consider the simple printf.pyx file:

def printf():
    print "Hello"

which we compile into C using cython printf.pyx. The resulting C file is quite lengthy, but the relevant bits are in the __Pyx_PrintOne() function:

static int __Pyx_PrintOne(PyObject* f, PyObject *o) {
    if (!f) {
        if (!(f = __Pyx_GetStdout()))
            return -1;
    }
    if (PyFile_SoftSpace(f, 0)) {
        if (PyFile_WriteString(" ", f) < 0)
            return -1;
    }
    if (PyFile_WriteObject(o, f, Py_PRINT_RAW) < 0)
        return -1;
    if (PyFile_WriteString("n", f) < 0)
        return -1;
    return 0;
    /* the line below is just to avoid compiler
     * compiler warnings about unused functions */
    return __Pyx_Print(f, NULL, 0);
}

The __Pyx_GetStdout() function is nothing more than a thin wrapper to PySys_GetObject((char *)"stdout") with a bit of error checking.

Putting this all together, a simple reporting function (without any error checking) becomes:

void report(std::string msg) {
  PyObject *f = PySys_GetObject((char *)"stdout");
  PyFile_WriteString(msg.c_str(), f);
  PyFile_WriteString("n", f);
}

For an example module using this code, see gist 1284927.

Update: After writing this, I learned of PySys_WriteStdout() which is a nearly drop-in replacement of printf. However the above method is still be useful if you need to print more than 1000 bytes at a time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s