Skip to content

Commit

Permalink
Fix kwargs
Browse files Browse the repository at this point in the history
kwargs was broken by a check for the number of given arguments. Only
apply this check if no arbitary number of keyword arguments are allowed
by a "**" parameter of `#[args(...)`.

Closes PyO3#318
  • Loading branch information
Alexander-N committed Jan 24, 2019
1 parent 27ef337 commit fbd0126
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/derive_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub fn parse_fn_args<'p>(
) -> PyResult<()> {
let nargs = args.len();
let nkeywords = kwargs.map_or(0, |d| d.len());
if !accept_args && (nargs + nkeywords > params.len()) {
if !accept_args && !accept_kwargs && (nargs + nkeywords > params.len()) {
return Err(TypeError::py_err(format!(
"{}{} takes at most {} argument{} ({} given)",
fname.unwrap_or("function"),
Expand Down
52 changes: 52 additions & 0 deletions tests/test_variable_arguments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#![feature(custom_attribute)]
#![feature(specialization)]

extern crate pyo3;

use pyo3::prelude::*;
use pyo3::types::{PyDict, PyTuple};

#[macro_use]
mod common;

#[pyclass]
struct MyClass {}

#[pymethods]
impl MyClass {
#[staticmethod]
#[args(args = "*")]
fn test_args(args: &PyTuple) -> PyResult<&PyTuple> {
Ok(args)
}

#[staticmethod]
#[args(kwargs = "**")]
fn test_kwargs(kwargs: Option<&PyDict>) -> PyResult<Option<&PyDict>> {
Ok(kwargs)
}
}

#[test]
fn variable_args() {
let gil = Python::acquire_gil();
let py = gil.python();
let my_obj = py.get_type::<MyClass>();
py_assert!(py, my_obj, "my_obj.test_args() == ()");
py_assert!(py, my_obj, "my_obj.test_args(1) == (1,)");
py_assert!(py, my_obj, "my_obj.test_args(1, 2) == (1, 2)");
}

#[test]
fn variable_kwargs() {
let gil = Python::acquire_gil();
let py = gil.python();
let my_obj = py.get_type::<MyClass>();
py_assert!(py, my_obj, "my_obj.test_kwargs() == None");
py_assert!(py, my_obj, "my_obj.test_kwargs(test=1) == {'test': 1}");
py_assert!(
py,
my_obj,
"my_obj.test_kwargs(test1=1, test2=2) == {'test1':1, 'test2':2}"
);
}

0 comments on commit fbd0126

Please sign in to comment.