Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Doc/c-api/file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,12 @@ the :mod:`io` APIs instead.

Write object *obj* to file object *p*. The only supported flag for *flags* is
:c:macro:`Py_PRINT_RAW`; if given, the :func:`str` of the object is written
instead of the :func:`repr`. Return ``0`` on success or ``-1`` on failure; the
appropriate exception will be set.
instead of the :func:`repr`.

If *obj* is ``NULL``, write string ``"<NULL>"``.

Return ``0`` on success or ``-1`` on failure; the
appropriate exception will be set.

.. c:function:: int PyFile_WriteString(const char *s, PyObject *p)

Expand Down
8 changes: 8 additions & 0 deletions Doc/c-api/object.rst
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ Object Protocol
representation on success, ``NULL`` on failure. This is the equivalent of the
Python expression ``repr(o)``. Called by the :func:`repr` built-in function.

If argument is ``NULL``, return string ``'<NULL>'``.

.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
Expand All @@ -377,6 +379,8 @@ Object Protocol
a string similar to that returned by :c:func:`PyObject_Repr` in Python 2.
Called by the :func:`ascii` built-in function.

If argument is ``NULL``, return string ``'<NULL>'``.

.. index:: string; PyObject_Str (C function)


Expand All @@ -387,6 +391,8 @@ Object Protocol
Python expression ``str(o)``. Called by the :func:`str` built-in function
and, therefore, by the :func:`print` function.

If argument is ``NULL``, return string ``'<NULL>'``.

.. versionchanged:: 3.4
This function now includes a debug assertion to help ensure that it
does not silently discard an active exception.
Expand All @@ -402,6 +408,8 @@ Object Protocol
a TypeError is raised when *o* is an integer instead of a zero-initialized
bytes object.

If argument is ``NULL``, return :class:`bytes` object ``b'<NULL>'``.


.. c:function:: int PyObject_IsSubclass(PyObject *derived, PyObject *cls)

Expand Down
2 changes: 2 additions & 0 deletions Doc/c-api/unicode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,8 @@ object.

Call :c:func:`PyObject_Repr` on *obj* and write the output into *writer*.

If *obj* is ``NULL``, write string ``"<NULL>"`` into *writer*.

On success, return ``0``.
On error, set an exception, leave the writer unchanged, and return ``-1``.

Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_capi/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ def test_list_extend(self):
# CRASHES list_extend(NULL, [])
# CRASHES list_extend([], NULL)

def test_uninitialized_list_repr(self):
lst = _testlimitedcapi.list_new(3)
self.assertEqual(repr(lst), '[<NULL>, <NULL>, <NULL>]')


if __name__ == "__main__":
unittest.main()
5 changes: 5 additions & 0 deletions Lib/test/test_capi/test_tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def test_tuple_new(self):
self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN)
self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX)


def test_tuple_fromarray(self):
# Test PyTuple_FromArray()
tuple_fromarray = _testcapi.tuple_fromarray
Expand Down Expand Up @@ -357,6 +358,10 @@ def my_iter():
self.assertEqual(tuple(my_iter()), (TAG, *range(10)))
self.assertEqual(tuples, [])

def test_uninitialized_tuple_repr(self):
tup = _testlimitedcapi.tuple_new(3)
self.assertEqual(repr(tup), '(<NULL>, <NULL>, <NULL>)')


if __name__ == "__main__":
unittest.main()
7 changes: 7 additions & 0 deletions Lib/test/test_capi/test_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -1779,6 +1779,13 @@ def test_basic(self):
self.assertEqual(writer.finish(),
"var=long value 'repr'")

def test_repr_null(self):
writer = self.create_writer(0)
writer.write_utf8(b'var=', -1)
writer.write_repr(NULL)
self.assertEqual(writer.finish(),
"var=<NULL>")

def test_utf8(self):
writer = self.create_writer(0)
writer.write_utf8(b"ascii", -1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:c:func:`PyUnicodeWriter_WriteRepr` now supports ``NULL`` argument.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :meth:`!list.__repr__` for lists containing ``NULL``\ s.
1 change: 1 addition & 0 deletions Modules/_testcapi/unicode.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ writer_write_repr(PyObject *self_raw, PyObject *args)
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
NULLABLE(obj);

if (PyUnicodeWriter_WriteRepr(self->writer, obj) < 0) {
return NULL;
Expand Down
2 changes: 1 addition & 1 deletion Objects/listobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ list_repr_impl(PyListObject *v)
so must refetch the list size on each iteration. */
for (Py_ssize_t i = 0; i < Py_SIZE(v); ++i) {
/* Hold a strong reference since repr(item) can mutate the list */
item = Py_NewRef(v->ob_item[i]);
item = Py_XNewRef(v->ob_item[i]);

if (i > 0) {
if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
Expand Down
4 changes: 4 additions & 0 deletions Objects/unicode_writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
int
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
{
if (obj == NULL) {
return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer, "<NULL>", 6);
}

if (Py_TYPE(obj) == &PyLong_Type) {
return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
}
Expand Down
Loading