From a0cb5cdf0673481f2f9850541f4d42b89698c476 Mon Sep 17 00:00:00 2001 From: Trey Moen <50057480+greatgitsby@users.noreply.github.com> Date: Mon, 21 Sep 2026 17:26:44 -0700 Subject: [PATCH] fix: check field type via C++ schema in from_dict to avoid a reference cycle (#407) from_dict called self.schema.fields for str values, which builds _StructSchemaField wrappers that reference the schema, so every message built via kwargs stayed alive until a GC pass. Follow-up to #401, which only skipped the lookup for non-str values. --- capnp/includes/capnp_cpp.pxd | 3 ++- capnp/lib/capnp.pyx | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/capnp/includes/capnp_cpp.pxd b/capnp/includes/capnp_cpp.pxd index ebb81e5..a5bc62c 100644 --- a/capnp/includes/capnp_cpp.pxd +++ b/capnp/includes/capnp_cpp.pxd @@ -128,6 +128,7 @@ cdef extern from "capnp/schema.h" namespace " ::capnp": cbool isEnum() cbool isStruct() cbool isInterface() + cbool isData() StructSchema asStruct() except +reraise_kj_exception EnumSchema asEnum() except +reraise_kj_exception @@ -185,7 +186,7 @@ cdef extern from "capnp/schema.h" namespace " ::capnp": FieldSubset getUnionFields() FieldSubset getNonUnionFields() - Field getFieldByName(char * name) + Field getFieldByName(char * name) except +reraise_kj_exception cbool operator == (StructSchema) diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index fd84deb..d4e6f5c 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -1879,9 +1879,8 @@ cdef class _DynamicStructBuilder: for key, val in d.iteritems(): if key != 'which': if isinstance(val, str): - field = self.schema.fields.get(key) - dtype = field.proto.slot.type.which() - if dtype == "data": + key_bytes = key.encode() + if self.thisptr.getSchema().getFieldByName(key_bytes).getType().isData(): # decode bytes from utf-8 base64 encoding val = base64.b64decode(val) try: