| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 49a230b commit 3c9f7b3
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -69,6 +69,7 @@ | |||
| 69 | 69 | - ([@OneBlue](https://github.com/OneBlue)) | |
| 70 | 70 | - ([@rico-chet](https://github.com/rico-chet)) | |
| 71 | 71 | - ([@rmadsen-ks](https://github.com/rmadsen-ks)) | |
| 72 | + - ([@SnGmng](https://github.com/SnGmng)) | ||
| 72 | 73 | - ([@stonebig](https://github.com/stonebig)) | |
| 73 | 74 | - ([@testrunner123](https://github.com/testrunner123)) | |
| 74 | 75 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,6 +18,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 18 | 18 | - Added Runtime.None to be able to pass None as parameter into Python from .NET | |
| 19 | 19 | - Added PyObject.IsNone() to check if a Python object is None in .NET. | |
| 20 | 20 | - Support for Python 3.8 | |
| 21 | + - Added Python 3 buffer api support and PyBuffer interface for fast byte and numpy array read/write ([#980][p980]) | ||
| 21 | 22 | ||
| 22 | 23 | ### Changed | |
| 23 | 24 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -97,6 +97,7 @@ | |||
| 97 | 97 | <Compile Include="TestFinalizer.cs" /> | |
| 98 | 98 | <Compile Include="TestInstanceWrapping.cs" /> | |
| 99 | 99 | <Compile Include="TestPyAnsiString.cs" /> | |
| 100 | + <Compile Include="TestPyBuffer.cs" /> | ||
| 100 | 101 | <Compile Include="TestPyFloat.cs" /> | |
| 101 | 102 | <Compile Include="TestPyInt.cs" /> | |
| 102 | 103 | <Compile Include="TestPyList.cs" /> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,72 @@ | |||
| 1 | + using System.Text; | ||
| 2 | + using NUnit.Framework; | ||
| 3 | + using Python.Runtime; | ||
| 4 | + | ||
| 5 | + namespace Python.EmbeddingTest { | ||
| 6 | + class TestPyBuffer | ||
| 7 | + { | ||
| 8 | + [OneTimeSetUp] | ||
| 9 | + public void SetUp() | ||
| 10 | + { | ||
| 11 | + PythonEngine.Initialize(); | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + [OneTimeTearDown] | ||
| 15 | + public void Dispose() | ||
| 16 | + { | ||
| 17 | + PythonEngine.Shutdown(); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + [Test] | ||
| 21 | + public void TestBufferWrite() | ||
| 22 | + { | ||
| 23 | + if (Runtime.Runtime.pyversionnumber < 35) return; | ||
| 24 | + | ||
| 25 | + string bufferTestString = "hello world! !$%&/()=?"; | ||
| 26 | + | ||
| 27 | + using (Py.GIL()) | ||
| 28 | + { | ||
| 29 | + using (var scope = Py.CreateScope()) | ||
| 30 | + { | ||
| 31 | + scope.Exec($"arr = bytearray({bufferTestString.Length})"); | ||
| 32 | + PyObject pythonArray = scope.Get("arr"); | ||
| 33 | + byte[] managedArray = new UTF8Encoding().GetBytes(bufferTestString); | ||
| 34 | + | ||
| 35 | + using (PyBuffer buf = pythonArray.GetBuffer()) | ||
| 36 | + { | ||
| 37 | + buf.Write(managedArray, 0, managedArray.Length); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + string result = scope.Eval("arr.decode('utf-8')").ToString(); | ||
| 41 | + Assert.IsTrue(result == bufferTestString); | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + [Test] | ||
| 47 | + public void TestBufferRead() | ||
| 48 | + { | ||
| 49 | + if (Runtime.Runtime.pyversionnumber < 35) return; | ||
| 50 | + | ||
| 51 | + string bufferTestString = "hello world! !$%&/()=?"; | ||
| 52 | + | ||
| 53 | + using (Py.GIL()) | ||
| 54 | + { | ||
| 55 | + using (var scope = Py.CreateScope()) | ||
| 56 | + { | ||
| 57 | + scope.Exec($"arr = b'{bufferTestString}'"); | ||
| 58 | + PyObject pythonArray = scope.Get("arr"); | ||
| 59 | + byte[] managedArray = new byte[bufferTestString.Length]; | ||
| 60 | + | ||
| 61 | + using (PyBuffer buf = pythonArray.GetBuffer()) | ||
| 62 | + { | ||
| 63 | + buf.Read(managedArray, 0, managedArray.Length); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + string result = new UTF8Encoding().GetString(managedArray); | ||
| 67 | + Assert.IsTrue(result == bufferTestString); | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -89,6 +89,7 @@ | |||
| 89 | 89 | <Compile Include="arrayobject.cs" /> | |
| 90 | 90 | <Compile Include="assemblymanager.cs" /> | |
| 91 | 91 | <Compile Include="BorrowedReference.cs" /> | |
| 92 | + <Compile Include="bufferinterface.cs" /> | ||
| 92 | 93 | <Compile Include="classderived.cs" /> | |
| 93 | 94 | <Compile Include="classbase.cs" /> | |
| 94 | 95 | <Compile Include="classmanager.cs" /> | |
@@ -130,6 +131,7 @@ | |||
| 130 | 131 | <Compile Include="overload.cs" /> | |
| 131 | 132 | <Compile Include="propertyobject.cs" /> | |
| 132 | 133 | <Compile Include="pyansistring.cs" /> | |
| 134 | + <Compile Include="pybuffer.cs" /> | ||
| 133 | 135 | <Compile Include="pydict.cs" /> | |
| 134 | 136 | <Compile Include="PyExportAttribute.cs" /> | |
| 135 | 137 | <Compile Include="pyfloat.cs" /> | |
@@ -183,4 +185,4 @@ | |||
| 183 | 185 | <Copy SourceFiles="$(TargetAssembly)" DestinationFolder="$(PythonBuildDir)" /> | |
| 184 | 186 | <!--Copy SourceFiles="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" DestinationFolder="$(PythonBuildDir)" /--> | |
| 185 | 187 | </Target> | |
| 186 | - </Project> | ||
| 188 | + </Project> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,106 @@ | |||
| 1 | + using System; | ||
| 2 | + using System.Runtime.InteropServices; | ||
| 3 | + | ||
| 4 | + namespace Python.Runtime | ||
| 5 | + { | ||
| 6 | + /* buffer interface */ | ||
| 7 | + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | ||
| 8 | + internal struct Py_buffer { | ||
| 9 | + public IntPtr buf; | ||
| 10 | + public IntPtr obj; /* owned reference */ | ||
| 11 | + [MarshalAs(UnmanagedType.SysInt)] | ||
| 12 | + public IntPtr len; | ||
| 13 | + [MarshalAs(UnmanagedType.SysInt)] | ||
| 14 | + public IntPtr itemsize; /* This is Py_ssize_t so it can be | ||
| 15 | + pointed to by strides in simple case.*/ | ||
| 16 | + [MarshalAs(UnmanagedType.Bool)] | ||
| 17 | + public bool _readonly; | ||
| 18 | + public int ndim; | ||
| 19 | + [MarshalAs(UnmanagedType.LPStr)] | ||
| 20 | + public string format; | ||
| 21 | + public IntPtr shape; | ||
| 22 | + public IntPtr strides; | ||
| 23 | + public IntPtr suboffsets; | ||
| 24 | + public IntPtr _internal; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public enum BufferOrderStyle | ||
| 28 | + { | ||
| 29 | + C, | ||
| 30 | + Fortran, | ||
| 31 | + EitherOne, | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + /* Flags for getting buffers */ | ||
| 35 | + public enum PyBUF | ||
| 36 | + { | ||
| 37 | + /// <summary> | ||
| 38 | + /// Simple buffer without shape strides and suboffsets | ||
| 39 | + /// </summary> | ||
| 40 | + SIMPLE = 0, | ||
| 41 | + /// <summary> | ||
| 42 | + /// Controls the <see cref="PyBuffer.ReadOnly"/> field. If set, the exporter MUST provide a writable buffer or else report failure. Otherwise, the exporter MAY provide either a read-only or writable buffer, but the choice MUST be consistent for all consumers. | ||
| 43 | + /// </summary> | ||
| 44 | + WRITABLE = 0x0001, | ||
| 45 | + /// <summary> | ||
| 46 | + /// Controls the <see cref="PyBuffer.Format"/> field. If set, this field MUST be filled in correctly. Otherwise, this field MUST be NULL. | ||
| 47 | + /// </summary> | ||
| 48 | + FORMATS = 0x0004, | ||
| 49 | + /// <summary> | ||
| 50 | + /// N-Dimensional buffer with shape | ||
| 51 | + /// </summary> | ||
| 52 | + ND = 0x0008, | ||
| 53 | + /// <summary> | ||
| 54 | + /// Buffer with strides and shape | ||
| 55 | + /// </summary> | ||
| 56 | + STRIDES = (0x0010 | ND), | ||
| 57 | + /// <summary> | ||
| 58 | + /// C-Contigous buffer with strides and shape | ||
| 59 | + /// </summary> | ||
| 60 | + C_CONTIGUOUS = (0x0020 | STRIDES), | ||
| 61 | + /// <summary> | ||
| 62 | + /// F-Contigous buffer with strides and shape | ||
| 63 | + /// </summary> | ||
| 64 | + F_CONTIGUOUS = (0x0040 | STRIDES), | ||
| 65 | + /// <summary> | ||
| 66 | + /// C or Fortran contigous buffer with strides and shape | ||
| 67 | + /// </summary> | ||
| 68 | + ANY_CONTIGUOUS = (0x0080 | STRIDES), | ||
| 69 | + /// <summary> | ||
| 70 | + /// Buffer with suboffsets (if needed) | ||
| 71 | + /// </summary> | ||
| 72 | + INDIRECT = (0x0100 | STRIDES), | ||
| 73 | + /// <summary> | ||
| 74 | + /// Writable C-Contigous buffer with shape | ||
| 75 | + /// </summary> | ||
| 76 | + CONTIG = (ND | WRITABLE), | ||
| 77 | + /// <summary> | ||
| 78 | + /// Readonly C-Contigous buffer with shape | ||
| 79 | + /// </summary> | ||
| 80 | + CONTIG_RO = (ND), | ||
| 81 | + /// <summary> | ||
| 82 | + /// Writable buffer with shape and strides | ||
| 83 | + /// </summary> | ||
| 84 | + STRIDED = (STRIDES | WRITABLE), | ||
| 85 | + /// <summary> | ||
| 86 | + /// Readonly buffer with shape and strides | ||
| 87 | + /// </summary> | ||
| 88 | + STRIDED_RO = (STRIDES), | ||
| 89 | + /// <summary> | ||
| 90 | + /// Writable buffer with shape, strides and format | ||
| 91 | + /// </summary> | ||
| 92 | + RECORDS = (STRIDES | WRITABLE | FORMATS), | ||
| 93 | + /// <summary> | ||
| 94 | + /// Readonly buffer with shape, strides and format | ||
| 95 | + /// </summary> | ||
| 96 | + RECORDS_RO = (STRIDES | FORMATS), | ||
| 97 | + /// <summary> | ||
| 98 | + /// Writable indirect buffer with shape, strides, format and suboffsets (if needed) | ||
| 99 | + /// </summary> | ||
| 100 | + FULL = (INDIRECT | WRITABLE | FORMATS), | ||
| 101 | + /// <summary> | ||
| 102 | + /// Readonly indirect buffer with shape, strides, format and suboffsets (if needed) | ||
| 103 | + /// </summary> | ||
| 104 | + FULL_RO = (INDIRECT | FORMATS), | ||
| 105 | + } | ||
| 106 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments