pyo3/types/module.rs
1use crate::callback::IntoPyCallbackOutput;
2use crate::err::{PyErr, PyResult};
3use crate::ffi_ptr_ext::FfiPtrExt;
4use crate::py_result_ext::PyResultExt;
5use crate::pyclass::PyClass;
6use crate::types::{
7 any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString,
8};
9use crate::{exceptions, ffi, Bound, IntoPy, Py, PyObject, Python};
10use std::ffi::CString;
11use std::str;
12
13#[cfg(feature = "gil-refs")]
14use {super::PyStringMethods, crate::PyNativeType};
15
16/// Represents a Python [`module`][1] object.
17///
18/// Values of this type are accessed via PyO3's smart pointers, e.g. as
19/// [`Py<PyModule>`][crate::Py] or [`Bound<'py, PyModule>`][Bound].
20///
21/// For APIs available on `module` objects, see the [`PyModuleMethods`] trait which is implemented for
22/// [`Bound<'py, PyModule>`][Bound].
23///
24/// As with all other Python objects, modules are first class citizens.
25/// This means they can be passed to or returned from functions,
26/// created dynamically, assigned to variables and so forth.
27///
28/// [1]: https://docs.python.org/3/tutorial/modules.html
29#[repr(transparent)]
30pub struct PyModule(PyAny);
31
32pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::PyModule_Type), #checkfunction=ffi::PyModule_Check);
33
34impl PyModule {
35 /// Creates a new module object with the `__name__` attribute set to `name`.
36 ///
37 /// # Examples
38 ///
39 /// ``` rust
40 /// use pyo3::prelude::*;
41 ///
42 /// # fn main() -> PyResult<()> {
43 /// Python::with_gil(|py| -> PyResult<()> {
44 /// let module = PyModule::new_bound(py, "my_module")?;
45 ///
46 /// assert_eq!(module.name()?, "my_module");
47 /// Ok(())
48 /// })?;
49 /// # Ok(())}
50 /// ```
51 pub fn new_bound<'py>(py: Python<'py>, name: &str) -> PyResult<Bound<'py, PyModule>> {
52 // Could use PyModule_NewObject, but it doesn't exist on PyPy.
53 let name = CString::new(name)?;
54 unsafe {
55 ffi::PyModule_New(name.as_ptr())
56 .assume_owned_or_err(py)
57 .downcast_into_unchecked()
58 }
59 }
60
61 /// Imports the Python module with the specified name.
62 ///
63 /// # Examples
64 ///
65 /// ```no_run
66 /// # fn main() {
67 /// use pyo3::prelude::*;
68 ///
69 /// Python::with_gil(|py| {
70 /// let module = PyModule::import_bound(py, "antigravity").expect("No flying for you.");
71 /// });
72 /// # }
73 /// ```
74 ///
75 /// This is equivalent to the following Python expression:
76 /// ```python
77 /// import antigravity
78 /// ```
79 pub fn import_bound<N>(py: Python<'_>, name: N) -> PyResult<Bound<'_, PyModule>>
80 where
81 N: IntoPy<Py<PyString>>,
82 {
83 let name: Py<PyString> = name.into_py(py);
84 unsafe {
85 ffi::PyImport_Import(name.as_ptr())
86 .assume_owned_or_err(py)
87 .downcast_into_unchecked()
88 }
89 }
90
91 /// Creates and loads a module named `module_name`,
92 /// containing the Python code passed to `code`
93 /// and pretending to live at `file_name`.
94 ///
95 /// <div class="information">
96 /// <div class="tooltip compile_fail" style="">⚠ ️</div>
97 /// </div><div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
98 //
99 /// <strong>Warning</strong>: This will compile and execute code. <strong>Never</strong> pass untrusted code to this function!
100 ///
101 /// </pre></div>
102 ///
103 /// # Errors
104 ///
105 /// Returns `PyErr` if:
106 /// - `code` is not syntactically correct Python.
107 /// - Any Python exceptions are raised while initializing the module.
108 /// - Any of the arguments cannot be converted to [`CString`]s.
109 ///
110 /// # Example: bundle in a file at compile time with [`include_str!`][std::include_str]:
111 ///
112 /// ```rust
113 /// use pyo3::prelude::*;
114 ///
115 /// # fn main() -> PyResult<()> {
116 /// // This path is resolved relative to this file.
117 /// let code = include_str!("../../assets/script.py");
118 ///
119 /// Python::with_gil(|py| -> PyResult<()> {
120 /// PyModule::from_code_bound(py, code, "example.py", "example")?;
121 /// Ok(())
122 /// })?;
123 /// # Ok(())
124 /// # }
125 /// ```
126 ///
127 /// # Example: Load a file at runtime with [`std::fs::read_to_string`].
128 ///
129 /// ```rust
130 /// use pyo3::prelude::*;
131 ///
132 /// # fn main() -> PyResult<()> {
133 /// // This path is resolved by however the platform resolves paths,
134 /// // which also makes this less portable. Consider using `include_str`
135 /// // if you just want to bundle a script with your module.
136 /// let code = std::fs::read_to_string("assets/script.py")?;
137 ///
138 /// Python::with_gil(|py| -> PyResult<()> {
139 /// PyModule::from_code_bound(py, &code, "example.py", "example")?;
140 /// Ok(())
141 /// })?;
142 /// Ok(())
143 /// # }
144 /// ```
145 pub fn from_code_bound<'py>(
146 py: Python<'py>,
147 code: &str,
148 file_name: &str,
149 module_name: &str,
150 ) -> PyResult<Bound<'py, PyModule>> {
151 let data = CString::new(code)?;
152 let filename = CString::new(file_name)?;
153 let module = CString::new(module_name)?;
154
155 unsafe {
156 let code = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input)
157 .assume_owned_or_err(py)?;
158
159 ffi::PyImport_ExecCodeModuleEx(module.as_ptr(), code.as_ptr(), filename.as_ptr())
160 .assume_owned_or_err(py)
161 .downcast_into()
162 }
163 }
164}
165
166#[cfg(feature = "gil-refs")]
167impl PyModule {
168 /// Deprecated form of [`PyModule::new_bound`].
169 #[inline]
170 #[deprecated(
171 since = "0.21.0",
172 note = "`PyModule::new` will be replaced by `PyModule::new_bound` in a future PyO3 version"
173 )]
174 pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<&'py PyModule> {
175 Self::new_bound(py, name).map(Bound::into_gil_ref)
176 }
177
178 /// Deprecated form of [`PyModule::import_bound`].
179 #[inline]
180 #[deprecated(
181 since = "0.21.0",
182 note = "`PyModule::import` will be replaced by `PyModule::import_bound` in a future PyO3 version"
183 )]
184 pub fn import<N>(py: Python<'_>, name: N) -> PyResult<&PyModule>
185 where
186 N: IntoPy<Py<PyString>>,
187 {
188 Self::import_bound(py, name).map(Bound::into_gil_ref)
189 }
190
191 /// Deprecated form of [`PyModule::from_code_bound`].
192 #[inline]
193 #[deprecated(
194 since = "0.21.0",
195 note = "`PyModule::from_code` will be replaced by `PyModule::from_code_bound` in a future PyO3 version"
196 )]
197 pub fn from_code<'py>(
198 py: Python<'py>,
199 code: &str,
200 file_name: &str,
201 module_name: &str,
202 ) -> PyResult<&'py PyModule> {
203 Self::from_code_bound(py, code, file_name, module_name).map(Bound::into_gil_ref)
204 }
205
206 /// Returns the module's `__dict__` attribute, which contains the module's symbol table.
207 pub fn dict(&self) -> &PyDict {
208 self.as_borrowed().dict().into_gil_ref()
209 }
210
211 /// Returns the index (the `__all__` attribute) of the module,
212 /// creating one if needed.
213 ///
214 /// `__all__` declares the items that will be imported with `from my_module import *`.
215 pub fn index(&self) -> PyResult<&PyList> {
216 self.as_borrowed().index().map(Bound::into_gil_ref)
217 }
218
219 /// Returns the name (the `__name__` attribute) of the module.
220 ///
221 /// May fail if the module does not have a `__name__` attribute.
222 pub fn name(&self) -> PyResult<&str> {
223 self.as_borrowed().name()?.into_gil_ref().to_str()
224 }
225
226 /// Returns the filename (the `__file__` attribute) of the module.
227 ///
228 /// May fail if the module does not have a `__file__` attribute.
229 pub fn filename(&self) -> PyResult<&str> {
230 self.as_borrowed().filename()?.into_gil_ref().to_str()
231 }
232
233 /// Adds an attribute to the module.
234 ///
235 /// For adding classes, functions or modules, prefer to use [`PyModule::add_class`],
236 /// [`PyModule::add_function`] or [`PyModule::add_submodule`] instead, respectively.
237 ///
238 /// # Examples
239 ///
240 /// ```rust
241 /// use pyo3::prelude::*;
242 ///
243 /// #[pymodule]
244 /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
245 /// module.add("c", 299_792_458)?;
246 /// Ok(())
247 /// }
248 /// ```
249 ///
250 /// Python code can then do the following:
251 ///
252 /// ```python
253 /// from my_module import c
254 ///
255 /// print("c is", c)
256 /// ```
257 ///
258 /// This will result in the following output:
259 ///
260 /// ```text
261 /// c is 299792458
262 /// ```
263 pub fn add<V>(&self, name: &str, value: V) -> PyResult<()>
264 where
265 V: IntoPy<PyObject>,
266 {
267 self.as_borrowed().add(name, value)
268 }
269
270 /// Adds a new class to the module.
271 ///
272 /// Notice that this method does not take an argument.
273 /// Instead, this method is *generic*, and requires us to use the
274 /// "turbofish" syntax to specify the class we want to add.
275 ///
276 /// # Examples
277 ///
278 /// ```rust
279 /// use pyo3::prelude::*;
280 ///
281 /// #[pyclass]
282 /// struct Foo { /* fields omitted */ }
283 ///
284 /// #[pymodule]
285 /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
286 /// module.add_class::<Foo>()?;
287 /// Ok(())
288 /// }
289 /// ```
290 ///
291 /// Python code can see this class as such:
292 /// ```python
293 /// from my_module import Foo
294 ///
295 /// print("Foo is", Foo)
296 /// ```
297 ///
298 /// This will result in the following output:
299 /// ```text
300 /// Foo is <class 'builtins.Foo'>
301 /// ```
302 ///
303 /// Note that as we haven't defined a [constructor][1], Python code can't actually
304 /// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
305 /// anything that can return instances of `Foo`).
306 ///
307 #[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
308 pub fn add_class<T>(&self) -> PyResult<()>
309 where
310 T: PyClass,
311 {
312 self.as_borrowed().add_class::<T>()
313 }
314
315 /// Adds a function or a (sub)module to a module, using the functions name as name.
316 ///
317 /// Prefer to use [`PyModule::add_function`] and/or [`PyModule::add_submodule`] instead.
318 pub fn add_wrapped<'a, T>(&'a self, wrapper: &impl Fn(Python<'a>) -> T) -> PyResult<()>
319 where
320 T: IntoPyCallbackOutput<PyObject>,
321 {
322 self.as_borrowed().add_wrapped(wrapper)
323 }
324
325 /// Adds a submodule to a module.
326 ///
327 /// This is especially useful for creating module hierarchies.
328 ///
329 /// Note that this doesn't define a *package*, so this won't allow Python code
330 /// to directly import submodules by using
331 /// <span style="white-space: pre">`from my_module import submodule`</span>.
332 /// For more information, see [#759][1] and [#1517][2].
333 ///
334 /// # Examples
335 ///
336 /// ```rust
337 /// use pyo3::prelude::*;
338 ///
339 /// #[pymodule]
340 /// fn my_module(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
341 /// let submodule = PyModule::new_bound(py, "submodule")?;
342 /// submodule.add("super_useful_constant", "important")?;
343 ///
344 /// module.add_submodule(&submodule)?;
345 /// Ok(())
346 /// }
347 /// ```
348 ///
349 /// Python code can then do the following:
350 ///
351 /// ```python
352 /// import my_module
353 ///
354 /// print("super_useful_constant is", my_module.submodule.super_useful_constant)
355 /// ```
356 ///
357 /// This will result in the following output:
358 ///
359 /// ```text
360 /// super_useful_constant is important
361 /// ```
362 ///
363 /// [1]: https://github.com/PyO3/pyo3/issues/759
364 /// [2]: https://github.com/PyO3/pyo3/issues/1517#issuecomment-808664021
365 pub fn add_submodule(&self, module: &PyModule) -> PyResult<()> {
366 self.as_borrowed().add_submodule(&module.as_borrowed())
367 }
368
369 /// Add a function to a module.
370 ///
371 /// Note that this also requires the [`wrap_pyfunction!`][2] macro
372 /// to wrap a function annotated with [`#[pyfunction]`][1].
373 ///
374 /// ```rust
375 /// use pyo3::prelude::*;
376 ///
377 /// #[pyfunction]
378 /// fn say_hello() {
379 /// println!("Hello world!")
380 /// }
381 /// #[pymodule]
382 /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
383 /// module.add_function(wrap_pyfunction!(say_hello, module)?)
384 /// }
385 /// ```
386 ///
387 /// Python code can then do the following:
388 ///
389 /// ```python
390 /// from my_module import say_hello
391 ///
392 /// say_hello()
393 /// ```
394 ///
395 /// This will result in the following output:
396 ///
397 /// ```text
398 /// Hello world!
399 /// ```
400 ///
401 /// [1]: crate::prelude::pyfunction
402 /// [2]: crate::wrap_pyfunction
403 pub fn add_function<'a>(&'a self, fun: &'a PyCFunction) -> PyResult<()> {
404 let name = fun
405 .as_borrowed()
406 .getattr(__name__(self.py()))?
407 .downcast_into::<PyString>()?;
408 let name = name.to_cow()?;
409 self.add(&name, fun)
410 }
411}
412
413/// Implementation of functionality for [`PyModule`].
414///
415/// These methods are defined for the `Bound<'py, PyModule>` smart pointer, so to use method call
416/// syntax these methods are separated into a trait, because stable Rust does not yet support
417/// `arbitrary_self_types`.
418#[doc(alias = "PyModule")]
419pub trait PyModuleMethods<'py>: crate::sealed::Sealed {
420 /// Returns the module's `__dict__` attribute, which contains the module's symbol table.
421 fn dict(&self) -> Bound<'py, PyDict>;
422
423 /// Returns the index (the `__all__` attribute) of the module,
424 /// creating one if needed.
425 ///
426 /// `__all__` declares the items that will be imported with `from my_module import *`.
427 fn index(&self) -> PyResult<Bound<'py, PyList>>;
428
429 /// Returns the name (the `__name__` attribute) of the module.
430 ///
431 /// May fail if the module does not have a `__name__` attribute.
432 fn name(&self) -> PyResult<Bound<'py, PyString>>;
433
434 /// Returns the filename (the `__file__` attribute) of the module.
435 ///
436 /// May fail if the module does not have a `__file__` attribute.
437 fn filename(&self) -> PyResult<Bound<'py, PyString>>;
438
439 /// Adds an attribute to the module.
440 ///
441 /// For adding classes, functions or modules, prefer to use [`PyModuleMethods::add_class`],
442 /// [`PyModuleMethods::add_function`] or [`PyModuleMethods::add_submodule`] instead,
443 /// respectively.
444 ///
445 /// # Examples
446 ///
447 /// ```rust
448 /// use pyo3::prelude::*;
449 ///
450 /// #[pymodule]
451 /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
452 /// module.add("c", 299_792_458)?;
453 /// Ok(())
454 /// }
455 /// ```
456 ///
457 /// Python code can then do the following:
458 ///
459 /// ```python
460 /// from my_module import c
461 ///
462 /// print("c is", c)
463 /// ```
464 ///
465 /// This will result in the following output:
466 ///
467 /// ```text
468 /// c is 299792458
469 /// ```
470 fn add<N, V>(&self, name: N, value: V) -> PyResult<()>
471 where
472 N: IntoPy<Py<PyString>>,
473 V: IntoPy<PyObject>;
474
475 /// Adds a new class to the module.
476 ///
477 /// Notice that this method does not take an argument.
478 /// Instead, this method is *generic*, and requires us to use the
479 /// "turbofish" syntax to specify the class we want to add.
480 ///
481 /// # Examples
482 ///
483 /// ```rust
484 /// use pyo3::prelude::*;
485 ///
486 /// #[pyclass]
487 /// struct Foo { /* fields omitted */ }
488 ///
489 /// #[pymodule]
490 /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
491 /// module.add_class::<Foo>()?;
492 /// Ok(())
493 /// }
494 /// ```
495 ///
496 /// Python code can see this class as such:
497 /// ```python
498 /// from my_module import Foo
499 ///
500 /// print("Foo is", Foo)
501 /// ```
502 ///
503 /// This will result in the following output:
504 /// ```text
505 /// Foo is <class 'builtins.Foo'>
506 /// ```
507 ///
508 /// Note that as we haven't defined a [constructor][1], Python code can't actually
509 /// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
510 /// anything that can return instances of `Foo`).
511 ///
512 #[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
513 fn add_class<T>(&self) -> PyResult<()>
514 where
515 T: PyClass;
516
517 /// Adds a function or a (sub)module to a module, using the functions name as name.
518 ///
519 /// Prefer to use [`PyModuleMethods::add_function`] and/or [`PyModuleMethods::add_submodule`]
520 /// instead.
521 fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>
522 where
523 T: IntoPyCallbackOutput<PyObject>;
524
525 /// Adds a submodule to a module.
526 ///
527 /// This is especially useful for creating module hierarchies.
528 ///
529 /// Note that this doesn't define a *package*, so this won't allow Python code
530 /// to directly import submodules by using
531 /// <span style="white-space: pre">`from my_module import submodule`</span>.
532 /// For more information, see [#759][1] and [#1517][2].
533 ///
534 /// # Examples
535 ///
536 /// ```rust
537 /// use pyo3::prelude::*;
538 ///
539 /// #[pymodule]
540 /// fn my_module(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
541 /// let submodule = PyModule::new_bound(py, "submodule")?;
542 /// submodule.add("super_useful_constant", "important")?;
543 ///
544 /// module.add_submodule(&submodule)?;
545 /// Ok(())
546 /// }
547 /// ```
548 ///
549 /// Python code can then do the following:
550 ///
551 /// ```python
552 /// import my_module
553 ///
554 /// print("super_useful_constant is", my_module.submodule.super_useful_constant)
555 /// ```
556 ///
557 /// This will result in the following output:
558 ///
559 /// ```text
560 /// super_useful_constant is important
561 /// ```
562 ///
563 /// [1]: https://github.com/PyO3/pyo3/issues/759
564 /// [2]: https://github.com/PyO3/pyo3/issues/1517#issuecomment-808664021
565 fn add_submodule(&self, module: &Bound<'_, PyModule>) -> PyResult<()>;
566
567 /// Add a function to a module.
568 ///
569 /// Note that this also requires the [`wrap_pyfunction!`][2] macro
570 /// to wrap a function annotated with [`#[pyfunction]`][1].
571 ///
572 /// ```rust
573 /// use pyo3::prelude::*;
574 ///
575 /// #[pyfunction]
576 /// fn say_hello() {
577 /// println!("Hello world!")
578 /// }
579 /// #[pymodule]
580 /// fn my_module(module: &Bound<'_, PyModule>) -> PyResult<()> {
581 /// module.add_function(wrap_pyfunction!(say_hello, module)?)
582 /// }
583 /// ```
584 ///
585 /// Python code can then do the following:
586 ///
587 /// ```python
588 /// from my_module import say_hello
589 ///
590 /// say_hello()
591 /// ```
592 ///
593 /// This will result in the following output:
594 ///
595 /// ```text
596 /// Hello world!
597 /// ```
598 ///
599 /// [1]: crate::prelude::pyfunction
600 /// [2]: crate::wrap_pyfunction
601 fn add_function(&self, fun: Bound<'_, PyCFunction>) -> PyResult<()>;
602}
603
604impl<'py> PyModuleMethods<'py> for Bound<'py, PyModule> {
605 fn dict(&self) -> Bound<'py, PyDict> {
606 unsafe {
607 // PyModule_GetDict returns borrowed ptr; must make owned for safety (see #890).
608 ffi::PyModule_GetDict(self.as_ptr())
609 .assume_borrowed(self.py())
610 .to_owned()
611 .downcast_into_unchecked()
612 }
613 }
614
615 fn index(&self) -> PyResult<Bound<'py, PyList>> {
616 let __all__ = __all__(self.py());
617 match self.getattr(__all__) {
618 Ok(idx) => idx.downcast_into().map_err(PyErr::from),
619 Err(err) => {
620 if err.is_instance_of::<exceptions::PyAttributeError>(self.py()) {
621 let l = PyList::empty_bound(self.py());
622 self.setattr(__all__, &l).map_err(PyErr::from)?;
623 Ok(l)
624 } else {
625 Err(err)
626 }
627 }
628 }
629 }
630
631 fn name(&self) -> PyResult<Bound<'py, PyString>> {
632 #[cfg(not(PyPy))]
633 {
634 unsafe {
635 ffi::PyModule_GetNameObject(self.as_ptr())
636 .assume_owned_or_err(self.py())
637 .downcast_into_unchecked()
638 }
639 }
640
641 #[cfg(PyPy)]
642 {
643 self.dict()
644 .get_item("__name__")
645 .map_err(|_| exceptions::PyAttributeError::new_err("__name__"))?
646 .downcast_into()
647 .map_err(PyErr::from)
648 }
649 }
650
651 fn filename(&self) -> PyResult<Bound<'py, PyString>> {
652 #[cfg(not(PyPy))]
653 unsafe {
654 ffi::PyModule_GetFilenameObject(self.as_ptr())
655 .assume_owned_or_err(self.py())
656 .downcast_into_unchecked()
657 }
658
659 #[cfg(PyPy)]
660 {
661 self.dict()
662 .get_item("__file__")
663 .map_err(|_| exceptions::PyAttributeError::new_err("__file__"))?
664 .downcast_into()
665 .map_err(PyErr::from)
666 }
667 }
668
669 fn add<N, V>(&self, name: N, value: V) -> PyResult<()>
670 where
671 N: IntoPy<Py<PyString>>,
672 V: IntoPy<PyObject>,
673 {
674 fn inner(
675 module: &Bound<'_, PyModule>,
676 name: Bound<'_, PyString>,
677 value: Bound<'_, PyAny>,
678 ) -> PyResult<()> {
679 module
680 .index()?
681 .append(&name)
682 .expect("could not append __name__ to __all__");
683 module.setattr(name, value.into_py(module.py()))
684 }
685
686 let py = self.py();
687 inner(
688 self,
689 name.into_py(py).into_bound(py),
690 value.into_py(py).into_bound(py),
691 )
692 }
693
694 fn add_class<T>(&self) -> PyResult<()>
695 where
696 T: PyClass,
697 {
698 let py = self.py();
699 self.add(T::NAME, T::lazy_type_object().get_or_try_init(py)?)
700 }
701
702 fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>
703 where
704 T: IntoPyCallbackOutput<PyObject>,
705 {
706 fn inner(module: &Bound<'_, PyModule>, object: Bound<'_, PyAny>) -> PyResult<()> {
707 let name = object.getattr(__name__(module.py()))?;
708 module.add(name.downcast_into::<PyString>()?, object)
709 }
710
711 let py = self.py();
712 inner(self, wrapper(py).convert(py)?.into_bound(py))
713 }
714
715 fn add_submodule(&self, module: &Bound<'_, PyModule>) -> PyResult<()> {
716 let name = module.name()?;
717 self.add(name, module)
718 }
719
720 fn add_function(&self, fun: Bound<'_, PyCFunction>) -> PyResult<()> {
721 let name = fun.getattr(__name__(self.py()))?;
722 self.add(name.downcast_into::<PyString>()?, fun)
723 }
724}
725
726fn __all__(py: Python<'_>) -> &Bound<'_, PyString> {
727 intern!(py, "__all__")
728}
729
730fn __name__(py: Python<'_>) -> &Bound<'_, PyString> {
731 intern!(py, "__name__")
732}
733
734#[cfg(test)]
735mod tests {
736 use crate::{
737 types::{module::PyModuleMethods, PyModule},
738 Python,
739 };
740
741 #[test]
742 fn module_import_and_name() {
743 Python::with_gil(|py| {
744 let builtins = PyModule::import_bound(py, "builtins").unwrap();
745 assert_eq!(builtins.name().unwrap(), "builtins");
746 })
747 }
748
749 #[test]
750 fn module_filename() {
751 use crate::types::string::PyStringMethods;
752 Python::with_gil(|py| {
753 let site = PyModule::import_bound(py, "site").unwrap();
754 assert!(site
755 .filename()
756 .unwrap()
757 .to_cow()
758 .unwrap()
759 .ends_with("site.py"));
760 })
761 }
762}