pyo3/types/
module.rs

1use pyo3_ffi::c_str;
2
3use crate::err::{PyErr, PyResult};
4use crate::ffi_ptr_ext::FfiPtrExt;
5use crate::impl_::callback::IntoPyCallbackOutput;
6use crate::py_result_ext::PyResultExt;
7use crate::pyclass::PyClass;
8use crate::types::{
9    any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString,
10};
11use crate::{
12    exceptions, ffi, Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, Py, Python,
13};
14#[cfg(all(not(Py_LIMITED_API), Py_GIL_DISABLED))]
15use std::ffi::c_int;
16use std::ffi::CStr;
17use std::str;
18
19/// Represents a Python [`module`][1] object.
20///
21/// Values of this type are accessed via PyO3's smart pointers, e.g. as
22/// [`Py<PyModule>`][crate::Py] or [`Bound<'py, PyModule>`][Bound].
23///
24/// For APIs available on `module` objects, see the [`PyModuleMethods`] trait which is implemented for
25/// [`Bound<'py, PyModule>`][Bound].
26///
27/// As with all other Python objects, modules are first class citizens.
28/// This means they can be passed to or returned from functions,
29/// created dynamically, assigned to variables and so forth.
30///
31/// [1]: https://docs.python.org/3/tutorial/modules.html
32#[repr(transparent)]
33pub struct PyModule(PyAny);
34
35pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::PyModule_Type), #checkfunction=ffi::PyModule_Check);
36
37impl PyModule {
38    /// Creates a new module object with the `__name__` attribute set to `name`.
39    ///
40    /// # Examples
41    ///
42    /// ``` rust
43    /// use pyo3::prelude::*;
44    ///
45    /// # fn main() -> PyResult<()> {
46    /// Python::attach(|py| -> PyResult<()> {
47    ///     let module = PyModule::new(py, "my_module")?;
48    ///
49    ///     assert_eq!(module.name()?, "my_module");
50    ///     Ok(())
51    /// })?;
52    /// # Ok(())}
53    ///  ```
54    pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<Bound<'py, PyModule>> {
55        let name = PyString::new(py, name);
56        unsafe {
57            ffi::PyModule_NewObject(name.as_ptr())
58                .assume_owned_or_err(py)
59                .cast_into_unchecked()
60        }
61    }
62
63    /// Imports the Python module with the specified name.
64    ///
65    /// # Examples
66    ///
67    /// ```no_run
68    /// # fn main() {
69    /// use pyo3::prelude::*;
70    ///
71    /// Python::attach(|py| {
72    ///     let module = PyModule::import(py, "antigravity").expect("No flying for you.");
73    /// });
74    /// # }
75    ///  ```
76    ///
77    /// This is equivalent to the following Python expression:
78    /// ```python
79    /// import antigravity
80    /// ```
81    ///
82    /// If you want to import a class, you can store a reference to it with
83    /// [`PyOnceLock::import`][crate::sync::PyOnceLock::import].
84    pub fn import<'py, N>(py: Python<'py>, name: N) -> PyResult<Bound<'py, PyModule>>
85    where
86        N: IntoPyObject<'py, Target = PyString>,
87    {
88        let name = name.into_pyobject_or_pyerr(py)?;
89        unsafe {
90            ffi::PyImport_Import(name.as_ptr())
91                .assume_owned_or_err(py)
92                .cast_into_unchecked()
93        }
94    }
95
96    /// Creates and loads a module named `module_name`,
97    /// containing the Python code passed to `code`
98    /// and pretending to live at `file_name`.
99    ///
100    /// If `file_name` is empty, it will be set to `<string>`.
101    ///
102    /// <div class="information">
103    ///     <div class="tooltip compile_fail" style="">&#x26a0; &#xfe0f;</div>
104    /// </div><div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
105    //
106    ///  <strong>Warning</strong>: This will compile and execute code. <strong>Never</strong> pass untrusted code to this function!
107    ///
108    /// </pre></div>
109    ///
110    /// # Errors
111    ///
112    /// Returns `PyErr` if:
113    /// - `code` is not syntactically correct Python.
114    /// - Any Python exceptions are raised while initializing the module.
115    /// - Any of the arguments cannot be converted to [`CString`][std::ffi::CString]s.
116    ///
117    /// # Example: bundle in a file at compile time with [`include_str!`][std::include_str]:
118    ///
119    /// ```rust
120    /// use pyo3::prelude::*;
121    /// use pyo3::ffi::c_str;
122    ///
123    /// # fn main() -> PyResult<()> {
124    /// // This path is resolved relative to this file.
125    /// let code = c_str!(include_str!("../../assets/script.py"));
126    ///
127    /// Python::attach(|py| -> PyResult<()> {
128    ///     PyModule::from_code(py, code, c_str!("example.py"), c_str!("example"))?;
129    ///     Ok(())
130    /// })?;
131    /// # Ok(())
132    /// # }
133    /// ```
134    ///
135    /// # Example: Load a file at runtime with [`std::fs::read_to_string`].
136    ///
137    /// ```rust
138    /// use pyo3::prelude::*;
139    /// use pyo3::ffi::c_str;
140    /// use std::ffi::CString;
141    ///
142    /// # fn main() -> PyResult<()> {
143    /// # #[cfg(not(target_arch = "wasm32"))]  // node fs doesn't see this file, maybe cwd wrong?
144    /// # {
145    /// // This path is resolved by however the platform resolves paths,
146    /// // which also makes this less portable. Consider using `include_str`
147    /// // if you just want to bundle a script with your module.
148    /// let code = std::fs::read_to_string("assets/script.py")?;
149    ///
150    /// Python::attach(|py| -> PyResult<()> {
151    ///     PyModule::from_code(py, CString::new(code)?.as_c_str(), c_str!("example.py"), c_str!("example"))?;
152    ///     Ok(())
153    /// })?;
154    /// # }
155    /// # Ok(())
156    /// # }
157    /// ```
158    pub fn from_code<'py>(
159        py: Python<'py>,
160        code: &CStr,
161        file_name: &CStr,
162        module_name: &CStr,
163    ) -> PyResult<Bound<'py, PyModule>> {
164        let file_name = if file_name.is_empty() {
165            c_str!("<string>")
166        } else {
167            file_name
168        };
169        unsafe {
170            let code = ffi::Py_CompileString(code.as_ptr(), file_name.as_ptr(), ffi::Py_file_input)
171                .assume_owned_or_err(py)?;
172
173            ffi::PyImport_ExecCodeModuleEx(module_name.as_ptr(), code.as_ptr(), file_name.as_ptr())
174                .assume_owned_or_err(py)
175                .cast_into()
176        }
177    }
178}
179
180/// Implementation of functionality for [`PyModule`].
181///
182/// These methods are defined for the `Bound<'py, PyModule>` smart pointer, so to use method call
183/// syntax these methods are separated into a trait, because stable Rust does not yet support
184/// `arbitrary_self_types`.
185#[doc(alias = "PyModule")]
186pub trait PyModuleMethods<'py>: crate::sealed::Sealed {
187    /// Returns the module's `__dict__` attribute, which contains the module's symbol table.
188    fn dict(&self) -> Bound<'py, PyDict>;
189
190    /// Returns the index (the `__all__` attribute) of the module,
191    /// creating one if needed.
192    ///
193    /// `__all__` declares the items that will be imported with `from my_module import *`.
194    fn index(&self) -> PyResult<Bound<'py, PyList>>;
195
196    /// Returns the name (the `__name__` attribute) of the module.
197    ///
198    /// May fail if the module does not have a `__name__` attribute.
199    fn name(&self) -> PyResult<Bound<'py, PyString>>;
200
201    /// Returns the filename (the `__file__` attribute) of the module.
202    ///
203    /// May fail if the module does not have a `__file__` attribute.
204    fn filename(&self) -> PyResult<Bound<'py, PyString>>;
205
206    /// Adds an attribute to the module.
207    ///
208    /// For adding classes, functions or modules, prefer to use [`PyModuleMethods::add_class`],
209    /// [`PyModuleMethods::add_function`] or [`PyModuleMethods::add_submodule`] instead,
210    /// respectively.
211    ///
212    /// # Examples
213    ///
214    /// ```rust,no_run
215    /// use pyo3::prelude::*;
216    ///
217    /// #[pymodule]
218    /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
219    ///     module.add("c", 299_792_458)?;
220    ///     Ok(())
221    /// }
222    /// ```
223    ///
224    /// Python code can then do the following:
225    ///
226    /// ```python
227    /// from my_module import c
228    ///
229    /// print("c is", c)
230    /// ```
231    ///
232    /// This will result in the following output:
233    ///
234    /// ```text
235    /// c is 299792458
236    /// ```
237    fn add<N, V>(&self, name: N, value: V) -> PyResult<()>
238    where
239        N: IntoPyObject<'py, Target = PyString>,
240        V: IntoPyObject<'py>;
241
242    /// Adds a new class to the module.
243    ///
244    /// Notice that this method does not take an argument.
245    /// Instead, this method is *generic*, and requires us to use the
246    /// "turbofish" syntax to specify the class we want to add.
247    ///
248    /// # Examples
249    ///
250    /// ```rust,no_run
251    /// use pyo3::prelude::*;
252    ///
253    /// #[pyclass]
254    /// struct Foo { /* fields omitted */ }
255    ///
256    /// #[pymodule]
257    /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
258    ///     module.add_class::<Foo>()?;
259    ///     Ok(())
260    /// }
261    ///  ```
262    ///
263    /// Python code can see this class as such:
264    /// ```python
265    /// from my_module import Foo
266    ///
267    /// print("Foo is", Foo)
268    /// ```
269    ///
270    /// This will result in the following output:
271    /// ```text
272    /// Foo is <class 'builtins.Foo'>
273    /// ```
274    ///
275    /// Note that as we haven't defined a [constructor][1], Python code can't actually
276    /// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
277    /// anything that can return instances of `Foo`).
278    ///
279    #[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
280    fn add_class<T>(&self) -> PyResult<()>
281    where
282        T: PyClass;
283
284    /// Adds a function or a (sub)module to a module, using the functions name as name.
285    ///
286    /// Prefer to use [`PyModuleMethods::add_function`] and/or [`PyModuleMethods::add_submodule`]
287    /// instead.
288    fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>
289    where
290        T: IntoPyCallbackOutput<'py, Py<PyAny>>;
291
292    /// Adds a submodule to a module.
293    ///
294    /// This is especially useful for creating module hierarchies.
295    ///
296    /// Note that this doesn't define a *package*, so this won't allow Python code
297    /// to directly import submodules by using
298    /// <span style="white-space: pre">`from my_module import submodule`</span>.
299    /// For more information, see [#759][1] and [#1517][2].
300    ///
301    /// # Examples
302    ///
303    /// ```rust,no_run
304    /// use pyo3::prelude::*;
305    ///
306    /// #[pymodule]
307    /// fn my_module(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
308    ///     let submodule = PyModule::new(py, "submodule")?;
309    ///     submodule.add("super_useful_constant", "important")?;
310    ///
311    ///     module.add_submodule(&submodule)?;
312    ///     Ok(())
313    /// }
314    /// ```
315    ///
316    /// Python code can then do the following:
317    ///
318    /// ```python
319    /// import my_module
320    ///
321    /// print("super_useful_constant is", my_module.submodule.super_useful_constant)
322    /// ```
323    ///
324    /// This will result in the following output:
325    ///
326    /// ```text
327    /// super_useful_constant is important
328    /// ```
329    ///
330    /// [1]: https://github.com/PyO3/pyo3/issues/759
331    /// [2]: https://github.com/PyO3/pyo3/issues/1517#issuecomment-808664021
332    fn add_submodule(&self, module: &Bound<'_, PyModule>) -> PyResult<()>;
333
334    /// Add a function to a module.
335    ///
336    /// Note that this also requires the [`wrap_pyfunction!`][2] macro
337    /// to wrap a function annotated with [`#[pyfunction]`][1].
338    ///
339    /// ```rust,no_run
340    /// use pyo3::prelude::*;
341    ///
342    /// #[pyfunction]
343    /// fn say_hello() {
344    ///     println!("Hello world!")
345    /// }
346    /// #[pymodule]
347    /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
348    ///     module.add_function(wrap_pyfunction!(say_hello, module)?)
349    /// }
350    /// ```
351    ///
352    /// Python code can then do the following:
353    ///
354    /// ```python
355    /// from my_module import say_hello
356    ///
357    /// say_hello()
358    /// ```
359    ///
360    /// This will result in the following output:
361    ///
362    /// ```text
363    /// Hello world!
364    /// ```
365    ///
366    /// [1]: crate::prelude::pyfunction
367    /// [2]: crate::wrap_pyfunction
368    fn add_function(&self, fun: Bound<'_, PyCFunction>) -> PyResult<()>;
369
370    /// Declare whether or not this module supports running with the GIL disabled
371    ///
372    /// If the module does not rely on the GIL for thread safety, you can pass
373    /// `false` to this function to indicate the module does not rely on the GIL
374    /// for thread-safety.
375    ///
376    /// This function sets the [`Py_MOD_GIL`
377    /// slot](https://docs.python.org/3/c-api/module.html#c.Py_mod_gil) on the
378    /// module object. The default is `Py_MOD_GIL_USED`, so passing `true` to
379    /// this function is a no-op unless you have already set `Py_MOD_GIL` to
380    /// `Py_MOD_GIL_NOT_USED` elsewhere.
381    ///
382    /// # Examples
383    ///
384    /// ```rust,no_run
385    /// use pyo3::prelude::*;
386    ///
387    /// #[pymodule(gil_used = false)]
388    /// fn my_module(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
389    ///     let submodule = PyModule::new(py, "submodule")?;
390    ///     submodule.gil_used(false)?;
391    ///     module.add_submodule(&submodule)?;
392    ///     Ok(())
393    /// }
394    /// ```
395    ///
396    /// The resulting module will not print a `RuntimeWarning` and re-enable the
397    /// GIL when Python imports it on the free-threaded build, since all module
398    /// objects defined in the extension have `Py_MOD_GIL` set to
399    /// `Py_MOD_GIL_NOT_USED`.
400    ///
401    /// This is a no-op on the GIL-enabled build.
402    fn gil_used(&self, gil_used: bool) -> PyResult<()>;
403}
404
405impl<'py> PyModuleMethods<'py> for Bound<'py, PyModule> {
406    fn dict(&self) -> Bound<'py, PyDict> {
407        unsafe {
408            // PyModule_GetDict returns borrowed ptr; must make owned for safety (see #890).
409            ffi::PyModule_GetDict(self.as_ptr())
410                .assume_borrowed(self.py())
411                .to_owned()
412                .cast_into_unchecked()
413        }
414    }
415
416    fn index(&self) -> PyResult<Bound<'py, PyList>> {
417        let __all__ = __all__(self.py());
418        match self.getattr(__all__) {
419            Ok(idx) => idx.cast_into().map_err(PyErr::from),
420            Err(err) => {
421                if err.is_instance_of::<exceptions::PyAttributeError>(self.py()) {
422                    let l = PyList::empty(self.py());
423                    self.setattr(__all__, &l)?;
424                    Ok(l)
425                } else {
426                    Err(err)
427                }
428            }
429        }
430    }
431
432    fn name(&self) -> PyResult<Bound<'py, PyString>> {
433        #[cfg(not(PyPy))]
434        {
435            unsafe {
436                ffi::PyModule_GetNameObject(self.as_ptr())
437                    .assume_owned_or_err(self.py())
438                    .cast_into_unchecked()
439            }
440        }
441
442        #[cfg(PyPy)]
443        {
444            self.dict()
445                .get_item("__name__")
446                .map_err(|_| exceptions::PyAttributeError::new_err("__name__"))?
447                .cast_into()
448                .map_err(PyErr::from)
449        }
450    }
451
452    fn filename(&self) -> PyResult<Bound<'py, PyString>> {
453        #[cfg(not(PyPy))]
454        unsafe {
455            ffi::PyModule_GetFilenameObject(self.as_ptr())
456                .assume_owned_or_err(self.py())
457                .cast_into_unchecked()
458        }
459
460        #[cfg(PyPy)]
461        {
462            self.dict()
463                .get_item("__file__")
464                .map_err(|_| exceptions::PyAttributeError::new_err("__file__"))?
465                .cast_into()
466                .map_err(PyErr::from)
467        }
468    }
469
470    fn add<N, V>(&self, name: N, value: V) -> PyResult<()>
471    where
472        N: IntoPyObject<'py, Target = PyString>,
473        V: IntoPyObject<'py>,
474    {
475        fn inner(
476            module: &Bound<'_, PyModule>,
477            name: Borrowed<'_, '_, PyString>,
478            value: Borrowed<'_, '_, PyAny>,
479        ) -> PyResult<()> {
480            module
481                .index()?
482                .append(name)
483                .expect("could not append __name__ to __all__");
484            module.setattr(name, value)
485        }
486
487        let py = self.py();
488        inner(
489            self,
490            name.into_pyobject_or_pyerr(py)?.as_borrowed(),
491            value.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
492        )
493    }
494
495    fn add_class<T>(&self) -> PyResult<()>
496    where
497        T: PyClass,
498    {
499        let py = self.py();
500        self.add(T::NAME, T::lazy_type_object().get_or_try_init(py)?)
501    }
502
503    fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>
504    where
505        T: IntoPyCallbackOutput<'py, Py<PyAny>>,
506    {
507        fn inner(module: &Bound<'_, PyModule>, object: Bound<'_, PyAny>) -> PyResult<()> {
508            let name = object.getattr(__name__(module.py()))?;
509            module.add(name.cast_into::<PyString>()?, object)
510        }
511
512        let py = self.py();
513        inner(self, wrapper(py).convert(py)?.into_bound(py))
514    }
515
516    fn add_submodule(&self, module: &Bound<'_, PyModule>) -> PyResult<()> {
517        let name = module.name()?;
518        self.add(name, module)
519    }
520
521    fn add_function(&self, fun: Bound<'_, PyCFunction>) -> PyResult<()> {
522        let name = fun.getattr(__name__(self.py()))?;
523        self.add(name.cast_into::<PyString>()?, fun)
524    }
525
526    #[cfg_attr(any(Py_LIMITED_API, not(Py_GIL_DISABLED)), allow(unused_variables))]
527    fn gil_used(&self, gil_used: bool) -> PyResult<()> {
528        #[cfg(all(not(Py_LIMITED_API), Py_GIL_DISABLED))]
529        {
530            let gil_used = match gil_used {
531                true => ffi::Py_MOD_GIL_USED,
532                false => ffi::Py_MOD_GIL_NOT_USED,
533            };
534            match unsafe { ffi::PyUnstable_Module_SetGIL(self.as_ptr(), gil_used) } {
535                c_int::MIN..=-1 => Err(PyErr::fetch(self.py())),
536                0..=c_int::MAX => Ok(()),
537            }
538        }
539        #[cfg(any(Py_LIMITED_API, not(Py_GIL_DISABLED)))]
540        Ok(())
541    }
542}
543
544fn __all__(py: Python<'_>) -> &Bound<'_, PyString> {
545    intern!(py, "__all__")
546}
547
548fn __name__(py: Python<'_>) -> &Bound<'_, PyString> {
549    intern!(py, "__name__")
550}
551
552#[cfg(test)]
553mod tests {
554    use pyo3_ffi::c_str;
555
556    use crate::{
557        types::{module::PyModuleMethods, PyModule},
558        Python,
559    };
560
561    #[test]
562    fn module_import_and_name() {
563        Python::attach(|py| {
564            let builtins = PyModule::import(py, "builtins").unwrap();
565            assert_eq!(builtins.name().unwrap(), "builtins");
566        })
567    }
568
569    #[test]
570    fn module_filename() {
571        use crate::types::string::PyStringMethods;
572        Python::attach(|py| {
573            let site = PyModule::import(py, "site").unwrap();
574            assert!(site
575                .filename()
576                .unwrap()
577                .to_cow()
578                .unwrap()
579                .ends_with("site.py"));
580        })
581    }
582
583    #[test]
584    fn module_from_code_empty_file() {
585        Python::attach(|py| {
586            let builtins = PyModule::from_code(py, c_str!(""), c_str!(""), c_str!("")).unwrap();
587            assert_eq!(builtins.filename().unwrap(), "<string>");
588        })
589    }
590}