Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1a1a9ab
Drop unused requirements.txt
filmor Feb 16, 2026
4ca65d6
Bump astral-sh/setup-uv from 6 to 7 (#2656)
dependabot[bot] Oct 28, 2025
0856eb4
Bump actions/checkout from 5 to 6 (#2663)
dependabot[bot] Nov 24, 2025
a7d0842
Only init/shutdown Python once
filmor Oct 22, 2025
f6ff431
Disable NUnit analyzer for now
filmor Oct 23, 2025
9fc08f3
Reset conversions after each codec test
filmor Oct 23, 2025
a8e5020
Remove shutdown from most tests, disable the rest for now
filmor Oct 23, 2025
0a6062e
Use python -m pytest, path seemingly not properly updated
filmor Oct 26, 2025
6b1bb92
Remove unused architecture from uv env activation
filmor Oct 26, 2025
d4d1768
Synchronize the environment
filmor Oct 26, 2025
40a3db7
Include the probed PythonDLL value in the exception
filmor Dec 7, 2025
96f428f
Use the actual pytest runner
filmor Dec 7, 2025
5459ac7
Move tests that require reinit and only run on .NET Framework
filmor Dec 8, 2025
abb6855
Bump NUnit3TestAdapter from 5.2.0 to 6.0.0 (#2667)
dependabot[bot] Dec 8, 2025
9882788
Fix line endings
filmor Dec 9, 2025
dc5c6c4
Add previous commit to ignore file
filmor Dec 9, 2025
caac33d
Initial 3.14 commit
filmor Aug 9, 2025
e10d333
Apply alignment fix
filmor Oct 22, 2025
e976558
Disable problematic GC tests
filmor Oct 22, 2025
65af098
Set ht_token to NULL in Python 3.14
filmor Oct 24, 2025
e244503
Fix lockfile
filmor Oct 26, 2025
8e0333d
Assign True instead of None to __clear_reentry_guard__
filmor Dec 6, 2025
cd108b8
Disable the three remaining failing tests
filmor Dec 6, 2025
698bf00
Take the GIL in sequence and list wrappers
filmor Dec 7, 2025
908e13b
Move tp_clear workaround to .NET
filmor Dec 7, 2025
c851b3a
Skip coreclr embedded tests for now
filmor Dec 7, 2025
08550d0
Workaround for blocked PyObject_GenericSetAttr in metatypes
filmor Dec 7, 2025
f1d90f3
Revert changes to tests
filmor Dec 7, 2025
a47555d
Bump macos image version and add arm64
filmor Dec 8, 2025
cebfd15
Reenable .NET Core embedding tests
filmor Dec 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Workaround for blocked PyObject_GenericSetAttr in metatypes
Python 3.14 introduced a new assertion that prevents us from using
PyObject_GenericSetAttr directly in our meta type. To work around
this, we manipulate the type dict directly.

This workaround is a simplified variant of Cython's workaround from
cython/cython#6325.

The relevant Python change is in
python/cpython#118454
  • Loading branch information
filmor committed Feb 24, 2026
commit 08550d090a88f91a84b028208cf57a8a3b9c1b58
3 changes: 3 additions & 0 deletions src/runtime/Native/PyIdentifier_.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ static class PyIdentifier
static IntPtr f__self__;
public static BorrowedReference __self__ => new(f__self__);
static IntPtr f__annotations__;
public static BorrowedReference __dictoffset__ => new(f__dictoffset__);
static IntPtr f__dictoffset__;
public static BorrowedReference __annotations__ => new(f__annotations__);
static IntPtr f__init__;
public static BorrowedReference __init__ => new(f__init__);
Expand Down Expand Up @@ -54,6 +56,7 @@ static partial class InternString
"__slots__",
"__self__",
"__annotations__",
"__dictoffset__",
"__init__",
"__repr__",
"__import__",
Expand Down
1 change: 1 addition & 0 deletions src/runtime/Native/PyIdentifier_.tt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"__slots__",
"__self__",
"__annotations__",
"__dictoffset__",

"__init__",
"__repr__",
Expand Down
44 changes: 43 additions & 1 deletion src/runtime/Types/MetaType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal sealed class MetaType : ManagedType
// set in Initialize
private static PyType PyCLRMetaType;
private static SlotsHolder _metaSlotsHodler;
private static int TypeDictOffset = -1;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.

internal static readonly string[] CustomMethods = new string[]
Expand All @@ -35,6 +36,25 @@ internal sealed class MetaType : ManagedType
public static PyType Initialize()
{
PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType), out _metaSlotsHodler);

// Retrieve the offset of the type's dictionary from PyType_Type for
// use in the tp_setattro implementation.
using (NewReference dictOffset = Runtime.PyObject_GetAttr(Runtime.PyTypeType, PyIdentifier.__dictoffset__))
{
if (dictOffset.IsNull())
{
throw new InvalidOperationException("Could not get __dictoffset__ from PyType_Type");
}

nint dictOffsetVal = Runtime.PyLong_AsSignedSize_t(dictOffset.Borrow());
if (dictOffsetVal <= 0)
{
throw new InvalidOperationException("Could not get __dictoffset__ from PyType_Type");
}

TypeDictOffset = checked((int)dictOffsetVal);
}

return PyCLRMetaType;
}

Expand All @@ -44,6 +64,7 @@ public static void Release()
{
_metaSlotsHodler.ResetSlots();
}
TypeDictOffset = -1;
PyCLRMetaType.Dispose();
}

Expand Down Expand Up @@ -287,7 +308,28 @@ public static int tp_setattro(BorrowedReference tp, BorrowedReference name, Borr
}
}

int res = Runtime.PyObject_GenericSetAttr(tp, name, value);
// Access the type's dictionary directly
//
// We can not use the PyObject_GenericSetAttr because since Python
// 3.14 as https://github.com/python/cpython/pull/118454 intrdoduced
// an assertion to prevent it from being called from metatypes.
//
// The direct dictionary access is equivalent to what Cython does
// to work around the same issue: https://github.com/cython/cython/pull/6325
BorrowedReference typeDict = new(Util.ReadIntPtr(tp, TypeDictOffset));
int res;
if (value.IsNull)
{
res = Runtime.PyDict_DelItem(typeDict, name);
if (res != 0)
{
Exceptions.SetError(Exceptions.AttributeError, "attribute not found");
}
}
else
{
res = Runtime.PyDict_SetItem(typeDict, name, value);
}
Runtime.PyType_Modified(tp);

return res;
Expand Down
1 change: 0 additions & 1 deletion tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,6 @@ def test_special_array_creation():
assert value.Length == 2


@pytest.mark.skip
def test_array_abuse():
"""Test array abuse."""
_class = Test.PublicArrayTest
Expand Down
1 change: 0 additions & 1 deletion tests/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,6 @@ def __setitem__(self, key, value):
assert table.Count == 3


@pytest.mark.skip
def test_add_and_remove_class_attribute():
from System import TimeSpan

Expand Down