Repository: cython/cython

Issue:
[BUG] `Py_UNICODE` is deprecated Python 3.13
### Describe the bug

While compiling using `3.13.0a3` getting error:

``` bash
Compiling src/liburing/file.pyx because it changed.
Compiling src/liburing/helper.pyx because it changed.                                                 
Compiling src/liburing/io_uring.pyx because it changed.    
Compiling src/liburing/liburing.pyx because it changed.
Compiling src/liburing/type.pyx because it changed.
Compiling src/liburing/version.pyx because it changed.                                               
[1/6] Cythonizing src/liburing/file.pyx
[2/6] Cythonizing src/liburing/helper.pyx                                                            
[3/6] Cythonizing src/liburing/io_uring.pyx                                                          
[4/6] Cythonizing src/liburing/liburing.pyx                                                          
[5/6] Cythonizing src/liburing/type.pyx                                                              
[6/6] Cythonizing src/liburing/version.pyx                                                           
running build_ext
building 'liburing.file' extension                                                                    
building 'liburing.helper' extension
creating build                            
creating build
creating build/temp.linux-x86_64-cpython-313
creating build/temp.linux-x86_64-cpython-313
building 'liburing.io_uring' extension
building 'liburing.liburing' extension
creating build/temp.linux-x86_64-cpython-313/src
building 'liburing.type' extension
creating build/temp.linux-x86_64-cpython-313/src
creating build/temp.linux-x86_64-cpython-313/src
building 'liburing.version' extension
creating build/temp.linux-x86_64-cpython-313/src/liburing
creating build/temp.linux-x86_64-cpython-313/src/liburing
creating build/temp.linux-x86_64-cpython-313/src/liburing
creating build/temp.linux-x86_64-cpython-313/src/liburing
creating build/temp.linux-x86_64-cpython-313/src/liburing
creating build/temp.linux-x86_64-cpython-313/src/liburing
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DCYTHON_TRACE_NOGIL=1 -Ilibs/liburing/src/include -I/opt/python/3.13/include/python3.13 -c src/liburing/io_uring.c -o build/temp.linux-x86_64-cpython-313/src/liburing/io_uring.o -Og
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DCYTHON_TRACE_NOGIL=1 -Ilibs/liburing/src/include -I/opt/python/3.13/include/python3.13 -c src/liburing/type.c -o build/temp.linux-x86_64-cpython-313/src/liburing/type.o -Og
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DCYTHON_TRACE_NOGIL=1 -Ilibs/liburing/src/include -I/opt/python/3.13/include/python3.13 -c src/liburing/helper.c -o build/temp.linux-x86_64-cpython-313/src/liburing/helper.o -Og
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DCYTHON_TRACE_NOGIL=1 -Ilibs/liburing/src/include -I/opt/python/3.13/include/python3.13 -c src/liburing/file.c -o build/temp.linux-x86_64-cpython-313/src/liburing/file.o -Og
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DCYTHON_TRACE_NOGIL=1 -Ilibs/liburing/src/include -I/opt/python/3.13/include/python3.13 -c src/liburing/liburing.c -o build/temp.linux-x86_64-cpython-313/src/liburing/liburing.o -Og
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -DCYTHON_TRACE_NOGIL=1 -Ilibs/liburing/src/include -I/opt/python/3.13/include/python3.13 -c src/liburing/version.c -o build/temp.linux-x86_64-cpython-313/src/liburing/version.o -Og
src/liburing/helper.c:1308:1: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]         
 1308 | static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)                      
      | ^~~~~~                                                                                        
src/liburing/helper.c: In function ‘__Pyx_Py_UNICODE_strlen’:                                         
src/liburing/helper.c:1310:5: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]         
 1310 |     const Py_UNICODE *u_end = u;                                                              
      |     ^~~~~                                                                                     
src/liburing/type.c:1322:1: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]           
 1322 | static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)                      
      | ^~~~~~                                                                                        
src/liburing/type.c: In function ‘__Pyx_Py_UNICODE_strlen’:                                           
src/liburing/type.c:1324:5: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]           
 1324 |     const Py_UNICODE *u_end = u;                                                              
      |     ^~~~~                                                                                     
src/liburing/io_uring.c:1324:1: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]       
 1324 | static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)                      
      | ^~~~~~                                                                                        
src/liburing/io_uring.c: In function ‘__Pyx_Py_UNICODE_strlen’:                                       
src/liburing/io_uring.c:1326:5: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]       
 1326 |     const Py_UNICODE *u_end = u;                                                              
      |     ^~~~~                                                                                     
src/liburing/version.c:1321:1: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]        
 1321 | static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)                      
      | ^~~~~~                                                                                        
src/liburing/version.c: In function ‘__Pyx_Py_UNICODE_strlen’:                                        
src/liburing/version.c:1323:5: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]        
 1323 |     const Py_UNICODE *u_end = u;                                                              
      |     ^~~~~                                                                                     
src/liburing/file.c:1324:1: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]           
 1324 | static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)                      
      | ^~~~~~                                                                                        
src/liburing/file.c: In function ‘__Pyx_Py_UNICODE_strlen’:                                           
src/liburing/file.c:1326:5: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]           
 1326 |     const Py_UNICODE *u_end = u;                                                              
      |     ^~~~~                                                                                     
src/liburing/liburing.c:1325:1: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]       
 1325 | static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u)                      
      | ^~~~~~                                                                                        
src/liburing/liburing.c: In function ‘__Pyx_Py_UNICODE_strlen’:                                       
src/liburing/liburing.c:1327:5: warning: ‘Py_UNICODE’ is deprecated [-Wdeprecated-declarations]       
 1327 |     const Py_UNICODE *u_end = u;                                                              
      |     ^~~~~                                                                                     
creating build/lib.linux-x86_64-cpython-313
creating build/lib.linux-x86_64-cpython-313/liburing
gcc -shared build/temp.linux-x86_64-cpython-313/src/liburing/version.o -Llibs/liburing/src -luring -o build/lib.linux-x86_64-cpython-313/liburing/version.cpython-313-x86_64-linux-gnu.so
gcc -shared build/temp.linux-x86_64-cpython-313/src/liburing/helper.o -Llibs/liburing/src -luring -o build/lib.linux-x86_64-cpython-313/liburing/helper.cpython-313-x86_64-linux-gnu.so
gcc -shared build/temp.linux-x86_64-cpython-313/src/liburing/file.o -Llibs/liburing/src -luring -o build/lib.linux-x86_64-cpython-313/liburing/file.cpython-313-x86_64-linux-gnu.so
gcc -shared build/temp.linux-x86_64-cpython-313/src/liburing/liburing.o -Llibs/liburing/src -luring -o build/lib.linux-x86_64-cpython-313/liburing/liburing.cpython-313-x86_64-linux-gnu.so
gcc -shared build/temp.linux-x86_64-cpython-313/src/liburing/type.o -Llibs/liburing/src -luring -o build/lib.linux-x86_64-cpython-313/liburing/type.cpython-313-x86_64-linux-gnu.so
gcc -shared build/temp.linux-x86_64-cpython-313/src/liburing/io_uring.o -Llibs/liburing/src -luring -o build/lib.linux-x86_64-cpython-313/liburing/io_uring.cpython-313-x86_64-linux-gnu.so
copying build/lib.linux-x86_64-cpython-313/liburing/file.cpython-313-x86_64-linux-gnu.so -> src/liburing
copying build/lib.linux-x86_64-cpython-313/liburing/helper.cpython-313-x86_64-linux-gnu.so -> src/liburing
copying build/lib.linux-x86_64-cpython-313/liburing/io_uring.cpython-313-x86_64-linux-gnu.so -> src/liburing
copying build/lib.linux-x86_64-cpython-313/liburing/liburing.cpython-313-x86_64-linux-gnu.so -> src/liburing
copying build/lib.linux-x86_64-cpython-313/liburing/type.cpython-313-x86_64-linux-gnu.so -> src/liburing
copying build/lib.linux-x86_64-cpython-313/liburing/version.cpython-313-x86_64-linux-gnu.so -> src/liburing
```
Works fine for `3.8 - 3.12`

According to https://docs.python.org/3.13/c-api/unicode.html 
> "Note:
The [Py_UNICODE](https://docs.python.org/3.13/c-api/unicode.html#c.Py_UNICODE) representation has been removed since Python 3.12 with deprecated APIs. See [PEP 623](https://peps.python.org/pep-0623/) for more information."

### Code to reproduce the behaviour:

```cython
# example code
```


### Expected behaviour

_No response_

### OS

Linux

### Python version

3.13.0a3

### Cython version

3.0.8

### Additional context

_No response_


Discussion:
Thanks for the report. The functions in question are unused in your file, so you can safely ignore the warning for now. But we should fix it.

`__Pyx_Py_UNICODE_strlen` looks to be defined as an inline function in the standard `TypeConversions` utility code that we include everywhere.

There's also an alternative limited api definition that we should probably just remove (because `Py_UNICODE` was never part of the limited API so there's little reason to support that).
My suggestion (which I don't have time to implement right now, but can have a go next week if it's still pending is):

wrap these functions in `#ifdef __Pyx_Py_UNICODE_USED` and `define __Pyx_Py_UNICODE_USED` used if we generate any of the utility code that requires it.
Thanks @da-woods,

Just warning, there is no actual error, codes/test works fine. I reported so `Cython` is ready for `Python 3.13` release.

From what I can tell this warning is raised wherever `str`, `' "` and doc string `''' """` are used.


Resolving patch:
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -5499,6 +5499,8 @@ def generate_result_code(self, code):
                         base_result,
                         start_code,
                         code.error_goto_if_null(result, self.pos)))
+                code.globalstate.use_utility_code(
+                    UtilityCode.load_cached("pyunicode_from_unicode", "StringTools.c"))
             else:
                 code.putln(
                     "%s = __Pyx_PyUnicode_FromUnicodeAndLength(%s + %s, %s - %s); %s" % (
@@ -5508,6 +5510,8 @@ def generate_result_code(self, code):
                         stop_code,
                         start_code,
                         code.error_goto_if_null(result, self.pos)))
+                code.globalstate.use_utility_code(
+                    UtilityCode.load_cached("pyunicode_from_unicode", "StringTools.c"))
 
         elif self.base.type is unicode_type:
             code.globalstate.use_utility_code(
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -1683,15 +1683,25 @@ class CType(PyrexType):
     #
 
     to_py_function = None
+    to_py_utility_code = None
     from_py_function = None
+    from_py_utility_code = None
     exception_value = None
     exception_check = 1
 
     def create_to_py_utility_code(self, env):
-        return self.to_py_function is not None
+        if self.to_py_function is not None:
+            if self.to_py_utility_code is not None:
+                env.use_utility_code(self.to_py_utility_code)
+            return True
+        return False
 
     def create_from_py_utility_code(self, env):
-        return self.from_py_function is not None
+        if self.from_py_function is not None:
+            if self.from_py_utility_code is not None:
+                env.use_utility_code(self.from_py_utility_code)
+            return True
+        return False
 
     def can_coerce_to_pyobject(self, env):
         return self.create_to_py_utility_code(env)
@@ -2679,6 +2689,8 @@ def __init__(self, base_type):
             self.exception_value = "NULL"
         elif self.is_pyunicode_ptr and not base_type.is_error:
             self.to_py_function = "__Pyx_PyUnicode_FromUnicode"
+            self.to_py_utility_code = UtilityCode.load_cached(
+                "pyunicode_from_unicode", "StringTools.c")
             if self.is_ptr:
                 self.from_py_function = "__Pyx_PyUnicode_AsUnicode"
             self.exception_value = "NULL"


Test patch: