- better finalizer, that actually calls PyBuffer_Release
- improved input parameter handling for common routines
- added support for copying data to/from large Python buffers

fixes https://github.com/pythonnet/pythonnet/issues/1556
This commit is contained in:
Victor Nova 2022-01-05 18:58:21 -08:00 коммит произвёл Victor
Родитель efad01cf2e
Коммит 88850f5dc9
6 изменённых файлов: 161 добавлений и 64 удалений

Просмотреть файл

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using NUnit.Framework; using NUnit.Framework;
using Python.Runtime; using Python.Runtime;
@ -24,24 +25,20 @@ namespace Python.EmbeddingTest {
public void TestBufferWrite() public void TestBufferWrite()
{ {
string bufferTestString = "hello world! !$%&/()=?"; string bufferTestString = "hello world! !$%&/()=?";
string bufferTestString2 = "h llo world! !$%&/()=?";
using (Py.GIL()) using var _ = Py.GIL();
using var pythonArray = ByteArrayFromAsciiString(bufferTestString);
using (PyBuffer buf = pythonArray.GetBuffer(PyBUF.WRITABLE))
{ {
using (var scope = Py.CreateScope()) byte[] managedArray = { (byte)' ' };
{ buf.Write(managedArray, 0, managedArray.Length, 1);
scope.Exec($"arr = bytearray({bufferTestString.Length})");
PyObject pythonArray = scope.Get("arr");
byte[] managedArray = new UTF8Encoding().GetBytes(bufferTestString);
using (PyBuffer buf = pythonArray.GetBuffer())
{
buf.Write(managedArray, 0, managedArray.Length);
}
string result = scope.Eval("arr.decode('utf-8')").ToString();
Assert.IsTrue(result == bufferTestString);
}
} }
string result = pythonArray.InvokeMethod("decode", "utf-8".ToPython()).As<string>();
Assert.IsTrue(result == bufferTestString2);
} }
[Test] [Test]
@ -49,23 +46,19 @@ namespace Python.EmbeddingTest {
{ {
string bufferTestString = "hello world! !$%&/()=?"; string bufferTestString = "hello world! !$%&/()=?";
using (Py.GIL()) using var _ = Py.GIL();
using var pythonArray = ByteArrayFromAsciiString(bufferTestString);
byte[] managedArray = new byte[bufferTestString.Length];
using (PyBuffer buf = pythonArray.GetBuffer())
{ {
using (var scope = Py.CreateScope()) managedArray[0] = (byte)' ';
{ buf.Read(managedArray, 1, managedArray.Length - 1, 1);
scope.Exec($"arr = b'{bufferTestString}'");
PyObject pythonArray = scope.Get("arr");
byte[] managedArray = new byte[bufferTestString.Length];
using (PyBuffer buf = pythonArray.GetBuffer())
{
buf.Read(managedArray, 0, managedArray.Length);
}
string result = new UTF8Encoding().GetString(managedArray);
Assert.IsTrue(result == bufferTestString);
}
} }
string result = new UTF8Encoding().GetString(managedArray);
Assert.IsTrue(result == " " + bufferTestString.Substring(1));
} }
[Test] [Test]
@ -77,5 +70,56 @@ namespace Python.EmbeddingTest {
Assert.AreEqual(1, mem[(0, 0).ToPython()].As<int>()); Assert.AreEqual(1, mem[(0, 0).ToPython()].As<int>());
Assert.AreEqual(array[1,0], mem[(1, 0).ToPython()].As<int>()); Assert.AreEqual(array[1,0], mem[(1, 0).ToPython()].As<int>());
} }
[Test]
public void RefCount()
{
using var _ = Py.GIL();
using var arr = ByteArrayFromAsciiString("hello world! !$%&/()=?");
Assert.AreEqual(1, arr.Refcount);
using (PyBuffer buf = arr.GetBuffer())
{
Assert.AreEqual(2, arr.Refcount);
}
Assert.AreEqual(1, arr.Refcount);
}
[Test]
public void Finalization()
{
if (Type.GetType("Mono.Runtime") is not null)
{
Assert.Inconclusive("test unreliable in Mono");
return;
}
using var _ = Py.GIL();
using var arr = ByteArrayFromAsciiString("hello world! !$%&/()=?");
Assert.AreEqual(1, arr.Refcount);
MakeBufAndLeak(arr);
GC.Collect();
GC.WaitForPendingFinalizers();
Finalizer.Instance.Collect();
Assert.AreEqual(1, arr.Refcount);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void MakeBufAndLeak(PyObject bufProvider)
{
PyBuffer buf = bufProvider.GetBuffer();
}
static PyObject ByteArrayFromAsciiString(string str)
{
using var scope = Py.CreateScope();
return Runtime.Runtime.PyByteArray_FromStringAndSize(str).MoveToPyObject();
}
} }
} }

Просмотреть файл

@ -8,10 +8,11 @@ namespace Python.Runtime
internal struct Py_buffer { internal struct Py_buffer {
public IntPtr buf; public IntPtr buf;
public IntPtr obj; /* owned reference */ public IntPtr obj; /* owned reference */
/// <summary>Buffer size in bytes</summary>
[MarshalAs(UnmanagedType.SysInt)] [MarshalAs(UnmanagedType.SysInt)]
public IntPtr len; public nint len;
[MarshalAs(UnmanagedType.SysInt)] [MarshalAs(UnmanagedType.SysInt)]
public IntPtr itemsize; /* This is Py_ssize_t so it can be public nint itemsize; /* This is Py_ssize_t so it can be
pointed to by strides in simple case.*/ pointed to by strides in simple case.*/
[MarshalAs(UnmanagedType.Bool)] [MarshalAs(UnmanagedType.Bool)]
public bool _readonly; public bool _readonly;

Просмотреть файл

@ -43,6 +43,7 @@ namespace Python.Runtime
private ConcurrentQueue<PendingFinalization> _objQueue = new(); private ConcurrentQueue<PendingFinalization> _objQueue = new();
private readonly ConcurrentQueue<PendingFinalization> _derivedQueue = new(); private readonly ConcurrentQueue<PendingFinalization> _derivedQueue = new();
private readonly ConcurrentQueue<Py_buffer> _bufferQueue = new();
private int _throttled; private int _throttled;
#region FINALIZER_CHECK #region FINALIZER_CHECK
@ -165,6 +166,19 @@ namespace Python.Runtime
_derivedQueue.Enqueue(pending); _derivedQueue.Enqueue(pending);
} }
internal void AddFinalizedBuffer(ref Py_buffer buffer)
{
if (buffer.obj == IntPtr.Zero)
throw new ArgumentNullException(nameof(buffer));
if (!Enable)
return;
var pending = buffer;
buffer = default;
_bufferQueue.Enqueue(pending);
}
internal static void Initialize() internal static void Initialize()
{ {
Instance.started = true; Instance.started = true;
@ -178,7 +192,7 @@ namespace Python.Runtime
internal nint DisposeAll() internal nint DisposeAll()
{ {
if (_objQueue.IsEmpty && _derivedQueue.IsEmpty) if (_objQueue.IsEmpty && _derivedQueue.IsEmpty && _bufferQueue.IsEmpty)
return 0; return 0;
nint collected = 0; nint collected = 0;
@ -242,6 +256,15 @@ namespace Python.Runtime
collected++; collected++;
} }
while (!_bufferQueue.IsEmpty)
{
if (!_bufferQueue.TryDequeue(out var buffer))
continue;
Runtime.PyBuffer_Release(ref buffer);
collected++;
}
} }
finally finally
{ {

Просмотреть файл

@ -89,7 +89,9 @@ namespace Python.Runtime
{ {
if (Runtime.PyVersion < new Version(3,9)) if (Runtime.PyVersion < new Version(3,9))
throw new NotSupportedException("SizeFromFormat requires at least Python 3.9"); throw new NotSupportedException("SizeFromFormat requires at least Python 3.9");
return (long)Runtime.PyBuffer_SizeFromFormat(format); nint result = Runtime.PyBuffer_SizeFromFormat(format);
if (result == -1) throw PythonException.ThrowLastAsClrException();
return result;
} }
/// <summary> /// <summary>
@ -113,7 +115,7 @@ namespace Python.Runtime
throw new ObjectDisposedException(nameof(PyBuffer)); throw new ObjectDisposedException(nameof(PyBuffer));
if (Runtime.PyVersion < new Version(3, 7)) if (Runtime.PyVersion < new Version(3, 7))
throw new NotSupportedException("GetPointer requires at least Python 3.7"); throw new NotSupportedException("GetPointer requires at least Python 3.7");
return Runtime.PyBuffer_GetPointer(ref _view, indices.Select(x => (IntPtr)x).ToArray()); return Runtime.PyBuffer_GetPointer(ref _view, indices.Select(x => checked((nint)x)).ToArray());
} }
/// <summary> /// <summary>
@ -126,7 +128,7 @@ namespace Python.Runtime
if (Runtime.PyVersion < new Version(3, 7)) if (Runtime.PyVersion < new Version(3, 7))
throw new NotSupportedException("FromContiguous requires at least Python 3.7"); throw new NotSupportedException("FromContiguous requires at least Python 3.7");
if (Runtime.PyBuffer_FromContiguous(ref _view, buf, (IntPtr)len, OrderStyleToChar(fort, false)) < 0) if (Runtime.PyBuffer_FromContiguous(ref _view, buf, checked((nint)len), OrderStyleToChar(fort, false)) < 0)
throw PythonException.ThrowLastAsClrException(); throw PythonException.ThrowLastAsClrException();
} }
@ -173,44 +175,60 @@ namespace Python.Runtime
/// <summary> /// <summary>
/// Writes a managed byte array into the buffer of a python object. This can be used to pass data like images from managed to python. /// Writes a managed byte array into the buffer of a python object. This can be used to pass data like images from managed to python.
/// </summary> /// </summary>
public void Write(byte[] buffer, int offset, int count) public void Write(byte[] buffer, int sourceOffset, int count, nint destinationOffset)
{ {
if (disposedValue) if (disposedValue)
throw new ObjectDisposedException(nameof(PyBuffer)); throw new ObjectDisposedException(nameof(PyBuffer));
if (ReadOnly)
throw new InvalidOperationException("Buffer is read-only");
if ((long)_view.len > int.MaxValue)
throw new NotSupportedException("Python buffers bigger than int.MaxValue are not supported.");
if (count > buffer.Length)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the buffer.");
if (count > (int)_view.len)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the python buffer.");
if (_view.ndim != 1) if (_view.ndim != 1)
throw new NotSupportedException("Multidimensional arrays, scalars and objects without a buffer are not supported."); throw new NotImplementedException("Multidimensional arrays, scalars and objects without a buffer are not supported.");
if (!this.IsContiguous(BufferOrderStyle.C)) if (!this.IsContiguous(BufferOrderStyle.C))
throw new NotImplementedException("Only continuous buffers are supported"); throw new NotImplementedException("Only continuous buffers are supported");
if (ReadOnly)
throw new InvalidOperationException("Buffer is read-only");
if (buffer is null)
throw new ArgumentNullException(nameof(buffer));
Marshal.Copy(buffer, offset, _view.buf, count); if (sourceOffset < 0)
throw new IndexOutOfRangeException($"{nameof(sourceOffset)} is negative");
if (destinationOffset < 0)
throw new IndexOutOfRangeException($"{nameof(destinationOffset)} is negative");
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count), count, "Value must be >= 0");
if (checked(count + sourceOffset) > buffer.Length)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the buffer.");
if (checked(count + destinationOffset) > _view.len)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the python buffer.");
Marshal.Copy(buffer, sourceOffset, _view.buf + destinationOffset, count);
} }
/// <summary> /// <summary>
/// Reads the buffer of a python object into a managed byte array. This can be used to pass data like images from python to managed. /// Reads the buffer of a python object into a managed byte array. This can be used to pass data like images from python to managed.
/// </summary> /// </summary>
public int Read(byte[] buffer, int offset, int count) { public void Read(byte[] buffer, int destinationOffset, int count, nint sourceOffset) {
if (disposedValue) if (disposedValue)
throw new ObjectDisposedException(nameof(PyBuffer)); throw new ObjectDisposedException(nameof(PyBuffer));
if (count > buffer.Length)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the buffer.");
if (_view.ndim != 1) if (_view.ndim != 1)
throw new NotSupportedException("Multidimensional arrays, scalars and objects without a buffer are not supported."); throw new NotImplementedException("Multidimensional arrays, scalars and objects without a buffer are not supported.");
if (_view.len.ToInt64() > int.MaxValue)
throw new NotSupportedException("Python buffers bigger than int.MaxValue are not supported.");
if (!this.IsContiguous(BufferOrderStyle.C)) if (!this.IsContiguous(BufferOrderStyle.C))
throw new NotImplementedException("Only continuous buffers are supported"); throw new NotImplementedException("Only continuous buffers are supported");
if (buffer is null)
throw new ArgumentNullException(nameof(buffer));
int copylen = count < (int)_view.len ? count : (int)_view.len; if (sourceOffset < 0)
Marshal.Copy(_view.buf, buffer, offset, copylen); throw new IndexOutOfRangeException($"{nameof(sourceOffset)} is negative");
return copylen; if (destinationOffset < 0)
throw new IndexOutOfRangeException($"{nameof(destinationOffset)} is negative");
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count), count, "Value must be >= 0");
if (checked(count + destinationOffset) > buffer.Length)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the buffer.");
if (checked(count + sourceOffset) > _view.len)
throw new ArgumentOutOfRangeException("count", "Count is bigger than the python buffer.");
Marshal.Copy(_view.buf + sourceOffset, buffer, destinationOffset, count);
} }
private bool disposedValue = false; // To detect redundant calls private bool disposedValue = false; // To detect redundant calls
@ -240,11 +258,7 @@ namespace Python.Runtime
if (_view.obj != IntPtr.Zero) if (_view.obj != IntPtr.Zero)
{ {
Finalizer.Instance.AddFinalizedObject(ref _view.obj, _exporter.run Finalizer.Instance.AddFinalizedBuffer(ref _view);
#if TRACE_ALLOC
, _exporter.Traceback
#endif
);
} }
Dispose(false); Dispose(false);

