Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

packaging: formal support for Python 3.10 #1889

Merged
merged 3 commits into from Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Packaging

- Support Python 3.10. [#1889](https://github.com/PyO3/pyo3/pull/1889)

### Added

- Add `PyList::get_item_unchecked` and `PyTuple::get_item_unchecked` to get items without bounds checks. [#1733](https://github.com/PyO3/pyo3/pull/1733)
Expand All @@ -17,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add range indexing implementations of `std::ops::Index` for `PyList`, `PyTuple` and `PySequence`. [#1829](https://github.com/PyO3/pyo3/pull/1829)
- Add commonly-used sequence methods to `PyList` and `PyTuple`. [#1849](https://github.com/PyO3/pyo3/pull/1849)
- Add `as_sequence` methods to `PyList` and `PyTuple`. [#1860](https://github.com/PyO3/pyo3/pull/1860)
- Add `abi3-py310` feature. [#1889](https://github.com/PyO3/pyo3/pull/1889)

### Changed

Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Expand Up @@ -66,7 +66,8 @@ abi3 = ["pyo3-build-config/abi3"]
abi3-py36 = ["abi3-py37", "pyo3-build-config/abi3-py36"]
abi3-py37 = ["abi3-py38", "pyo3-build-config/abi3-py37"]
abi3-py38 = ["abi3-py39", "pyo3-build-config/abi3-py38"]
abi3-py39 = ["abi3", "pyo3-build-config/abi3-py39"]
abi3-py39 = ["abi3-py310", "pyo3-build-config/abi3-py39"]
abi3-py310 = ["abi3", "pyo3-build-config/abi3-py310"]

# Changes `Python::with_gil` and `Python::acquire_gil` to automatically initialize the
# Python interpreter if needed.
Expand Down
6 changes: 4 additions & 2 deletions guide/src/features.md
Expand Up @@ -22,9 +22,11 @@ It restricts PyO3's API to a subset of the full Python API which is guaranteed b

See the [building and distribution](building_and_distribution.md#py_limited_apiabi3) section for further detail.

### `abi3-py36` / `abi3-py37` / `abi3-py38` / `abi3-py39`
### The `abi3-pyXY` features

These features are an extension of the `abi3` feature to specify the exact minimum Python version which the multiple-version-wheel will support.
(`abi3-py36`, `abi3-py37`, `abi3-py38`, `abi3-py39`, and `abi3-py310`)

These features are extensions of the `abi3` feature to specify the exact minimum Python version which the multiple-version-wheel will support.

See the [building and distribution](building_and_distribution.md#minimum-python-version-for-abi3) section for further detail.

Expand Down
3 changes: 2 additions & 1 deletion pyo3-build-config/Cargo.toml
Expand Up @@ -24,4 +24,5 @@ abi3 = []
abi3-py36 = ["abi3-py37"]
abi3-py37 = ["abi3-py38"]
abi3-py38 = ["abi3-py39"]
abi3-py39 = ["abi3"]
abi3-py39 = ["abi3-py310"]
abi3-py310 = ["abi3"]
12 changes: 4 additions & 8 deletions src/class/impl_.rs
Expand Up @@ -257,8 +257,7 @@ macro_rules! define_pyclass_binary_operator_slot {
_slf: *mut ffi::PyObject,
_other: *mut ffi::PyObject,
) -> PyResult<*mut ffi::PyObject> {
ffi::Py_INCREF(ffi::Py_NotImplemented());
Ok(ffi::Py_NotImplemented())
Ok(ffi::_Py_NewRef(ffi::Py_NotImplemented()))
}
}

Expand All @@ -273,8 +272,7 @@ macro_rules! define_pyclass_binary_operator_slot {
_slf: *mut ffi::PyObject,
_other: *mut ffi::PyObject,
) -> PyResult<*mut ffi::PyObject> {
ffi::Py_INCREF(ffi::Py_NotImplemented());
Ok(ffi::Py_NotImplemented())
Ok(ffi::_Py_NewRef(ffi::Py_NotImplemented()))
}
}

Expand Down Expand Up @@ -429,8 +427,7 @@ slot_fragment_trait! {
_other: *mut ffi::PyObject,
_mod: *mut ffi::PyObject,
) -> PyResult<*mut ffi::PyObject> {
ffi::Py_INCREF(ffi::Py_NotImplemented());
Ok(ffi::Py_NotImplemented())
Ok(ffi::_Py_NewRef(ffi::Py_NotImplemented()))
}
}

Expand All @@ -446,8 +443,7 @@ slot_fragment_trait! {
_other: *mut ffi::PyObject,
_mod: *mut ffi::PyObject,
) -> PyResult<*mut ffi::PyObject> {
ffi::Py_INCREF(ffi::Py_NotImplemented());
Ok(ffi::Py_NotImplemented())
Ok(ffi::_Py_NewRef(ffi::Py_NotImplemented()))
}
}

Expand Down
8 changes: 1 addition & 7 deletions src/conversion.rs
Expand Up @@ -64,13 +64,7 @@ where
T: AsPyPointer,
{
fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.as_ptr();
if !ptr.is_null() {
unsafe {
ffi::Py_INCREF(ptr);
}
}
ptr
unsafe { ffi::_Py_XNewRef(self.as_ptr()) }
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/ffi/abstract_.rs
Expand Up @@ -110,7 +110,9 @@ extern "C" {

#[cfg_attr(PyPy, link_name = "PyPyIter_Next")]
pub fn PyIter_Next(arg1: *mut PyObject) -> *mut PyObject;
// skipped non-limited / 3.10 PyIter_Send
#[cfg(all(not(PyPy), Py_3_10))]
#[cfg_attr(docsrs, doc(cfg(all(not(PyPy), Py_3_10))))]
pub fn PyIter_Send(iter: *mut PyObject, arg: *mut PyObject, presult: *mut *mut PyObject);

#[cfg_attr(PyPy, link_name = "PyPyNumber_Check")]
pub fn PyNumber_Check(o: *mut PyObject) -> c_int;
Expand Down
10 changes: 10 additions & 0 deletions src/ffi/boolobject.rs
Expand Up @@ -31,6 +31,16 @@ pub unsafe fn Py_True() -> *mut PyObject {
&mut _Py_TrueStruct as *mut PyLongObject as *mut PyObject
}

#[inline]
pub unsafe fn Py_IsTrue(x: *mut PyObject) -> c_int {
Py_Is(x, Py_True())
}

#[inline]
pub unsafe fn Py_IsFalse(x: *mut PyObject) -> c_int {
Py_Is(x, Py_False())
}

// skipped Py_RETURN_TRUE
// skipped Py_RETURN_FALSE

Expand Down
4 changes: 3 additions & 1 deletion src/ffi/codecs.rs
Expand Up @@ -3,7 +3,9 @@ use std::os::raw::{c_char, c_int};

extern "C" {
pub fn PyCodec_Register(search_function: *mut PyObject) -> c_int;
// skipped PyCodec_Unregister
#[cfg(Py_3_10)]
#[cfg(not(PyPy))]
pub fn PyCodec_Unregister(search_function: *mut PyObject) -> c_int;
// skipped non-limited _PyCodec_Lookup from Include/codecs.h
// skipped non-limited _PyCodec_Forget from Include/codecs.h
pub fn PyCodec_KnownEncoding(encoding: *const c_char) -> c_int;
Expand Down
8 changes: 0 additions & 8 deletions src/ffi/cpython/unicodeobject.rs
Expand Up @@ -323,14 +323,6 @@ extern "C" {
// skipped _PyUnicode_FormatAdvancedWriter

extern "C" {
#[cfg(Py_3_7)]
#[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8AndSize")]
pub fn PyUnicode_AsUTF8AndSize(unicode: *mut PyObject, size: *mut Py_ssize_t) -> *const c_char;

#[cfg(not(Py_3_7))]
#[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8AndSize")]
pub fn PyUnicode_AsUTF8AndSize(unicode: *mut PyObject, size: *mut Py_ssize_t) -> *mut c_char;

// skipped _PyUnicode_AsStringAndSize

#[cfg(Py_3_7)]
Expand Down
27 changes: 18 additions & 9 deletions src/ffi/modsupport.rs
Expand Up @@ -53,21 +53,30 @@ extern "C" {
// skipped non-limited _PyArg_UnpackKeywords
// skipped non-limited _PyArg_Fini

// skipped PyModule_AddObjectRef
#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn PyModule_AddObjectRef(
module: *mut PyObject,
name: *const c_char,
value: *mut PyObject,
) -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyModule_AddObject")]
pub fn PyModule_AddObject(
arg1: *mut PyObject,
arg2: *const c_char,
arg3: *mut PyObject,
module: *mut PyObject,
name: *const c_char,
value: *mut PyObject,
) -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyModule_AddIntConstant")]
pub fn PyModule_AddIntConstant(arg1: *mut PyObject, arg2: *const c_char, arg3: c_long)
-> c_int;
pub fn PyModule_AddIntConstant(
module: *mut PyObject,
name: *const c_char,
value: c_long,
) -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyModule_AddStringConstant")]
pub fn PyModule_AddStringConstant(
arg1: *mut PyObject,
arg2: *const c_char,
arg3: *const c_char,
module: *mut PyObject,
name: *const c_char,
value: *const c_char,
) -> c_int;
// skipped non-limited / 3.9 PyModule_AddType
// skipped PyModule_AddIntMacro
Expand Down
53 changes: 48 additions & 5 deletions src/ffi/object.rs
Expand Up @@ -85,6 +85,11 @@ pub struct PyVarObject {
// skipped _PyVarObject_CAST
// skipped _PyVarObject_CAST_CONST

#[inline]
pub unsafe fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int {
(x == y).into()
}

// skipped _Py_REFCNT: defined in Py_REFCNT

#[inline]
Expand Down Expand Up @@ -347,6 +352,14 @@ extern "C" {
// Flag bits for printing:
pub const Py_PRINT_RAW: c_int = 1; // No string quotes etc.

#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub const Py_TPFLAGS_DISALLOW_INSTANTIATION: c_ulong = 1 << 7;

#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub const Py_TPFLAGS_IMMUTABLETYPE: c_ulong = 1 << 8;

/// Set if the type object is dynamically allocated
pub const Py_TPFLAGS_HEAPTYPE: c_ulong = 1 << 9;

Expand Down Expand Up @@ -454,10 +467,28 @@ extern "C" {
#[cfg_attr(PyPy, link_name = "PyPy_DecRef")]
pub fn Py_DecRef(o: *mut PyObject);

// skipped Py_NewRef
// skipped Py_XNewRef
// skipped _Py_NewRef
// skipped _Py_XNewRef
#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn Py_NewRef(obj: *mut PyObject) -> *mut PyObject;
#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn Py_XNewRef(obj: *mut PyObject) -> *mut PyObject;
}

// Technically these macros are only available in the C header from 3.10 and up, however their
// implementation works on all supported Python versions so we define these macros on all
// versions for simplicity.

#[inline]
pub unsafe fn _Py_NewRef(obj: *mut PyObject) -> *mut PyObject {
Py_INCREF(obj);
obj
}

#[inline]
pub unsafe fn _Py_XNewRef(obj: *mut PyObject) -> *mut PyObject {
Py_XINCREF(obj);
obj
}

#[cfg_attr(windows, link(name = "pythonXY"))]
Expand All @@ -471,6 +502,11 @@ pub unsafe fn Py_None() -> *mut PyObject {
&mut _Py_NoneStruct
}

#[inline]
pub unsafe fn Py_IsNone(x: *mut PyObject) -> c_int {
Py_Is(x, Py_None())
}

// skipped Py_RETURN_NONE

#[cfg_attr(windows, link(name = "pythonXY"))]
Expand All @@ -494,7 +530,14 @@ pub const Py_NE: c_int = 3;
pub const Py_GT: c_int = 4;
pub const Py_GE: c_int = 5;

// skipped non-limited / 3.10 PySendResult
#[cfg(Py_3_10)]
#[repr(C)]
davidhewitt marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PySendResult {
PYGEN_RETURN = 0,
PYGEN_ERROR = -1,
PYGEN_NEXT = 1,
}

// skipped Py_RETURN_RICHCOMPARE

Expand Down
8 changes: 8 additions & 0 deletions src/ffi/objimpl.rs
Expand Up @@ -28,6 +28,14 @@ extern "C" {
pub fn _PyObject_NewVar(arg1: *mut PyTypeObject, arg2: Py_ssize_t) -> *mut PyVarObject;

pub fn PyGC_Collect() -> Py_ssize_t;

#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn PyGC_Enable() -> c_int;
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn PyGC_Disable() -> c_int;
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn PyGC_IsEnabled() -> c_int;
}

#[repr(C)]
Expand Down
7 changes: 5 additions & 2 deletions src/ffi/pyerrors.rs
Expand Up @@ -158,7 +158,7 @@ pub unsafe fn PyUnicodeDecodeError_Create(
end: Py_ssize_t,
_reason: *const c_char,
) -> *mut PyObject {
return crate::ffi::PyObject_CallFunction(
crate::ffi::PyObject_CallFunction(
PyExc_UnicodeDecodeError,
std::ffi::CStr::from_bytes_with_nul(b"sy#nns\0")
.unwrap()
Expand All @@ -168,7 +168,7 @@ pub unsafe fn PyUnicodeDecodeError_Create(
length,
start,
end,
);
)
}

#[cfg_attr(windows, link(name = "pythonXY"))]
Expand Down Expand Up @@ -374,6 +374,9 @@ extern "C" {
pub fn PyErr_CheckSignals() -> c_int;
#[cfg_attr(PyPy, link_name = "PyPyErr_SetInterrupt")]
pub fn PyErr_SetInterrupt();
#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub fn PyErr_SetInterruptEx(signum: c_int);
pub fn PyErr_SyntaxLocation(filename: *const c_char, lineno: c_int);
pub fn PyErr_SyntaxLocationEx(filename: *const c_char, lineno: c_int, col_offset: c_int);
pub fn PyErr_ProgramText(filename: *const c_char, lineno: c_int) -> *mut PyObject;
Expand Down
7 changes: 6 additions & 1 deletion src/ffi/setobject.rs
Expand Up @@ -117,7 +117,12 @@ pub unsafe fn PyAnySet_Check(ob: *mut PyObject) -> c_int {
|| PyType_IsSubtype(Py_TYPE(ob), &mut PyFrozenSet_Type) != 0) as c_int
}

// skipped PySet_CheckExact
#[inline]
#[cfg(Py_3_10)]
#[cfg_attr(docsrs, doc(cfg(Py_3_10)))]
pub unsafe fn PySet_CheckExact(op: *mut PyObject) -> c_int {
crate::ffi::Py_IS_TYPE(op, &mut PySet_Type)
}

extern "C" {
#[cfg(PyPy)]
Expand Down
8 changes: 8 additions & 0 deletions src/ffi/unicodeobject.rs
Expand Up @@ -165,6 +165,14 @@ extern "C" {
) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8String")]
pub fn PyUnicode_AsUTF8String(unicode: *mut PyObject) -> *mut PyObject;
#[cfg(any(Py_3_10, all(Py_3_7, not(Py_LIMITED_API))))]
#[cfg_attr(docsrs, doc(cfg(any(Py_3_10, not(Py_LIMITED_API)))))]
#[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8AndSize")]
pub fn PyUnicode_AsUTF8AndSize(unicode: *mut PyObject, size: *mut Py_ssize_t) -> *const c_char;
#[cfg(not(any(Py_3_7, Py_LIMITED_API)))]
#[cfg_attr(docsrs, doc(cfg(any(Py_3_10, not(Py_LIMITED_API)))))]
#[cfg_attr(PyPy, link_name = "PyPyUnicode_AsUTF8AndSize")]
pub fn PyUnicode_AsUTF8AndSize(unicode: *mut PyObject, size: *mut Py_ssize_t) -> *mut c_char;
#[cfg_attr(PyPy, link_name = "PyPyUnicode_DecodeUTF32")]
pub fn PyUnicode_DecodeUTF32(
string: *const c_char,
Expand Down
10 changes: 5 additions & 5 deletions src/types/dict.rs
Expand Up @@ -105,8 +105,7 @@ impl PyDict {
let ptr = ffi::PyDict_GetItem(self.as_ptr(), key);
NonNull::new(ptr).map(|p| {
// PyDict_GetItem return s borrowed ptr, must make it owned for safety (see #890).
ffi::Py_INCREF(p.as_ptr());
self.py().from_owned_ptr(p.as_ptr())
self.py().from_owned_ptr(ffi::_Py_NewRef(p.as_ptr()))
})
})
}
Expand Down Expand Up @@ -196,9 +195,10 @@ impl<'py> Iterator for PyDictIterator<'py> {
if ffi::PyDict_Next(self.dict.as_ptr(), &mut self.pos, &mut key, &mut value) != 0 {
let py = self.dict.py();
// PyDict_Next returns borrowed values; for safety must make them owned (see #890)
ffi::Py_INCREF(key);
ffi::Py_INCREF(value);
Some((py.from_owned_ptr(key), py.from_owned_ptr(value)))
Some((
py.from_owned_ptr(ffi::_Py_NewRef(key)),
py.from_owned_ptr(ffi::_Py_NewRef(value)),
))
} else {
None
}
Expand Down
3 changes: 1 addition & 2 deletions src/types/module.rs
Expand Up @@ -140,8 +140,7 @@ impl PyModule {
unsafe {
// PyModule_GetDict returns borrowed ptr; must make owned for safety (see #890).
let ptr = ffi::PyModule_GetDict(self.as_ptr());
ffi::Py_INCREF(ptr);
self.py().from_owned_ptr(ptr)
self.py().from_owned_ptr(ffi::_Py_NewRef(ptr))
}
}

Expand Down