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.
This commit is contained in:
Trey Moen
2026-09-21 17:26:44 -07:00
committed by GitHub
parent 8d80f4d69e
commit a0cb5cdf06
2 changed files with 4 additions and 4 deletions

View File

@@ -128,6 +128,7 @@ cdef extern from "capnp/schema.h" namespace " ::capnp":
cbool isEnum() cbool isEnum()
cbool isStruct() cbool isStruct()
cbool isInterface() cbool isInterface()
cbool isData()
StructSchema asStruct() except +reraise_kj_exception StructSchema asStruct() except +reraise_kj_exception
EnumSchema asEnum() 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 getUnionFields()
FieldSubset getNonUnionFields() FieldSubset getNonUnionFields()
Field getFieldByName(char * name) Field getFieldByName(char * name) except +reraise_kj_exception
cbool operator == (StructSchema) cbool operator == (StructSchema)

View File

@@ -1879,9 +1879,8 @@ cdef class _DynamicStructBuilder:
for key, val in d.iteritems(): for key, val in d.iteritems():
if key != 'which': if key != 'which':
if isinstance(val, str): if isinstance(val, str):
field = self.schema.fields.get(key) key_bytes = key.encode()
dtype = field.proto.slot.type.which() if self.thisptr.getSchema().getFieldByName(key_bytes).getType().isData():
if dtype == "data":
# decode bytes from utf-8 base64 encoding # decode bytes from utf-8 base64 encoding
val = base64.b64decode(val) val = base64.b64decode(val)
try: try: