Skip to main content

pyo3_ffi/
lib.rs

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