Skip to content

Commit 8cc541d

Browse files
committed
add tests
1 parent 852a5ea commit 8cc541d

File tree

3 files changed

+69
-5
lines changed

3 files changed

+69
-5
lines changed

src/conversion.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,38 @@ impl<'py> IntoPyObject<'py> for () {
602602
/// })
603603
/// ```
604604
mod test_no_clone {}
605+
606+
#[cfg(test)]
607+
mod tests {
608+
use crate::{types::PyAnyMethods, FromPyObject, IntoPyObject, PyErr, Python};
609+
610+
#[test]
611+
#[cfg(feature = "macros")]
612+
fn test_pyclass_skip_from_py_object() {
613+
#[crate::pyclass(crate = "crate", skip_from_py_object)]
614+
#[derive(Clone)]
615+
struct Foo(i32);
616+
617+
impl<'py> FromPyObject<'_, 'py> for Foo {
618+
type Error = PyErr;
619+
620+
fn extract(obj: crate::Borrowed<'_, 'py, crate::PyAny>) -> Result<Self, Self::Error> {
621+
if let Ok(obj) = obj.cast::<Self>() {
622+
Ok(obj.borrow().clone())
623+
} else {
624+
obj.extract::<i32>().map(Self)
625+
}
626+
}
627+
}
628+
Python::attach(|py| {
629+
let foo1 = 42i32.into_pyobject(py)?;
630+
assert_eq!(foo1.extract::<Foo>()?.0, 42);
631+
632+
let foo2 = Foo(0).into_pyobject(py)?;
633+
assert_eq!(foo2.extract::<Foo>()?.0, 0);
634+
635+
Ok::<_, PyErr>(())
636+
})
637+
.unwrap();
638+
}
639+
}

tests/ui/invalid_pyfunction_argument.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,13 @@ fn invalid_pyfunction_argument(arg: AtomicPtr<()>) {
66
let _ = arg;
77
}
88

9+
#[pyclass(skip_from_py_object)]
10+
#[derive(Clone)]
11+
struct Foo;
12+
13+
#[pyfunction]
14+
fn skip_from_py_object_without_custom_from_py_object(arg: Foo) {
15+
let _ = arg;
16+
}
17+
918
fn main() {}

tests/ui/invalid_pyfunction_argument.stderr

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ error[E0277]: `AtomicPtr<()>` cannot be used as a Python function argument
66
|
77
= note: implement `FromPyObject` to enable using `AtomicPtr<()>` as a function argument
88
= note: `Python<'py>` is also a valid argument type to pass the Python token into `#[pyfunction]`s and `#[pymethods]`
9-
= help: the following other types implement trait `PyFunctionArgument<'a, 'holder, 'py, IMPLEMENTS_FROMPYOBJECT>`:
10-
`&'a pyo3::Bound<'py, T>` implements `PyFunctionArgument<'a, '_, 'py, false>`
11-
`&'holder T` implements `PyFunctionArgument<'a, 'holder, '_, false>`
12-
`&'holder mut T` implements `PyFunctionArgument<'a, 'holder, '_, false>`
13-
`Option<T>` implements `PyFunctionArgument<'a, 'holder, 'py, false>`
9+
= help: the trait `PyClass` is implemented for `Foo`
1410
= note: required for `AtomicPtr<()>` to implement `FromPyObject<'_, '_>`
1511
= note: required for `AtomicPtr<()>` to implement `PyFunctionArgument<'_, '_, '_, true>`
1612
note: required by a bound in `extract_argument`
@@ -69,3 +65,27 @@ note: required by a bound in `extract_argument`
6965
...
7066
| T: PyFunctionArgument<'a, 'holder, 'py, IMPLEMENTS_FROMPYOBJECT>,
7167
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument`
68+
69+
error[E0277]: `Foo` cannot be used as a Python function argument
70+
--> tests/ui/invalid_pyfunction_argument.rs:14:59
71+
|
72+
14 | fn skip_from_py_object_without_custom_from_py_object(arg: Foo) {
73+
| ^^^ the trait `ExtractPyClassWithClone` is not implemented for `Foo`
74+
|
75+
= note: implement `FromPyObject` to enable using `Foo` as a function argument
76+
= note: `Python<'py>` is also a valid argument type to pass the Python token into `#[pyfunction]`s and `#[pymethods]`
77+
= help: the following other types implement trait `PyFunctionArgument<'a, 'holder, 'py, IMPLEMENTS_FROMPYOBJECT>`:
78+
`&'a pyo3::Bound<'py, T>` implements `PyFunctionArgument<'a, '_, 'py, false>`
79+
`&'holder T` implements `PyFunctionArgument<'a, 'holder, '_, false>`
80+
`&'holder mut T` implements `PyFunctionArgument<'a, 'holder, '_, false>`
81+
`Option<T>` implements `PyFunctionArgument<'a, 'holder, 'py, false>`
82+
= note: required for `Foo` to implement `FromPyObject<'_, '_>`
83+
= note: required for `Foo` to implement `PyFunctionArgument<'_, '_, '_, true>`
84+
note: required by a bound in `extract_argument`
85+
--> src/impl_/extract_argument.rs
86+
|
87+
| pub fn extract_argument<'a, 'holder, 'py, T, const IMPLEMENTS_FROMPYOBJECT: bool>(
88+
| ---------------- required by a bound in this function
89+
...
90+
| T: PyFunctionArgument<'a, 'holder, 'py, IMPLEMENTS_FROMPYOBJECT>,
91+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument`

0 commit comments

Comments
 (0)