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="">⚠ ️</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}