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:
parent
cc68f4a021
commit
1ae3d87973
|
@ -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 {
|
||||
|
|
|
@ -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`.
|
||||
|
|
167
src/types/any.rs
167
src/types/any.rs
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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="">⚠ ️</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)
|
||||
|
|
Loading…
Reference in New Issue