Skip to content

Commit

Permalink
Merge pull request #1889 from davidhewitt/py310
Browse files Browse the repository at this point in the history
packaging: formal support for Python 3.10
  • Loading branch information
davidhewitt authored Sep 29, 2021
2 parents 3adacae + 03ba4a5 commit c986b5d
Show file tree
Hide file tree
Showing 22 changed files with 138 additions and 61 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
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 @@ -18,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `PyMapping` type to represent the Python mapping protocol. [#1844](https://github.com/PyO3/pyo3/pull/1844)
- 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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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)]
#[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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,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 @@ -203,9 +202,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
Original file line number Diff line number Diff line change
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
Loading

0 comments on commit c986b5d

Please sign in to comment.