diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 0aa6bcecda5..c6b097dae43 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -58,6 +58,13 @@ the constructor functions work with any iterable Python object. .. versionadded:: 2.6 +.. cfunction:: int PyFrozenSet_Check(PyObject *p) + + Return true if *p* is a :class:`frozenset` object or an instance of a + subtype. + + .. versionadded:: 2.6 + .. cfunction:: int PyAnySet_Check(PyObject *p) Return true if *p* is a :class:`set` object, a :class:`frozenset` object, or an diff --git a/Include/setobject.h b/Include/setobject.h index fc32367724e..102796d315f 100644 --- a/Include/setobject.h +++ b/Include/setobject.h @@ -74,7 +74,11 @@ PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; PyType_IsSubtype(Py_TYPE(ob), &PySet_Type) || \ PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) #define PySet_Check(ob) \ - (Py_TYPE(ob) == &PySet_Type || PyType_IsSubtype(Py_TYPE(ob), &PySet_Type)) + (Py_TYPE(ob) == &PySet_Type || \ + PyType_IsSubtype(Py_TYPE(ob), &PySet_Type)) +#define PyFrozenSet_Check(ob) \ + (Py_TYPE(ob) == &PyFrozenSet_Type || \\ + PyType_IsSubtype(Py_TYPE(ob), &PyFrozenSet_Type)) PyAPI_FUNC(PyObject *) PySet_New(PyObject *); PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *); diff --git a/Misc/NEWS b/Misc/NEWS index 8dacce0e370..629172957da 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1471,6 +1471,12 @@ Build C API ----- +- ``PySet_Add()`` can now modify a newly created frozenset. Similarly to + ``PyTuple_SetItem``, it can be used to populate a brand new frozenset; but + it does not steal a reference to the added item. + +- Added ``PySet_Check()`` and ``PyFrozenSet_Check()`` to the set API. + - Backport of PyUnicode_FromString(), _FromStringAndSize(), _Format and _FormatV from Python 3.0. Made PyLong_AsSsize_t and PyLong_FromSsize_t public functions. diff --git a/Objects/setobject.c b/Objects/setobject.c index 4b4213ab8a3..53d284f6ccc 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2188,7 +2188,8 @@ PySet_Discard(PyObject *set, PyObject *key) int PySet_Add(PyObject *anyset, PyObject *key) { - if (!PyAnySet_Check(anyset)) { + if (!PySet_Check(anyset) && + (!PyFrozenSet_Check(anyset) || Py_REFCNT(anyset) != 1)) { PyErr_BadInternalCall(); return -1; } @@ -2306,6 +2307,10 @@ test_c_api(PySetObject *so) f = PyFrozenSet_New(dup); assertRaises(PySet_Clear(f) == -1, PyExc_SystemError); assertRaises(_PySet_Update(f, dup) == -1, PyExc_SystemError); + assert(PySet_Add(f, elem) == 0); + Py_INCREF(f); + assertRaises(PySet_Add(f, elem) == -1, PyExc_SystemError); + Py_DECREF(f); Py_DECREF(f); /* Exercise direct iteration */