Просмотреть файл

@ -179,6 +179,11 @@ namespace Python.Runtime
internal bool IsDisposed => rawPtr == IntPtr.Zero; internal bool IsDisposed => rawPtr == IntPtr.Zero;
void CheckDisposed()
{
if (IsDisposed) throw new ObjectDisposedException(nameof(PyObject));
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (IsDisposed) if (IsDisposed)
@ -1114,6 +1119,7 @@ namespace Python.Runtime
/// </remarks> /// </remarks>
public PyBuffer GetBuffer(PyBUF flags = PyBUF.SIMPLE) public PyBuffer GetBuffer(PyBUF flags = PyBUF.SIMPLE)
{ {
CheckDisposed();
return new PyBuffer(this, flags); return new PyBuffer(this, flags);
} }

Просмотреть файл

@ -1107,7 +1107,7 @@ namespace Python.Runtime
internal static int PyBuffer_IsContiguous(ref Py_buffer view, char order) => Delegates.PyBuffer_IsContiguous(ref view, order); internal static int PyBuffer_IsContiguous(ref Py_buffer view, char order) => Delegates.PyBuffer_IsContiguous(ref view, order);
internal static IntPtr PyBuffer_GetPointer(ref Py_buffer view, IntPtr[] indices) => Delegates.PyBuffer_GetPointer(ref view, indices); internal static IntPtr PyBuffer_GetPointer(ref Py_buffer view, nint[] indices) => Delegates.PyBuffer_GetPointer(ref view, indices);
internal static int PyBuffer_FromContiguous(ref Py_buffer view, IntPtr buf, IntPtr len, char fort) => Delegates.PyBuffer_FromContiguous(ref view, buf, len, fort); internal static int PyBuffer_FromContiguous(ref Py_buffer view, IntPtr buf, IntPtr len, char fort) => Delegates.PyBuffer_FromContiguous(ref view, buf, len, fort);
@ -1362,6 +1362,13 @@ namespace Python.Runtime
return Delegates.PyBytes_FromString((IntPtr)bytes); return Delegates.PyBytes_FromString((IntPtr)bytes);
} }
internal static NewReference PyByteArray_FromStringAndSize(IntPtr strPtr, nint len) => Delegates.PyByteArray_FromStringAndSize(strPtr, len);
internal static NewReference PyByteArray_FromStringAndSize(string s)
{
using var ptr = new StrPtr(s, Encoding.UTF8);
return PyByteArray_FromStringAndSize(ptr.RawPointer, checked((nint)ptr.ByteCount));
}
internal static IntPtr PyBytes_AsString(BorrowedReference ob) internal static IntPtr PyBytes_AsString(BorrowedReference ob)
{ {
Debug.Assert(ob != null); Debug.Assert(ob != null);
@ -1977,7 +1984,7 @@ namespace Python.Runtime
// only in 3.9+ // only in 3.9+
} }
PyBuffer_IsContiguous = (delegate* unmanaged[Cdecl]<ref Py_buffer, char, int>)GetFunctionByName(nameof(PyBuffer_IsContiguous), GetUnmanagedDll(_PythonDll)); PyBuffer_IsContiguous = (delegate* unmanaged[Cdecl]<ref Py_buffer, char, int>)GetFunctionByName(nameof(PyBuffer_IsContiguous), GetUnmanagedDll(_PythonDll));
PyBuffer_GetPointer = (delegate* unmanaged[Cdecl]<ref Py_buffer, IntPtr[], IntPtr>)GetFunctionByName(nameof(PyBuffer_GetPointer), GetUnmanagedDll(_PythonDll)); PyBuffer_GetPointer = (delegate* unmanaged[Cdecl]<ref Py_buffer, nint[], IntPtr>)GetFunctionByName(nameof(PyBuffer_GetPointer), GetUnmanagedDll(_PythonDll));
PyBuffer_FromContiguous = (delegate* unmanaged[Cdecl]<ref Py_buffer, IntPtr, IntPtr, char, int>)GetFunctionByName(nameof(PyBuffer_FromContiguous), GetUnmanagedDll(_PythonDll)); PyBuffer_FromContiguous = (delegate* unmanaged[Cdecl]<ref Py_buffer, IntPtr, IntPtr, char, int>)GetFunctionByName(nameof(PyBuffer_FromContiguous), GetUnmanagedDll(_PythonDll));
PyBuffer_ToContiguous = (delegate* unmanaged[Cdecl]<IntPtr, ref Py_buffer, IntPtr, char, int>)GetFunctionByName(nameof(PyBuffer_ToContiguous), GetUnmanagedDll(_PythonDll)); PyBuffer_ToContiguous = (delegate* unmanaged[Cdecl]<IntPtr, ref Py_buffer, IntPtr, char, int>)GetFunctionByName(nameof(PyBuffer_ToContiguous), GetUnmanagedDll(_PythonDll));
PyBuffer_FillContiguousStrides = (delegate* unmanaged[Cdecl]<int, IntPtr, IntPtr, int, char, void>)GetFunctionByName(nameof(PyBuffer_FillContiguousStrides), GetUnmanagedDll(_PythonDll)); PyBuffer_FillContiguousStrides = (delegate* unmanaged[Cdecl]<int, IntPtr, IntPtr, int, char, void>)GetFunctionByName(nameof(PyBuffer_FillContiguousStrides), GetUnmanagedDll(_PythonDll));
@ -2037,6 +2044,7 @@ namespace Python.Runtime
PySequence_List = (delegate* unmanaged[Cdecl]<BorrowedReference, NewReference>)GetFunctionByName(nameof(PySequence_List), GetUnmanagedDll(_PythonDll)); PySequence_List = (delegate* unmanaged[Cdecl]<BorrowedReference, NewReference>)GetFunctionByName(nameof(PySequence_List), GetUnmanagedDll(_PythonDll));
PyBytes_AsString = (delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr>)GetFunctionByName(nameof(PyBytes_AsString), GetUnmanagedDll(_PythonDll)); PyBytes_AsString = (delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr>)GetFunctionByName(nameof(PyBytes_AsString), GetUnmanagedDll(_PythonDll));
PyBytes_FromString = (delegate* unmanaged[Cdecl]<IntPtr, NewReference>)GetFunctionByName(nameof(PyBytes_FromString), GetUnmanagedDll(_PythonDll)); PyBytes_FromString = (delegate* unmanaged[Cdecl]<IntPtr, NewReference>)GetFunctionByName(nameof(PyBytes_FromString), GetUnmanagedDll(_PythonDll));
PyByteArray_FromStringAndSize = (delegate* unmanaged[Cdecl]<IntPtr, nint, NewReference>)GetFunctionByName(nameof(PyByteArray_FromStringAndSize), GetUnmanagedDll(_PythonDll));
PyBytes_Size = (delegate* unmanaged[Cdecl]<BorrowedReference, nint>)GetFunctionByName(nameof(PyBytes_Size), GetUnmanagedDll(_PythonDll)); PyBytes_Size = (delegate* unmanaged[Cdecl]<BorrowedReference, nint>)GetFunctionByName(nameof(PyBytes_Size), GetUnmanagedDll(_PythonDll));
PyUnicode_AsUTF8 = (delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr>)GetFunctionByName(nameof(PyUnicode_AsUTF8), GetUnmanagedDll(_PythonDll)); PyUnicode_AsUTF8 = (delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr>)GetFunctionByName(nameof(PyUnicode_AsUTF8), GetUnmanagedDll(_PythonDll));
PyUnicode_DecodeUTF16 = (delegate* unmanaged[Cdecl]<IntPtr, nint, IntPtr, IntPtr, NewReference>)GetFunctionByName(nameof(PyUnicode_DecodeUTF16), GetUnmanagedDll(_PythonDll)); PyUnicode_DecodeUTF16 = (delegate* unmanaged[Cdecl]<IntPtr, nint, IntPtr, IntPtr, NewReference>)GetFunctionByName(nameof(PyUnicode_DecodeUTF16), GetUnmanagedDll(_PythonDll));
@ -2250,7 +2258,7 @@ namespace Python.Runtime
internal static delegate* unmanaged[Cdecl]<ref Py_buffer, void> PyBuffer_Release { get; } internal static delegate* unmanaged[Cdecl]<ref Py_buffer, void> PyBuffer_Release { get; }
internal static delegate* unmanaged[Cdecl]<StrPtr, nint> PyBuffer_SizeFromFormat { get; } internal static delegate* unmanaged[Cdecl]<StrPtr, nint> PyBuffer_SizeFromFormat { get; }
internal static delegate* unmanaged[Cdecl]<ref Py_buffer, char, int> PyBuffer_IsContiguous { get; } internal static delegate* unmanaged[Cdecl]<ref Py_buffer, char, int> PyBuffer_IsContiguous { get; }
internal static delegate* unmanaged[Cdecl]<ref Py_buffer, IntPtr[], IntPtr> PyBuffer_GetPointer { get; } internal static delegate* unmanaged[Cdecl]<ref Py_buffer, nint[], IntPtr> PyBuffer_GetPointer { get; }
internal static delegate* unmanaged[Cdecl]<ref Py_buffer, IntPtr, IntPtr, char, int> PyBuffer_FromContiguous { get; } internal static delegate* unmanaged[Cdecl]<ref Py_buffer, IntPtr, IntPtr, char, int> PyBuffer_FromContiguous { get; }
internal static delegate* unmanaged[Cdecl]<IntPtr, ref Py_buffer, IntPtr, char, int> PyBuffer_ToContiguous { get; } internal static delegate* unmanaged[Cdecl]<IntPtr, ref Py_buffer, IntPtr, char, int> PyBuffer_ToContiguous { get; }
internal static delegate* unmanaged[Cdecl]<int, IntPtr, IntPtr, int, char, void> PyBuffer_FillContiguousStrides { get; } internal static delegate* unmanaged[Cdecl]<int, IntPtr, IntPtr, int, char, void> PyBuffer_FillContiguousStrides { get; }
@ -2310,6 +2318,7 @@ namespace Python.Runtime
internal static delegate* unmanaged[Cdecl]<BorrowedReference, NewReference> PySequence_List { get; } internal static delegate* unmanaged[Cdecl]<BorrowedReference, NewReference> PySequence_List { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr> PyBytes_AsString { get; } internal static delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr> PyBytes_AsString { get; }
internal static delegate* unmanaged[Cdecl]<IntPtr, NewReference> PyBytes_FromString { get; } internal static delegate* unmanaged[Cdecl]<IntPtr, NewReference> PyBytes_FromString { get; }
internal static delegate* unmanaged[Cdecl]<IntPtr, nint, NewReference> PyByteArray_FromStringAndSize { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, nint> PyBytes_Size { get; } internal static delegate* unmanaged[Cdecl]<BorrowedReference, nint> PyBytes_Size { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr> PyUnicode_AsUTF8 { get; } internal static delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr> PyUnicode_AsUTF8 { get; }
internal static delegate* unmanaged[Cdecl]<IntPtr, nint, IntPtr, IntPtr, NewReference> PyUnicode_DecodeUTF16 { get; } internal static delegate* unmanaged[Cdecl]<IntPtr, nint, IntPtr, IntPtr, NewReference> PyUnicode_DecodeUTF16 { get; }