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

Skip to content

Commit eec30c0

Browse files
committed
make methods of PyObject inherited from its base C# classes GIL-safe
fixes pythonnet#1642
1 parent 303378a commit eec30c0

File tree

6 files changed

+28
-16
lines changed

6 files changed

+28
-16
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ details about the cause of the failure
4747
- floating point values passed from Python are no longer silently truncated
4848
when .NET expects an integer [#1342][i1342]
4949
- More specific error messages for method argument mismatch
50+
- members of `PyObject` inherited from `System.Object and `DynamicObject` now autoacquire GIL
5051
- BREAKING: when inheriting from .NET types in Python if you override `__init__` you
5152
must explicitly call base constructor using `super().__init__(.....)`. Not doing so will lead
5253
to undefined behavior.
@@ -69,6 +70,7 @@ One must now either use enum members (e.g. `MyEnum.Option`), or use enum constru
6970
- BREAKING: Names of .NET types (e.g. `str(__class__)`) changed to better support generic types
7071
- BREAKING: overload resolution will no longer prefer basic types. Instead, first matching overload will
7172
be chosen.
73+
- BREAKING: acquiring GIL using `Py.GIL` no longer forces `PythonEngine` to initialize
7274
- BREAKING: `Exec` and `Eval` from `PythonEngine` no longer accept raw pointers.
7375
- BREAKING: .NET collections and arrays are no longer automatically converted to
7476
Python collections. Instead, they implement standard Python

src/embed_tests/Codecs.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ public DecoderReturningPredefinedValue(PyObject objectType, TTarget decodeResult
473473
}
474474

475475
public bool CanDecode(PyType objectType, Type targetType)
476-
=> objectType.Handle == TheOnlySupportedSourceType.Handle
476+
=> PythonReferenceComparer.Instance.Equals(objectType, TheOnlySupportedSourceType)
477477
&& targetType == typeof(TTarget);
478478
public bool TryDecode<T>(PyObject pyObj, out T value)
479479
{

src/embed_tests/TestPyObject.cs

+7
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ public void GetAttrDefault_IgnoresAttributeErrorOnly()
9494
);
9595
Assert.AreEqual(Exceptions.TypeError, typeErrResult.Type);
9696
}
97+
98+
// regression test from https://github.com/pythonnet/pythonnet/issues/1642
99+
[Test]
100+
public void InheritedMethodsAutoacquireGIL()
101+
{
102+
PythonEngine.Exec("from System import String\nString.Format('{0},{1}', 1, 2)");
103+
}
97104
}
98105

99106
public class PyObjectTestMethods

src/runtime/InternString.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static void Initialize()
3939
{
4040
NewReference pyStr = Runtime.PyUnicode_InternFromString(name);
4141
var op = new PyString(pyStr.StealOrThrow());
42-
Debug.Assert(name == op.ToString());
42+
Debug.Assert(name == op.As<string>());
4343
SetIntern(name, op);
4444
var field = type.GetField("f" + name, PyIdentifierFieldFlags)!;
4545
field.SetValue(null, op.rawPtr);

src/runtime/Py.cs

+1-9
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,7 @@ namespace Python.Runtime;
1010

1111
public static class Py
1212
{
13-
public static GILState GIL()
14-
{
15-
if (!PythonEngine.IsInitialized)
16-
{
17-
PythonEngine.Initialize();
18-
}
19-
20-
return PythonEngine.DebugGIL ? new DebugGILState() : new GILState();
21-
}
13+
public static GILState GIL() => PythonEngine.DebugGIL ? new DebugGILState() : new GILState();
2214

2315
public static PyModule CreateScope() => new();
2416
public static PyModule CreateScope(string name)

src/runtime/PythonTypes/PyObject.cs

+16-5
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,7 @@ public PyList Dir()
10561056
/// </remarks>
10571057
public override string? ToString()
10581058
{
1059+
using var _ = Py.GIL();
10591060
using var strval = Runtime.PyObject_Str(obj);
10601061
return Runtime.GetManagedString(strval.BorrowOrThrow());
10611062
}
@@ -1072,7 +1073,11 @@ public PyList Dir()
10721073
/// Return true if this object is equal to the given object. This
10731074
/// method is based on Python equality semantics.
10741075
/// </remarks>
1075-
public override bool Equals(object o) => Equals(o as PyObject);
1076+
public override bool Equals(object o)
1077+
{
1078+
using var _ = Py.GIL();
1079+
return Equals(o as PyObject);
1080+
}
10761081

10771082
public virtual bool Equals(PyObject? other)
10781083
{
@@ -1101,6 +1106,7 @@ public virtual bool Equals(PyObject? other)
11011106
/// </remarks>
11021107
public override int GetHashCode()
11031108
{
1109+
using var _ = Py.GIL();
11041110
nint pyHash = Runtime.PyObject_Hash(obj);
11051111
if (pyHash == -1 && Exceptions.ErrorOccurred())
11061112
{
@@ -1135,12 +1141,14 @@ public long Refcount
11351141

11361142
public override bool TryGetMember(GetMemberBinder binder, out object? result)
11371143
{
1144+
using var _ = Py.GIL();
11381145
result = CheckNone(this.GetAttr(binder.Name));
11391146
return true;
11401147
}
11411148

11421149
public override bool TrySetMember(SetMemberBinder binder, object? value)
11431150
{
1151+
using var _ = Py.GIL();
11441152
using var newVal = Converter.ToPythonDetectType(value);
11451153
int r = Runtime.PyObject_SetAttrString(obj, binder.Name, newVal.Borrow());
11461154
if (r < 0)
@@ -1234,6 +1242,7 @@ private static NewReference GetPythonObject(object? target)
12341242

12351243
public override bool TryInvokeMember(InvokeMemberBinder binder, object?[] args, out object? result)
12361244
{
1245+
using var _ = Py.GIL();
12371246
if (this.HasAttr(binder.Name) && this.GetAttr(binder.Name).IsCallable())
12381247
{
12391248
PyTuple? pyargs = null;
@@ -1258,6 +1267,7 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object?[] args,
12581267

12591268
public override bool TryInvoke(InvokeBinder binder, object?[] args, out object? result)
12601269
{
1270+
using var _ = Py.GIL();
12611271
if (this.IsCallable())
12621272
{
12631273
PyTuple? pyargs = null;
@@ -1282,6 +1292,7 @@ public override bool TryInvoke(InvokeBinder binder, object?[] args, out object?
12821292

12831293
public override bool TryConvert(ConvertBinder binder, out object? result)
12841294
{
1295+
using var _ = Py.GIL();
12851296
// always try implicit conversion first
12861297
if (Converter.ToManaged(this.obj, binder.Type, out result, false))
12871298
{
@@ -1307,6 +1318,7 @@ public override bool TryConvert(ConvertBinder binder, out object? result)
13071318

13081319
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object? result)
13091320
{
1321+
using var _ = Py.GIL();
13101322
NewReference res;
13111323
if (!(arg is PyObject))
13121324
{
@@ -1419,6 +1431,7 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg
14191431

14201432
public override bool TryUnaryOperation(UnaryOperationBinder binder, out object? result)
14211433
{
1434+
using var _ = Py.GIL();
14221435
int r;
14231436
NewReference res;
14241437
switch (binder.Operation)
@@ -1463,10 +1476,8 @@ public override bool TryUnaryOperation(UnaryOperationBinder binder, out object?
14631476
/// <returns>A sequence that contains dynamic member names.</returns>
14641477
public override IEnumerable<string> GetDynamicMemberNames()
14651478
{
1466-
foreach (PyObject pyObj in Dir())
1467-
{
1468-
yield return pyObj.ToString()!;
1469-
}
1479+
using var _ = Py.GIL();
1480+
return Dir().Select(pyObj => pyObj.ToString()!).ToArray();
14701481
}
14711482

14721483
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)

0 commit comments

Comments
 (0)