Skip to content

Python 3.12 #2249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
fail-fast: false
matrix:
os: [windows, ubuntu, macos]
python: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
platform: [x64, x86]
exclude:
- os: ubuntu
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].

### Added

- use enum name in repr
- Use enum name in `repr`
- Support for Python 3.12

### Changed

Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies = [
"clr_loader>=0.2.6,<0.3.0"
]

requires-python = ">=3.7, <3.12"
requires-python = ">=3.7, <3.13"

classifiers = [
"Development Status :: 5 - Production/Stable",
Expand All @@ -26,6 +26,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS :: MacOS X",
Expand Down
22 changes: 17 additions & 5 deletions src/embed_tests/Codecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,23 @@ public void FloatDerivedDecoded()
[Test]
public void ExceptionDecodedNoInstance()
{
PyObjectConversions.RegisterDecoder(new InstancelessExceptionDecoder());
using var scope = Py.CreateScope();
var error = Assert.Throws<ValueErrorWrapper>(() => PythonEngine.Exec(
$"[].__iter__().__next__()"));
Assert.AreEqual(TestExceptionMessage, error.Message);
if (Runtime.PyVersion < new Version(3, 12))
{
PyObjectConversions.RegisterDecoder(new InstancelessExceptionDecoder());
using var scope = Py.CreateScope();

var error = Assert.Throws<ValueErrorWrapper>(() =>
PythonEngine.Exec($"[].__iter__().__next__()")
);
Assert.AreEqual(TestExceptionMessage, error.Message);
}
else
{
Assert.Ignore(
"This test does not work for Python 3.12, see " +
"https://github.com/python/cpython/issues/101578"
);
}
}

public static void AcceptsDateTime(DateTime v) {}
Expand Down
6 changes: 2 additions & 4 deletions src/runtime/Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -686,10 +686,8 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
{
if (Runtime.PyUnicode_GetLength(value) == 1)
{
IntPtr unicodePtr = Runtime.PyUnicode_AsUnicode(value);
Char[] buff = new Char[1];
Marshal.Copy(unicodePtr, buff, 0, 1);
result = buff[0];
int chr = Runtime.PyUnicode_ReadChar(value, 0);
result = (Char)chr;
return true;
}
goto type_error;
Expand Down
144 changes: 144 additions & 0 deletions src/runtime/Native/TypeOffset312.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@

// Auto-generated by geninterop.py.
// DO NOT MODIFY BY HAND.

// Python 3.12: ABI flags: ''

// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;

using Python.Runtime.Native;

namespace Python.Runtime
{
[SuppressMessage("Style", "IDE1006:Naming Styles",
Justification = "Following CPython",
Scope = "type")]

[StructLayout(LayoutKind.Sequential)]
internal class TypeOffset312 : GeneratedTypeOffsets, ITypeOffsets
{
public TypeOffset312() { }
// Auto-generated from PyHeapTypeObject in Python.h
public int ob_refcnt { get; private set; }
public int ob_type { get; private set; }
public int ob_size { get; private set; }
public int tp_name { get; private set; }
public int tp_basicsize { get; private set; }
public int tp_itemsize { get; private set; }
public int tp_dealloc { get; private set; }
public int tp_vectorcall_offset { get; private set; }
public int tp_getattr { get; private set; }
public int tp_setattr { get; private set; }
public int tp_as_async { get; private set; }
public int tp_repr { get; private set; }
public int tp_as_number { get; private set; }
public int tp_as_sequence { get; private set; }
public int tp_as_mapping { get; private set; }
public int tp_hash { get; private set; }
public int tp_call { get; private set; }
public int tp_str { get; private set; }
public int tp_getattro { get; private set; }
public int tp_setattro { get; private set; }
public int tp_as_buffer { get; private set; }
public int tp_flags { get; private set; }
public int tp_doc { get; private set; }
public int tp_traverse { get; private set; }
public int tp_clear { get; private set; }
public int tp_richcompare { get; private set; }
public int tp_weaklistoffset { get; private set; }
public int tp_iter { get; private set; }
public int tp_iternext { get; private set; }
public int tp_methods { get; private set; }
public int tp_members { get; private set; }
public int tp_getset { get; private set; }
public int tp_base { get; private set; }
public int tp_dict { get; private set; }
public int tp_descr_get { get; private set; }
public int tp_descr_set { get; private set; }
public int tp_dictoffset { get; private set; }
public int tp_init { get; private set; }
public int tp_alloc { get; private set; }
public int tp_new { get; private set; }
public int tp_free { get; private set; }
public int tp_is_gc { get; private set; }
public int tp_bases { get; private set; }
public int tp_mro { get; private set; }
public int tp_cache { get; private set; }
public int tp_subclasses { get; private set; }
public int tp_weaklist { get; private set; }
public int tp_del { get; private set; }
public int tp_version_tag { get; private set; }
public int tp_finalize { get; private set; }
public int tp_vectorcall { get; private set; }
public int tp_watched { get; private set; }
public int am_await { get; private set; }
public int am_aiter { get; private set; }
public int am_anext { get; private set; }
public int am_send { get; private set; }
public int nb_add { get; private set; }
public int nb_subtract { get; private set; }
public int nb_multiply { get; private set; }
public int nb_remainder { get; private set; }
public int nb_divmod { get; private set; }
public int nb_power { get; private set; }
public int nb_negative { get; private set; }
public int nb_positive { get; private set; }
public int nb_absolute { get; private set; }
public int nb_bool { get; private set; }
public int nb_invert { get; private set; }
public int nb_lshift { get; private set; }
public int nb_rshift { get; private set; }
public int nb_and { get; private set; }
public int nb_xor { get; private set; }
public int nb_or { get; private set; }
public int nb_int { get; private set; }
public int nb_reserved { get; private set; }
public int nb_float { get; private set; }
public int nb_inplace_add { get; private set; }
public int nb_inplace_subtract { get; private set; }
public int nb_inplace_multiply { get; private set; }
public int nb_inplace_remainder { get; private set; }
public int nb_inplace_power { get; private set; }
public int nb_inplace_lshift { get; private set; }
public int nb_inplace_rshift { get; private set; }
public int nb_inplace_and { get; private set; }
public int nb_inplace_xor { get; private set; }
public int nb_inplace_or { get; private set; }
public int nb_floor_divide { get; private set; }
public int nb_true_divide { get; private set; }
public int nb_inplace_floor_divide { get; private set; }
public int nb_inplace_true_divide { get; private set; }
public int nb_index { get; private set; }
public int nb_matrix_multiply { get; private set; }
public int nb_inplace_matrix_multiply { get; private set; }
public int mp_length { get; private set; }
public int mp_subscript { get; private set; }
public int mp_ass_subscript { get; private set; }
public int sq_length { get; private set; }
public int sq_concat { get; private set; }
public int sq_repeat { get; private set; }
public int sq_item { get; private set; }
public int was_sq_slice { get; private set; }
public int sq_ass_item { get; private set; }
public int was_sq_ass_slice { get; private set; }
public int sq_contains { get; private set; }
public int sq_inplace_concat { get; private set; }
public int sq_inplace_repeat { get; private set; }
public int bf_getbuffer { get; private set; }
public int bf_releasebuffer { get; private set; }
public int name { get; private set; }
public int ht_slots { get; private set; }
public int qualname { get; private set; }
public int ht_cached_keys { get; private set; }
public int ht_module { get; private set; }
public int _ht_tpname { get; private set; }
public int spec_cache_getitem { get; private set; }
public int getitem_version { get; private set; }
}
}

2 changes: 1 addition & 1 deletion src/runtime/PythonEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public static string PythonPath
}

public static Version MinSupportedVersion => new(3, 7);
public static Version MaxSupportedVersion => new(3, 11, int.MaxValue, int.MaxValue);
public static Version MaxSupportedVersion => new(3, 12, int.MaxValue, int.MaxValue);
public static bool IsSupportedVersion(Version version) => version >= MinSupportedVersion && version <= MaxSupportedVersion;

public static string Version
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/Runtime.Delegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ static Delegates()
PyUnicode_AsUTF8 = (delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr>)GetFunctionByName(nameof(PyUnicode_AsUTF8), GetUnmanagedDll(_PythonDll));
PyUnicode_DecodeUTF16 = (delegate* unmanaged[Cdecl]<IntPtr, nint, IntPtr, IntPtr, NewReference>)GetFunctionByName(nameof(PyUnicode_DecodeUTF16), GetUnmanagedDll(_PythonDll));
PyUnicode_GetLength = (delegate* unmanaged[Cdecl]<BorrowedReference, nint>)GetFunctionByName(nameof(PyUnicode_GetLength), GetUnmanagedDll(_PythonDll));
PyUnicode_AsUnicode = (delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr>)GetFunctionByName(nameof(PyUnicode_AsUnicode), GetUnmanagedDll(_PythonDll));
PyUnicode_AsUTF16String = (delegate* unmanaged[Cdecl]<BorrowedReference, NewReference>)GetFunctionByName(nameof(PyUnicode_AsUTF16String), GetUnmanagedDll(_PythonDll));
PyUnicode_ReadChar = (delegate* unmanaged[Cdecl]<BorrowedReference, nint, int>)GetFunctionByName(nameof(PyUnicode_ReadChar), GetUnmanagedDll(_PythonDll));
PyUnicode_FromOrdinal = (delegate* unmanaged[Cdecl]<int, NewReference>)GetFunctionByName(nameof(PyUnicode_FromOrdinal), GetUnmanagedDll(_PythonDll));
PyUnicode_InternFromString = (delegate* unmanaged[Cdecl]<StrPtr, NewReference>)GetFunctionByName(nameof(PyUnicode_InternFromString), GetUnmanagedDll(_PythonDll));
PyUnicode_Compare = (delegate* unmanaged[Cdecl]<BorrowedReference, BorrowedReference, int>)GetFunctionByName(nameof(PyUnicode_Compare), GetUnmanagedDll(_PythonDll));
Expand Down Expand Up @@ -441,7 +441,7 @@ static Delegates()
internal static delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr> PyUnicode_AsUTF8 { get; }
internal static delegate* unmanaged[Cdecl]<IntPtr, nint, IntPtr, IntPtr, NewReference> PyUnicode_DecodeUTF16 { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, nint> PyUnicode_GetLength { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, IntPtr> PyUnicode_AsUnicode { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, nint, int> PyUnicode_ReadChar { get; }
internal static delegate* unmanaged[Cdecl]<BorrowedReference, NewReference> PyUnicode_AsUTF16String { get; }
internal static delegate* unmanaged[Cdecl]<int, NewReference> PyUnicode_FromOrdinal { get; }
internal static delegate* unmanaged[Cdecl]<StrPtr, NewReference> PyUnicode_InternFromString { get; }
Expand Down
51 changes: 3 additions & 48 deletions src/runtime/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -598,23 +598,8 @@ internal static void CheckExceptionOccurred()
[Obsolete("Use NewReference or PyObject constructor instead")]
internal static unsafe void XIncref(BorrowedReference op)
{
#if !CUSTOM_INCDEC_REF
Py_IncRef(op);
return;
#else
var p = (void*)op;
if ((void*)0 != p)
{
if (Is32Bit)
{
(*(int*)p)++;
}
else
{
(*(long*)p)++;
}
}
#endif
}

internal static unsafe void XDecref(StolenReference op)
Expand All @@ -623,40 +608,9 @@ internal static unsafe void XDecref(StolenReference op)
Debug.Assert(op == null || Refcount(new BorrowedReference(op.Pointer)) > 0);
Debug.Assert(_isInitialized || Py_IsInitialized() != 0 || _Py_IsFinalizing() != false);
#endif
#if !CUSTOM_INCDEC_REF
if (op == null) return;
Py_DecRef(op.AnalyzerWorkaround());
return;
#else
var p = (void*)op;
if ((void*)0 != p)
{
if (Is32Bit)
{
--(*(int*)p);
}
else
{
--(*(long*)p);
}
if ((*(int*)p) == 0)
{
// PyObject_HEAD: struct _typeobject *ob_type
void* t = Is32Bit
? (void*)(*((uint*)p + 1))
: (void*)(*((ulong*)p + 1));
// PyTypeObject: destructor tp_dealloc
void* f = Is32Bit
? (void*)(*((uint*)t + 6))
: (void*)(*((ulong*)t + 6));
if ((void*)0 == f)
{
return;
}
NativeCall.Void_Call_1(new IntPtr(f), op);
}
}
#endif
}

[Pure]
Expand Down Expand Up @@ -985,7 +939,7 @@ internal static BorrowedReference PyObject_GetWeakRefList(BorrowedReference ob)
Debug.Assert(ob != null);
var type = PyObject_TYPE(ob);
int offset = Util.ReadInt32(type, TypeOffset.tp_weaklistoffset);
if (offset == 0) return BorrowedReference.Null;
if (offset <= 0) return BorrowedReference.Null;
Debug.Assert(offset > 0);
return Util.ReadRef(ob, offset);
}
Expand Down Expand Up @@ -1336,9 +1290,10 @@ internal static IntPtr PyBytes_AsString(BorrowedReference ob)
internal static nint PyUnicode_GetLength(BorrowedReference ob) => Delegates.PyUnicode_GetLength(ob);


internal static IntPtr PyUnicode_AsUnicode(BorrowedReference ob) => Delegates.PyUnicode_AsUnicode(ob);
internal static NewReference PyUnicode_AsUTF16String(BorrowedReference ob) => Delegates.PyUnicode_AsUTF16String(ob);

internal static int PyUnicode_ReadChar(BorrowedReference ob, nint index) => Delegates.PyUnicode_ReadChar(ob, index);



internal static NewReference PyUnicode_FromOrdinal(int c) => Delegates.PyUnicode_FromOrdinal(c);
Expand Down
14 changes: 13 additions & 1 deletion tools/geninterop/geninterop.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def visit(self, node):
self.visit_ptrdecl(node)
elif isinstance(node, c_ast.IdentifierType):
self.visit_identifier(node)
elif isinstance(node, c_ast.Union):
self.visit_union(node)

def visit_ast(self, ast):
for _name, node in ast.children():
Expand Down Expand Up @@ -119,6 +121,16 @@ def visit_identifier(self, identifier):
type_name = " ".join(identifier.names)
self._add_struct_member(type_name)

def visit_union(self, union):
# Treat the field as if it was just the first declaration for now. This
# is not really correct, but handles the one case that is relevant for
# us right now (ob_refcnt being "split" in Python 3.12)
if self._struct_members_stack and union.decls:
decl = union.decls[0]
self._struct_members_stack.pop(0)
self._struct_members_stack.insert(0, decl.name)
self.visit(decl)

def _add_struct_member(self, type_name):
if not (self._struct_stack and self._struct_members_stack):
return
Expand Down Expand Up @@ -245,7 +257,7 @@ def gen_interop_head(writer, version, abi_flags):
// Auto-generated by {filename}.
// DO NOT MODIFY BY HAND.

// Python {".".join(version[:2])}: ABI flags: '{abi_flags}'
// Python {".".join(map(str, version[:2]))}: ABI flags: '{abi_flags}'

// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo
Expand Down