mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	gh-124502: Add PyUnicode_Equal() function (#124504)
This commit is contained in:
		
							parent
							
								
									c5df1cb7bd
								
							
						
					
					
						commit
						a7f0727ca5
					
				
					 11 changed files with 111 additions and 2 deletions
				
			
		|  | @ -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) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								Doc/data/stable_abi.dat
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Doc/data/stable_abi.dat
									
										
									
										generated
									
									
									
								
							|  | @ -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 @@ def test_recover_error(self): | ||||||
| 
 | 
 | ||||||
|         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() | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								Lib/test/test_stable_abi_ctypes.py
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Lib/test/test_stable_abi_ctypes.py
									
										
									
										generated
									
									
									
								
							|  | @ -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) | ||||||
| { | { | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								PC/python3dll.c
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								PC/python3dll.c
									
										
									
										generated
									
									
									
								
							|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner