| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8e108b4 commit d932176
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -88,6 +88,7 @@ | |||
| 88 | 88 | <Compile Include="pyimport.cs" /> | |
| 89 | 89 | <Compile Include="pyinitialize.cs" /> | |
| 90 | 90 | <Compile Include="pyrunstring.cs" /> | |
| 91 | + <Compile Include="References.cs" /> | ||
| 91 | 92 | <Compile Include="TestConverter.cs" /> | |
| 92 | 93 | <Compile Include="TestCustomMarshal.cs" /> | |
| 93 | 94 | <Compile Include="TestDomainReload.cs" /> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + namespace Python.EmbeddingTest | ||
| 2 | + { | ||
| 3 | + using NUnit.Framework; | ||
| 4 | + using Python.Runtime; | ||
| 5 | + | ||
| 6 | + public class References | ||
| 7 | + { | ||
| 8 | + private Py.GILState _gs; | ||
| 9 | + | ||
| 10 | + [SetUp] | ||
| 11 | + public void SetUp() | ||
| 12 | + { | ||
| 13 | + _gs = Py.GIL(); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + [TearDown] | ||
| 17 | + public void Dispose() | ||
| 18 | + { | ||
| 19 | + _gs.Dispose(); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + [Test] | ||
| 23 | + public void MoveToPyObject_SetsNull() | ||
| 24 | + { | ||
| 25 | + var dict = new PyDict(); | ||
| 26 | + NewReference reference = Runtime.PyDict_Items(dict.Handle); | ||
| 27 | + try | ||
| 28 | + { | ||
| 29 | + Assert.IsFalse(reference.IsNull()); | ||
| 30 | + | ||
| 31 | + using (reference.MoveToPyObject()) | ||
| 32 | + Assert.IsTrue(reference.IsNull()); | ||
| 33 | + } | ||
| 34 | + finally | ||
| 35 | + { | ||
| 36 | + reference.Dispose(); | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,26 +1,23 @@ | |||
| 1 | 1 | namespace Python.Runtime | |
| 2 | 2 | { | |
| 3 | 3 | using System; | |
| 4 | + using System.Diagnostics.Contracts; | ||
| 5 | + | ||
| 4 | 6 | /// <summary> | |
| 5 | 7 | /// Represents a reference to a Python object, that is tracked by Python's reference counting. | |
| 6 | 8 | /// </summary> | |
| 7 | 9 | [NonCopyable] | |
| 8 | 10 | ref struct NewReference | |
| 9 | 11 | { | |
| 10 | 12 | IntPtr pointer; | |
| 11 | - public bool IsNull => this.pointer == IntPtr.Zero; | ||
| 12 | - | ||
| 13 | - /// <summary>Gets a raw pointer to the Python object</summary> | ||
| 14 | - public IntPtr DangerousGetAddress() | ||
| 15 | - => this.IsNull ? throw new NullReferenceException() : this.pointer; | ||
| 16 | 13 | ||
| 17 | 14 | /// <summary> | |
| 18 | 15 | /// Returns <see cref="PyObject"/> wrapper around this reference, which now owns | |
| 19 | 16 | /// the pointer. Sets the original reference to <c>null</c>, as it no longer owns it. | |
| 20 | 17 | /// </summary> | |
| 21 | 18 | public PyObject MoveToPyObject() | |
| 22 | 19 | { | |
| 23 | - if (this.IsNull) throw new NullReferenceException(); | ||
| 20 | + if (this.IsNull()) throw new NullReferenceException(); | ||
| 24 | 21 | ||
| 25 | 22 | var result = new PyObject(this.pointer); | |
| 26 | 23 | this.pointer = IntPtr.Zero; | |
@@ -31,9 +28,32 @@ public PyObject MoveToPyObject() | |||
| 31 | 28 | /// </summary> | |
| 32 | 29 | public void Dispose() | |
| 33 | 30 | { | |
| 34 | - if (!this.IsNull) | ||
| 31 | + if (!this.IsNull()) | ||
| 35 | 32 | Runtime.XDecref(this.pointer); | |
| 36 | 33 | this.pointer = IntPtr.Zero; | |
| 37 | 34 | } | |
| 35 | + | ||
| 36 | + [Pure] | ||
| 37 | + internal static IntPtr DangerousGetAddress(in NewReference reference) | ||
| 38 | + => IsNull(reference) ? throw new NullReferenceException() : reference.pointer; | ||
| 39 | + [Pure] | ||
| 40 | + internal static bool IsNull(in NewReference reference) | ||
| 41 | + => reference.pointer == IntPtr.Zero; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /// <summary> | ||
| 45 | + /// These members can not be directly in <see cref="NewReference"/> type, | ||
| 46 | + /// because <c>this</c> is always passed by value, which we need to avoid. | ||
| 47 | + /// (note <code>this in NewReference</code> vs the usual <code>this NewReference</code>) | ||
| 48 | + /// </summary> | ||
| 49 | + static class NewReferenceExtensions | ||
| 50 | + { | ||
| 51 | + /// <summary>Gets a raw pointer to the Python object</summary> | ||
| 52 | + [Pure] | ||
| 53 | + public static IntPtr DangerousGetAddress(this in NewReference reference) | ||
| 54 | + => NewReference.DangerousGetAddress(reference); | ||
| 55 | + [Pure] | ||
| 56 | + public static bool IsNull(this in NewReference reference) | ||
| 57 | + => NewReference.IsNull(reference); | ||
| 38 | 58 | } | |
| 39 | 59 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -141,6 +141,7 @@ | |||
| 141 | 141 | <Compile Include="pythonengine.cs" /> | |
| 142 | 142 | <Compile Include="pythonexception.cs" /> | |
| 143 | 143 | <Compile Include="pytuple.cs" /> | |
| 144 | + <Compile Include="ReferenceExtensions.cs" /> | ||
| 144 | 145 | <Compile Include="runtime.cs" /> | |
| 145 | 146 | <Compile Include="typemanager.cs" /> | |
| 146 | 147 | <Compile Include="typemethod.cs" /> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,20 @@ | |||
| 1 | + namespace Python.Runtime | ||
| 2 | + { | ||
| 3 | + using System.Diagnostics.Contracts; | ||
| 4 | + | ||
| 5 | + static class ReferenceExtensions | ||
| 6 | + { | ||
| 7 | + /// <summary> | ||
| 8 | + /// Checks if the reference points to Python object <c>None</c>. | ||
| 9 | + /// </summary> | ||
| 10 | + [Pure] | ||
| 11 | + public static bool IsNone(this in NewReference reference) | ||
| 12 | + => reference.DangerousGetAddress() == Runtime.PyNone; | ||
| 13 | + /// <summary> | ||
| 14 | + /// Checks if the reference points to Python object <c>None</c>. | ||
| 15 | + /// </summary> | ||
| 16 | + [Pure] | ||
| 17 | + public static bool IsNone(this BorrowedReference reference) | ||
| 18 | + => reference.DangerousGetAddress() == Runtime.PyNone; | ||
| 19 | + } | ||
| 20 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -142,7 +142,7 @@ public PyObject Items() | |||
| 142 | 142 | var items = Runtime.PyDict_Items(this.obj); | |
| 143 | 143 | try | |
| 144 | 144 | { | |
| 145 | - if (items.IsNull) | ||
| 145 | + if (items.IsNull()) | ||
| 146 | 146 | { | |
| 147 | 147 | throw new PythonException(); | |
| 148 | 148 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -278,11 +278,19 @@ public PyObject Eval(string code, PyDict locals = null) | |||
| 278 | 278 | Check(); | |
| 279 | 279 | IntPtr _locals = locals == null ? variables : locals.obj; | |
| 280 | 280 | var flag = (IntPtr)Runtime.Py_eval_input; | |
| 281 | - IntPtr ptr = Runtime.PyRun_String( | ||
| 281 | + | ||
| 282 | + NewReference reference = Runtime.PyRun_String( | ||
| 282 | 283 | code, flag, variables, _locals | |
| 283 | 284 | ); | |
| 284 | - Runtime.CheckExceptionOccurred(); | ||
| 285 | - return new PyObject(ptr); | ||
| 285 | + try | ||
| 286 | + { | ||
| 287 | + Runtime.CheckExceptionOccurred(); | ||
| 288 | + return reference.MoveToPyObject(); | ||
| 289 | + } | ||
| 290 | + finally | ||
| 291 | + { | ||
| 292 | + reference.Dispose(); | ||
| 293 | + } | ||
| 286 | 294 | } | |
| 287 | 295 | ||
| 288 | 296 | /// <summary> | |
@@ -316,15 +324,22 @@ public void Exec(string code, PyDict locals = null) | |||
| 316 | 324 | private void Exec(string code, IntPtr _globals, IntPtr _locals) | |
| 317 | 325 | { | |
| 318 | 326 | var flag = (IntPtr)Runtime.Py_file_input; | |
| 319 | - IntPtr ptr = Runtime.PyRun_String( | ||
| 327 | + NewReference reference = Runtime.PyRun_String( | ||
| 320 | 328 | code, flag, _globals, _locals | |
| 321 | 329 | ); | |
| 322 | - Runtime.CheckExceptionOccurred(); | ||
| 323 | - if (ptr != Runtime.PyNone) | ||
| 330 | + | ||
| 331 | + try | ||
| 324 | 332 | { | |
| 325 | - throw new PythonException(); | ||
| 333 | + Runtime.CheckExceptionOccurred(); | ||
| 334 | + if (!reference.IsNone()) | ||
| 335 | + { | ||
| 336 | + throw new PythonException(); | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | + finally | ||
| 340 | + { | ||
| 341 | + reference.Dispose(); | ||
| 326 | 342 | } | |
| 327 | - Runtime.XDecref(ptr); | ||
| 328 | 343 | } | |
| 329 | 344 | ||
| 330 | 345 | /// <summary> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -543,12 +543,13 @@ public static PyObject Eval(string code, IntPtr? globals = null, IntPtr? locals | |||
| 543 | 543 | /// </remarks> | |
| 544 | 544 | public static void Exec(string code, IntPtr? globals = null, IntPtr? locals = null) | |
| 545 | 545 | { | |
| 546 | - PyObject result = RunString(code, globals, locals, RunFlagType.File); | ||
| 547 | - if (result.obj != Runtime.PyNone) | ||
| 546 | + using (PyObject result = RunString(code, globals, locals, RunFlagType.File)) | ||
| 548 | 547 | { | |
| 549 | - throw new PythonException(); | ||
| 548 | + if (result.obj != Runtime.PyNone) | ||
| 549 | + { | ||
| 550 | + throw new PythonException(); | ||
| 551 | + } | ||
| 550 | 552 | } | |
| 551 | - result.Dispose(); | ||
| 552 | 553 | } | |
| 553 | 554 | ||
| 554 | 555 | ||
@@ -594,13 +595,20 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals, | |||
| 594 | 595 | ||
| 595 | 596 | try | |
| 596 | 597 | { | |
| 597 | - IntPtr result = Runtime.PyRun_String( | ||
| 598 | + NewReference result = Runtime.PyRun_String( | ||
| 598 | 599 | code, (IntPtr)flag, globals.Value, locals.Value | |
| 599 | 600 | ); | |
| 600 | 601 | ||
| 601 | - Runtime.CheckExceptionOccurred(); | ||
| 602 | + try | ||
| 603 | + { | ||
| 604 | + Runtime.CheckExceptionOccurred(); | ||
| 602 | 605 | ||
| 603 | - return new PyObject(result); | ||
| 606 | + return result.MoveToPyObject(); | ||
| 607 | + } | ||
| 608 | + finally | ||
| 609 | + { | ||
| 610 | + result.Dispose(); | ||
| 611 | + } | ||
| 604 | 612 | } | |
| 605 | 613 | finally | |
| 606 | 614 | { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -802,7 +802,7 @@ public static extern int Py_Main( | |||
| 802 | 802 | internal static extern int PyRun_SimpleString(string code); | |
| 803 | 803 | ||
| 804 | 804 | [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | |
| 805 | - internal static extern IntPtr PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); | ||
| 805 | + internal static extern NewReference PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); | ||
| 806 | 806 | ||
| 807 | 807 | [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] | |
| 808 | 808 | internal static extern IntPtr PyEval_EvalCode(IntPtr co, IntPtr globals, IntPtr locals); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments