Skip to content

Commit 7055a43

Browse files
committed
Improve coverage of PyObject_Print
1 parent 29b391b commit 7055a43

File tree

2 files changed

+178
-0
lines changed

2 files changed

+178
-0
lines changed

Lib/test/test_class.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,77 @@ class A(0, 1, 2, 3, 4, 5, 6, 7, **d): pass
740740
class A(0, *range(1, 8), **d, foo='bar'): pass
741741
self.assertEqual(A, (tuple(range(8)), {'foo': 'bar'}))
742742

743+
def testPyObjectPrintObject(self):
744+
import os
745+
import test.support.os_helper as os_helper
746+
from test.support import import_helper
747+
748+
_testcapi = import_helper.import_module('_testcapi')
749+
750+
class PrintableObject:
751+
752+
def __repr__(self):
753+
return "spam spam spam"
754+
755+
def __str__(self):
756+
return "egg egg egg"
757+
758+
obj = PrintableObject()
759+
output_filename = os_helper.TESTFN
760+
# Test repr printing
761+
_testcapi.call_pyobject_print(obj, output_filename, False)
762+
with open(output_filename, 'r') as output_file:
763+
self.assertEqual(output_file.read(), repr(obj))
764+
# Test str printing
765+
_testcapi.call_pyobject_print(obj, output_filename, True)
766+
with open(output_filename, 'r') as output_file:
767+
self.assertEqual(output_file.read(), str(obj))
768+
769+
os.remove(output_filename)
770+
771+
def testPyObjectPrintNULL(self):
772+
import os
773+
import test.support.os_helper as os_helper
774+
from test.support import import_helper
775+
776+
_testcapi = import_helper.import_module('_testcapi')
777+
778+
output_filename = os_helper.TESTFN
779+
# Test repr printing
780+
_testcapi.pyobject_print_null(output_filename)
781+
with open(output_filename, 'r') as output_file:
782+
self.assertEqual(output_file.read(), '<nil>')
783+
784+
os.remove(output_filename)
785+
786+
def testPyObjectPrintNoRefObject(self):
787+
import os
788+
import test.support.os_helper as os_helper
789+
from test.support import import_helper
790+
791+
_testcapi = import_helper.import_module('_testcapi')
792+
793+
output_filename = os_helper.TESTFN
794+
# Test repr printing
795+
correct_output = _testcapi.pyobject_print_noref_object(output_filename)
796+
with open(output_filename, 'r') as output_file:
797+
self.assertEqual(output_file.read(), correct_output)
798+
799+
os.remove(output_filename)
800+
801+
def testPyObjectPrintOSError(self):
802+
import os
803+
import test.support.os_helper as os_helper
804+
from test.support import import_helper
805+
806+
_testcapi = import_helper.import_module('_testcapi')
807+
808+
output_filename = os_helper.TESTFN
809+
open(output_filename, "w+").close()
810+
with self.assertRaises(OSError):
811+
_testcapi.pyobject_print_os_error(output_filename)
812+
813+
os.remove(output_filename)
743814

744815
if __name__ == '__main__':
745816
unittest.main()

Modules/_testcapimodule.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,109 @@ pyobject_bytes_from_null(PyObject *self, PyObject *Py_UNUSED(ignored))
20012001
return PyObject_Bytes(NULL);
20022002
}
20032003

2004+
static PyObject *
2005+
call_pyobject_print(PyObject *self, PyObject * args)
2006+
{
2007+
PyObject *object;
2008+
PyObject *filename;
2009+
PyObject *print_raw;
2010+
FILE *fp;
2011+
int flags = 0;
2012+
2013+
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 3, 3, &object, &filename, &print_raw)) {
2014+
return NULL;
2015+
}
2016+
2017+
fp = _Py_fopen_obj(filename, "w+");
2018+
2019+
if (Py_IsTrue(print_raw)) {
2020+
flags = Py_PRINT_RAW;
2021+
}
2022+
2023+
if (PyObject_Print(object, fp, flags) < 0) {
2024+
return NULL;
2025+
}
2026+
2027+
fclose(fp);
2028+
2029+
Py_RETURN_NONE;
2030+
}
2031+
2032+
static PyObject *
2033+
pyobject_print_null(PyObject *self, PyObject *args)
2034+
{
2035+
PyObject *filename;
2036+
FILE *fp;
2037+
2038+
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
2039+
return NULL;
2040+
}
2041+
2042+
fp = _Py_fopen_obj(filename, "w+");
2043+
2044+
if (PyObject_Print(NULL, fp, 0) < 0) {
2045+
return NULL;
2046+
}
2047+
2048+
fclose(fp);
2049+
2050+
Py_RETURN_NONE;
2051+
}
2052+
2053+
static PyObject *
2054+
pyobject_print_noref_object(PyObject *self, PyObject *args)
2055+
{
2056+
PyObject *test_string;
2057+
PyObject *filename;
2058+
FILE *fp;
2059+
char correct_string[100];
2060+
2061+
test_string = PyUnicode_FromString("Spam spam spam");
2062+
2063+
Py_DECREF(test_string);
2064+
2065+
snprintf(correct_string, 100, "<refcnt %zd at %p>", Py_REFCNT(test_string), (void *)test_string);
2066+
2067+
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
2068+
return NULL;
2069+
}
2070+
2071+
fp = _Py_fopen_obj(filename, "w+");
2072+
2073+
if (PyObject_Print(test_string, fp, 0) < 0){
2074+
return NULL;
2075+
}
2076+
2077+
fclose(fp);
2078+
2079+
return PyUnicode_FromString(correct_string);
2080+
}
2081+
2082+
static PyObject *
2083+
pyobject_print_os_error(PyObject *self, PyObject *args)
2084+
{
2085+
PyObject *test_string;
2086+
PyObject *filename;
2087+
FILE *fp;
2088+
2089+
test_string = PyUnicode_FromString("Spam spam spam");
2090+
2091+
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
2092+
return NULL;
2093+
}
2094+
2095+
// open file in read mode to induce OSError
2096+
fp = _Py_fopen_obj(filename, "r");
2097+
2098+
if (PyObject_Print(test_string, fp, 0) < 0) {
2099+
return NULL;
2100+
}
2101+
2102+
fclose(fp);
2103+
2104+
Py_RETURN_NONE;
2105+
}
2106+
20042107
static PyObject *
20052108
raise_exception(PyObject *self, PyObject *args)
20062109
{
@@ -5969,6 +6072,10 @@ static PyMethodDef TestMethods[] = {
59696072
{"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS},
59706073
{"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS},
59716074
{"pyobject_bytes_from_null", pyobject_bytes_from_null, METH_NOARGS},
6075+
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
6076+
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
6077+
{"pyobject_print_noref_object", pyobject_print_noref_object, METH_VARARGS},
6078+
{"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS},
59726079
{"test_with_docstring", test_with_docstring, METH_NOARGS,
59736080
PyDoc_STR("This is a pretty normal docstring.")},
59746081
{"test_string_to_double", test_string_to_double, METH_NOARGS},

0 commit comments

Comments
 (0)