Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix IntoPyCallbackOutput paper cuts #2326

Merged
merged 9 commits into from
May 9, 2022
Merged

Fix IntoPyCallbackOutput paper cuts #2326

merged 9 commits into from
May 9, 2022

Conversation

mejrs
Copy link
Member

@mejrs mejrs commented Apr 23, 2022

struct Blah;

#[pyfunction]
fn blah() -> Blah{
    Blah
}

Current error:

error[E0277]: the trait bound `Blah: IntoPyCallbackOutput<_>` is not satisfied
   --> src\lib.rs:5:1
    |
5   | #[pyfunction]
    | ^^^^^^^^^^^^^ the trait `IntoPyCallbackOutput<_>` is not implemented for `Blah`
    |
note: required by a bound in `pyo3::callback::convert`
   --> C:\Users\bruno\rust\pyo3\src\callback.rs:182:8
    |
182 |     T: IntoPyCallbackOutput<U>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `pyo3::callback::convert`
    = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.

Error with this PR:

error[E0599]: the method `into_result` exists for struct `Blah`, but its trait bounds were not satisfied
   --> src\lib.rs:5:1
    |
3   | struct Blah;
    | ------------
    | |
    | method `into_result` not found for this
    | doesn't satisfy `Blah: IntoPy<Py<PyAny>>`
    | doesn't satisfy `Blah: IntoResult<Result<Blah, PyErr>>`
4   |
5   | #[pyfunction]
    | ^^^^^^^^^^^^^ method cannot be called on `Blah` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
            `Blah: IntoPy<Py<PyAny>>`
            which is required by `Blah: IntoResult<Result<Blah, PyErr>>`
            `&Blah: IntoPy<Py<PyAny>>`
            which is required by `&Blah: IntoResult<Result<&Blah, PyErr>>`
            `&mut Blah: IntoPy<Py<PyAny>>`
            which is required by `&mut Blah: IntoResult<Result<&mut Blah, PyErr>>`
note: the following trait must be implemented
   --> C:\Users\bruno\rust\pyo3\src\conversion.rs:182:1
    |
182 | / pub trait IntoPy<T>: Sized {
183 | |     /// Performs the conversion.
184 | |     fn into_py(self, py: Python<'_>) -> T;
185 | | }
    | |_^
    = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0599`.

Todo:

  • Changelog
  • Tests
  • Some ui tests

Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

First commit message - "Make arrays of pyclasses easier to sue" - oops :)

@mejrs mejrs marked this pull request as draft April 28, 2022 21:48
@mejrs mejrs force-pushed the callback branch 2 times, most recently from 7e54611 to 7477842 Compare May 1, 2022 09:07
@mejrs mejrs marked this pull request as ready for review May 1, 2022 20:49
Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice! Just a few final thoughts, and I think it would be better to change from IntoPyResult<R> -> IntoPyResult<T>. After that, I think this is good to merge 👍

Comment on lines 486 to 489
if false {
use _pyo3::impl_::ghost::IntoPyResult;
ret.into_py_result();
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer this approach over what I did before. This won't actually call into_py_result if an user accidentally writes it for their type.

Comment on lines 1 to 19
/// If it does nothing, was it ever really there? 👻
///
/// This is code that is just type checked to e.g. create better compile errors,
/// but that never affects anything at runtime,
use crate::{IntoPy, PyErr, PyObject};

#[allow(clippy::wrong_self_convention)]
pub trait IntoPyResult<T> {
fn into_py_result(&mut self) {}
}

impl<T> IntoPyResult<T> for T where T: IntoPy<PyObject> {}

impl<T, E> IntoPyResult<T> for Result<T, E>
where
T: IntoPy<PyObject>,
E: Into<PyErr>,
{
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer this approach of code that doesn't actually do anything 😉

Comment on lines +27 to +38
error[E0277]: the trait bound `Blah: IntoPyCallbackOutput<_>` is not satisfied
--> tests/ui/missing_intopy.rs:3:1
|
3 | #[pyo3::pyfunction]
| ^^^^^^^^^^^^^^^^^^^ the trait `IntoPyCallbackOutput<_>` is not implemented for `Blah`
|
note: required by a bound in `pyo3::callback::convert`
--> src/callback.rs
|
| T: IntoPyCallbackOutput<U>,
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `pyo3::callback::convert`
= note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unfortunate this IntoPyCallbackOutput part is back - but overall I think it's worth it. The first part of the error is very very good.

Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sneaky! Nicely done 👍

/// but that never affects anything at runtime,
use crate::{IntoPy, PyErr, PyObject};

#[allow(clippy::wrong_self_convention)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this lint actually necessary? I wonder if it's a hangover from experimentation.

Copy link
Member Author

@mejrs mejrs May 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that hits the methods called into_* usually take self by value lint. The reason it takes &mut self is to prevent a cascade like this:

           which is required by `Blah: IntoResult<Result<Blah, PyErr>>`
            which is required by `Blah: IntoPyResult<Result<Blah, PyErr>>`
            `&Blah: IntoPy<Py<PyAny>>`
            which is required by `&Blah: IntoResult<Result<&Blah, PyErr>>`
            which is required by `&Blah: IntoPyResult<Result<&Blah, PyErr>>`
            `&mut Blah: IntoPy<Py<PyAny>>`
            which is required by `&mut Blah: IntoResult<Result<&mut Blah, PyErr>>`
            which is required by `&mut Blah: IntoPyResult<Result<&mut Blah, PyErr>>`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see! Do you think we should name the method differently then? E.g. into_py_result_hint or assert_into_py_result?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure 👍

Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM! To squash out the various interim commits I'm gonna squash-merge this one 👍

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

IntoPyCallbackOutput<_> is not implimented for arrays of pyclass
2 participants