(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine)
| 379 | type Args = FuncArgs; |
| 380 | |
| 381 | fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult { |
| 382 | // Clone and release lock before calling Python code to prevent deadlock |
| 383 | let (func, stored_args, keywords, phcount) = { |
| 384 | let inner = zelf.inner.read(); |
| 385 | ( |
| 386 | inner.func.clone(), |
| 387 | inner.args.clone(), |
| 388 | inner.keywords.clone(), |
| 389 | inner.phcount, |
| 390 | ) |
| 391 | }; |
| 392 | |
| 393 | // Check if we have enough args to fill placeholders |
| 394 | if phcount > 0 && args.args.len() < phcount { |
| 395 | return Err(vm.new_type_error(format!( |
| 396 | "missing positional arguments in 'partial' call; expected at least {}, got {}", |
| 397 | phcount, |
| 398 | args.args.len() |
| 399 | ))); |
| 400 | } |
| 401 | |
| 402 | // Build combined args, replacing placeholders |
| 403 | let mut combined_args = Vec::with_capacity(stored_args.len() + args.args.len()); |
| 404 | let mut new_args_iter = args.args.iter(); |
| 405 | |
| 406 | for stored_arg in stored_args.as_slice() { |
| 407 | if is_placeholder(stored_arg) { |
| 408 | // Replace placeholder with next new arg |
| 409 | if let Some(new_arg) = new_args_iter.next() { |
| 410 | combined_args.push(new_arg.clone()); |
| 411 | } else { |
| 412 | // This shouldn't happen if phcount check passed |
| 413 | combined_args.push(stored_arg.clone()); |
| 414 | } |
| 415 | } else { |
| 416 | combined_args.push(stored_arg.clone()); |
| 417 | } |
| 418 | } |
| 419 | // Append remaining new args |
| 420 | combined_args.extend(new_args_iter.cloned()); |
| 421 | |
| 422 | // Merge keywords from self.keywords and args.kwargs |
| 423 | let mut final_kwargs = IndexMap::new(); |
| 424 | |
| 425 | // Add keywords from self.keywords |
| 426 | for (key, value) in &*keywords { |
| 427 | let key_str = key |
| 428 | .downcast_ref::<crate::builtins::PyStr>() |
| 429 | .ok_or_else(|| vm.new_type_error("keywords must be strings"))?; |
| 430 | final_kwargs.insert(key_str.expect_str().to_owned(), value); |
| 431 | } |
| 432 | |
| 433 | // Add keywords from args.kwargs (these override self.keywords) |
| 434 | for (key, value) in args.kwargs { |
| 435 | final_kwargs.insert(key, value); |
| 436 | } |
| 437 | |
| 438 | func.call(FuncArgs::new(combined_args, KwArgs::new(final_kwargs)), vm) |
no test coverage detected