mirror of https://github.com/python/cpython
bpo-43916: PyStdPrinter_Type uses Py_TPFLAGS_DISALLOW_INSTANTIATION (GH-25749)
The PyStdPrinter_Type type now uses the Py_TPFLAGS_DISALLOW_INSTANTIATION flag to disallow instantiation, rather than seting a tp_init method which always fail. Write also unit tests for PyStdPrinter_Type.
This commit is contained in:
parent
0cad068ec1
commit
4908fae3d5
|
@ -1473,11 +1473,67 @@ class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
timeout=support.SHORT_TIMEOUT,
|
timeout=support.SHORT_TIMEOUT,
|
||||||
returncode=1)
|
returncode=1)
|
||||||
|
|
||||||
|
|
||||||
class MiscTests(EmbeddingTestsMixin, unittest.TestCase):
|
class MiscTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
def test_unicode_id_init(self):
|
def test_unicode_id_init(self):
|
||||||
# bpo-42882: Test that _PyUnicode_FromId() works
|
# bpo-42882: Test that _PyUnicode_FromId() works
|
||||||
# when Python is initialized multiples times.
|
# when Python is initialized multiples times.
|
||||||
self.run_embedded_interpreter("test_unicode_id_init")
|
self.run_embedded_interpreter("test_unicode_id_init")
|
||||||
|
|
||||||
|
|
||||||
|
class StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
|
# Test PyStdPrinter_Type which is used by _PySys_SetPreliminaryStderr():
|
||||||
|
# "Set up a preliminary stderr printer until we have enough
|
||||||
|
# infrastructure for the io module in place."
|
||||||
|
|
||||||
|
def get_stdout_fd(self):
|
||||||
|
return sys.__stdout__.fileno()
|
||||||
|
|
||||||
|
def create_printer(self, fd):
|
||||||
|
ctypes = import_helper.import_module('ctypes')
|
||||||
|
PyFile_NewStdPrinter = ctypes.pythonapi.PyFile_NewStdPrinter
|
||||||
|
PyFile_NewStdPrinter.argtypes = (ctypes.c_int,)
|
||||||
|
PyFile_NewStdPrinter.restype = ctypes.py_object
|
||||||
|
return PyFile_NewStdPrinter(fd)
|
||||||
|
|
||||||
|
def test_write(self):
|
||||||
|
message = "unicode:\xe9-\u20ac-\udc80!\n"
|
||||||
|
|
||||||
|
stdout_fd = self.get_stdout_fd()
|
||||||
|
stdout_fd_copy = os.dup(stdout_fd)
|
||||||
|
self.addCleanup(os.close, stdout_fd_copy)
|
||||||
|
|
||||||
|
rfd, wfd = os.pipe()
|
||||||
|
self.addCleanup(os.close, rfd)
|
||||||
|
self.addCleanup(os.close, wfd)
|
||||||
|
try:
|
||||||
|
# PyFile_NewStdPrinter() only accepts fileno(stdout)
|
||||||
|
# or fileno(stderr) file descriptor.
|
||||||
|
os.dup2(wfd, stdout_fd)
|
||||||
|
|
||||||
|
printer = self.create_printer(stdout_fd)
|
||||||
|
printer.write(message)
|
||||||
|
finally:
|
||||||
|
os.dup2(stdout_fd_copy, stdout_fd)
|
||||||
|
|
||||||
|
data = os.read(rfd, 100)
|
||||||
|
self.assertEqual(data, message.encode('utf8', 'backslashreplace'))
|
||||||
|
|
||||||
|
def test_methods(self):
|
||||||
|
fd = self.get_stdout_fd()
|
||||||
|
printer = self.create_printer(fd)
|
||||||
|
self.assertEqual(printer.fileno(), fd)
|
||||||
|
self.assertEqual(printer.isatty(), os.isatty(fd))
|
||||||
|
printer.flush() # noop
|
||||||
|
printer.close() # noop
|
||||||
|
|
||||||
|
def test_disallow_instantiation(self):
|
||||||
|
fd = self.get_stdout_fd()
|
||||||
|
printer = self.create_printer(fd)
|
||||||
|
PyStdPrinter_Type = type(printer)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
PyStdPrinter_Type(fd)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -325,29 +325,6 @@ typedef struct {
|
||||||
int fd;
|
int fd;
|
||||||
} PyStdPrinter_Object;
|
} PyStdPrinter_Object;
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews)
|
|
||||||
{
|
|
||||||
PyStdPrinter_Object *self;
|
|
||||||
|
|
||||||
assert(type != NULL && type->tp_alloc != NULL);
|
|
||||||
|
|
||||||
self = (PyStdPrinter_Object *) type->tp_alloc(type, 0);
|
|
||||||
if (self != NULL) {
|
|
||||||
self->fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (PyObject *) self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
stdprinter_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"cannot create 'stderrprinter' instances");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyFile_NewStdPrinter(int fd)
|
PyFile_NewStdPrinter(int fd)
|
||||||
{
|
{
|
||||||
|
@ -390,7 +367,7 @@ stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encode Unicode to UTF-8/surrogateescape */
|
/* Encode Unicode to UTF-8/backslashreplace */
|
||||||
str = PyUnicode_AsUTF8AndSize(unicode, &n);
|
str = PyUnicode_AsUTF8AndSize(unicode, &n);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
@ -507,7 +484,7 @@ PyTypeObject PyStdPrinter_Type = {
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, /* tp_flags */
|
||||||
0, /* tp_doc */
|
0, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
|
@ -523,9 +500,9 @@ PyTypeObject PyStdPrinter_Type = {
|
||||||
0, /* tp_descr_get */
|
0, /* tp_descr_get */
|
||||||
0, /* tp_descr_set */
|
0, /* tp_descr_set */
|
||||||
0, /* tp_dictoffset */
|
0, /* tp_dictoffset */
|
||||||
stdprinter_init, /* tp_init */
|
0, /* tp_init */
|
||||||
PyType_GenericAlloc, /* tp_alloc */
|
PyType_GenericAlloc, /* tp_alloc */
|
||||||
stdprinter_new, /* tp_new */
|
0, /* tp_new */
|
||||||
PyObject_Del, /* tp_free */
|
PyObject_Del, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3007,7 +3007,7 @@ err_occurred:
|
||||||
/* Set up a preliminary stderr printer until we have enough
|
/* Set up a preliminary stderr printer until we have enough
|
||||||
infrastructure for the io module in place.
|
infrastructure for the io module in place.
|
||||||
|
|
||||||
Use UTF-8/surrogateescape and ignore EAGAIN errors. */
|
Use UTF-8/backslashreplace and ignore EAGAIN errors. */
|
||||||
static PyStatus
|
static PyStatus
|
||||||
_PySys_SetPreliminaryStderr(PyObject *sysdict)
|
_PySys_SetPreliminaryStderr(PyObject *sysdict)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue