(
zelf: &Py<Self>,
attr_name: &Py<PyStr>,
value: PySetterValue,
vm: &VirtualMachine,
)
| 595 | |
| 596 | impl SetAttr for PyCStructType { |
| 597 | fn setattro( |
| 598 | zelf: &Py<Self>, |
| 599 | attr_name: &Py<PyStr>, |
| 600 | value: PySetterValue, |
| 601 | vm: &VirtualMachine, |
| 602 | ) -> PyResult<()> { |
| 603 | // Check if _fields_ is being set |
| 604 | if attr_name.as_bytes() == b"_fields_" { |
| 605 | let pytype: &Py<PyType> = zelf.to_base(); |
| 606 | |
| 607 | // Check finalization in separate scope to release read lock before process_fields |
| 608 | // This prevents deadlock: process_fields needs write lock on the same RwLock |
| 609 | let is_final = { |
| 610 | let Some(stg_info) = pytype.get_type_data::<StgInfo>() else { |
| 611 | return Err(vm.new_type_error("ctypes state is not initialized")); |
| 612 | }; |
| 613 | stg_info.is_final() |
| 614 | }; // Read lock released here |
| 615 | |
| 616 | if is_final { |
| 617 | return Err(vm.new_attribute_error("_fields_ is final")); |
| 618 | } |
| 619 | |
| 620 | // Process _fields_ and set attribute |
| 621 | let PySetterValue::Assign(fields_value) = value else { |
| 622 | return Err(vm.new_attribute_error("cannot delete _fields_")); |
| 623 | }; |
| 624 | // Process fields (this will also set DICTFLAG_FINAL) |
| 625 | PyCStructType::process_fields(pytype, fields_value.clone(), vm)?; |
| 626 | // Set the _fields_ attribute on the type |
| 627 | pytype |
| 628 | .attributes |
| 629 | .write() |
| 630 | .insert(vm.ctx.intern_str("_fields_"), fields_value); |
| 631 | return Ok(()); |
| 632 | } |
| 633 | // Delegate to PyType's setattro logic for type attributes |
| 634 | let attr_name_interned = vm.ctx.intern_str(attr_name.as_wtf8()); |
| 635 | let pytype: &Py<PyType> = zelf.to_base(); |
| 636 | |
| 637 | // Check for data descriptor first |
| 638 | if let Some(attr) = pytype.get_class_attr(attr_name_interned) { |
| 639 | let descr_set = attr.class().slots.descr_set.load(); |
| 640 | if let Some(descriptor) = descr_set { |
| 641 | return descriptor(&attr, pytype.to_owned().into(), value, vm); |
| 642 | } |
| 643 | } |
| 644 | |
| 645 | // Store in type's attributes dict |
| 646 | if let PySetterValue::Assign(value) = value { |
| 647 | pytype.attributes.write().insert(attr_name_interned, value); |
| 648 | } else { |
| 649 | let prev = pytype.attributes.write().shift_remove(attr_name_interned); |
| 650 | if prev.is_none() { |
| 651 | return Err(vm.new_attribute_error(format!( |
| 652 | "type object '{}' has no attribute '{}'", |
| 653 | pytype.name(), |
| 654 | attr_name.as_wtf8(), |
nothing calls this directly
no test coverage detected