Skip to content

Commit c7e377a

Browse files
committed
[derive_utils] Copy kwargs not to modify it
1 parent 96b71bf commit c7e377a

File tree

2 files changed

+23
-16
lines changed

2 files changed

+23
-16
lines changed

pyo3-derive-backend/src/pymethod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,12 +475,12 @@ pub fn impl_arg_params(spec: &FnSpec<'_>, body: TokenStream) -> TokenStream {
475475

476476
// Workaround to use the question mark operator without rewriting everything
477477
let _result = (|| {
478-
pyo3::derive_utils::parse_fn_args(
478+
let (_args, _kwargs) = pyo3::derive_utils::parse_fn_args(
479479
_py,
480480
Some(_LOCATION),
481481
PARAMS,
482-
&mut _args,
483-
&mut _kwargs,
482+
_args,
483+
_kwargs,
484484
#accept_args,
485485
#accept_kwargs,
486486
&mut output

src/derive_utils.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,24 @@ pub fn parse_fn_args<'p>(
3636
py: Python<'p>,
3737
fname: Option<&str>,
3838
params: &[ParamDescription],
39-
args: &mut &'p PyTuple,
40-
kwargs: &mut Option<&'p PyDict>,
39+
args: &'p PyTuple,
40+
kwargs: Option<&'p PyDict>,
4141
accept_args: bool,
4242
accept_kwargs: bool,
4343
output: &mut [Option<&'p PyAny>],
44-
) -> PyResult<()> {
44+
) -> PyResult<(&'p PyTuple, Option<&'p PyDict>)> {
4545
let nargs = args.len();
4646
let mut used_args = 0;
4747
macro_rules! raise_error {
4848
($s: expr $(,$arg:expr)*) => (return Err(TypeError::py_err(format!(
4949
concat!("{} ", $s), fname.unwrap_or("function") $(,$arg)*
5050
))))
5151
}
52+
// Copy kwargs not to modify it
53+
let kwargs = match kwargs {
54+
Some(k) => Some(k.copy()?),
55+
None => None,
56+
};
5257
// Iterate through the parameters and assign values to output:
5358
for (i, (p, out)) in params.iter().zip(output).enumerate() {
5459
*out = match kwargs.and_then(|d| d.get_item(p.name)) {
@@ -93,16 +98,18 @@ pub fn parse_fn_args<'p>(
9398
)
9499
}
95100
// Adjust the remaining args
96-
if accept_args {
97-
let slice = args
98-
.slice(used_args as isize, nargs as isize)
99-
.into_object(py);
100-
*args = py.checked_cast_as(slice).unwrap();
101-
}
102-
if accept_kwargs && is_kwargs_empty {
103-
*kwargs = None;
104-
}
105-
Ok(())
101+
let args = if accept_args {
102+
let slice = args.slice(used_args as isize, nargs as isize).into_py(py);
103+
py.checked_cast_as(slice).unwrap()
104+
} else {
105+
args
106+
};
107+
let kwargs = if accept_kwargs && is_kwargs_empty {
108+
None
109+
} else {
110+
kwargs
111+
};
112+
Ok((args, kwargs))
106113
}
107114

108115
/// Builds a module (or null) from a user given initializer. Used for `#[pymodule]`.

0 commit comments

Comments
 (0)