Skip to content

#[pymodule(module="MODULE")] does not set the __module__ attribute #4870

Open
@amorenoz

Description

@amorenoz

Bug Description

#[pyclass(module = "module")]
struct Foo {}

Correctly sets the __module__ attribute of the class.

The same behavior for other (sub) pymodules is expected.
The attribute is needed for tools such as https://github.com/mkdocstrings/griffe to properly find the submodule. See PyO3/maturin#1365.

What seems to happen is the module value of the submodule is used to determine the module value of the (inlined) pyclasses.

Steps to Reproduce

  1. Create a module with a submodule. Use module="..."
/// Module documentation: A Python module implemented in Rust.
#[pymodule]
mod mymodule {
    use pyo3::prelude::*;

    /// Sub-Module documentation!!!
    #[pymodule(module="mymodule.mymodule.submodule")]
    mod submodule {
    	use super::*;

        #[pyclass]
        struct Foo{};

        /// Hack: workaround for https://github.com/PyO3/pyo3/issues/759   
        fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
            Python::with_gil(|py| {
                py.import("sys")?
                    .getattr("modules")?
                    .set_item("mymodule.submodule", m)
            })
        }
   }
}
  1. Check the __module__ attribute`
>>> from mymodule import submodule
>>> submodule.__module__
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    submodule.__module__
AttributeError: module 'submodule' has no attribute '__module__'

Backtrace

Your operating system and version

Fedora 41

Your Python version (python --version)

Python 3.13.1

Your Rust version (rustc --version)

rustc 1.81.0 (eeb90cda1 2024-09-04)

Your PyO3 version

pyo3 v0.23.3 (https://github.com/PyO3/pyo3#5c363b5d)

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

dnf install python

Additional Info

As a workaround, __module__ attribute could be set manually:

        fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
            Python::with_gil(|py| {
                py.import("sys")?
                    .getattr("modules")?
                    .set_item("mymodule.submodule", m)
            })?;
            m.setattr("__module__", "mymodule.mymodule.submodule") // <-- Add this
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions