More docs+examples (freelist, pyany, pymodule, puthon::check_signals) (#1600)

* expanded freelist docs

* added check_signals doc example

* added doc examples for pyany methods

* doc examples for pymodule + deprecate add_wrapped

* fixed tabs+whitespace...

* stronger wording on running signal handler code

Co-authored-by: Georg Brandl <georg@python.org>

* fix keyboardinterrupt spelling

Co-authored-by: Georg Brandl <georg@python.org>

* remove semicolon

Co-authored-by: Georg Brandl <georg@python.org>

* add space

Co-authored-by: Georg Brandl <georg@python.org>

* add space

Co-authored-by: Georg Brandl <georg@python.org>

* added suggested changes

* fixed doctest

* fixed triple backslash

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>

* spacing inside struct

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>

* use ? rather than unwrap in doc examples

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>

* remove use of "we", "us", "you" from docs

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>

* add that freelist shouldnt be impl'd by users

* added suggested changes

Co-authored-by: Georg Brandl <georg@python.org>
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
This commit is contained in:
mejrs 2021-05-12 08:32:46 +02:00 committed by GitHub
parent cc68f4a021
commit 1ae3d87973
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 414 additions and 101 deletions

View File

@ -1,6 +1,14 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
//! Free allocation list
//! Support for [free allocation lists][1].
//!
//! This can improve performance for types that are often created and deleted in quick succession.
//!
//! Rather than implementing this manually,
//! implement it by annotating a struct with `#[pyclass(freelist = N)]`,
//! where `N` is the size of the freelist.
//!
//! [1]: https://en.wikipedia.org/wiki/Free_list
use crate::class::impl_::PyClassImpl;
use crate::pyclass::{get_type_free, tp_free_fallback, PyClassAlloc};
@ -9,13 +17,15 @@ use crate::{ffi, AsPyPointer, FromPyPointer, PyAny, Python};
use std::mem;
use std::os::raw::c_void;
/// Implementing this trait for custom class adds free allocation list to class.
/// The performance improvement applies to types that are often created and deleted in a row,
/// so that they can benefit from a freelist.
/// Implements a freelist.
///
/// Do not implement this trait manually. Instead, use `#[pyclass(freelist = N)]`
/// on a Rust struct to implement it.
pub trait PyClassWithFreeList {
fn get_free_list(py: Python) -> &mut FreeList<*mut ffi::PyObject>;
}
/// Represents a slot of a [`FreeList`].
pub enum Slot<T> {
Empty,
Filled(T),
@ -28,7 +38,7 @@ pub struct FreeList<T> {
}
impl<T> FreeList<T> {
/// Create new `FreeList` instance with specified capacity
/// Creates a new `FreeList` instance with specified capacity.
pub fn with_capacity(capacity: usize) -> FreeList<T> {
let entries = (0..capacity).map(|_| Slot::Empty).collect::<Vec<_>>();
@ -39,7 +49,7 @@ impl<T> FreeList<T> {
}
}
/// Pop first non empty item
/// Pops the first non empty item.
pub fn pop(&mut self) -> Option<T> {
let idx = self.split;
if idx == 0 {
@ -55,7 +65,7 @@ impl<T> FreeList<T> {
}
}
/// Insert a value into the list
/// Inserts a value into the list. Returns `None` if the `FreeList` is full.
pub fn insert(&mut self, val: T) -> Option<T> {
let next = self.split + 1;
if next < self.capacity {

View File

@ -556,17 +556,41 @@ impl<'p> Python<'p> {
FromPyPointer::from_borrowed_ptr_or_opt(self, ptr)
}
/// Lets the Python interpreter check for pending signals and invoke the
/// corresponding signal handlers. This can run arbitrary Python code.
/// Lets the Python interpreter check and handle any pending signals. This will invoke the
/// corresponding signal handlers registered in Python (if any).
///
/// If an exception is raised by the signal handler, or the default signal
/// handler raises an exception (such as `KeyboardInterrupt` for `SIGINT`),
/// an `Err` is returned.
/// Returns `Err(PyErr)` if any signal handler raises an exception.
///
/// This is a wrapper of the C function `PyErr_CheckSignals()`. It is good
/// practice to call this regularly in a long-running calculation since
/// SIGINT and other signals handled by Python code are left pending for its
/// entire duration.
/// These signals include `SIGINT` (normally raised by CTRL + C), which by default raises
/// `KeyboardInterrupt`. For this reason it is good practice to call this function regularly
/// as part of long-running Rust functions so that users can cancel it.
///
/// # Example
///
/// ```rust
/// use pyo3::prelude::*;
/// # fn main(){
/// #[pyfunction]
/// fn loop_forever(py: Python) -> PyResult<()> {
/// loop {
/// // As this loop is infinite it should check for signals every once in a while.
/// // Using `?` causes any `PyErr` (potentially containing `KeyboardInterrupt`) to break out of the loop.
/// py.check_signals()?;
///
/// // do work here
/// # break Ok(()) // don't actually loop forever
/// }
/// }
/// # }
/// ```
///
/// # Note
/// This function calls [`PyErr_CheckSignals()`][1] which in turn may call signal handlers.
/// As Python's [`signal`][2] API allows users to define custom signal handlers, calling this
/// function allows arbitary Python code inside signal handlers to run.
///
/// [1]: https://docs.python.org/3/c-api/exceptions.html?highlight=pyerr_checksignals#c.PyErr_CheckSignals
/// [2]: https://docs.python.org/3/library/signal.html
pub fn check_signals(self) -> PyResult<()> {
let v = unsafe { ffi::PyErr_CheckSignals() };
if v == -1 {
@ -605,6 +629,7 @@ impl<'p> Python<'p> {
/// released.
///
/// # Examples
///
/// ```rust
/// # use pyo3::prelude::*;
/// Python::with_gil(|py| {
@ -624,6 +649,7 @@ impl<'p> Python<'p> {
/// ```
///
/// # Safety
///
/// Extreme care must be taken when using this API, as misuse can lead to accessing invalid
/// memory. In addition, the caller is responsible for guaranteeing that the GIL remains held
/// for the entire lifetime of the returned `GILPool`.

View File

@ -194,7 +194,46 @@ impl PyAny {
}
}
/// Determines whether this object is callable.
/// Determines whether this object appears callable.
///
/// This is equivalent to Python's [`callable()`][1] function.
///
/// This function returning `true` does not guarantee that a call will succeed.
/// For this reason, avoid calling potentially callable objects like this:
///
/// ```ignore
/// if some_object.is_callable() {
/// let value = some_object.call0().unwrap();
/// };
/// ```
///
/// Instead, just attempt to call it and handle any errors:
///
/// ```ignore
/// match some_object.call0() {
/// Ok(value) => ...,
/// Err(e) => ...,
/// }
/// ```
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let builtins = PyModule::import(py, "builtins")?;
/// let print = builtins.getattr("print")?;
/// assert!(print.is_callable());
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
///
/// This is equivalent to the Python expression `assert callable(print)`.
///
/// [1]: https://docs.python.org/3/library/functions.html#callable
pub fn is_callable(&self) -> bool {
unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
}
@ -223,6 +262,23 @@ impl PyAny {
/// Calls the object without arguments.
///
/// This is equivalent to the Python expression `self()`.
///
/// # Examples
///
/// ```no_run
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::import(py, "builtins")?;
/// let help = module.getattr("help")?;
/// help.call0()?;
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
///
/// This is equivalent to the Python expression `help()`.
pub fn call0(&self) -> PyResult<&PyAny> {
cfg_if::cfg_if! {
// TODO: Use PyObject_CallNoArgs instead after https://bugs.python.org/issue42415.
@ -241,6 +297,32 @@ impl PyAny {
/// Calls the object with only positional arguments.
///
/// This is equivalent to the Python expression `self(*args)`.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::import(py, "operator")?;
/// let add = module.getattr("add")?;
/// let args = (1,2);
/// let value = add.call1(args)?;
/// assert_eq!(value.extract::<i32>()?, 3);
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
///
/// This is equivalent to the following Python code:
///
/// ```python
/// from operator import add
///
/// value = add(1,2)
/// assert value == 3
/// ```
pub fn call1(&self, args: impl IntoPy<Py<PyTuple>>) -> PyResult<&PyAny> {
self.call(args, None)
}
@ -250,20 +332,30 @@ impl PyAny {
/// This is equivalent to the Python expression `self.name(*args, **kwargs)`.
///
/// # Examples
///
/// ```rust
/// # use pyo3::prelude::*;
/// use pyo3::types::IntoPyDict;
/// use pyo3::prelude::*;
/// use pyo3::types::{PyDict, PyList};
/// use crate::pyo3::types::IntoPyDict;
///
/// Python::with_gil(|py| {
/// let list = vec![3, 6, 5, 4, 7].to_object(py);
/// let dict = vec![("reverse", true)].into_py_dict(py);
/// list.call_method(py, "sort", (), Some(dict)).unwrap();
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3]);
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let list = PyList::new(py, vec![3, 6, 5, 4, 7]);
/// let kwargs = vec![("reverse", true)].into_py_dict(py);
///
/// let new_element = 1.to_object(py);
/// list.call_method(py, "append", (new_element,), None).unwrap();
/// assert_eq!(list.extract::<Vec<i32>>(py).unwrap(), vec![7, 6, 5, 4, 3, 1]);
/// });
/// list.call_method("sort", (), Some(kwargs))?;
/// assert_eq!(list.extract::<Vec<i32>>()?, vec![7, 6, 5, 4, 3]);
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
///
/// This is equivalent to the following Python code:
///
/// ```python
/// my_list = [3, 6, 5, 4, 7]
/// my_list.sort(reverse = True)
/// assert my_list == [7, 6, 5, 4, 3]
/// ```
pub fn call_method(
&self,
@ -291,6 +383,33 @@ impl PyAny {
/// Calls a method on the object without arguments.
///
/// This is equivalent to the Python expression `self.name()`.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyFloat;
/// use std::f64::consts::PI;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let pi = PyFloat::new(py, PI);
/// let ratio = pi.call_method0("as_integer_ratio")?;
/// let (a, b) = ratio.extract::<(u64, u64)>()?;
/// assert_eq!(a, 884_279_719_003_555);
/// assert_eq!(b, 281_474_976_710_656);
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
///
/// This is equivalent to the following Python code:
///
/// ```python
/// import math
///
/// a, b = math.pi.as_integer_ratio()
/// ```
pub fn call_method0(&self, name: &str) -> PyResult<&PyAny> {
cfg_if::cfg_if! {
if #[cfg(all(Py_3_9, not(Py_LIMITED_API)))] {
@ -308,6 +427,30 @@ impl PyAny {
/// Calls a method on the object with only positional arguments.
///
/// This is equivalent to the Python expression `self.name(*args)`.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyList;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let list = PyList::new(py, vec![1, 3, 4]);
/// list.call_method1("insert", (1, 2))?;
/// assert_eq!(list.extract::<Vec<u8>>()?, [1, 2, 3, 4]);
/// Ok(())
/// })?;
/// # Ok(()) }
/// ```
///
/// This is equivalent to the following Python code:
///
/// ```python
/// list_ = [1,3,4]
/// list_.insert(1,2)
/// assert list_ == [1,2,3,4]
/// ```
pub fn call_method1(&self, name: &str, args: impl IntoPy<Py<PyTuple>>) -> PyResult<&PyAny> {
self.call_method(name, args, None)
}

View File

@ -15,14 +15,35 @@ use crate::{AsPyPointer, IntoPy, Py, PyObject, Python};
use std::ffi::{CStr, CString};
use std::str;
/// Represents a Python `module` object.
/// Represents a Python [`module`][1] object.
///
/// As with all other Python objects, modules are first class citizens.
/// This means they can be passed to or returned from functions,
/// created dynamically, assigned to variables and so forth.
///
/// [1]: https://docs.python.org/3/tutorial/modules.html
#[repr(transparent)]
pub struct PyModule(PyAny);
pyobject_native_type_core!(PyModule, ffi::PyModule_Type, #checkfunction=ffi::PyModule_Check);
impl PyModule {
/// Creates a new module object with the `__name__` attribute set to name.
/// Creates a new module object with the `__name__` attribute set to `name`.
///
/// # Examples
///
/// ``` rust
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()>{
/// Python::with_gil(|py| -> PyResult<()>{
/// let module = PyModule::new(py, "my_module")?;
///
/// assert_eq!(module.name()?, "my_module");
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
// Could use PyModule_NewObject, but it doesn't exist on PyPy.
let name = CString::new(name)?;
@ -30,17 +51,65 @@ impl PyModule {
}
/// Imports the Python module with the specified name.
///
/// # Examples
///
/// ```no_run
/// # fn main(){
/// use pyo3::prelude::*;
///
/// Python::with_gil(|py| {
/// let module = PyModule::import(py, "antigravity").expect("No flying for you.");
/// });
/// # }
/// ```
///
/// This is equivalent to the following Python expression:
///
/// ```python
/// import antigravity
/// ```
pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
let name: PyObject = name.into_py(py);
unsafe { py.from_owned_ptr_or_err(ffi::PyImport_Import(name.as_ptr())) }
}
/// Loads the Python code specified into a new module.
/// Creates and loads a module named `module_name`,
/// containing the Python code passed to `code`
/// and pretending to live at `file_name`.
///
/// `code` is the raw Python you want to load into the module.
/// `file_name` is the file name to associate with the module
/// (this is used when Python reports errors, for example).
/// `module_name` is the name to give the module.
/// <div class="information">
/// <div class="tooltip compile_fail" style="">&#x26a0; &#xfe0f;</div>
/// </div><div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
//
/// <strong>Warning</strong>: This will compile and execute code. <strong>Never</strong> pass untrusted code to this function!
///
/// </pre></div>
///
/// # Errors
///
/// Returns `PyErr` if:
/// - `code` is not syntactically correct Python.
/// - Any Python exceptions are raised while initializing the module.
/// - Any of the arguments cannot be converted to [`CString`](std::ffi::CString)s.
///
/// # Examples
///
/// ```no_run
/// use pyo3::prelude::*;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let module = PyModule::from_code(
/// py,
/// "print(__file__, __name__)",
/// "my_file",
/// "my_module"
/// )?;
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
pub fn from_code<'p>(
py: Python<'p>,
code: &str,
@ -66,8 +135,7 @@ impl PyModule {
}
}
/// Return the dictionary object that implements module's namespace;
/// this object is the same as the `__dict__` attribute of the module object.
/// Returns the module's `__dict__` attribute, which contains the module's symbol table.
pub fn dict(&self) -> &PyDict {
unsafe {
// PyModule_GetDict returns borrowed ptr; must make owned for safety (see #890).
@ -77,7 +145,10 @@ impl PyModule {
}
}
/// Return the index (`__all__`) of the module, creating one if needed.
/// Returns the index (the `__all__` attribute) of the module,
/// creating one if needed.
///
/// `__all__` declares the items that will be imported with `from my_module import *`.
pub fn index(&self) -> PyResult<&PyList> {
match self.getattr("__all__") {
Ok(idx) => idx.downcast().map_err(PyErr::from),
@ -93,7 +164,7 @@ impl PyModule {
}
}
/// Returns the module's name.
/// Returns the name (the `__name__` attribute) of the module.
///
/// May fail if the module does not have a `__name__` attribute.
pub fn name(&self) -> PyResult<&str> {
@ -108,7 +179,7 @@ impl PyModule {
}
}
/// Returns the module's filename.
/// Returns the filename (the `__file__` attribute) of the module.
///
/// May fail if the module does not have a `__file__` attribute.
#[cfg(not(all(windows, PyPy)))]
@ -122,9 +193,36 @@ impl PyModule {
}
}
/// Adds a member to the module.
/// Adds an attribute to the module.
///
/// This is a convenience function which can be used from the module's initialization function.
/// For adding classes, functions or modules, prefer to use [`PyModule::add_class`],
/// [`PyModule::add_function`] or [`PyModule::add_submodule`] instead, respectively.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
///
/// #[pymodule]
/// fn my_module(_py: Python, module: &PyModule) -> PyResult<()> {
/// module.add("c", 299_792_458)?;
/// Ok(())
/// }
/// ```
///
/// Python code can then do the following:
///
/// ```python
/// from my_module import c
///
/// print("c is", c)
/// ```
///
/// This will result in the following output:
///
/// ```text
/// c is 299792458
/// ```
pub fn add<V>(&self, name: &str, value: V) -> PyResult<()>
where
V: IntoPy<PyObject>,
@ -135,11 +233,46 @@ impl PyModule {
self.setattr(name, value.into_py(self.py()))
}
/// Adds a new extension type to the module.
/// Adds a new class to the module.
///
/// This is a convenience function that initializes the `class`,
/// sets `new_type.__module__` to this module's name,
/// and adds the type to this module.
/// Notice that this method does not take an argument.
/// Instead, this method is *generic*, and requires us to use the
/// "turbofish" syntax to specify the class we want to add.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
///
/// #[pyclass]
/// struct Foo { /* fields omitted */ }
///
/// #[pymodule]
/// fn my_module(_py: Python, module: &PyModule) -> PyResult<()> {
/// module.add_class::<Foo>()?;
/// Ok(())
/// }
/// ```
///
/// Python code can see this class as such:
///
/// ```python
/// from my_module import Foo
///
/// print("Foo is", Foo)
/// ```
///
/// This will result in the following output:
///
/// ```text
/// Foo is <class 'builtins.Foo'>
/// ```
///
/// Note that as we haven't defined a [constructor][1], Python code can't actually
/// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
/// anything that can return instances of `Foo`).
///
/// [1]: https://pyo3.rs/main/class.html#constructor
pub fn add_class<T>(&self) -> PyResult<()>
where
T: PyClass,
@ -147,37 +280,9 @@ impl PyModule {
self.add(T::NAME, <T as PyTypeObject>::type_object(self.py()))
}
/// Adds a function or a (sub)module to a module, using the functions __name__ as name.
/// Adds a function or a (sub)module to a module, using the functions name as name.
///
/// Use this together with the`#[pyfunction]` and [wrap_pyfunction!] or `#[pymodule]` and
/// [wrap_pymodule!].
///
/// ```rust
/// use pyo3::prelude::*;
/// #[pymodule]
/// fn utils(_py: Python, _module: &PyModule) -> PyResult<()> {
/// Ok(())
/// }
///
/// #[pyfunction]
/// fn double(x: usize) -> usize {
/// x * 2
/// }
/// #[pymodule]
/// fn top_level(_py: Python, module: &PyModule) -> PyResult<()> {
/// module.add_wrapped(pyo3::wrap_pymodule!(utils))?;
/// module.add_wrapped(pyo3::wrap_pyfunction!(double))
/// }
/// ```
///
/// You can also add a function with a custom name using [add](PyModule::add):
///
/// ```rust,ignore
/// m.add("also_double", wrap_pyfunction!(double)(m)?)?;
/// ```
///
/// **This function will be deprecated in the next release. Please use the specific
/// [PyModule::add_function] and [PyModule::add_submodule] functions instead.**
/// Prefer to use [`PyModule::add_function`] and/or [`PyModule::add_submodule`] instead.
pub fn add_wrapped<'a, T>(&'a self, wrapper: &impl Fn(Python<'a>) -> T) -> PyResult<()>
where
T: IntoPyCallbackOutput<PyObject>,
@ -189,23 +294,46 @@ impl PyModule {
self.add(name, function)
}
/// Add a submodule to a module.
/// Adds a submodule to a module.
///
/// Use this together with `#[pymodule]` and [wrap_pymodule!].
/// This is especially useful for creating module hierarchies.
///
/// Note that this doesn't define a *package*, so this won't allow Python code
/// to directly import submodules by using
/// <span style="white-space: pre">`from my_module import submodule`</span>.
/// For more information, see [#759][1] and [#1517][2].
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
///
/// fn init_utils(module: &PyModule) -> PyResult<()> {
/// module.add("super_useful_constant", "important")
/// }
/// #[pymodule]
/// fn top_level(py: Python, module: &PyModule) -> PyResult<()> {
/// let utils = PyModule::new(py, "utils")?;
/// init_utils(utils)?;
/// module.add_submodule(utils)
/// fn my_module(py: Python, module: &PyModule) -> PyResult<()> {
/// let submodule = PyModule::new(py, "submodule")?;
/// submodule.add("super_useful_constant", "important")?;
///
/// module.add_submodule(submodule)?;
/// Ok(())
/// }
/// ```
///
/// Python code can then do the following:
///
/// ```python
/// import my_module
///
/// print("super_useful_constant is", my_module.submodule.super_useful_constant)
/// ```
///
/// This will result in the following output:
///
/// ```text
/// super_useful_constant is important
/// ```
///
/// [1]: https://github.com/PyO3/pyo3/issues/759
/// [2]: https://github.com/PyO3/pyo3/issues/1517#issuecomment-808664021
pub fn add_submodule(&self, module: &PyModule) -> PyResult<()> {
let name = module.name()?;
self.add(name, module)
@ -213,33 +341,39 @@ impl PyModule {
/// Add a function to a module.
///
/// Use this together with the`#[pyfunction]` and [wrap_pyfunction!].
/// Note that this also requires the [`wrap_pyfunction!`][2] macro
/// to wrap a function annotated with [`#[pyfunction]`][1].
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::wrap_pyfunction;
///
/// #[pyfunction]
/// fn double(x: usize) -> usize {
/// x * 2
/// fn say_hello() {
/// println!("Hello world!")
/// }
/// #[pymodule]
/// fn double_mod(_py: Python, module: &PyModule) -> PyResult<()> {
/// module.add_function(pyo3::wrap_pyfunction!(double, module)?)
/// fn my_module(_py: Python, module: &PyModule) -> PyResult<()> {
/// module.add_function(wrap_pyfunction!(say_hello, module)?)
/// }
/// ```
///
/// You can also add a function with a custom name using [add](PyModule::add):
/// Python code can then do the following:
///
/// ```rust
/// use pyo3::prelude::*;
/// #[pyfunction]
/// fn double(x: usize) -> usize {
/// x * 2
/// }
/// #[pymodule]
/// fn double_mod(_py: Python, module: &PyModule) -> PyResult<()> {
/// module.add("also_double", pyo3::wrap_pyfunction!(double, module)?)
/// }
/// ```python
/// from my_module import say_hello
///
/// say_hello()
/// ```
///
/// This will result in the following output:
///
/// ```text
/// Hello world!
/// ```
///
/// [1]: crate::prelude::pyfunction
/// [2]: crate::wrap_pyfunction
pub fn add_function<'a>(&'a self, fun: &'a PyCFunction) -> PyResult<()> {
let name = fun.getattr("__name__")?.extract()?;
self.add(name, fun)