Skip to content

Commit 826d897

Browse files
committed
Patch 1352 (continued in issue 1329) by Christian Heimes.
Before sys.stderr is set to the proper thing, set it to a really simple file-like object that can print tracebacks using direct file descriptor I/O. This is handy for debugging.
1 parent 1cd5bd2 commit 826d897

4 files changed

Lines changed: 136 additions & 1 deletion

File tree

Include/fileobject.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
2121
*/
2222
PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding;
2323

24+
/* Internal API
25+
26+
The std printer acts as a preliminary sys.stderr until the new io
27+
infrastructure is in place. */
28+
PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
29+
PyAPI_DATA(PyTypeObject) PyStdPrinter_Type;
30+
2431
#ifdef __cplusplus
2532
}
2633
#endif

Objects/fileobject.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,124 @@ Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj)
325325
return buf;
326326
}
327327

328+
/* **************************** std printer **************************** */
329+
330+
typedef struct {
331+
PyObject_HEAD
332+
int fd;
333+
} PyStdPrinter_Object;
334+
335+
static PyObject *
336+
stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews)
337+
{
338+
PyStdPrinter_Object *self;
339+
340+
assert(type != NULL && type->tp_alloc != NULL);
341+
342+
self = (PyStdPrinter_Object *) type->tp_alloc(type, 0);
343+
if (self != NULL) {
344+
self->fd = -1;
345+
}
346+
347+
return (PyObject *) self;
348+
}
349+
350+
PyObject *
351+
PyFile_NewStdPrinter(int fd)
352+
{
353+
PyStdPrinter_Object *self;
354+
355+
if (fd != 1 && fd != 2) {
356+
PyErr_BadInternalCall();
357+
return NULL;
358+
}
359+
360+
self = PyObject_New(PyStdPrinter_Object,
361+
&PyStdPrinter_Type);
362+
self->fd = fd;
363+
return (PyObject*)self;
364+
}
365+
366+
PyObject *
367+
stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
368+
{
369+
char *c;
370+
Py_ssize_t n;
371+
372+
if (self->fd < 0) {
373+
PyErr_SetString(PyExc_ValueError,
374+
"I/O operation on closed file");
375+
return NULL;
376+
}
377+
378+
if (!PyArg_ParseTuple(args, "s#", &c, &n)) {
379+
return NULL;
380+
}
381+
382+
Py_BEGIN_ALLOW_THREADS
383+
errno = 0;
384+
n = write(self->fd, c, n);
385+
Py_END_ALLOW_THREADS
386+
387+
if (n < 0) {
388+
if (errno == EAGAIN)
389+
Py_RETURN_NONE;
390+
PyErr_SetFromErrno(PyExc_IOError);
391+
return NULL;
392+
}
393+
394+
return PyInt_FromSsize_t(n);
395+
}
396+
397+
static PyMethodDef stdprinter_methods[] = {
398+
{"write", (PyCFunction)stdprinter_write, METH_VARARGS, ""},
399+
{NULL, NULL} /* sentinel */
400+
};
401+
402+
PyTypeObject PyStdPrinter_Type = {
403+
PyVarObject_HEAD_INIT(&PyType_Type, 0)
404+
"stderrprinter", /* tp_name */
405+
sizeof(PyStdPrinter_Object), /* tp_basicsize */
406+
0, /* tp_itemsize */
407+
/* methods */
408+
0, /* tp_dealloc */
409+
0, /* tp_print */
410+
0, /* tp_getattr */
411+
0, /* tp_setattr */
412+
0, /* tp_compare */
413+
0, /* tp_repr */
414+
0, /* tp_as_number */
415+
0, /* tp_as_sequence */
416+
0, /* tp_as_mapping */
417+
0, /* tp_hash */
418+
0, /* tp_call */
419+
0, /* tp_str */
420+
PyObject_GenericGetAttr, /* tp_getattro */
421+
0, /* tp_setattro */
422+
0, /* tp_as_buffer */
423+
Py_TPFLAGS_DEFAULT, /* tp_flags */
424+
0, /* tp_doc */
425+
0, /* tp_traverse */
426+
0, /* tp_clear */
427+
0, /* tp_richcompare */
428+
0, /* tp_weaklistoffset */
429+
0, /* tp_iter */
430+
0, /* tp_iternext */
431+
stdprinter_methods, /* tp_methods */
432+
0, /* tp_members */
433+
0, /* tp_getset */
434+
0, /* tp_base */
435+
0, /* tp_dict */
436+
0, /* tp_descr_get */
437+
0, /* tp_descr_set */
438+
0, /* tp_dictoffset */
439+
0, /* tp_init */
440+
PyType_GenericAlloc, /* tp_alloc */
441+
stdprinter_new, /* tp_new */
442+
PyObject_Del, /* tp_free */
443+
};
444+
445+
328446
#ifdef __cplusplus
329447
}
330448
#endif

Objects/object.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,9 @@ _Py_ReadyTypes(void)
15951595

15961596
if (PyType_Ready(&PyCode_Type) < 0)
15971597
Py_FatalError("Can't initialize 'code'");
1598+
1599+
if (PyType_Ready(&PyStdPrinter_Type) < 0)
1600+
Py_FatalError("Can't initialize StdPrinter");
15981601
}
15991602

16001603

Python/pythonrun.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ Py_InitializeEx(int install_sigs)
151151
{
152152
PyInterpreterState *interp;
153153
PyThreadState *tstate;
154-
PyObject *bimod, *sysmod;
154+
PyObject *bimod, *sysmod, *pstderr;
155155
char *p;
156156
#if defined(HAVE_LANGINFO_H) && defined(CODESET)
157157
char *codeset;
@@ -228,6 +228,13 @@ Py_InitializeEx(int install_sigs)
228228
PyDict_SetItemString(interp->sysdict, "modules",
229229
interp->modules);
230230

231+
/* Set up a preliminary stderr printer until we have enough
232+
infrastructure for the io module in place. */
233+
pstderr = PyFile_NewStdPrinter(fileno(stderr));
234+
if (pstderr == NULL)
235+
Py_FatalError("Py_Initialize: can't set preliminary stderr");
236+
PySys_SetObject("stderr", pstderr);
237+
231238
_PyImport_Init();
232239

233240
/* initialize builtin exceptions */

0 commit comments

Comments
 (0)