Skip to main content

pyo3/types/
module.rs

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