This function returns ``-1`` upon failure, so one should call
:c:func:`PyErr_Occurred` to check for errors.
+ .. seealso::
+
+ The :c:func:`PyUnicode_Equal` function.
+
+
+.. c:function:: int PyUnicode_Equal(PyObject *a, PyObject *b)
+
+ Test if two strings are equal:
+
+ * Return ``1`` if *a* is equal to *b*.
+ * Return ``0`` if *a* is not equal to *b*.
+ * Set a :exc:`TypeError` exception and return ``-1`` if *a* or *b* is not a
+ :class:`str` object.
+
+ The function always succeeds if *a* and *b* are :class:`str` objects.
+
+ The function works for :class:`str` subclasses, but does not honor custom
+ ``__eq__()`` method.
+
+ .. seealso::
+
+ The :c:func:`PyUnicode_Compare` function.
+
+ .. versionadded:: 3.14
+
.. c:function:: int PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *string, Py_ssize_t size)
func,PyUnicode_EncodeCodePage,3.7,on Windows,
func,PyUnicode_EncodeFSDefault,3.2,,
func,PyUnicode_EncodeLocale,3.7,,
+func,PyUnicode_Equal,3.14,,
func,PyUnicode_EqualToUTF8,3.13,,
func,PyUnicode_EqualToUTF8AndSize,3.13,,
func,PyUnicode_FSConverter,3.2,,
<https://peps.python.org/pep-0630/#type-checking>`__ mentioned in :pep:`630`
(:gh:`124153`).
+* Add :c:func:`PyUnicode_Equal` function to the limited C API:
+ test if two strings are equal.
+ (Contributed by Victor Stinner in :gh:`124502`.)
+
Porting to Python 3.14
----------------------
PyAPI_FUNC(int) PyUnicode_EqualToUTF8AndSize(PyObject *, const char *, Py_ssize_t);
#endif
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000
+PyAPI_FUNC(int) PyUnicode_Equal(PyObject *str1, PyObject *str2);
+#endif
+
/* Rich compare two strings and return one of the following:
- NULL in case an exception was raised
self.assertEqual(writer.finish(), 'Hello World.')
+ def test_unicode_equal(self):
+ unicode_equal = _testlimitedcapi.unicode_equal
+
+ def copy(text):
+ return text.encode().decode()
+
+ self.assertTrue(unicode_equal("", ""))
+ self.assertTrue(unicode_equal("abc", "abc"))
+ self.assertTrue(unicode_equal("abc", copy("abc")))
+ self.assertTrue(unicode_equal("\u20ac", copy("\u20ac")))
+ self.assertTrue(unicode_equal("\U0010ffff", copy("\U0010ffff")))
+
+ self.assertFalse(unicode_equal("abc", "abcd"))
+ self.assertFalse(unicode_equal("\u20ac", "\u20ad"))
+ self.assertFalse(unicode_equal("\U0010ffff", "\U0010fffe"))
+
+ # str subclass
+ self.assertTrue(unicode_equal("abc", Str("abc")))
+ self.assertTrue(unicode_equal(Str("abc"), "abc"))
+ self.assertFalse(unicode_equal("abc", Str("abcd")))
+ self.assertFalse(unicode_equal(Str("abc"), "abcd"))
+
+ # invalid type
+ for invalid_type in (b'bytes', 123, ("tuple",)):
+ with self.subTest(invalid_type=invalid_type):
+ with self.assertRaises(TypeError):
+ unicode_equal("abc", invalid_type)
+ with self.assertRaises(TypeError):
+ unicode_equal(invalid_type, "abc")
+
+ # CRASHES unicode_equal("abc", NULL)
+ # CRASHES unicode_equal(NULL, "abc")
+
if __name__ == "__main__":
unittest.main()
"PyUnicode_DecodeUnicodeEscape",
"PyUnicode_EncodeFSDefault",
"PyUnicode_EncodeLocale",
+ "PyUnicode_Equal",
"PyUnicode_EqualToUTF8",
"PyUnicode_EqualToUTF8AndSize",
"PyUnicode_FSConverter",
--- /dev/null
+Add :c:func:`PyUnicode_Equal` function to the limited C API: test if two
+strings are equal. Patch by Victor Stinner.
added = '3.14'
[const.Py_TP_USE_SPEC]
added = '3.14'
+[function.PyUnicode_Equal]
+ added = '3.14'
#include "pyconfig.h" // Py_GIL_DISABLED
#ifndef Py_GIL_DISABLED
- // Need limited C API 3.13 to test PyUnicode_EqualToUTF8()
-# define Py_LIMITED_API 0x030d0000
+ // Need limited C API 3.14 to test PyUnicode_Equal()
+# define Py_LIMITED_API 0x030e0000
#endif
#include "parts.h"
#undef CHECK_FORMAT_0
}
+
+/* Test PyUnicode_Equal() */
+static PyObject *
+unicode_equal(PyObject *module, PyObject *args)
+{
+ PyObject *str1, *str2;
+ if (!PyArg_ParseTuple(args, "OO", &str1, &str2)) {
+ return NULL;
+ }
+
+ NULLABLE(str1);
+ NULLABLE(str2);
+ RETURN_INT(PyUnicode_Equal(str1, str2));
+}
+
+
+
static PyMethodDef TestMethods[] = {
{"codec_incrementalencoder", codec_incrementalencoder, METH_VARARGS},
{"codec_incrementaldecoder", codec_incrementaldecoder, METH_VARARGS},
{"unicode_format", unicode_format, METH_VARARGS},
{"unicode_contains", unicode_contains, METH_VARARGS},
{"unicode_isidentifier", unicode_isidentifier, METH_O},
+ {"unicode_equal", unicode_equal, METH_VARARGS},
{NULL},
};
}
+int
+PyUnicode_Equal(PyObject *str1, PyObject *str2)
+{
+ if (!PyUnicode_Check(str1)) {
+ PyErr_Format(PyExc_TypeError,
+ "first argument must be str, not %T", str1);
+ return -1;
+ }
+ if (!PyUnicode_Check(str2)) {
+ PyErr_Format(PyExc_TypeError,
+ "second argument must be str, not %T", str2);
+ return -1;
+ }
+
+ return _PyUnicode_Equal(str1, str2);
+}
+
+
int
PyUnicode_Compare(PyObject *left, PyObject *right)
{
EXPORT_FUNC(PyUnicode_EncodeCodePage)
EXPORT_FUNC(PyUnicode_EncodeFSDefault)
EXPORT_FUNC(PyUnicode_EncodeLocale)
+EXPORT_FUNC(PyUnicode_Equal)
EXPORT_FUNC(PyUnicode_EqualToUTF8)
EXPORT_FUNC(PyUnicode_EqualToUTF8AndSize)
EXPORT_FUNC(PyUnicode_Find)