1//! Raw FFI declarations for Python's C API.
2//!
3//! PyO3 can be used to write native Python modules or run Python code and modules from Rust.
4//!
5//! This crate just provides low level bindings to the Python interpreter.
6//! It is meant for advanced users only - regular PyO3 users shouldn't
7//! need to interact with this crate at all.
8//!
9//! The contents of this crate are not documented here, as it would entail
10//! basically copying the documentation from CPython. Consult the [Python/C API Reference
11//! Manual][capi] for up-to-date documentation.
12//!
13//! # Safety
14//!
15//! The functions in this crate lack individual safety documentation, but
16//! generally the following apply:
17//! - Pointer arguments have to point to a valid Python object of the correct type,
18//! although null pointers are sometimes valid input.
19//! - The vast majority can only be used safely while the GIL is held.
20//! - Some functions have additional safety requirements, consult the
21//! [Python/C API Reference Manual][capi]
22//! for more information.
23//!
24//!
25//! # Feature flags
26//!
27//! PyO3 uses [feature flags] to enable you to opt-in to additional functionality. For a detailed
28//! description, see the [Features chapter of the guide].
29//!
30//! ## Optional feature flags
31//!
32//! The following features customize PyO3's behavior:
33//!
34//! - `abi3`: Restricts PyO3's API to a subset of the full Python API which is guaranteed by
35//! [PEP 384] to be forward-compatible with future Python versions.
36//! - `extension-module`: This will tell the linker to keep the Python symbols unresolved, so that
37//! your module can also be used with statically linked Python interpreters. Use this feature when
38//! building an extension module.
39//!
40//! ## `rustc` environment flags
41//!
42//! PyO3 uses `rustc`'s `--cfg` flags to enable or disable code used for different Python versions.
43//! If you want to do this for your own crate, you can do so with the [`pyo3-build-config`] crate.
44//!
45//! - `Py_3_7`, `Py_3_8`, `Py_3_9`, `Py_3_10`: Marks code that is only enabled when
46//! compiling for a given minimum Python version.
47//! - `Py_LIMITED_API`: Marks code enabled when the `abi3` feature flag is enabled.
48//! - `PyPy` - Marks code enabled when compiling for PyPy.
49//!
50//! # Minimum supported Rust and Python versions
51//!
52//! PyO3 supports the following software versions:
53//! - Python 3.7 and up (CPython and PyPy)
54//! - Rust 1.56 and up
55//!
56//! # Example: Building Python Native modules
57//!
58//! PyO3 can be used to generate a native Python module. The easiest way to try this out for the
59//! first time is to use [`maturin`]. `maturin` is a tool for building and publishing Rust-based
60//! Python packages with minimal configuration. The following steps set up some files for an example
61//! Python module, install `maturin`, and then show how to build and import the Python module.
62//!
63//! First, create a new folder (let's call it `string_sum`) containing the following two files:
64//!
65//! **`Cargo.toml`**
66//!
67//! ```toml
68//! [lib]
69//! name = "string_sum"
70//! # "cdylib" is necessary to produce a shared library for Python to import from.
71//! #
72//! # Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
73//! # to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:
74//! # crate-type = ["cdylib", "rlib"]
75//! crate-type = ["cdylib"]
76//!
77//! [dependencies.pyo3-ffi]
78#![doc = concat!("version = \"", env!("CARGO_PKG_VERSION"), "\"")]
79//! features = ["extension-module"]
80//! ```
81//!
82//! **`src/lib.rs`**
83//! ```rust
84//! use std::os::raw::c_char;
85//! use std::ptr;
86//!
87//! use pyo3_ffi::*;
88//!
89//! static mut MODULE_DEF: PyModuleDef = PyModuleDef {
90//! m_base: PyModuleDef_HEAD_INIT,
91//! m_name: "string_sum\0".as_ptr().cast::<c_char>(),
92//! m_doc: "A Python module written in Rust.\0"
93//! .as_ptr()
94//! .cast::<c_char>(),
95//! m_size: 0,
96//! m_methods: unsafe { METHODS.as_mut_ptr().cast() },
97//! m_slots: std::ptr::null_mut(),
98//! m_traverse: None,
99//! m_clear: None,
100//! m_free: None,
101//! };
102//!
103//! static mut METHODS: [PyMethodDef; 2] = [
104//! PyMethodDef {
105//! ml_name: "sum_as_string\0".as_ptr().cast::<c_char>(),
106//! ml_meth: PyMethodDefPointer {
107//! _PyCFunctionFast: sum_as_string,
108//! },
109//! ml_flags: METH_FASTCALL,
110//! ml_doc: "returns the sum of two integers as a string\0"
111//! .as_ptr()
112//! .cast::<c_char>(),
113//! },
114//! // A zeroed PyMethodDef to mark the end of the array.
115//! PyMethodDef::zeroed()
116//! ];
117//!
118//! // The module initialization function, which must be named `PyInit_<your_module>`.
119//! #[allow(non_snake_case)]
120//! #[no_mangle]
121//! pub unsafe extern "C" fn PyInit_string_sum() -> *mut PyObject {
122//! PyModule_Create(ptr::addr_of_mut!(MODULE_DEF))
123//! }
124//!
125//! pub unsafe extern "C" fn sum_as_string(
126//! _self: *mut PyObject,
127//! args: *mut *mut PyObject,
128//! nargs: Py_ssize_t,
129//! ) -> *mut PyObject {
130//! if nargs != 2 {
131//! PyErr_SetString(
132//! PyExc_TypeError,
133//! "sum_as_string() expected 2 positional arguments\0"
134//! .as_ptr()
135//! .cast::<c_char>(),
136//! );
137//! return std::ptr::null_mut();
138//! }
139//!
140//! let arg1 = *args;
141//! if PyLong_Check(arg1) == 0 {
142//! PyErr_SetString(
143//! PyExc_TypeError,
144//! "sum_as_string() expected an int for positional argument 1\0"
145//! .as_ptr()
146//! .cast::<c_char>(),
147//! );
148//! return std::ptr::null_mut();
149//! }
150//!
151//! let arg1 = PyLong_AsLong(arg1);
152//! if !PyErr_Occurred().is_null() {
153//! return ptr::null_mut();
154//! }
155//!
156//! let arg2 = *args.add(1);
157//! if PyLong_Check(arg2) == 0 {
158//! PyErr_SetString(
159//! PyExc_TypeError,
160//! "sum_as_string() expected an int for positional argument 2\0"
161//! .as_ptr()
162//! .cast::<c_char>(),
163//! );
164//! return std::ptr::null_mut();
165//! }
166//!
167//! let arg2 = PyLong_AsLong(arg2);
168//! if !PyErr_Occurred().is_null() {
169//! return ptr::null_mut();
170//! }
171//!
172//! match arg1.checked_add(arg2) {
173//! Some(sum) => {
174//! let string = sum.to_string();
175//! PyUnicode_FromStringAndSize(string.as_ptr().cast::<c_char>(), string.len() as isize)
176//! }
177//! None => {
178//! PyErr_SetString(
179//! PyExc_OverflowError,
180//! "arguments too large to add\0".as_ptr().cast::<c_char>(),
181//! );
182//! std::ptr::null_mut()
183//! }
184//! }
185//! }
186//! ```
187//!
188//! With those two files in place, now `maturin` needs to be installed. This can be done using
189//! Python's package manager `pip`. First, load up a new Python `virtualenv`, and install `maturin`
190//! into it:
191//! ```bash
192//! $ cd string_sum
193//! $ python -m venv .env
194//! $ source .env/bin/activate
195//! $ pip install maturin
196//! ```
197//!
198//! Now build and execute the module:
199//! ```bash
200//! $ maturin develop
201//! # lots of progress output as maturin runs the compilation...
202//! $ python
203//! >>> import string_sum
204//! >>> string_sum.sum_as_string(5, 20)
205//! '25'
206//! ```
207//!
208//! As well as with `maturin`, it is possible to build using [setuptools-rust] or
209//! [manually][manual_builds]. Both offer more flexibility than `maturin` but require further
210//! configuration.
211//!
212//!
213//! # Using Python from Rust
214//!
215//! To embed Python into a Rust binary, you need to ensure that your Python installation contains a
216//! shared library. The following steps demonstrate how to ensure this (for Ubuntu).
217//!
218//! To install the Python shared library on Ubuntu:
219//! ```bash
220//! sudo apt install python3-dev
221//! ```
222//!
223//! While most projects use the safe wrapper provided by pyo3,
224//! you can take a look at the [`orjson`] library as an example on how to use `pyo3-ffi` directly.
225//! For those well versed in C and Rust the [tutorials] from the CPython documentation
226//! can be easily converted to rust as well.
227//!
228//! [tutorials]: https://docs.python.org/3/extending/
229//! [`orjson`]: https://github.com/ijl/orjson
230//! [capi]: https://docs.python.org/3/c-api/index.html
231//! [`maturin`]: https://github.com/PyO3/maturin "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages"
232//! [`pyo3-build-config`]: https://docs.rs/pyo3-build-config
233//! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html "Features - The Cargo Book"
234//! [manual_builds]: https://pyo3.rs/latest/building_and_distribution.html#manual-builds "Manual builds - Building and Distribution - PyO3 user guide"
235//! [setuptools-rust]: https://github.com/PyO3/setuptools-rust "Setuptools plugin for Rust extensions"
236//! [PEP 384]: https://www.python.org/dev/peps/pep-0384 "PEP 384 -- Defining a Stable ABI"
237//! [Features chapter of the guide]: https://pyo3.rs/latest/features.html#features-reference "Features Reference - PyO3 user guide"
238
239#![allow(
240 missing_docs,
241 non_camel_case_types,
242 non_snake_case,
243 non_upper_case_globals,
244 clippy::upper_case_acronyms,
245 clippy::missing_safety_doc
246)]
247#![warn(elided_lifetimes_in_paths, unused_lifetimes)]
248
249// Until `extern type` is stabilized, use the recommended approach to
250// model opaque types:
251// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
252macro_rules! opaque_struct {
253 ($name:ident) => {
254 #[repr(C)]
255 pub struct $name([u8; 0]);
256 };
257}
258
259pub use self::abstract_::*;
260pub use self::bltinmodule::*;
261pub use self::boolobject::*;
262pub use self::bytearrayobject::*;
263pub use self::bytesobject::*;
264pub use self::ceval::*;
265#[cfg(Py_LIMITED_API)]
266pub use self::code::*;
267pub use self::codecs::*;
268pub use self::compile::*;
269pub use self::complexobject::*;
270#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
271pub use self::context::*;
272#[cfg(not(Py_LIMITED_API))]
273pub use self::datetime::*;
274pub use self::descrobject::*;
275pub use self::dictobject::*;
276pub use self::enumobject::*;
277pub use self::fileobject::*;
278pub use self::fileutils::*;
279pub use self::floatobject::*;
280pub use self::import::*;
281pub use self::intrcheck::*;
282pub use self::iterobject::*;
283pub use self::listobject::*;
284pub use self::longobject::*;
285#[cfg(not(Py_LIMITED_API))]
286pub use self::marshal::*;
287pub use self::memoryobject::*;
288pub use self::methodobject::*;
289pub use self::modsupport::*;
290pub use self::moduleobject::*;
291pub use self::object::*;
292pub use self::objimpl::*;
293pub use self::osmodule::*;
294#[cfg(not(any(PyPy, Py_LIMITED_API, Py_3_10)))]
295pub use self::pyarena::*;
296#[cfg(Py_3_11)]
297pub use self::pybuffer::*;
298pub use self::pycapsule::*;
299pub use self::pyerrors::*;
300pub use self::pyframe::*;
301pub use self::pyhash::*;
302pub use self::pylifecycle::*;
303pub use self::pymem::*;
304pub use self::pyport::*;
305pub use self::pystate::*;
306pub use self::pystrtod::*;
307pub use self::pythonrun::*;
308pub use self::rangeobject::*;
309pub use self::setobject::*;
310pub use self::sliceobject::*;
311pub use self::structseq::*;
312pub use self::sysmodule::*;
313pub use self::traceback::*;
314pub use self::tupleobject::*;
315pub use self::typeslots::*;
316pub use self::unicodeobject::*;
317pub use self::warnings::*;
318pub use self::weakrefobject::*;
319
320mod abstract_;
321// skipped asdl.h
322// skipped ast.h
323mod bltinmodule;
324mod boolobject;
325mod bytearrayobject;
326mod bytesobject;
327// skipped cellobject.h
328mod ceval;
329// skipped classobject.h
330#[cfg(Py_LIMITED_API)]
331mod code;
332mod codecs;
333mod compile;
334mod complexobject;
335#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
336mod context; // It's actually 3.7.1, but no cfg for patches.
337#[cfg(not(Py_LIMITED_API))]
338pub(crate) mod datetime;
339mod descrobject;
340mod dictobject;
341// skipped dynamic_annotations.h
342mod enumobject;
343// skipped errcode.h
344// skipped exports.h
345mod fileobject;
346mod fileutils;
347mod floatobject;
348// skipped empty frameobject.h
349// skipped genericaliasobject.h
350mod import;
351// skipped interpreteridobject.h
352mod intrcheck;
353mod iterobject;
354mod listobject;
355// skipped longintrepr.h
356mod longobject;
357#[cfg(not(Py_LIMITED_API))]
358pub mod marshal;
359mod memoryobject;
360mod methodobject;
361mod modsupport;
362mod moduleobject;
363// skipped namespaceobject.h
364mod object;
365mod objimpl;
366// skipped odictobject.h
367// skipped opcode.h
368// skipped osdefs.h
369mod osmodule;
370// skipped parser_interface.h
371// skipped patchlevel.h
372// skipped picklebufobject.h
373// skipped pyctype.h
374// skipped py_curses.h
375#[cfg(not(any(PyPy, Py_LIMITED_API, Py_3_10)))]
376mod pyarena;
377#[cfg(Py_3_11)]
378mod pybuffer;
379mod pycapsule;
380// skipped pydtrace.h
381mod pyerrors;
382// skipped pyexpat.h
383// skipped pyfpe.h
384mod pyframe;
385mod pyhash;
386mod pylifecycle;
387// skipped pymacconfig.h
388// skipped pymacro.h
389// skipped pymath.h
390mod pymem;
391mod pyport;
392mod pystate;
393// skipped pystats.h
394mod pythonrun;
395// skipped pystrhex.h
396// skipped pystrcmp.h
397mod pystrtod;
398// skipped pythread.h
399// skipped pytime.h
400mod rangeobject;
401mod setobject;
402mod sliceobject;
403mod structseq;
404mod sysmodule;
405mod traceback;
406// skipped tracemalloc.h
407mod tupleobject;
408mod typeslots;
409mod unicodeobject;
410mod warnings;
411mod weakrefobject;
412
413// Additional headers that are not exported by Python.h
414#[deprecated(note = "Python 3.12")]
415pub mod structmember;
416
417// "Limited API" definitions matching Python's `include/cpython` directory.
418#[cfg(not(Py_LIMITED_API))]
419mod cpython;
420
421#[cfg(not(Py_LIMITED_API))]
422pub use self::cpython::*;
423