reduce_newobj - creates reduce tuple for protocol >= 2
(obj: PyObjectRef, vm: &VirtualMachine)
| 688 | |
| 689 | /// reduce_newobj - creates reduce tuple for protocol >= 2 |
| 690 | fn reduce_newobj(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { |
| 691 | // Check if type has tp_new |
| 692 | let cls = obj.class(); |
| 693 | if cls.slots.new.load().is_none() { |
| 694 | return Err(vm.new_type_error(format!("cannot pickle '{}' object", cls.name()))); |
| 695 | } |
| 696 | |
| 697 | let (args, kwargs) = get_new_arguments(&obj, vm)?; |
| 698 | |
| 699 | let copyreg = vm.import("copyreg", 0)?; |
| 700 | |
| 701 | let has_args = args.is_some(); |
| 702 | |
| 703 | let (newobj, newargs): (PyObjectRef, PyObjectRef) = if kwargs.is_none() |
| 704 | || kwargs.as_ref().is_some_and(|k| k.is_empty()) |
| 705 | { |
| 706 | // Use copyreg.__newobj__ |
| 707 | let newobj = copyreg.get_attr("__newobj__", vm)?; |
| 708 | |
| 709 | let args_vec: Vec<PyObjectRef> = args.map(|a| a.as_slice().to_vec()).unwrap_or_default(); |
| 710 | |
| 711 | // Create (cls, *args) tuple |
| 712 | let mut newargs_vec: Vec<PyObjectRef> = vec![cls.to_owned().into()]; |
| 713 | newargs_vec.extend(args_vec); |
| 714 | let newargs = vm.ctx.new_tuple(newargs_vec); |
| 715 | |
| 716 | (newobj, newargs.into()) |
| 717 | } else { |
| 718 | // args == NULL with non-empty kwargs is BadInternalCall |
| 719 | let Some(args) = args else { |
| 720 | return Err(vm.new_system_error("bad internal call")); |
| 721 | }; |
| 722 | // Use copyreg.__newobj_ex__ |
| 723 | let newobj = copyreg.get_attr("__newobj_ex__", vm)?; |
| 724 | let args_tuple: PyObjectRef = args.into(); |
| 725 | let kwargs_dict: PyObjectRef = kwargs |
| 726 | .map(|k| k.into()) |
| 727 | .unwrap_or_else(|| vm.ctx.new_dict().into()); |
| 728 | |
| 729 | let newargs = vm |
| 730 | .ctx |
| 731 | .new_tuple(vec![cls.to_owned().into(), args_tuple, kwargs_dict]); |
| 732 | (newobj, newargs.into()) |
| 733 | }; |
| 734 | |
| 735 | // Determine if state is required |
| 736 | // required = !(has_args || is_list || is_dict) |
| 737 | let is_list = obj.fast_isinstance(vm.ctx.types.list_type); |
| 738 | let is_dict = obj.fast_isinstance(vm.ctx.types.dict_type); |
| 739 | let required = !(has_args || is_list || is_dict); |
| 740 | |
| 741 | let state = object_getstate(&obj, required, vm)?; |
| 742 | |
| 743 | let (listitems, dictitems) = get_items_iter(&obj, vm)?; |
| 744 | |
| 745 | let result = vm |
| 746 | .ctx |
| 747 | .new_tuple(vec![newobj, newargs, state, listitems, dictitems]); |
no test coverage detected