Skip to main content

pyo3_ffi/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3//! Raw FFI declarations for Python's C API.
4//!
5//! PyO3 can be used to write native Python modules or run Python code and modules from Rust.
6//!
7//! This crate just provides low level bindings to the Python interpreter.
8//! It is meant for advanced users only - regular PyO3 users shouldn't
9//! need to interact with this crate at all.
10//!
11//! The contents of this crate are not documented here, as it would entail
12//! basically copying the documentation from CPython. Consult the [Python/C API Reference
13//! Manual][capi] for up-to-date documentation.
14//!
15//! # Safety
16//!
17//! The functions in this crate lack individual safety documentation, but
18//! generally the following apply:
19//! - Pointer arguments have to point to a valid Python object of the correct type,
20//! although null pointers are sometimes valid input.
21//! - The vast majority can only be used safely while the thread is attached to the Python interpreter.
22//! - Some functions have additional safety requirements, consult the
23//! [Python/C API Reference Manual][capi]
24//! for more information.
25//!
26//!
27//! # Feature flags
28//!
29//! PyO3 uses [feature flags] to enable you to opt-in to additional functionality. For a detailed
30//! description, see the [Features chapter of the guide].
31//!
32//! ## Optional feature flags
33//!
34//! The following features customize PyO3's behavior:
35//!
36//! - `abi3`: Restricts PyO3's API to a subset of the full Python API which is guaranteed by
37//! [PEP 384] to be forward-compatible with future Python versions.
38//!
39//! ## `rustc` environment flags
40//!
41//! PyO3 uses `rustc`'s `--cfg` flags to enable or disable code used for different Python versions.
42//! If you want to do this for your own crate, you can do so with the [`pyo3-build-config`] crate.
43//!
44//! - `Py_3_9`, `Py_3_10`, `Py_3_11`, `Py_3_12`, `Py_3_13`, `Py_3_14`, `Py_3_15`: Marks code that is
45//!    only enabled when compiling for a given minimum Python version.
46//! - `Py_LIMITED_API`: Marks code enabled when the `abi3` feature flag is enabled.
47//! - `Py_GIL_DISABLED`: Marks code that runs only in the free-threaded build of CPython.
48//! - `PyPy` - Marks code enabled when compiling for PyPy.
49//! - `GraalPy` - Marks code enabled when compiling for GraalPy.
50//!
51//! Additionally, you can query for the values `Py_DEBUG`, `Py_REF_DEBUG`,
52//! `Py_TRACE_REFS`, and `COUNT_ALLOCS` from `py_sys_config` to query for the
53//! corresponding C build-time defines. For example, to conditionally define
54//! debug code using `Py_DEBUG`, you could do:
55//!
56//! ```rust,ignore
57//! #[cfg(py_sys_config = "Py_DEBUG")]
58//! println!("only runs if python was compiled with Py_DEBUG")
59//! ```
60//!
61//! To use these attributes, add [`pyo3-build-config`] as a build dependency in
62//! your `Cargo.toml`:
63//!
64//! ```toml
65//! [build-dependencies]
66#![doc = concat!("pyo3-build-config =\"", env!("CARGO_PKG_VERSION"),  "\"")]
67//! ```
68//!
69//! And then either create a new `build.rs` file in the project root or modify
70//! the existing `build.rs` file to call `use_pyo3_cfgs()`:
71//!
72//! ```rust,ignore
73//! fn main() {
74//!     pyo3_build_config::use_pyo3_cfgs();
75//! }
76//! ```
77//!
78//! # Minimum supported Rust and Python versions
79//!
80//! `pyo3-ffi` supports the following Python distributions:
81//!   - CPython 3.9 or greater
82//!   - PyPy 7.3 (Python 3.11+)
83//!   - GraalPy 24.0 or greater (Python 3.10+)
84//!
85//! # Example: Building Python Native modules
86//!
87//! PyO3 can be used to generate a native Python module. The easiest way to try this out for the
88//! first time is to use [`maturin`]. `maturin` is a tool for building and publishing Rust-based
89//! Python packages with minimal configuration. The following steps set up some files for an example
90//! Python module, install `maturin`, and then show how to build and import the Python module.
91//!
92//! First, create a new folder (let's call it `string_sum`) containing the following two files:
93//!
94//! **`Cargo.toml`**
95//!
96//! ```toml
97//! [lib]
98//! name = "string_sum"
99//! # "cdylib" is necessary to produce a shared library for Python to import from.
100//! #
101//! # Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
102//! # to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:
103//! # crate-type = ["cdylib", "rlib"]
104//! crate-type = ["cdylib"]
105//!
106//! [dependencies]
107#![doc = concat!("pyo3-ffi = \"", env!("CARGO_PKG_VERSION"),  "\"")]
108//!
109//! [build-dependencies]
110//! # This is only necessary if you need to configure your build based on
111//! # the Python version or the compile-time configuration for the interpreter.
112#![doc = concat!("pyo3_build_config = \"", env!("CARGO_PKG_VERSION"),  "\"")]
113//! ```
114//!
115//! If you need to use conditional compilation based on Python version or how
116//! Python was compiled, you need to add `pyo3-build-config` as a
117//! `build-dependency` in your `Cargo.toml` as in the example above and either
118//! create a new `build.rs` file or modify an existing one so that
119//! `pyo3_build_config::use_pyo3_cfgs()` gets called at build time:
120//!
121//! **`build.rs`**
122//! ```rust,ignore
123//! fn main() {
124//!     pyo3_build_config::use_pyo3_cfgs()
125//! }
126//! ```
127//!
128//! **`src/lib.rs`**
129//! ```rust,no_run
130//! #[cfg(Py_3_15)]
131//! use core::ffi::c_void;
132//! #[cfg(not(Py_3_15))]
133//! use core::ffi::c_int;
134//! use core::ffi::{c_char, c_long};
135//! use core::ptr;
136//!
137//! use pyo3_ffi::*;
138//!
139//! #[cfg(not(Py_3_15))]
140//! static mut MODULE_DEF: PyModuleDef = PyModuleDef {
141//!     m_base: PyModuleDef_HEAD_INIT,
142//!     m_name: c"string_sum".as_ptr(),
143//!     m_doc: c"A Python module written in Rust.".as_ptr(),
144//!     m_size: 0,
145//!     m_methods: (&raw mut METHODS).cast(),
146//!     m_slots: (&raw mut SLOTS).cast(),
147//!     m_traverse: None,
148//!     m_clear: None,
149//!     m_free: None,
150//! };
151//!
152//! static mut METHODS: [PyMethodDef; 2] = [
153//!     PyMethodDef {
154//!         ml_name: c"sum_as_string".as_ptr(),
155//!         ml_meth: PyMethodDefPointer {
156//!             PyCFunctionFast: sum_as_string,
157//!         },
158//!         ml_flags: METH_FASTCALL,
159//!         ml_doc: c"returns the sum of two integers as a string".as_ptr(),
160//!     },
161//!     // A zeroed PyMethodDef to mark the end of the array.
162//!     PyMethodDef::zeroed(),
163//! ];
164//!
165//! const SLOTS_LEN: usize =
166//!     1 + cfg!(Py_3_12) as usize + cfg!(Py_GIL_DISABLED) as usize + 4 * (cfg!(Py_3_15) as usize);
167//!
168//! #[cfg(not(Py_3_15))]
169//! static mut SLOTS: [PyModuleDef_Slot; SLOTS_LEN] = [
170//!     #[cfg(Py_3_12)]
171//!     PyModuleDef_Slot {
172//!         slot: Py_mod_multiple_interpreters,
173//!         value: Py_MOD_PER_INTERPRETER_GIL_SUPPORTED,
174//!     },
175//!     #[cfg(Py_GIL_DISABLED)]
176//!     PyModuleDef_Slot {
177//!         slot: Py_mod_gil,
178//!         value: Py_MOD_GIL_NOT_USED,
179//!     },
180//!     PyModuleDef_Slot {
181//!         slot: 0,
182//!         value: ptr::null_mut(),
183//!     },
184//! ];
185//!
186//! #[cfg(Py_3_15)]
187//! PyABIInfo_VAR!(ABI_INFO);
188//!
189//! #[cfg(Py_3_15)]
190//! static mut SLOTS: [PySlot; SLOTS_LEN] = [
191//!     PySlot_STATIC_DATA(Py_mod_abi, core::ptr::addr_of_mut!(ABI_INFO).cast()),
192//!     PySlot_STATIC_DATA(Py_mod_name, c"string_sum".as_ptr() as *mut c_void),
193//!     PySlot_STATIC_DATA(Py_mod_doc, c"A Python module written in Rust.".as_ptr() as *mut c_void),
194//!     PySlot_STATIC_DATA(Py_mod_methods, (&raw mut METHODS).cast()),
195//!     PySlot_DATA(Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED),
196//!     #[cfg(Py_GIL_DISABLED)]
197//!     PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
198//!     PySlot_END(),
199//! ];
200//!
201//! // The module initialization function
202//! #[cfg(not(Py_3_15))]
203//! #[allow(non_snake_case, reason = "must be named `PyInit_<your_module>`")]
204//! #[no_mangle]
205//! pub unsafe extern "C" fn PyInit_string_sum() -> *mut PyObject {
206//!     PyModuleDef_Init(&raw mut MODULE_DEF)
207//! }
208//!
209//! #[cfg(Py_3_15)]
210//! #[allow(non_snake_case, reason = "must be named `PyModExport_<your_module>`")]
211//! #[no_mangle]
212//! pub unsafe extern "C" fn PyModExport_string_sum() -> *mut PySlot {
213//!     (&raw mut SLOTS).cast()
214//! }
215//!
216//! /// A helper to parse function arguments
217//! /// If we used PyO3's proc macros they'd handle all of this boilerplate for us :)
218//! unsafe fn parse_arg_as_i32(obj: *mut PyObject, n_arg: usize) -> Option<i32> {
219//!     if PyLong_Check(obj) == 0 {
220//!         let msg = format!(
221//!             "sum_as_string expected an int for positional argument {}\0",
222//!             n_arg
223//!         );
224//!         PyErr_SetString(PyExc_TypeError, msg.as_ptr().cast::<c_char>());
225//!         return None;
226//!     }
227//!
228//!     // Let's keep the behaviour consistent on platforms where `c_long` is bigger than 32 bits.
229//!     // In particular, it is an i32 on Windows but i64 on most Linux systems
230//!     let mut overflow = 0;
231//!     let i_long: c_long = PyLong_AsLongAndOverflow(obj, &mut overflow);
232//!
233//!     #[allow(
234//!         irrefutable_let_patterns,
235//!         reason = "some platforms have c_long equal to i32"
236//!     )]
237//!     if overflow != 0 {
238//!         raise_overflowerror(obj);
239//!         None
240//!     } else if let Ok(i) = i_long.try_into() {
241//!         Some(i)
242//!     } else {
243//!         raise_overflowerror(obj);
244//!         None
245//!     }
246//! }
247//!
248//! unsafe fn raise_overflowerror(obj: *mut PyObject) {
249//!     let obj_repr = PyObject_Str(obj);
250//!     if !obj_repr.is_null() {
251//!         let mut size = 0;
252//!         let p = PyUnicode_AsUTF8AndSize(obj_repr, &mut size);
253//!         if !p.is_null() {
254//!             let s = core::str::from_utf8_unchecked(core::slice::from_raw_parts(
255//!                 p.cast::<u8>(),
256//!                 size as usize,
257//!             ));
258//!             let msg = format!("cannot fit {} in 32 bits\0", s);
259//!
260//!             PyErr_SetString(PyExc_OverflowError, msg.as_ptr().cast::<c_char>());
261//!         }
262//!         Py_DECREF(obj_repr);
263//!     }
264//! }
265//!
266//! pub unsafe extern "C" fn sum_as_string(
267//!     _self: *mut PyObject,
268//!     args: *mut *mut PyObject,
269//!     nargs: Py_ssize_t,
270//! ) -> *mut PyObject {
271//!     if nargs != 2 {
272//!         PyErr_SetString(
273//!             PyExc_TypeError,
274//!             c"sum_as_string expected 2 positional arguments".as_ptr(),
275//!         );
276//!         return core::ptr::null_mut();
277//!     }
278//!
279//!     let (first, second) = (*args, *args.add(1));
280//!
281//!     let first = match parse_arg_as_i32(first, 1) {
282//!         Some(x) => x,
283//!         None => return core::ptr::null_mut(),
284//!     };
285//!     let second = match parse_arg_as_i32(second, 2) {
286//!         Some(x) => x,
287//!         None => return core::ptr::null_mut(),
288//!     };
289//!
290//!     match first.checked_add(second) {
291//!         Some(sum) => {
292//!             let string = sum.to_string();
293//!             PyUnicode_FromStringAndSize(string.as_ptr().cast::<c_char>(), string.len() as isize)
294//!         }
295//!         None => {
296//!             PyErr_SetString(PyExc_OverflowError, c"arguments too large to add".as_ptr());
297//!             core::ptr::null_mut()
298//!         }
299//!     }
300//! }
301//! ```
302//!
303//! With those two files in place, now `maturin` needs to be installed. This can be done using
304//! Python's package manager `pip`. First, load up a new Python `virtualenv`, and install `maturin`
305//! into it:
306//! ```bash
307//! $ cd string_sum
308//! $ python -m venv .env
309//! $ source .env/bin/activate
310//! $ pip install maturin
311//! ```
312//!
313//! Now build and execute the module:
314//! ```bash
315//! $ maturin develop
316//! # lots of progress output as maturin runs the compilation...
317//! $ python
318//! >>> import string_sum
319//! >>> string_sum.sum_as_string(5, 20)
320//! '25'
321//! ```
322//!
323//! As well as with `maturin`, it is possible to build using [setuptools-rust] or
324//! [manually][manual_builds]. Both offer more flexibility than `maturin` but require further
325//! configuration.
326//!
327//! This example stores the module definition statically and uses the `PyModule_Create` function
328//! in the CPython C API to register the module. This is the "old" style for registering modules
329//! and has the limitation that it cannot support subinterpreters. You can also create a module
330//! using the new multi-phase initialization API that does support subinterpreters. See the
331//! `sequential` project located in the `examples` directory at the root of the `pyo3-ffi` crate
332//! for a worked example of how to this using `pyo3-ffi`.
333//!
334//! # Using Python from Rust
335//!
336//! To embed Python into a Rust binary, you need to ensure that your Python installation contains a
337//! shared library. The following steps demonstrate how to ensure this (for Ubuntu).
338//!
339//! To install the Python shared library on Ubuntu:
340//! ```bash
341//! sudo apt install python3-dev
342//! ```
343//!
344//! While most projects use the safe wrapper provided by pyo3,
345//! you can take a look at the [`orjson`] library as an example on how to use `pyo3-ffi` directly.
346//! For those well versed in C and Rust the [tutorials] from the CPython documentation
347//! can be easily converted to rust as well.
348//!
349//! [tutorials]: https://docs.python.org/3/extending/
350//! [`orjson`]: https://github.com/ijl/orjson
351//! [capi]: https://docs.python.org/3/c-api/index.html
352//! [`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"
353//! [`pyo3-build-config`]: https://docs.rs/pyo3-build-config
354//! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html "Features - The Cargo Book"
355#![doc = concat!("[manual_builds]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/building-and-distribution.html#manual-builds \"Manual builds - Building and Distribution - PyO3 user guide\"")]
356//! [setuptools-rust]: https://github.com/PyO3/setuptools-rust "Setuptools plugin for Rust extensions"
357//! [PEP 384]: https://www.python.org/dev/peps/pep-0384 "PEP 384 -- Defining a Stable ABI"
358#![doc = concat!("[Features chapter of the guide]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/features.html#features-reference \"Features reference - PyO3 user guide\"")]
359#![allow(
360    missing_docs,
361    non_camel_case_types,
362    non_snake_case,
363    non_upper_case_globals,
364    clippy::upper_case_acronyms,
365    clippy::missing_safety_doc,
366    clippy::ptr_eq
367)]
368#![warn(
369    clippy::alloc_instead_of_core,
370    clippy::std_instead_of_alloc,
371    clippy::std_instead_of_core
372)]
373#![warn(elided_lifetimes_in_paths, unused_lifetimes)]
374// This crate is a hand-maintained translation of CPython's headers, so requiring "unsafe"
375// blocks within those translations increases maintenance burden without providing any
376// additional safety. The safety of the functions in this crate is determined by the
377// original CPython headers
378#![allow(unsafe_op_in_unsafe_fn)]
379
380#[cfg(not(PyPy))]
381extern crate alloc;
382#[cfg(not(any(Py_3_14, target_arch = "wasm32")))]
383extern crate std;
384
385// Until `extern type` is stabilized, use the recommended approach to
386// model opaque types:
387// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
388macro_rules! opaque_struct {
389    ($(#[$attrs:meta])* $pub:vis $name:ident) => {
390        $(#[$attrs])*
391        #[repr(C)]
392        $pub struct $name {
393            _data: (),
394            _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
395        }
396    };
397}
398
399/// This is a helper macro to create a `&'static CStr`.
400///
401/// It can be used on all Rust versions supported by PyO3, unlike c"" literals which
402/// were stabilised in Rust 1.77.
403///
404/// Due to the nature of PyO3 making heavy use of C FFI interop with Python, it is
405/// common for PyO3 to use CStr.
406///
407/// Examples:
408///
409/// ```rust,no_run
410/// use core::ffi::CStr;
411///
412/// const HELLO: &CStr = pyo3_ffi::c_str!("hello");
413/// static WORLD: &CStr = pyo3_ffi::c_str!("world");
414/// ```
415#[macro_export]
416macro_rules! c_str {
417    // TODO: deprecate this now MSRV is above 1.77
418    ($s:expr) => {
419        $crate::_cstr_from_utf8_with_nul_checked(concat!($s, "\0"))
420    };
421}
422
423/// Private helper for `c_str!` macro.
424#[doc(hidden)]
425pub const fn _cstr_from_utf8_with_nul_checked(s: &str) -> &core::ffi::CStr {
426    match core::ffi::CStr::from_bytes_with_nul(s.as_bytes()) {
427        Ok(cstr) => cstr,
428        Err(_) => panic!("string contains nul bytes"),
429    }
430}
431
432// Macros for declaring `extern` blocks that link against libpython.
433// See `impl_/macros.rs` for the implementation.
434include!("impl_/macros.rs");
435
436pub mod compat;
437mod impl_;
438
439pub use self::abstract_::*;
440#[cfg(not(RustPython))]
441pub use self::bltinmodule::*;
442pub use self::boolobject::*;
443pub use self::bytearrayobject::*;
444pub use self::bytesobject::*;
445pub use self::ceval::*;
446pub use self::codecs::*;
447pub use self::compile::*;
448pub use self::complexobject::*;
449#[cfg(Py_3_13)]
450pub use self::critical_section::*;
451#[cfg(not(Py_LIMITED_API))]
452pub use self::datetime::*;
453pub use self::descrobject::*;
454pub use self::dictobject::*;
455#[cfg(not(RustPython))]
456pub use self::enumobject::*;
457pub use self::fileobject::*;
458pub use self::fileutils::*;
459pub use self::floatobject::*;
460pub use self::genericaliasobject::*;
461pub use self::import::*;
462pub use self::intrcheck::*;
463pub use self::iterobject::*;
464pub use self::listobject::*;
465pub use self::longobject::*;
466pub use self::memoryobject::*;
467pub use self::methodobject::*;
468pub use self::modsupport::*;
469pub use self::moduleobject::*;
470pub use self::object::*;
471pub use self::objimpl::*;
472pub use self::osmodule::*;
473#[cfg(not(any(PyPy, Py_LIMITED_API, Py_3_10)))]
474pub use self::pyarena::*;
475#[cfg(Py_3_11)]
476pub use self::pybuffer::*;
477pub use self::pycapsule::*;
478pub use self::pyerrors::*;
479pub use self::pyframe::*;
480pub use self::pyhash::*;
481pub use self::pylifecycle::*;
482pub use self::pymem::*;
483pub use self::pyport::*;
484pub use self::pystate::*;
485pub use self::pystrtod::*;
486pub use self::pythonrun::*;
487pub use self::pytypedefs::*;
488pub use self::rangeobject::*;
489pub use self::refcount::*;
490pub use self::setobject::*;
491pub use self::sliceobject::*;
492#[cfg(Py_3_15)]
493pub use self::slots::*;
494pub use self::slots_generated::*;
495pub use self::structseq::*;
496pub use self::sysmodule::*;
497pub use self::traceback::*;
498pub use self::tupleobject::*;
499pub use self::unicodeobject::*;
500pub use self::warnings::*;
501pub use self::weakrefobject::*;
502
503mod abstract_;
504// skipped asdl.h
505// skipped ast.h
506#[cfg(not(RustPython))]
507mod bltinmodule;
508mod boolobject;
509mod bytearrayobject;
510mod bytesobject;
511// skipped cellobject.h
512mod ceval;
513// skipped classobject.h
514mod codecs;
515mod compile;
516mod complexobject;
517mod critical_section;
518#[cfg(not(Py_LIMITED_API))]
519pub(crate) mod datetime;
520mod descrobject;
521mod dictobject;
522// skipped dynamic_annotations.h
523#[cfg(not(RustPython))]
524mod enumobject;
525// skipped errcode.h
526// skipped exports.h
527mod fileobject;
528mod fileutils;
529mod floatobject;
530// skipped empty frameobject.h
531mod genericaliasobject;
532mod import;
533// skipped interpreteridobject.h
534mod intrcheck;
535mod iterobject;
536mod listobject;
537mod longobject;
538mod memoryobject;
539mod methodobject;
540mod modsupport;
541mod moduleobject;
542// skipped namespaceobject.h
543mod object;
544mod objimpl;
545// skipped odictobject.h
546// skipped opcode.h
547// skipped osdefs.h
548mod osmodule;
549// skipped parser_interface.h
550// skipped patchlevel.h
551// skipped picklebufobject.h
552// skipped pyctype.h
553// skipped py_curses.h
554#[cfg(not(any(PyPy, Py_LIMITED_API, Py_3_10)))]
555mod pyarena;
556#[cfg(Py_3_11)]
557mod pybuffer;
558mod pycapsule;
559// skipped pydtrace.h
560mod pyerrors;
561// skipped pyexpat.h
562// skipped pyfpe.h
563mod pyframe;
564mod pyhash;
565mod pylifecycle;
566// skipped pymacconfig.h
567// skipped pymacro.h
568// skipped pymath.h
569mod pymem;
570mod pyport;
571mod pystate;
572// skipped pystats.h
573mod pythonrun;
574// skipped pystrhex.h
575// skipped pystrcmp.h
576mod pystrtod;
577// skipped pythread.h
578// skipped pytime.h
579mod pytypedefs;
580mod rangeobject;
581mod refcount;
582mod setobject;
583mod sliceobject;
584mod slots;
585mod slots_generated;
586mod structseq;
587mod sysmodule;
588mod traceback;
589// skipped tracemalloc.h
590mod tupleobject;
591mod unicodeobject;
592mod warnings;
593mod weakrefobject;
594
595// Additional headers that are not exported by Python.h
596#[deprecated(note = "Python 3.12")]
597pub mod structmember;
598
599// "Limited API" definitions matching Python's `include/cpython` directory.
600#[cfg(not(any(Py_LIMITED_API, RustPython)))]
601mod cpython;
602
603#[cfg(not(any(Py_LIMITED_API, RustPython)))]
604pub use self::cpython::*;
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here