Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 41de69d

Browse files
authored
Merge branch 'master' into PR/Codecs
2 parents 5619fb9 + 770fc01 commit 41de69d

12 files changed

+117
-13
lines changed

src/embed_tests/TestRuntime.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using NUnit.Framework;
34
using Python.Runtime;
45
using Python.Runtime.Platform;
@@ -110,9 +111,15 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test()
110111
// Create an instance of threading.Lock, which is one of the very few types that does not have the
111112
// TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check.
112113
var threading = Runtime.Runtime.PyImport_ImportModule("threading");
114+
Exceptions.ErrorCheck(threading);
113115
var threadingDict = Runtime.Runtime.PyModule_GetDict(threading);
116+
Exceptions.ErrorCheck(threadingDict);
114117
var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock");
118+
if (lockType == IntPtr.Zero)
119+
throw new KeyNotFoundException("class 'Lock' was not found in 'threading'");
120+
115121
var lockInstance = Runtime.Runtime.PyObject_CallObject(lockType, Runtime.Runtime.PyTuple_New(0));
122+
Exceptions.ErrorCheck(lockInstance);
116123

117124
Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance));
118125
Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance));

src/runtime/BorrowedReference.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace Python.Runtime
2+
{
3+
using System;
4+
/// <summary>
5+
/// Represents a reference to a Python object, that is being lent, and
6+
/// can only be safely used until execution returns to the caller.
7+
/// </summary>
8+
readonly ref struct BorrowedReference
9+
{
10+
readonly 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+
17+
BorrowedReference(IntPtr pointer)
18+
{
19+
this.pointer = pointer;
20+
}
21+
}
22+
}

src/runtime/NewReference.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
namespace Python.Runtime
2+
{
3+
using System;
4+
/// <summary>
5+
/// Represents a reference to a Python object, that is tracked by Python's reference counting.
6+
/// </summary>
7+
[NonCopyable]
8+
ref struct NewReference
9+
{
10+
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+
17+
/// <summary>
18+
/// Returns <see cref="PyObject"/> wrapper around this reference, which now owns
19+
/// the pointer. Sets the original reference to <c>null</c>, as it no longer owns it.
20+
/// </summary>
21+
public PyObject MoveToPyObject()
22+
{
23+
if (this.IsNull) throw new NullReferenceException();
24+
25+
var result = new PyObject(this.pointer);
26+
this.pointer = IntPtr.Zero;
27+
return result;
28+
}
29+
/// <summary>
30+
/// Removes this reference to a Python object, and sets it to <c>null</c>.
31+
/// </summary>
32+
public void Dispose()
33+
{
34+
if (!this.IsNull)
35+
Runtime.XDecref(this.pointer);
36+
this.pointer = IntPtr.Zero;
37+
}
38+
}
39+
}

src/runtime/NonCopyableAttribute.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Python.Runtime
2+
{
3+
using System;
4+
[AttributeUsage(AttributeTargets.Struct)]
5+
class NonCopyableAttribute : Attribute { }
6+
}

src/runtime/Python.Runtime.15.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@
129129
<PackageReference Include="Microsoft.TargetingPack.NETFramework.v4.5" Version="1.0.1" ExcludeAssets="All" PrivateAssets="All" />
130130
</ItemGroup>
131131

132+
<ItemGroup>
133+
<PackageReference Include="NonCopyableAnalyzer" Version="0.5.1">
134+
<PrivateAssets>all</PrivateAssets>
135+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
136+
</PackageReference>
137+
</ItemGroup>
138+
132139
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
133140

134141
<PropertyGroup>

src/runtime/Python.Runtime.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
</Compile>
8686
<Compile Include="arrayobject.cs" />
8787
<Compile Include="assemblymanager.cs" />
88+
<Compile Include="BorrowedReference.cs" />
8889
<Compile Include="classderived.cs" />
8990
<Compile Include="classbase.cs" />
9091
<Compile Include="classmanager.cs" />
@@ -121,6 +122,8 @@
121122
<Compile Include="moduleobject.cs" />
122123
<Compile Include="modulepropertyobject.cs" />
123124
<Compile Include="nativecall.cs" />
125+
<Compile Include="NewReference.cs" />
126+
<Compile Include="NonCopyableAttribute.cs" />
124127
<Compile Include="overload.cs" />
125128
<Compile Include="propertyobject.cs" />
126129
<Compile Include="pyansistring.cs" />

