Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

create_exception: the trait bound MyError: pyo3::PyNativeType is not satisfied #4562

Open
Wicpar opened this issue Sep 17, 2024 · 2 comments
Labels

Comments

@Wicpar
Copy link

Wicpar commented Sep 17, 2024

Bug Description

while migrating to pyo3 0.22.3 the declared exceptions were no longer compiling due to a missing trait bound

Steps to Reproduce

  1. define a create_exception!(my_module, MyError, PyException, "Some description.");
  2. it doen't compile

Backtrace

error[E0277]: the trait bound `MyError: pyo3::PyNativeType` is not satisfied
  --> \bindings\python\src\exceptions.rs:4:1
   |
4  | create_exception!(my_module, MyError, PyException, "Some description.");
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `pyo3::PyNativeType` is not implemented for `MyError`
   |
   = help: the following other types implement trait `pyo3::PyNativeType`:
             PyArray<T, D>
             PyArrayDescr
             PyUntypedArray
             PyCell<T>
             PyAny
             PyBool
             PyByteArray
             PyBytes
           and 115 others
   = note: required for `MyError` to implement `HasPyGilRef`
note: required by a bound in `PyTypeInfo`
  --> .cargo\registry\src\index.crates.io-6f17d22bba15001f\pyo3-0.22.3\src\type_object.rs:63:38
   |
63 | pub unsafe trait PyTypeInfo: Sized + HasPyGilRef {
   |                                      ^^^^^^^^^^^ required by this bound in `PyTypeInfo`
   = note: this error originates in the macro `$crate::create_exception_type_object` which comes from the expansion of the macro `create_exception` (in Nightly builds, run with -Z macro-backtrace for more info)

Your operating system and version

Windows 10

Your Python version (python --version)

3.12

Your Rust version (rustc --version)

1.75

Your PyO3 version

0.22

How did you install python? Did you use a virtualenv?

python is not required to reproduce the issue

Additional Info

No response

@Wicpar Wicpar added the bug label Sep 17, 2024
@davidhewitt
Copy link
Member

Thanks for the report. Can you please provide a more complete minimal reproduction? I cannot reproduce this locally.

@Wicpar
Copy link
Author

Wicpar commented Sep 18, 2024

Before i got there i found the issue:

The macro expands to:
#[repr(transparent)]
#[allow(non_camel_case_types)]
#[doc = "Some description."]
pub struct MyError(::pyo3::PyAny);
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl ::std::convert::From<&MyError> for ::pyo3::PyErr {
    #[inline]
    fn from(err: &MyError) -> ::pyo3::PyErr {
        #[allow(deprecated)]
        ::pyo3::PyErr::from_value(err)
    }
}
impl MyError {
    ///   Creates a new  [ `PyErr` ]  of this type. 
    ///
    ///   [`PyErr`] :  https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html   "PyErr in pyo3" 
    #[inline]
    #[allow(dead_code)]
    pub fn new_err<A>(args: A) -> ::pyo3::PyErr
    where
        A: ::pyo3::PyErrArguments + ::std::marker::Send + ::std::marker::Sync + 'static,
    {
        ::pyo3::PyErr::new::<MyError, A>(args)
    }
}
#[cfg(feature = "gil-refs")]
impl ::std::error::Error for MyError {
    fn source(&self) -> ::std::option::Option<&(   dyn ::std::error::Error + 'static   )> {
        #[allow(unsafe_code)]
        unsafe {
            #[allow(deprecated)]
            let cause: &::pyo3::exceptions::PyBaseException = self
                .py()
                .from_owned_ptr_or_opt(::pyo3::ffi::PyException_GetCause(self.as_ptr()))?;

            ::std::option::Option::Some(cause)
        }
    }
}
impl ::pyo3::ToPyErr for MyError {}
#[cfg(feature = "gil-refs")]
#[allow(unsafe_code)]
unsafe impl<> ::pyo3::PyNativeType for MyError {
    type AsRefSource = Self;
}
#[cfg(feature = "gil-refs")]
impl<> ::std::fmt::Debug for MyError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>)
           -> ::std::result::Result<(), ::std::fmt::Error>
    {
        use ::pyo3::{PyNativeType, types::{PyAnyMethods, PyStringMethods}};
        let s = self.as_borrowed().repr().or(::std::result::Result::Err(::std::fmt::Error))?;
        f.write_str(&s.to_string_lossy())
    }
}
#[cfg(feature = "gil-refs")]
impl<> ::std::fmt::Display for MyError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>)
           -> ::std::result::Result<(), ::std::fmt::Error>
    {
        use ::pyo3::{PyNativeType, types::{PyAnyMethods, PyStringMethods, PyTypeMethods}};
        match self.as_borrowed().str() {
            ::std::result::Result::Ok(s) => return f.write_str(&s.to_string_lossy()),
            ::std::result::Result::Err(err) => err.write_unraisable_bound(self.py(), ::std::option::Option::Some(&self.as_borrowed())),
        }

        match self.as_borrowed().get_type().name() {
            ::std::result::Result::Ok(name) => ::std::write!(f, "<unprintable {} object>", name),
            ::std::result::Result::Err(_err) => f.write_str("<unprintable object>"),
        }
    }
}
#[cfg(feature = "gil-refs")]
impl<> ::pyo3::ToPyObject for MyError
{
    #[inline]
    fn to_object(&self, py: ::pyo3::Python<'_>) -> ::pyo3::PyObject {
        #[allow(unsafe_code)]
        unsafe { ::pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
    }
}
impl<> ::std::convert::AsRef<::pyo3::PyAny> for MyError {
    #[inline]
    fn as_ref(&self) -> &::pyo3::PyAny {
        &self.0
    }
}
impl<> ::std::ops::Deref for MyError {
    type Target = ::pyo3::PyAny;

