Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-94808:Improve coverage of PyObject_Print #98749

Merged
Next Next commit
Improve coverage of PyObject_Print
  • Loading branch information
MonadChains committed Oct 26, 2022
commit 7055a432f11ca811e32dbb85899d74dcba70f810
71 changes: 71 additions & 0 deletions Lib/test/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,77 @@ class A(0, 1, 2, 3, 4, 5, 6, 7, **d): pass
class A(0, *range(1, 8), **d, foo='bar'): pass
self.assertEqual(A, (tuple(range(8)), {'foo': 'bar'}))

def testPyObjectPrintObject(self):
import os
import test.support.os_helper as os_helper
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')

class PrintableObject:

def __repr__(self):
return "spam spam spam"

def __str__(self):
return "egg egg egg"

obj = PrintableObject()
output_filename = os_helper.TESTFN
# Test repr printing
_testcapi.call_pyobject_print(obj, output_filename, False)
with open(output_filename, 'r') as output_file:
self.assertEqual(output_file.read(), repr(obj))
# Test str printing
_testcapi.call_pyobject_print(obj, output_filename, True)
with open(output_filename, 'r') as output_file:
self.assertEqual(output_file.read(), str(obj))

os.remove(output_filename)

def testPyObjectPrintNULL(self):
import os
import test.support.os_helper as os_helper
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')

output_filename = os_helper.TESTFN
# Test repr printing
_testcapi.pyobject_print_null(output_filename)
with open(output_filename, 'r') as output_file:
self.assertEqual(output_file.read(), '<nil>')

os.remove(output_filename)

def testPyObjectPrintNoRefObject(self):
import os
import test.support.os_helper as os_helper
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')

output_filename = os_helper.TESTFN
# Test repr printing
correct_output = _testcapi.pyobject_print_noref_object(output_filename)
with open(output_filename, 'r') as output_file:
self.assertEqual(output_file.read(), correct_output)

os.remove(output_filename)

def testPyObjectPrintOSError(self):
import os
import test.support.os_helper as os_helper
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')

output_filename = os_helper.TESTFN
open(output_filename, "w+").close()
with self.assertRaises(OSError):
_testcapi.pyobject_print_os_error(output_filename)

os.remove(output_filename)

if __name__ == '__main__':
unittest.main()
107 changes: 107 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2001,6 +2001,109 @@ pyobject_bytes_from_null(PyObject *self, PyObject *Py_UNUSED(ignored))
return PyObject_Bytes(NULL);
}

static PyObject *
call_pyobject_print(PyObject *self, PyObject * args)
{
PyObject *object;
PyObject *filename;
PyObject *print_raw;
FILE *fp;
int flags = 0;

if (!PyArg_UnpackTuple(args, "call_pyobject_print", 3, 3, &object, &filename, &print_raw)) {
return NULL;
}

fp = _Py_fopen_obj(filename, "w+");

if (Py_IsTrue(print_raw)) {
flags = Py_PRINT_RAW;
}

if (PyObject_Print(object, fp, flags) < 0) {
return NULL;
}

fclose(fp);

Py_RETURN_NONE;
}

static PyObject *
pyobject_print_null(PyObject *self, PyObject *args)
{
PyObject *filename;
FILE *fp;

if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
return NULL;
}

fp = _Py_fopen_obj(filename, "w+");

if (PyObject_Print(NULL, fp, 0) < 0) {
return NULL;
}

fclose(fp);

Py_RETURN_NONE;
}

static PyObject *
pyobject_print_noref_object(PyObject *self, PyObject *args)
{
PyObject *test_string;
PyObject *filename;
FILE *fp;
char correct_string[100];

test_string = PyUnicode_FromString("Spam spam spam");

Py_DECREF(test_string);

snprintf(correct_string, 100, "<refcnt %zd at %p>", Py_REFCNT(test_string), (void *)test_string);

if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
return NULL;
}

fp = _Py_fopen_obj(filename, "w+");

if (PyObject_Print(test_string, fp, 0) < 0){
return NULL;
}

fclose(fp);

return PyUnicode_FromString(correct_string);
}

static PyObject *
pyobject_print_os_error(PyObject *self, PyObject *args)
{
PyObject *test_string;
PyObject *filename;
FILE *fp;

test_string = PyUnicode_FromString("Spam spam spam");

if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
return NULL;
}

// open file in read mode to induce OSError
fp = _Py_fopen_obj(filename, "r");

if (PyObject_Print(test_string, fp, 0) < 0) {
return NULL;
}

fclose(fp);

Py_RETURN_NONE;
}

static PyObject *
raise_exception(PyObject *self, PyObject *args)
{
Expand Down Expand Up @@ -5969,6 +6072,10 @@ static PyMethodDef TestMethods[] = {
{"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS},
{"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS},
{"pyobject_bytes_from_null", pyobject_bytes_from_null, METH_NOARGS},
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
{"pyobject_print_noref_object", pyobject_print_noref_object, METH_VARARGS},
{"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS},
{"test_with_docstring", test_with_docstring, METH_NOARGS,
PyDoc_STR("This is a pretty normal docstring.")},
{"test_string_to_double", test_string_to_double, METH_NOARGS},
Expand Down