src/runtime/Util.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Python.Runtime
55
{
6-
internal class Util
6+
internal static class Util
77
{
88
internal const string UnstableApiMessage =
99
"This API is unstable, and might be changed or removed in the next minor release";
@@ -32,5 +32,12 @@ internal static void WriteCLong(IntPtr type, int offset, Int64 flags)
3232
Marshal.WriteInt64(type, offset, flags);
3333
}
3434
}
35+
36+
/// <summary>
37+
/// Null-coalesce: if <paramref name="primary"/> parameter is not
38+
/// <see cref="IntPtr.Zero"/>, return it. Otherwise return <paramref name="fallback"/>.
39+
/// </summary>
40+
internal static IntPtr Coalesce(this IntPtr primary, IntPtr fallback)
41+
=> primary == IntPtr.Zero ? fallback : primary;
3542
}
3643
}

src/runtime/assemblymanager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ internal static void UpdatePath()
145145
probed.Clear();
146146
for (var i = 0; i < count; i++)
147147
{
148-
IntPtr item = Runtime.PyList_GetItem(list, i);
148+
BorrowedReference item = Runtime.PyList_GetItem(list, i);
149149
string path = Runtime.GetManagedString(item);
150150
if (path != null)
151151
{

src/runtime/methodbinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
292292
for (int i = 0; i < pynkwargs; ++i)
293293
{
294294
var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(keylist, i));
295-
kwargDict[keyStr] = Runtime.PyList_GetItem(valueList, i);
295+
kwargDict[keyStr] = Runtime.PyList_GetItem(valueList, i).DangerousGetAddress();
296296
}
297297
Runtime.XDecref(keylist);
298298
Runtime.XDecref(valueList);

src/runtime/pydict.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,20 @@ public PyObject Values()
139139
/// </remarks>
140140
public PyObject Items()
141141
{
142-
IntPtr items = Runtime.PyDict_Items(obj);
143-
if (items == IntPtr.Zero)
142+
var items = Runtime.PyDict_Items(this.obj);
143+
try
144144
{
145-
throw new PythonException();
145+
if (items.IsNull)
146+
{
147+
throw new PythonException();
148+
}
149+
150+
return items.MoveToPyObject();
151+
}
152+
finally
153+
{
154+
items.Dispose();
146155
}
147-
return new PyObject(items);
148156
}
149157

150158

src/runtime/pythonengine.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -760,11 +760,14 @@ public static void With(PyObject obj, Action<dynamic> Body)
760760
catch (PythonException e)
761761
{
762762
ex = e;
763-
type = ex.PyType;
764-
val = ex.PyValue;
765-
traceBack = ex.PyTB;
763+
type = ex.PyType.Coalesce(type);
764+
val = ex.PyValue.Coalesce(val);
765+
traceBack = ex.PyTB.Coalesce(traceBack);
766766
}
767767

768+
Runtime.XIncref(type);
769+
Runtime.XIncref(val);
770+
Runtime.XIncref(traceBack);
768771
var exitResult = obj.InvokeMethod("__exit__", new PyObject(type), new PyObject(val), new PyObject(traceBack));
769772

770773
if (ex != null && !exitResult.IsTrue()) throw ex;

src/runtime/runtime.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,8 @@ internal static IntPtr PyUnicode_FromString(string s)
15181518
return PyUnicode_FromUnicode(s, s.Length);
15191519
}
15201520

1521+
internal static string GetManagedString(in BorrowedReference borrowedReference)
1522+
=> GetManagedString(borrowedReference.DangerousGetAddress());
15211523
/// <summary>
15221524
/// Function to access the internal PyUnicode/PyString object and
15231525
/// convert it to a managed string with the correct encoding.
@@ -1600,7 +1602,7 @@ internal static bool PyDict_Check(IntPtr ob)
16001602
internal static extern IntPtr PyDict_Values(IntPtr pointer);
16011603

16021604
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
1603-
internal static extern IntPtr PyDict_Items(IntPtr pointer);
1605+
internal static extern NewReference PyDict_Items(IntPtr pointer);
16041606

16051607
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
16061608
internal static extern IntPtr PyDict_Copy(IntPtr pointer);
@@ -1640,13 +1642,13 @@ internal static IntPtr PyList_New(long size)
16401642
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
16411643
internal static extern IntPtr PyList_AsTuple(IntPtr pointer);
16421644

1643-
internal static IntPtr PyList_GetItem(IntPtr pointer, long index)
1645+
internal static BorrowedReference PyList_GetItem(IntPtr pointer, long index)
16441646
{
16451647
return PyList_GetItem(pointer, new IntPtr(index));
16461648
}
16471649

16481650
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
1649-
private static extern IntPtr PyList_GetItem(IntPtr pointer, IntPtr index);
1651+
private static extern BorrowedReference PyList_GetItem(IntPtr pointer, IntPtr index);
16501652

16511653
internal static int PyList_SetItem(IntPtr pointer, long index, IntPtr value)
16521654
{

0 commit comments

Comments
 (0)