Skip to content

Commit

Permalink
Merge pull request #2592 from davidhewitt/issue-2280
Browse files Browse the repository at this point in the history
pyfunction: fix from_py_with on Option<T> argument
  • Loading branch information
davidhewitt committed Aug 26, 2022
2 parents f927cdb + 9d543b3 commit 73c8532
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Fix visibility of `PyDictItems`, `PyDictKeys`, and `PyDictValues` types added in PyO3 0.17.0.
- Fix compile failure when using `#[pyo3(from_py_with = "...")]` attribute on an argument of type `Option<T>`. [#2592](https://github.com/PyO3/pyo3/pull/2592)

## [0.17.0] - 2022-08-23

Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/params.rs
Expand Up @@ -247,7 +247,7 @@ fn impl_arg_param(
}
(None, true) => {
quote_arg_span! {
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || Some(None))?
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || None)?
}
}
(None, false) => {
Expand Down
36 changes: 36 additions & 0 deletions tests/test_pyfunction.rs
Expand Up @@ -165,6 +165,42 @@ fn test_function_with_custom_conversion_error() {
});
}

#[test]
fn test_from_py_with_defaults() {
fn optional_int(x: &PyAny) -> PyResult<Option<i32>> {
if x.is_none() {
Ok(None)
} else {
Some(x.extract()).transpose()
}
}

// issue 2280 combination of from_py_with and Option<T> did not compile
#[pyfunction]
fn from_py_with_option(#[pyo3(from_py_with = "optional_int")] int: Option<i32>) -> i32 {
int.unwrap_or(0)
}

#[pyfunction(len = "0")]
fn from_py_with_default(#[pyo3(from_py_with = "PyAny::len")] len: usize) -> usize {
len
}

Python::with_gil(|py| {
let f = wrap_pyfunction!(from_py_with_option)(py).unwrap();

assert_eq!(f.call0().unwrap().extract::<i32>().unwrap(), 0);
assert_eq!(f.call1((123,)).unwrap().extract::<i32>().unwrap(), 123);
assert_eq!(f.call1((999,)).unwrap().extract::<i32>().unwrap(), 999);

let f2 = wrap_pyfunction!(from_py_with_default)(py).unwrap();

assert_eq!(f2.call0().unwrap().extract::<usize>().unwrap(), 0);
assert_eq!(f2.call1(("123",)).unwrap().extract::<usize>().unwrap(), 3);
assert_eq!(f2.call1(("1234",)).unwrap().extract::<usize>().unwrap(), 4);
});
}

#[pyclass]
#[derive(Debug, FromPyObject)]
struct ValueClass {
Expand Down

0 comments on commit 73c8532

Please sign in to comment.