Skip to content

Commit 28160b8

Browse files
committed
fix(TypeTree): support py3.14+ annotation fetching
1 parent 06087c1 commit 28160b8

3 files changed

Lines changed: 24 additions & 14 deletions

File tree

‎UnityPy/helpers/TypeTreeHelper.py‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import re
4+
from sys import version_info as py_version_info
45
from typing import TYPE_CHECKING, Any, Optional, Union
56

67
from attrs import define
@@ -108,6 +109,17 @@ def get_ref_type_node(ref_object: dict, assetfile: SerializedFile) -> Optional[T
108109
raise ValueError(f"Referenced type not found: {cls} {ns} {asm}")
109110

110111

112+
if py_version_info >= (3, 14):
113+
from annotationlib import get_annotations as annotationlib_get_annotations
114+
115+
def get_annotation_keys(clz) -> set[str]:
116+
return set(annotationlib_get_annotations(clz).keys())
117+
else:
118+
119+
def get_annotation_keys(clz) -> set[str]:
120+
return set(clz.__annotations__)
121+
122+
111123
def read_typetree(
112124
root_node: TypeTreeNode,
113125
reader: EndianBinaryReader,
@@ -231,7 +243,7 @@ def read_value(
231243
value = clz(**value)
232244
except TypeError:
233245
keys = set(value.keys())
234-
annotation_keys = set(clz.__annotations__)
246+
annotation_keys = get_annotation_keys(clz)
235247
missing_keys = annotation_keys - keys
236248
if clz is UnknownObject or missing_keys:
237249
value = UnknownObject(node, **value)
@@ -319,7 +331,7 @@ def read_value_array(
319331
UnknownObject,
320332
)
321333
keys = set(child._clean_name for child in node.m_Children)
322-
annotation_keys = set(clz.__annotations__)
334+
annotation_keys = get_annotation_keys(clz)
323335
missing_keys = annotation_keys - keys
324336
extra_keys = keys - annotation_keys
325337
if missing_keys or clz is UnknownObject:

‎UnityPyBoost/TypeTreeHelper.cpp‎

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -432,22 +432,12 @@ inline PyObject *read_class(ReaderT *reader, TypeTreeNodeObject *node, TypeTreeR
432432
return value;
433433
}
434434

435-
#if PY_VERSION_HEX >= 0x030e0000
436-
PyObject *get_annotations = nullptr;
437-
#endif
435+
static PyObject *_get_annotations = nullptr;
438436

439437
inline PyObject *get_annotations(PyObject *clz)
440438
{
441439
#if PY_VERSION_HEX >= 0x030e0000
442-
if (get_annotations == nullptr)
443-
{
444-
// from annotationlib import get_annotations
445-
PyObject *annotationlib = PyImport_ImportModule("annotationlib");
446-
get_annotations = PyObject_GetAttrString(annotationlib, "get_annotations");
447-
Py_INCREF(get_annotations);
448-
Py_DECREF(annotationlib);
449-
}
450-
return PyObject_CallFunctionObjArgs(get_annotations, clz, NULL);
440+
return PyObject_CallFunctionObjArgs(_get_annotations, clz, NULL);
451441
#else
452442
return PyObject_GetAttrString(clz, "__annotations__");
453443
#endif
@@ -1266,5 +1256,12 @@ int add_typetreenode_to_module(PyObject *m)
12661256
return -1;
12671257
Py_INCREF(&TypeTreeNodeType);
12681258
PyModule_AddObject(m, "TypeTreeNode", (PyObject *)&TypeTreeNodeType);
1259+
#if PY_VERSION_HEX >= 0x030e0000
1260+
PyObject *annotationlib = PyImport_ImportModule("annotationlib");
1261+
_get_annotations = PyObject_GetAttrString(annotationlib, "get_annotations");
1262+
PyModule_AddObject(m, "_get_annotations", _get_annotations); // steals ref
1263+
Py_INCREF(_get_annotations);
1264+
Py_DECREF(annotationlib);
1265+
#endif
12691266
return 0;
12701267
}

‎pyproject.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ classifiers = [
3232
"Programming Language :: Python :: 3.11",
3333
"Programming Language :: Python :: 3.12",
3434
"Programming Language :: Python :: 3.13",
35+
"Programming Language :: Python :: 3.14",
3536
"Topic :: Software Development :: Libraries :: Python Modules",
3637
"Topic :: Games/Entertainment",
3738
"Topic :: Multimedia :: Graphics",

0 commit comments

Comments
 (0)