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.