Skip to content

Allow #[new] to return a SubClass of Class #5560

@ion-elgreco

Description

@ion-elgreco

I have a class that with its init returns a subclass of itself and then another class_method that returns another subclass version. Take these structs:

#[pyclass(subclass)]
pub struct Base;

#[pyclass(extends=Base)]
pub struct SingleBase;

#[pyclass(extends=Base)]
pub struct MultiBase;

This for example wouldn't compile

#[pymethods]
impl Base {
    #[new]
    #[classmethod]
    fn new(cls: &Bound<'_, PyType>) -> PyResult<Py<SingleBase>> {
        let base = Base {};
        let py_obj = Py::new(cls.py(), (SingleBase {}, base))?;
        Ok(py_obj)
    }

    #[classmethod]
    fn from_multi(cls: &Bound<'_, PyType>) -> PyResult<Py<PyAny>> {
        let base = Base {};
        let py_obj = Py::new(cls.py(), (MultiBase {}, base))?;
        Ok(py_obj.into_any())
    }
}
the trait bound PyClassInitializer<Base>: From<pyo3::Py<SingleBase>> is not satisfied
the following other types implement trait From<T>:
PyClassInitializer<S> implements From<(S, B)>
PyClassInitializer<T> implements From<T>
PyClassInitializer<T> implements From<pyo3::Bound<'_, T>>
PyClassInitializer<T> implements From<pyo3::Py<T>>
required for pyo3::Py<SingleBase> to implement Into<PyClassInitializer<Base>>
required for pyo3::Py<SingleBase> to implement IntoPyCallbackOutput<'_, PyClassInitializer<Base>>
1 redundant requirement hidden
required for Result<pyo3::Py<SingleBase>, PyErr> to implement IntoPyCallbackOutput<'_, PyClassInitializer<Base>> 

But this works 🙈

#[pymethods]
impl Base {
    #[new]
    fn new(_cls: &Bound<'_, PyType>) -> PyResult<Py<Base>> {
        let result: Py<Base> = _cls.call_method0("__internal_new__")?.extract()?;
        Ok(result)
    }

    #[classmethod]
    fn __internal_new__(cls: &Bound<'_, PyType>) -> PyResult<Py<PyAny>> {
        let base = Base {};
        let py_obj = Py::new(cls.py(), (SingleBase {}, base))?;
        Ok(py_obj.into_any())
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions