@@ -452,6 +452,7 @@ typedef struct {
452452#endif
453453 PyObject *astimezone;
454454 PyObject *re_compile;
455+ PyObject *get_annotate_from_class_namespace;
455456 uint8_t gc_cycle;
456457} MsgspecState;
457458
@@ -5814,12 +5815,45 @@ structmeta_is_classvar(
58145815
58155816static int
58165817structmeta_collect_fields(StructMetaInfo *info, MsgspecState *mod, bool kwonly) {
5817- PyObject *annotations = PyDict_GetItemString(
5818+ PyObject *annotations = PyDict_GetItemString( // borrowed reference
58185819 info->namespace, "__annotations__"
58195820 );
5820- if (annotations == NULL) return 0;
5821+ if (annotations == NULL) {
5822+ if (mod->get_annotate_from_class_namespace != NULL) {
5823+ PyObject *annotate = PyObject_CallOneArg(
5824+ mod->get_annotate_from_class_namespace, info->namespace
5825+ );
5826+ if (annotate == NULL) {
5827+ return -1;
5828+ }
5829+ if (annotate == Py_None) {
5830+ Py_DECREF(annotate);
5831+ return 0;
5832+ }
5833+ PyObject *format = PyLong_FromLong(1); /* annotationlib.Format.VALUE */
5834+ if (format == NULL) {
5835+ Py_DECREF(annotate);
5836+ return -1;
5837+ }
5838+ annotations = PyObject_CallOneArg(
5839+ annotate, format
5840+ );
5841+ Py_DECREF(annotate);
5842+ Py_DECREF(format);
5843+ if (annotations == NULL) {
5844+ return -1;
5845+ }
5846+ }
5847+ else {
5848+ return 0; // No annotations, nothing to do
5849+ }
5850+ }
5851+ else {
5852+ Py_INCREF(annotations);
5853+ }
58215854
58225855 if (!PyDict_Check(annotations)) {
5856+ Py_DECREF(annotations);
58235857 PyErr_SetString(PyExc_TypeError, "__annotations__ must be a dict");
58245858 return -1;
58255859 }
@@ -5869,6 +5903,7 @@ structmeta_collect_fields(StructMetaInfo *info, MsgspecState *mod, bool kwonly)
58695903 }
58705904 return 0;
58715905error:
5906+ Py_DECREF(annotations);
58725907 Py_XDECREF(module_ns);
58735908 return -1;
58745909}
@@ -22225,6 +22260,26 @@ PyInit__core(void)
2222522260 Py_DECREF(temp_module);
2222622261 if (st->re_compile == NULL) return NULL;
2222722262
22263+ /* annotationlib.get_annotate_from_class_namespace */
22264+ temp_module = PyImport_ImportModule("annotationlib");
22265+ if (temp_module == NULL) {
22266+ if (PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) {
22267+ // Below Python 3.14
22268+ PyErr_Clear();
22269+ st->get_annotate_from_class_namespace = NULL;
22270+ }
22271+ else {
22272+ return NULL;
22273+ }
22274+ }
22275+ else {
22276+ st->get_annotate_from_class_namespace = PyObject_GetAttrString(
22277+ temp_module, "get_annotate_from_class_namespace"
22278+ );
22279+ Py_DECREF(temp_module);
22280+ if (st->get_annotate_from_class_namespace == NULL) return NULL;
22281+ }
22282+
2222822283 /* Initialize cached constant strings */
2222922284#define CACHED_STRING(attr, str) \
2223022285 if ((st->attr = PyUnicode_InternFromString(str)) == NULL) return NULL
0 commit comments