Skip to content

Commit 8e6861e

Browse files
committed
Be strict about not loading on Python 3.13
That way we don't have to check for Py_REFCNT.
1 parent 3445b08 commit 8e6861e

2 files changed

Lines changed: 38 additions & 15 deletions

File tree

‎src/runtime/Native/ABI.cs‎

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
using static System.FormattableString;
2+
using System;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
17
namespace Python.Runtime.Native
28
{
3-
using System;
4-
using System.Globalization;
5-
using System.Linq;
6-
using System.Reflection;
7-
89
static class ABI
910
{
1011
// GIL builds only. FT splits the refcount; Refcount uses Py_REFCNT.
@@ -19,22 +20,28 @@ static class ABI
1920
internal static void Initialize(Version version)
2021
{
2122
IsFreeThreaded = DetectFreeThreaded();
23+
if (IsFreeThreaded && version < new Version(3, 14))
24+
{
25+
// We need Py_REFCNT to be available as a symbol, which is only
26+
// present in Python 3.14 and later.
27+
throw new NotSupportedException($"Python ABI v{version} is not supported: Free-threaded builds are only supported on Python 3.14 and later.");
28+
}
29+
2230
RefCountOffset = IsFreeThreaded ? -1 : ProbeRefCountOffset();
2331
ObjectHeadOffset = IsFreeThreaded
2432
? (IntPtr.Size == 4 ? 12 : 16)
2533
: RefCountOffset;
2634

27-
string offsetsClassSuffix = string.Format(CultureInfo.InvariantCulture,
28-
"{0}{1}", version.Major, version.Minor);
29-
3035
var thisAssembly = Assembly.GetExecutingAssembly();
3136

3237
const string nativeTypeOffsetClassName = "Python.Runtime.NativeTypeOffset";
33-
string className = "Python.Runtime.TypeOffset" + offsetsClassSuffix;
38+
string className = Invariant($"Python.Runtime.TypeOffset{version.Major}{version.Minor}");
39+
3440
Type nativeOffsetsClass = thisAssembly.GetType(nativeTypeOffsetClassName, throwOnError: false);
3541
Type typeOffsetsClass =
3642
// Try platform native offsets first. It is only present when generated by setup.py
3743
nativeOffsetsClass ?? thisAssembly.GetType(className, throwOnError: false);
44+
3845
if (typeOffsetsClass is null)
3946
{
4047
var types = thisAssembly.GetTypes().Select(type => type.Name).Where(name => name.StartsWith("TypeOffset"));
@@ -53,12 +60,30 @@ static bool DetectFreeThreaded()
5360
{
5461
// sys._is_gil_enabled() was added in Python 3.13; absent means GIL build.
5562
using var sys = Runtime.PyImport_ImportModule("sys");
56-
if (sys.IsNull()) { Runtime.PyErr_Clear(); return false; }
63+
64+
if (sys.IsNull())
65+
{
66+
Runtime.PyErr_Clear();
67+
return false;
68+
}
69+
5770
using var func = Runtime.PyObject_GetAttrString(sys.Borrow(), "_is_gil_enabled");
58-
if (func.IsNull()) { Runtime.PyErr_Clear(); return false; }
71+
72+
if (func.IsNull())
73+
{
74+
Runtime.PyErr_Clear();
75+
return false;
76+
}
77+
5978
using var args = Runtime.PyTuple_New(0);
6079
using var result = Runtime.PyObject_Call(func.Borrow(), args.Borrow(), default);
61-
if (result.IsNull()) { Runtime.PyErr_Clear(); return false; }
80+
81+
if (result.IsNull())
82+
{
83+
Runtime.PyErr_Clear();
84+
return false;
85+
}
86+
6287
return Runtime.PyObject_IsTrue(result.Borrow()) == 0;
6388
}
6489

@@ -71,7 +96,7 @@ static unsafe int ProbeRefCountOffset()
7196
using var tempObject = Runtime.PyList_New(0);
7297
IntPtr* tempPtr = (IntPtr*)tempObject.DangerousGetAddress();
7398
int offset = 0;
74-
while(tempPtr[offset] != (IntPtr)1)
99+
while (tempPtr[offset] != (IntPtr)1)
75100
{
76101
offset++;
77102
if (offset > 100)

‎src/runtime/Runtime.cs‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
using System.Text;
66
using System.Threading;
77
using System.Collections.Generic;
8-
using System.IO;
98
using Python.Runtime.Native;
109
using System.Linq;
11-
using static System.FormattableString;
1210

1311
namespace Python.Runtime
1412
{

0 commit comments

Comments
 (0)