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
|
This function returns ``-1`` upon failure, so one should call
|
||||||
:c:func:`PyErr_Occurred` to check for errors.
|
: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)
|
.. 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_EncodeCodePage,3.7,on Windows,
|
||||||
func,PyUnicode_EncodeFSDefault,3.2,,
|
func,PyUnicode_EncodeFSDefault,3.2,,
|
||||||
func,PyUnicode_EncodeLocale,3.7,,
|
func,PyUnicode_EncodeLocale,3.7,,
|
||||||
|
func,PyUnicode_Equal,3.14,,
|
||||||
func,PyUnicode_EqualToUTF8,3.13,,
|
func,PyUnicode_EqualToUTF8,3.13,,
|
||||||
func,PyUnicode_EqualToUTF8AndSize,3.13,,
|
func,PyUnicode_EqualToUTF8AndSize,3.13,,
|
||||||
func,PyUnicode_FSConverter,3.2,,
|
func,PyUnicode_FSConverter,3.2,,
|
||||||
|
|
|
@ -687,6 +687,10 @@ New Features
|
||||||
<https://peps.python.org/pep-0630/#type-checking>`__ mentioned in :pep:`630`
|
<https://peps.python.org/pep-0630/#type-checking>`__ mentioned in :pep:`630`
|
||||||
(:gh:`124153`).
|
(: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
|
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);
|
PyAPI_FUNC(int) PyUnicode_EqualToUTF8AndSize(PyObject *, const char *, Py_ssize_t);
|
||||||
#endif
|
#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:
|
/* Rich compare two strings and return one of the following:
|
||||||
|
|
||||||
- NULL in case an exception was raised
|
- NULL in case an exception was raised
|
||||||
|
|
|
@ -1903,6 +1903,39 @@ class PyUnicodeWriterFormatTest(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual(writer.finish(), 'Hello World.')
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -805,6 +805,7 @@ SYMBOL_NAMES = (
|
||||||
"PyUnicode_DecodeUnicodeEscape",
|
"PyUnicode_DecodeUnicodeEscape",
|
||||||
"PyUnicode_EncodeFSDefault",
|
"PyUnicode_EncodeFSDefault",
|
||||||
"PyUnicode_EncodeLocale",
|
"PyUnicode_EncodeLocale",
|
||||||
|
"PyUnicode_Equal",
|
||||||
"PyUnicode_EqualToUTF8",
|
"PyUnicode_EqualToUTF8",
|
||||||
"PyUnicode_EqualToUTF8AndSize",
|
"PyUnicode_EqualToUTF8AndSize",
|
||||||
"PyUnicode_FSConverter",
|
"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'
|
added = '3.14'
|
||||||
[const.Py_TP_USE_SPEC]
|
[const.Py_TP_USE_SPEC]
|
||||||
added = '3.14'
|
added = '3.14'
|
||||||
|
[function.PyUnicode_Equal]
|
||||||
|
added = '3.14'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "pyconfig.h" // Py_GIL_DISABLED
|
#include "pyconfig.h" // Py_GIL_DISABLED
|
||||||
#ifndef Py_GIL_DISABLED
|
#ifndef Py_GIL_DISABLED
|
||||||
// Need limited C API 3.13 to test PyUnicode_EqualToUTF8()
|
// Need limited C API 3.14 to test PyUnicode_Equal()
|
||||||
# define Py_LIMITED_API 0x030d0000
|
# define Py_LIMITED_API 0x030e0000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "parts.h"
|
#include "parts.h"
|
||||||
|
@ -1837,6 +1837,23 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
#undef CHECK_FORMAT_0
|
#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[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"codec_incrementalencoder", codec_incrementalencoder, METH_VARARGS},
|
{"codec_incrementalencoder", codec_incrementalencoder, METH_VARARGS},
|
||||||
{"codec_incrementaldecoder", codec_incrementaldecoder, METH_VARARGS},
|
{"codec_incrementaldecoder", codec_incrementaldecoder, METH_VARARGS},
|
||||||
|
@ -1924,6 +1941,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"unicode_format", unicode_format, METH_VARARGS},
|
{"unicode_format", unicode_format, METH_VARARGS},
|
||||||
{"unicode_contains", unicode_contains, METH_VARARGS},
|
{"unicode_contains", unicode_contains, METH_VARARGS},
|
||||||
{"unicode_isidentifier", unicode_isidentifier, METH_O},
|
{"unicode_isidentifier", unicode_isidentifier, METH_O},
|
||||||
|
{"unicode_equal", unicode_equal, METH_VARARGS},
|
||||||
{NULL},
|
{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
|
int
|
||||||
PyUnicode_Compare(PyObject *left, PyObject *right)
|
PyUnicode_Compare(PyObject *left, PyObject *right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -717,6 +717,7 @@ EXPORT_FUNC(PyUnicode_DecodeUTF8Stateful)
|
||||||
EXPORT_FUNC(PyUnicode_EncodeCodePage)
|
EXPORT_FUNC(PyUnicode_EncodeCodePage)
|
||||||
EXPORT_FUNC(PyUnicode_EncodeFSDefault)
|
EXPORT_FUNC(PyUnicode_EncodeFSDefault)
|
||||||
EXPORT_FUNC(PyUnicode_EncodeLocale)
|
EXPORT_FUNC(PyUnicode_EncodeLocale)
|
||||||
|
EXPORT_FUNC(PyUnicode_Equal)
|
||||||
EXPORT_FUNC(PyUnicode_EqualToUTF8)
|
EXPORT_FUNC(PyUnicode_EqualToUTF8)
|
||||||
EXPORT_FUNC(PyUnicode_EqualToUTF8AndSize)
|
EXPORT_FUNC(PyUnicode_EqualToUTF8AndSize)
|
||||||
EXPORT_FUNC(PyUnicode_Find)
|
EXPORT_FUNC(PyUnicode_Find)
|
||||||
|
|
Loading…
Reference in New Issue