mirror of https://github.com/python/cpython
gh-124502: Add PyUnicode_Equal() function (#124504)
This commit is contained in:
parent
c5df1cb7bd
commit
a7f0727ca5
|
@ -1438,6 +1438,31 @@ They all return ``NULL`` or ``-1`` if an exception occurs.
|
|||
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)
|
||||
|
||||
|
|
|
@ -783,6 +783,7 @@ func,PyUnicode_DecodeUnicodeEscape,3.2,,
|
|||
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,,
|
||||
|
|
|
@ -687,6 +687,10 @@ New Features
|
|||
<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
|
||||
----------------------
|
||||
|
|
|
@ -966,6 +966,10 @@ PyAPI_FUNC(int) PyUnicode_EqualToUTF8(PyObject *, const char *);
|
|||
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
|
||||
|
|
|
@ -1903,6 +1903,39 @@ class PyUnicodeWriterFormatTest(unittest.TestCase):
|
|||
|
||||
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()
|
||||
|
|
|
@ -805,6 +805,7 @@ SYMBOL_NAMES = (
|
|||
"PyUnicode_DecodeUnicodeEscape",
|
||||
"PyUnicode_EncodeFSDefault",
|
||||
"PyUnicode_EncodeLocale",
|
||||
"PyUnicode_Equal",
|
||||
"PyUnicode_EqualToUTF8",
|
||||
"PyUnicode_EqualToUTF8AndSize",
|
||||
"PyUnicode_FSConverter",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Add :c:func:`PyUnicode_Equal` function to the limited C API: test if two
|
||||
strings are equal. Patch by Victor Stinner.
|
|
@ -2536,3 +2536,5 @@
|
|||
added = '3.14'
|
||||
[const.Py_TP_USE_SPEC]
|
||||
added = '3.14'
|
||||
[function.PyUnicode_Equal]
|
||||
added = '3.14'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#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"
|
||||
|
@ -1837,6 +1837,23 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
#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},
|
||||
|
@ -1924,6 +1941,7 @@ static PyMethodDef TestMethods[] = {
|
|||
{"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},
|
||||
};
|
||||
|
||||
|
|
|
@ -11001,6 +11001,24 @@ _PyUnicode_Equal(PyObject *str1, PyObject *str2)
|
|||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -717,6 +717,7 @@ EXPORT_FUNC(PyUnicode_DecodeUTF8Stateful)
|
|||
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)
|
||||
|
|
Loading…
Reference in New Issue