    #[inline]
    fn deref(&self) -> &::pyo3::PyAny {
        &self.0
    }
}
#[allow(unsafe_code)]
unsafe impl<> ::pyo3::AsPyPointer for MyError {
    ///   Gets the underlying FFI pointer, returns a borrowed pointer. 
    #[inline]
    fn as_ptr(&self) -> *mut ::pyo3::ffi::PyObject {
        self.0.as_ptr()
    }
}
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<> ::pyo3::IntoPy<::pyo3::Py<MyError>> for &'_ MyError {
    #[inline]
    fn into_py(self, py: ::pyo3::Python<'_>) -> ::pyo3::Py<MyError> {
        #[allow(unsafe_code)]
        unsafe { ::pyo3::Py::from_borrowed_ptr(py, self.as_ptr()) }
    }
}
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<> ::std::convert::From<&'_ MyError> for ::pyo3::Py<MyError> {
    #[inline]
    fn from(other: &MyError) -> Self {
        use ::pyo3::PyNativeType;
        #[allow(unsafe_code)]
        unsafe { ::pyo3::Py::from_borrowed_ptr(other.py(), other.as_ptr()) }
    }
}
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<'a, > ::std::convert::From<&'a MyError> for &'a ::pyo3::PyAny {
    fn from(ob: &'a MyError) -> Self {
        #[allow(unsafe_code)]
        unsafe { &*(ob as *const MyError as *const ::pyo3::PyAny) }
    }
}
impl ::pyo3::types::DerefToPyAny for MyError {}
#[allow(unsafe_code)]
unsafe impl<> ::pyo3::type_object::PyTypeInfo for MyError {
    const NAME: &'static str = "MyError";
    const MODULE: ::std::option::Option<&'static str> = (::std::option::Option::Some("my_module")
    );

    #[inline]
    #[allow(clippy::redundant_closure_call)]
    fn type_object_raw(py: ::pyo3::Python<'_>) -> *mut ::pyo3::ffi::PyTypeObject {
        MyError::type_object_raw(py)
    }
}
impl MyError {
    #[doc(hidden)]
    pub const _PYO3_DEF: ::pyo3::impl_::pymodule::AddTypeToModule<Self> = ::pyo3::impl_::pymodule::AddTypeToModule::new();
}
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<'py, > ::pyo3::FromPyObject<'py> for &'py MyError {
    #[inline]
    fn extract_bound(obj: &::pyo3::Bound<'py, ::pyo3::PyAny>) -> ::pyo3::PyResult<Self> {
        ::std::clone::Clone::clone(obj).into_gil_ref().downcast().map_err(::std::convert::Into::into)
    }
}
impl MyError {
    fn type_object_raw(py: ::pyo3::Python<'_>) -> *mut ::pyo3::ffi::PyTypeObject {
        use ::pyo3::sync::GILOnceCell;
        static TYPE_OBJECT: GILOnceCell<::pyo3::Py<::pyo3::types::PyType>> =
            GILOnceCell::new();

        TYPE_OBJECT
            .get_or_init(py, ||
                ::pyo3::PyErr::new_type_bound(
                    py,
                    "my_module.MyError",
                    (::std::option::Option::Some("Some description.")
                    ),
                    ::std::option::Option::Some(&py.get_type_bound::<PyException>()),
                    ::std::option::Option::None,
                ).expect("Failed to initialize new exception type."),
            ).as_ptr() as *mut ::pyo3::ffi::PyTypeObject
    }
}

#[cfg(feature = "gil-refs")] is a feature requried on the current crate, not on the dependency.
However more importantly it is applied to the PyNativeType but not to PyTypeInfo which requires PyNativeType.

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

No branches or pull requests

2 participants