Skip to content

Commit 73c8532

Browse files
authored
Merge pull request #2592 from davidhewitt/issue-2280
pyfunction: fix from_py_with on Option<T> argument
2 parents f927cdb + 9d543b3 commit 73c8532

3 files changed

Lines changed: 38 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
### Fixed
1212

1313
- Fix visibility of `PyDictItems`, `PyDictKeys`, and `PyDictValues` types added in PyO3 0.17.0.
14+
- 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)
1415

1516
## [0.17.0] - 2022-08-23
1617

pyo3-macros-backend/src/params.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ fn impl_arg_param(
247247
}
248248
(None, true) => {
249249
quote_arg_span! {
250-
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || Some(None))?
250+
_pyo3::impl_::extract_argument::from_py_with_with_default(#arg_value, #name_str, #expr_path, || None)?
251251
}
252252
}
253253
(None, false) => {

tests/test_pyfunction.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,42 @@ fn test_function_with_custom_conversion_error() {
165165
});
166166
}
167167

168+
#[test]
169+
fn test_from_py_with_defaults() {
170+
fn optional_int(x: &PyAny) -> PyResult<Option<i32>> {
171+
if x.is_none() {
172+
Ok(None)
173+
} else {
174+
Some(x.extract()).transpose()
175+
}
176+
}
177+
178+
// issue 2280 combination of from_py_with and Option<T> did not compile
179+
#[pyfunction]
180+
fn from_py_with_option(#[pyo3(from_py_with = "optional_int")] int: Option<i32>) -> i32 {
181+
int.unwrap_or(0)
182+
}
183+
184+
#[pyfunction(len = "0")]
185+
fn from_py_with_default(#[pyo3(from_py_with = "PyAny::len")] len: usize) -> usize {
186+
len
187+
}
188+
189+
Python::with_gil(|py| {
190+
let f = wrap_pyfunction!(from_py_with_option)(py).unwrap();
191+
192+
assert_eq!(f.call0().unwrap().extract::<i32>().unwrap(), 0);
193+
assert_eq!(f.call1((123,)).unwrap().extract::<i32>().unwrap(), 123);
194+
assert_eq!(f.call1((999,)).unwrap().extract::<i32>().unwrap(), 999);
195+
196+
let f2 = wrap_pyfunction!(from_py_with_default)(py).unwrap();
197+
198+
assert_eq!(f2.call0().unwrap().extract::<usize>().unwrap(), 0);
199+
assert_eq!(f2.call1(("123",)).unwrap().extract::<usize>().unwrap(), 3);
200+
assert_eq!(f2.call1(("1234",)).unwrap().extract::<usize>().unwrap(), 4);
201+
});
202+
}
203+
168204
#[pyclass]
169205
#[derive(Debug, FromPyObject)]
170206
struct ValueClass {

0 commit comments

Comments
 (0)