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 |
252 | macro_rules! opaque_struct { |
253 | ($name:ident) => { |
254 | #[repr(C)] |
255 | pub struct $name([u8; 0]); |
256 | }; |
257 | } |
258 | |
259 | pub use self::abstract_::*; |
260 | pub use self::bltinmodule::*; |
261 | pub use self::boolobject::*; |
262 | pub use self::bytearrayobject::*; |
263 | pub use self::bytesobject::*; |
264 | pub use self::ceval::*; |
265 | #[cfg (Py_LIMITED_API)] |
266 | pub use self::code::*; |
267 | pub use self::codecs::*; |
268 | pub use self::compile::*; |
269 | pub use self::complexobject::*; |
270 | #[cfg (all(Py_3_8, not(Py_LIMITED_API)))] |
271 | pub use self::context::*; |
272 | #[cfg (not(Py_LIMITED_API))] |
273 | pub use self::datetime::*; |
274 | pub use self::descrobject::*; |
275 | pub use self::dictobject::*; |
276 | pub use self::enumobject::*; |
277 | pub use self::fileobject::*; |
278 | pub use self::fileutils::*; |
279 | pub use self::floatobject::*; |
280 | pub use self::import::*; |
281 | pub use self::intrcheck::*; |
282 | pub use self::iterobject::*; |
283 | pub use self::listobject::*; |
284 | pub use self::longobject::*; |
285 | #[cfg (not(Py_LIMITED_API))] |
286 | pub use self::marshal::*; |
287 | pub use self::memoryobject::*; |
288 | pub use self::methodobject::*; |
289 | pub use self::modsupport::*; |
290 | pub use self::moduleobject::*; |
291 | pub use self::object::*; |
292 | pub use self::objimpl::*; |
293 | pub use self::osmodule::*; |
294 | #[cfg (not(any(PyPy, Py_LIMITED_API, Py_3_10)))] |
295 | pub use self::pyarena::*; |
296 | #[cfg (Py_3_11)] |
297 | pub use self::pybuffer::*; |
298 | pub use self::pycapsule::*; |
299 | pub use self::pyerrors::*; |
300 | pub use self::pyframe::*; |
301 | pub use self::pyhash::*; |
302 | pub use self::pylifecycle::*; |
303 | pub use self::pymem::*; |
304 | pub use self::pyport::*; |
305 | pub use self::pystate::*; |
306 | pub use self::pystrtod::*; |
307 | pub use self::pythonrun::*; |
308 | pub use self::rangeobject::*; |
309 | pub use self::setobject::*; |
310 | pub use self::sliceobject::*; |
311 | pub use self::structseq::*; |
312 | pub use self::sysmodule::*; |
313 | pub use self::traceback::*; |
314 | pub use self::tupleobject::*; |
315 | pub use self::typeslots::*; |
316 | pub use self::unicodeobject::*; |
317 | pub use self::warnings::*; |
318 | pub use self::weakrefobject::*; |
319 | |
320 | mod abstract_; |
321 | // skipped asdl.h |
322 | // skipped ast.h |
323 | mod bltinmodule; |
324 | mod boolobject; |
325 | mod bytearrayobject; |
326 | mod bytesobject; |
327 | // skipped cellobject.h |
328 | mod ceval; |
329 | // skipped classobject.h |
330 | #[cfg (Py_LIMITED_API)] |
331 | mod code; |
332 | mod codecs; |
333 | mod compile; |
334 | mod complexobject; |
335 | #[cfg (all(Py_3_8, not(Py_LIMITED_API)))] |
336 | mod context; // It's actually 3.7.1, but no cfg for patches. |
337 | #[cfg (not(Py_LIMITED_API))] |
338 | pub(crate) mod datetime; |
339 | mod descrobject; |
340 | mod dictobject; |
341 | // skipped dynamic_annotations.h |
342 | mod enumobject; |
343 | // skipped errcode.h |
344 | // skipped exports.h |
345 | mod fileobject; |
346 | mod fileutils; |
347 | mod floatobject; |
348 | // skipped empty frameobject.h |
349 | // skipped genericaliasobject.h |
350 | mod import; |
351 | // skipped interpreteridobject.h |
352 | mod intrcheck; |
353 | mod iterobject; |
354 | mod listobject; |
355 | // skipped longintrepr.h |
356 | mod longobject; |
357 | #[cfg (not(Py_LIMITED_API))] |
358 | pub mod marshal; |
359 | mod memoryobject; |
360 | mod methodobject; |
361 | mod modsupport; |
362 | mod moduleobject; |
363 | // skipped namespaceobject.h |
364 | mod object; |
365 | mod objimpl; |
366 | // skipped odictobject.h |
367 | // skipped opcode.h |
368 | // skipped osdefs.h |
369 | mod 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)))] |
376 | mod pyarena; |
377 | #[cfg (Py_3_11)] |
378 | mod pybuffer; |
379 | mod pycapsule; |
380 | // skipped pydtrace.h |
381 | mod pyerrors; |
382 | // skipped pyexpat.h |
383 | // skipped pyfpe.h |
384 | mod pyframe; |
385 | mod pyhash; |
386 | mod pylifecycle; |
387 | // skipped pymacconfig.h |
388 | // skipped pymacro.h |
389 | // skipped pymath.h |
390 | mod pymem; |
391 | mod pyport; |
392 | mod pystate; |
393 | // skipped pystats.h |
394 | mod pythonrun; |
395 | // skipped pystrhex.h |
396 | // skipped pystrcmp.h |
397 | mod pystrtod; |
398 | // skipped pythread.h |
399 | // skipped pytime.h |
400 | mod rangeobject; |
401 | mod setobject; |
402 | mod sliceobject; |
403 | mod structseq; |
404 | mod sysmodule; |
405 | mod traceback; |
406 | // skipped tracemalloc.h |
407 | mod tupleobject; |
408 | mod typeslots; |
409 | mod unicodeobject; |
410 | mod warnings; |
411 | mod weakrefobject; |
412 | |
413 | // Additional headers that are not exported by Python.h |
414 | #[deprecated (note = "Python 3.12" )] |
415 | pub mod structmember; |
416 | |
417 | // "Limited API" definitions matching Python's `include/cpython` directory. |
418 | #[cfg (not(Py_LIMITED_API))] |
419 | mod cpython; |
420 | |
421 | #[cfg (not(Py_LIMITED_API))] |
422 | pub use self::cpython::*; |
423 | |