From a5d0aa777c8307ee4211313a11a927bd4f12c8df Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 24 Sep 2021 22:53:55 +0100 Subject: [PATCH 1/3] py310: add abi3-py310 feature --- CHANGELOG.md | 1 + Cargo.toml | 3 ++- guide/src/features.md | 6 ++++-- pyo3-build-config/Cargo.toml | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7be6095cb6..51a1c3b24a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,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 diff --git a/Cargo.toml b/Cargo.toml index 0ff374c2963..b9a1606e294 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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. diff --git a/guide/src/features.md b/guide/src/features.md index 0a485eb4b9b..4be93e6d550 100644 --- a/guide/src/features.md +++ b/guide/src/features.md @@ -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. diff --git a/pyo3-build-config/Cargo.toml b/pyo3-build-config/Cargo.toml index 0b164b707aa..09200147c3e 100644 --- a/pyo3-build-config/Cargo.toml +++ b/pyo3-build-config/Cargo.toml @@ -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"] From 7c4503e0ca44fd5aa8328c7f239f1394c8be83b6 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Sun, 26 Sep 2021 09:44:40 +0100 Subject: [PATCH 2/3] ffi: updates for Python 3.10 Co-authored-by: Bruno Kolenbrander <59372212+mejrs@users.noreply.github.com> --- CHANGELOG.md | 4 +++ src/ffi/abstract_.rs | 4 ++- src/ffi/boolobject.rs | 10 ++++++ src/ffi/codecs.rs | 4 ++- src/ffi/cpython/unicodeobject.rs | 8 ----- src/ffi/modsupport.rs | 27 ++++++++++------ src/ffi/object.rs | 53 +++++++++++++++++++++++++++++--- src/ffi/objimpl.rs | 8 +++++ src/ffi/pyerrors.rs | 7 +++-- src/ffi/setobject.rs | 7 ++++- src/ffi/unicodeobject.rs | 8 +++++ src/types/string.rs | 4 +-- 12 files changed, 115 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51a1c3b24a7..3df38503e31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/src/ffi/abstract_.rs b/src/ffi/abstract_.rs index bb38f8ae367..556eb8e5ec7 100644 --- a/src/ffi/abstract_.rs +++ b/src/ffi/abstract_.rs @@ -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; diff --git a/src/ffi/boolobject.rs b/src/ffi/boolobject.rs index c895638ed42..92d77d018b0 100644 --- a/src/ffi/boolobject.rs +++ b/src/ffi/boolobject.rs @@ -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 diff --git a/src/ffi/codecs.rs b/src/ffi/codecs.rs index 303da1772a9..6c23e29602f 100644 --- a/src/ffi/codecs.rs +++ b/src/ffi/codecs.rs @@ -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; diff --git a/src/ffi/cpython/unicodeobject.rs b/src/ffi/cpython/unicodeobject.rs index 22ea980289b..03400859219 100644 --- a/src/ffi/cpython/unicodeobject.rs +++ b/src/ffi/cpython/unicodeobject.rs @@ -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)] diff --git a/src/ffi/modsupport.rs b/src/ffi/modsupport.rs index 799f5015c1d..7362c2885ad 100644 --- a/src/ffi/modsupport.rs +++ b/src/ffi/modsupport.rs @@ -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 diff --git a/src/ffi/object.rs b/src/ffi/object.rs index 42d5b09c318..cd9a96af516 100644 --- a/src/ffi/object.rs +++ b/src/ffi/object.rs @@ -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] @@ -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; @@ -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"))] @@ -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"))] @@ -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 diff --git a/src/ffi/objimpl.rs b/src/ffi/objimpl.rs index e2f5665efe0..3891b902b22 100644 --- a/src/ffi/objimpl.rs +++ b/src/ffi/objimpl.rs @@ -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)] diff --git a/src/ffi/pyerrors.rs b/src/ffi/pyerrors.rs index f4e66c79396..af0c109cd39 100644 --- a/src/ffi/pyerrors.rs +++ b/src/ffi/pyerrors.rs @@ -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() @@ -168,7 +168,7 @@ pub unsafe fn PyUnicodeDecodeError_Create( length, start, end, - ); + ) } #[cfg_attr(windows, link(name = "pythonXY"))] @@ -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; diff --git a/src/ffi/setobject.rs b/src/ffi/setobject.rs index b71c275b65b..70d1adb9dd3 100644 --- a/src/ffi/setobject.rs +++ b/src/ffi/setobject.rs @@ -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)] diff --git a/src/ffi/unicodeobject.rs b/src/ffi/unicodeobject.rs index 9f215cf8299..cbe3bf96f4a 100644 --- a/src/ffi/unicodeobject.rs +++ b/src/ffi/unicodeobject.rs @@ -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, diff --git a/src/types/string.rs b/src/types/string.rs index 551287c5515..c934e6f623c 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -167,8 +167,8 @@ impl PyString { pub fn to_str(&self) -> PyResult<&str> { let utf8_slice = { cfg_if::cfg_if! { - if #[cfg(not(Py_LIMITED_API))] { - // PyUnicode_AsUTF8AndSize only available on limited API. + if #[cfg(any(Py_3_10, not(Py_LIMITED_API)))] { + // PyUnicode_AsUTF8AndSize only available on limited API before 3.10. let mut size: ffi::Py_ssize_t = 0; let data = unsafe { ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) }; if data.is_null() { From 03ba4a55975a528897a89f836dcc16bb12237173 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Sun, 26 Sep 2021 13:45:47 +0100 Subject: [PATCH 3/3] ffi: use _Py_NewRef for clarity --- src/class/impl_.rs | 12 ++++-------- src/conversion.rs | 8 +------- src/types/dict.rs | 10 +++++----- src/types/module.rs | 3 +-- src/types/set.rs | 3 +-- tests/test_buffer.rs | 3 +-- tests/test_buffer_protocol.rs | 3 +-- 7 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/class/impl_.rs b/src/class/impl_.rs index dc38c0380fe..de3e581276c 100644 --- a/src/class/impl_.rs +++ b/src/class/impl_.rs @@ -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())) } } @@ -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())) } } @@ -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())) } } @@ -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())) } } diff --git a/src/conversion.rs b/src/conversion.rs index 0463d670e80..a0fb7fd48a0 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -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()) } } } diff --git a/src/types/dict.rs b/src/types/dict.rs index 89e29bb4d67..698d727a151 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -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())) }) }) } @@ -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 } diff --git a/src/types/module.rs b/src/types/module.rs index 97bdef366e1..e3cd30f2244 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -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)) } } diff --git a/src/types/set.rs b/src/types/set.rs index 01ffafbaa89..8650e99c797 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -164,8 +164,7 @@ impl<'py> Iterator for PySetIterator<'py> { let mut hash: ffi::Py_hash_t = 0; if ffi::_PySet_NextEntry(self.set.as_ptr(), &mut self.pos, &mut key, &mut hash) != 0 { // _PySet_NextEntry returns borrowed object; for safety must make owned (see #890) - ffi::Py_INCREF(key); - Some(self.set.py().from_owned_ptr(key)) + Some(self.set.py().from_owned_ptr(ffi::_Py_NewRef(key))) } else { None } diff --git a/tests/test_buffer.rs b/tests/test_buffer.rs index 462cc556765..bcdfda1cd5f 100644 --- a/tests/test_buffer.rs +++ b/tests/test_buffer.rs @@ -39,8 +39,7 @@ impl PyBufferProtocol for TestBufferErrors { } unsafe { - (*view).obj = slf.as_ptr(); - ffi::Py_INCREF((*view).obj); + (*view).obj = ffi::_Py_NewRef(slf.as_ptr()); } let bytes = &slf.buf; diff --git a/tests/test_buffer_protocol.rs b/tests/test_buffer_protocol.rs index e5831d1b151..f7174449004 100644 --- a/tests/test_buffer_protocol.rs +++ b/tests/test_buffer_protocol.rs @@ -33,8 +33,7 @@ impl PyBufferProtocol for TestBufferClass { } unsafe { - (*view).obj = slf.as_ptr(); - ffi::Py_INCREF((*view).obj); + (*view).obj = ffi::_Py_NewRef(slf.as_ptr()); } let bytes = &slf.vec;