diff rust/hg-pyo3/src/util.rs @ 52438:c5128c541021

rust-pyo3: facility for submodule registration, using it for dagop It turns out that PyO3 has the exact same problem that we encountered long ago with rust-cpython. The only difference is that the value of `__name__` is not within the `mercurial` package at this point of registration. We reimplement the solution (equivalent to the suggestions in PyO3 issue tracker anyway), this time in a generic module to limit the amount of boilerplate in subsequent applications.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Fri, 29 Nov 2024 23:47:37 +0100
parents
children 42b219a1404a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hg-pyo3/src/util.rs	Fri Nov 29 23:47:37 2024 +0100
@@ -0,0 +1,28 @@
+use pyo3::prelude::*;
+use pyo3::types::PyDict;
+/// Create the module, with `__package__` given from parent
+///
+/// According to PyO3 documentation, which links to
+/// <https://github.com/PyO3/pyo3/issues/1517>, the same convoluted
+/// write to sys.modules has to be made as with the `cpython` crate.
+pub(crate) fn new_submodule<'py>(
+    py: Python<'py>,
+    package_name: &str,
+    name: &str,
+) -> PyResult<Bound<'py, PyModule>> {
+    let dotted_name = &format!("{}.{}", package_name, name);
+    let m = PyModule::new(py, name)?;
+    m.add("__package__", package_name)?;
+    m.add("__doc__", "DAG operations - Rust implementation")?;
+
+    let sys = PyModule::import(py, "sys")?;
+    // according to the doc, we could make a static PyString out of
+    // "modules" with the `intern!` macro, but this is used only at
+    // registration so it may not be worth the effort.
+    let sys_modules: Bound<'_, PyDict> = sys.getattr("modules")?.extract()?;
+    sys_modules.set_item(dotted_name, &m)?;
+    // Example C code (see pyexpat.c and import.c) will "give away the
+    // reference", but we won't because it will be consumed once the
+    // Rust PyObject is dropped.
+    Ok(m)
+}