Currently libxml2 ignores the value of sys.stderr and prints straight to c stderr. This caught me out a couple of times in the past, when using from within apache (ended up raw in the error log) and when trying to pass on the problems reported to another process. Setting your own callback can get the desired effect, but it would be nice for this to just work. Anyway, while I was looking at something more complicated on the error handling front (fixing it so the exceptions actually included the info), I thought I'd try and patch this in passing. Went hunting for how other cpython deals with error logging, found a couple of things along the right lines. In ctypes PrintError < http://svn.python.org/view/python/trunk/Modules/_ctypes/callbacks.c?view=markup> (attached, extract_ctypes_callback.c) is a minimal version. In python itself, PySys_WriteStderr <http://svn.python.org/view/python/trunk/Python/sysmodule.c?view=markup> (attached, extract_python_sysmodule.c) is pretty much perfect for a default error callback, but for the arg mismatch (no dummy void*). The mywrite function that actually does all the work covers all bases, including short circuiting the common case. So, one approach is to adapt (err... "copy wholesale") that function (attached, libxml2_stderr.patch) for use with the current callback function. Do the libxslt bindings also need looking at? I don't suggest taking the patch exactly as-is (borrowed function should probably go somewhere else at least), but something along these lines would be nice. Martin
static void
PrintError(char *msg, ...)
{
char buf[512];
PyObject *f = PySys_GetObject("stderr");
va_list marker;
va_start(marker, msg);
vsnprintf(buf, sizeof(buf), msg, marker);
va_end(marker);
if (f)
PyFile_WriteString(buf, f);
PyErr_Print();
}
/* APIs to write to sys.stdout or sys.stderr using a printf-like interface.
Adapted from code submitted by Just van Rossum.
PySys_WriteStdout(format, ...)
PySys_WriteStderr(format, ...)
The first function writes to sys.stdout; the second to sys.stderr. When
there is a problem, they write to the real (C level) stdout or stderr;
no exceptions are raised.
Both take a printf-style format string as their first argument followed
by a variable length argument list determined by the format string.
*** WARNING ***
The format should limit the total size of the formatted output string to
1000 bytes. In particular, this means that no unrestricted "%s" formats
should occur; these should be limited using "%.<N>s where <N> is a
decimal number calculated so that <N> plus the maximum size of other
formatted text does not exceed 1000 bytes. Also watch out for "%f",
which can print hundreds of digits for very large numbers.
*/
static void
mywrite(char *name, FILE *fp, const char *format, va_list va)
{
PyObject *file;
PyObject *error_type, *error_value, *error_traceback;
PyErr_Fetch(&error_type, &error_value, &error_traceback);
file = PySys_GetObject(name);
if (file == NULL || PyFile_AsFile(file) == fp)
vfprintf(fp, format, va);
else {
char buffer[1001];
const int written = PyOS_vsnprintf(buffer, sizeof(buffer),
format, va);
if (PyFile_WriteString(buffer, file) != 0) {
PyErr_Clear();
fputs(buffer, fp);
}
if (written < 0 || (size_t)written >= sizeof(buffer)) {
const char *truncated = "... truncated";
if (PyFile_WriteString(truncated, file) != 0) {
PyErr_Clear();
fputs(truncated, fp);
}
}
}
PyErr_Restore(error_type, error_value, error_traceback);
}
void
PySys_WriteStdout(const char *format, ...)
{
va_list va;
va_start(va, format);
mywrite("stdout", stdout, format, va);
va_end(va);
}
void
PySys_WriteStderr(const char *format, ...)
{
va_list va;
va_start(va, format);
mywrite("stderr", stderr, format, va);
va_end(va);
}
Attachment:
libxml2_stderr.patch
Description: Binary data