feature gate APIs using `into_gil_ref` (Part 2) (#4166)

This commit is contained in:
Icxolu 2024-05-10 00:21:48 +02:00 committed by GitHub
parent 7beb64a8ca
commit 21c02484d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 93 additions and 165 deletions

View File

@ -265,7 +265,7 @@ use pyo3::prelude::*;
#[derive(FromPyObject)]
# #[derive(Debug)]
enum RustyEnum<'a> {
enum RustyEnum<'py> {
Int(usize), // input is a positive int
String(String), // input is a string
IntTuple(usize, usize), // input is a 2-tuple with positive ints
@ -284,7 +284,7 @@ enum RustyEnum<'a> {
b: usize,
},
#[pyo3(transparent)]
CatchAll(&'a PyAny), // This extraction never fails
CatchAll(Bound<'py, PyAny>), // This extraction never fails
}
#
# use pyo3::types::{PyBytes, PyString};
@ -394,7 +394,7 @@ enum RustyEnum<'a> {
# assert_eq!(
# b"text",
# match rust_thing {
# RustyEnum::CatchAll(i) => i.downcast::<PyBytes>()?.as_bytes(),
# RustyEnum::CatchAll(ref i) => i.downcast::<PyBytes>()?.as_bytes(),
# other => unreachable!("Error extracting: {:?}", other),
# }
# );

View File

@ -128,5 +128,5 @@ defines exceptions for several standard library modules.
[`PyErr`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyErr.html
[`PyResult`]: {{#PYO3_DOCS_URL}}/pyo3/type.PyResult.html
[`PyErr::from_value`]: {{#PYO3_DOCS_URL}}/pyo3/struct.PyErr.html#method.from_value
[`PyAny::is_instance`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.is_instance
[`PyAny::is_instance_of`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.is_instance_of
[`PyAny::is_instance`]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.is_instance
[`PyAny::is_instance_of`]: {{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.is_instance_of

View File

@ -34,9 +34,11 @@ held. (If PyO3 could not assume this, every PyO3 API would need to take a
very simple and easy-to-understand programs like this:
```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*;
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API
let hello = py
@ -57,9 +59,11 @@ it owns are decreased, releasing them to the Python garbage collector. Most
of the time we don't have to think about this, but consider the following:
```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*;
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
Python::with_gil(|py| -> PyResult<()> {
for _ in 0..10 {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API
@ -96,9 +100,11 @@ In general we don't want unbounded memory growth during loops! One workaround
is to acquire and release the GIL with each iteration of the loop.
```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*;
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
for _ in 0..10 {
Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API
@ -118,9 +124,11 @@ times. Another workaround is to work with the `GILPool` object directly, but
this is unsafe.
```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*;
# use pyo3::types::PyString;
# fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
Python::with_gil(|py| -> PyResult<()> {
for _ in 0..10 {
#[allow(deprecated)] // `new_pool` is not needed in code not using the GIL Refs API

View File

@ -54,7 +54,7 @@ pyo3 = { version = "0.21", features = ["gil-refs"] }
The `PyTryFrom` trait has aged poorly, its `try_from` method now conflicts with `TryFrom::try_from` in the 2021 edition prelude. A lot of its functionality was also duplicated with `PyTypeInfo`.
To tighten up the PyO3 traits as part of the deprecation of the GIL Refs API the `PyTypeInfo` trait has had a simpler companion `PyTypeCheck`. The methods [`PyAny::downcast`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.downcast) and [`PyAny::downcast_exact`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.downcast_exact) no longer use `PyTryFrom` as a bound, instead using `PyTypeCheck` and `PyTypeInfo` respectively.
To tighten up the PyO3 traits as part of the deprecation of the GIL Refs API the `PyTypeInfo` trait has had a simpler companion `PyTypeCheck`. The methods `PyAny::downcast` and `PyAny::downcast_exact` no longer use `PyTryFrom` as a bound, instead using `PyTypeCheck` and `PyTypeInfo` respectively.
To migrate, switch all type casts to use `obj.downcast()` instead of `try_from(obj)` (and similar for `downcast_exact`).

View File

@ -467,8 +467,10 @@ let _: &mut MyClass = &mut *py_ref_mut;
`PyCell<T>` was also accessed like a Python-native type.
```rust
#![allow(unused_imports)]
# use pyo3::prelude::*;
# #[pyclass] struct MyClass { }
# #[cfg(feature = "gil-refs")]
# Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // &PyCell is part of the deprecate GIL Refs API
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass {})?;

View File

@ -63,30 +63,6 @@ impl AssertingBaseClass {
}
}
#[allow(deprecated)]
mod deprecated {
use super::*;
#[pyclass(subclass)]
#[derive(Clone, Debug)]
pub struct AssertingBaseClassGilRef;
#[pymethods]
impl AssertingBaseClassGilRef {
#[new]
#[classmethod]
fn new(cls: &PyType, expected_type: &PyType) -> PyResult<Self> {
if !cls.is(expected_type) {
return Err(PyValueError::new_err(format!(
"{:?} != {:?}",
cls, expected_type
)));
}
Ok(Self)
}
}
}
#[pyclass]
struct ClassWithoutConstructor;
@ -95,7 +71,7 @@ pub fn pyclasses(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<EmptyClass>()?;
m.add_class::<PyClassIter>()?;
m.add_class::<AssertingBaseClass>()?;
m.add_class::<deprecated::AssertingBaseClassGilRef>()?;
m.add_class::<ClassWithoutConstructor>()?;
Ok(())
}

View File

@ -12,7 +12,7 @@ fn array_to_array_i32(arr: [i32; 3]) -> [i32; 3] {
}
#[pyfunction]
fn vec_to_vec_pystring(vec: Vec<&PyString>) -> Vec<&PyString> {
fn vec_to_vec_pystring(vec: Vec<Bound<'_, PyString>>) -> Vec<Bound<'_, PyString>> {
vec
}

View File

@ -65,17 +65,6 @@ def test_new_classmethod():
_ = AssertingSubClass(expected_type=str)
def test_new_classmethod_gil_ref():
class AssertingSubClass(pyclasses.AssertingBaseClassGilRef):
pass
# The `AssertingBaseClass` constructor errors if it is not passed the
# relevant subclass.
_ = AssertingSubClass(expected_type=AssertingSubClass)
with pytest.raises(ValueError):
_ = AssertingSubClass(expected_type=str)
class ClassWithoutConstructorPy:
def __new__(cls):
raise TypeError("No constructor defined")

View File

@ -345,6 +345,7 @@ where
}
#[allow(deprecated)]
#[cfg(feature = "gil-refs")]
impl<'py, T> FromPyObject<'py> for &'py crate::PyCell<T>
where
T: PyClass,

View File

@ -347,7 +347,7 @@ impl FromPyObject<'_> for FixedOffset {
/// does not supports microseconds.
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<FixedOffset> {
#[cfg(not(Py_LIMITED_API))]
let ob: &PyTzInfo = ob.extract()?;
let ob = ob.downcast::<PyTzInfo>()?;
#[cfg(Py_LIMITED_API)]
check_type(ob, &DatetimeTypes::get(ob.py()).tzinfo, "PyTzInfo")?;

View File

@ -147,6 +147,7 @@ impl<'a> IntoPy<PyObject> for &'a OsString {
#[cfg(test)]
mod tests {
use crate::types::{PyAnyMethods, PyStringMethods};
use crate::{types::PyString, IntoPy, PyObject, Python, ToPyObject};
use std::fmt::Debug;
use std::{
@ -179,7 +180,7 @@ mod tests {
Python::with_gil(|py| {
fn test_roundtrip<T: ToPyObject + AsRef<OsStr> + Debug>(py: Python<'_>, obj: T) {
let pyobject = obj.to_object(py);
let pystring: &PyString = pyobject.extract(py).unwrap();
let pystring = pyobject.downcast_bound::<PyString>(py).unwrap();
assert_eq!(pystring.to_string_lossy(), obj.as_ref().to_string_lossy());
let roundtripped_obj: OsString = pystring.extract().unwrap();
assert_eq!(obj.as_ref(), roundtripped_obj.as_os_str());
@ -200,7 +201,7 @@ mod tests {
obj: T,
) {
let pyobject = obj.clone().into_py(py);
let pystring: &PyString = pyobject.extract(py).unwrap();
let pystring = pyobject.downcast_bound::<PyString>(py).unwrap();
assert_eq!(pystring.to_string_lossy(), obj.as_ref().to_string_lossy());
let roundtripped_obj: OsString = pystring.extract().unwrap();
assert!(obj.as_ref() == roundtripped_obj.as_os_str());

View File

@ -64,6 +64,7 @@ impl<'a> IntoPy<PyObject> for &'a PathBuf {
#[cfg(test)]
mod tests {
use crate::types::{PyAnyMethods, PyStringMethods};
use crate::{types::PyString, IntoPy, PyObject, Python, ToPyObject};
use std::borrow::Cow;
use std::fmt::Debug;
@ -95,7 +96,7 @@ mod tests {
Python::with_gil(|py| {
fn test_roundtrip<T: ToPyObject + AsRef<Path> + Debug>(py: Python<'_>, obj: T) {
let pyobject = obj.to_object(py);
let pystring: &PyString = pyobject.extract(py).unwrap();
let pystring = pyobject.downcast_bound::<PyString>(py).unwrap();
assert_eq!(pystring.to_string_lossy(), obj.as_ref().to_string_lossy());
let roundtripped_obj: PathBuf = pystring.extract().unwrap();
assert_eq!(obj.as_ref(), roundtripped_obj.as_path());
@ -116,7 +117,7 @@ mod tests {
obj: T,
) {
let pyobject = obj.clone().into_py(py);
let pystring: &PyString = pyobject.extract(py).unwrap();
let pystring = pyobject.downcast_bound::<PyString>(py).unwrap();
assert_eq!(pystring.to_string_lossy(), obj.as_ref().to_string_lossy());
let roundtripped_obj: PathBuf = pystring.extract().unwrap();
assert_eq!(obj.as_ref(), roundtripped_obj.as_path());

View File

@ -13,7 +13,7 @@ impl<'a> PyFunctionArguments<'a> {
match self {
PyFunctionArguments::Python(py) => (py, None),
PyFunctionArguments::PyModule(module) => {
let py = module.py();
let py = crate::PyNativeType::py(module);
(py, Some(module))
}
}

View File

@ -1000,6 +1000,7 @@ where
}
/// Convert `PyDowncastError` to Python `TypeError`.
#[cfg(feature = "gil-refs")]
impl<'a> std::convert::From<PyDowncastError<'a>> for PyErr {
fn from(err: PyDowncastError<'_>) -> PyErr {
let args = PyDowncastErrorArguments {

View File

@ -32,6 +32,7 @@ macro_rules! impl_exception_boilerplate {
$crate::impl_exception_boilerplate_bound!($name);
#[cfg(feature = "gil-refs")]
impl ::std::error::Error for $name {
fn source(&self) -> ::std::option::Option<&(dyn ::std::error::Error + 'static)> {
unsafe {
@ -58,6 +59,7 @@ macro_rules! impl_exception_boilerplate_bound {
///
/// [`PyErr`]: https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html "PyErr in pyo3"
#[inline]
#[allow(dead_code)]
pub fn new_err<A>(args: A) -> $crate::PyErr
where
A: $crate::PyErrArguments + ::std::marker::Send + ::std::marker::Sync + 'static,
@ -881,7 +883,9 @@ mod tests {
use super::*;
use crate::types::any::PyAnyMethods;
use crate::types::{IntoPyDict, PyDict};
use crate::{PyErr, PyNativeType};
use crate::PyErr;
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
import_exception_bound!(socket, gaierror);
import_exception_bound!(email.errors, MessageError);

View File

@ -29,39 +29,27 @@ impl<T> GilRefs<T> {
}
impl GilRefs<Python<'_>> {
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(since = "0.21.0", note = "use `wrap_pyfunction_bound!` instead")
)]
#[deprecated(since = "0.21.0", note = "use `wrap_pyfunction_bound!` instead")]
pub fn is_python(&self) {}
}
impl<T: IsGilRef> GilRefs<T> {
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "use `&Bound<'_, T>` instead for this function argument"
)
#[deprecated(
since = "0.21.0",
note = "use `&Bound<'_, T>` instead for this function argument"
)]
pub fn function_arg(&self) {}
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor"
)
#[deprecated(
since = "0.21.0",
note = "use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor"
)]
pub fn from_py_with_arg(&self) {}
}
impl<T: IsGilRef> OptionGilRefs<Option<T>> {
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "use `Option<&Bound<'_, T>>` instead for this function argument"
)
#[deprecated(
since = "0.21.0",
note = "use `Option<&Bound<'_, T>>` instead for this function argument"
)]
pub fn function_arg(&self) {}
}

View File

@ -790,10 +790,8 @@ fn push_parameter_list(msg: &mut String, parameter_names: &[&str]) {
#[cfg(test)]
mod tests {
use crate::{
types::{IntoPyDict, PyTuple},
PyAny, Python,
};
use crate::types::{IntoPyDict, PyTuple};
use crate::Python;
use super::{push_parameter_list, FunctionDescription, NoVarargs, NoVarkeywords};
@ -809,7 +807,7 @@ mod tests {
};
Python::with_gil(|py| {
let args = PyTuple::new_bound(py, Vec::<&PyAny>::new());
let args = PyTuple::empty_bound(py);
let kwargs = [("foo", 0u8)].into_py_dict_bound(py);
let err = unsafe {
function_description
@ -840,7 +838,7 @@ mod tests {
};
Python::with_gil(|py| {
let args = PyTuple::new_bound(py, Vec::<&PyAny>::new());
let args = PyTuple::empty_bound(py);
let kwargs = [(1u8, 1u8)].into_py_dict_bound(py);
let err = unsafe {
function_description
@ -871,7 +869,7 @@ mod tests {
};
Python::with_gil(|py| {
let args = PyTuple::new_bound(py, Vec::<&PyAny>::new());
let args = PyTuple::empty_bound(py);
let mut output = [None, None];
let err = unsafe {
function_description.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(

View File

@ -1283,7 +1283,7 @@ impl<T> Py<T> {
}
/// Returns whether `self` and `other` point to the same object. To compare
/// the equality of two objects (the `==` operator), use [`eq`](PyAny::eq).
/// the equality of two objects (the `==` operator), use [`eq`](PyAnyMethods::eq).
///
/// This is equivalent to the Python expression `self is other`.
#[inline]
@ -2142,7 +2142,7 @@ a = A()
fn test_is_ellipsis() {
Python::with_gil(|py| {
let v = py
.eval("...", None, None)
.eval_bound("...", None, None)
.map_err(|e| e.display(py))
.unwrap()
.to_object(py);

View File

@ -41,7 +41,7 @@
//! The [`#[pymethods]`](crate::pymethods) proc macro will generate this wrapper function (and more),
//! using [`PyCell`] under the hood:
//!
//! ```rust
//! ```rust,ignore
//! # use pyo3::prelude::*;
//! # #[pyclass]
//! # struct Number {
@ -148,7 +148,7 @@
//! ```
//!
//! It is better to write that function like this:
//! ```rust
//! ```rust,ignore
//! # #![allow(deprecated)]
//! # use pyo3::prelude::*;
//! # #[pyclass]

View File

@ -8,6 +8,7 @@ fn do_something(x: i32) -> crate::PyResult<i32> {
}
#[test]
#[cfg(feature = "gil-refs")]
fn invoke_wrap_pyfunction() {
crate::Python::with_gil(|py| {
#[allow(deprecated)]

View File

@ -1,15 +1,17 @@
use crate::class::basic::CompareOp;
use crate::conversion::{AsPyPointer, FromPyObjectBound, IntoPy, ToPyObject};
use crate::err::{DowncastError, DowncastIntoError, PyDowncastError, PyErr, PyResult};
use crate::err::{DowncastError, DowncastIntoError, PyErr, PyResult};
use crate::exceptions::{PyAttributeError, PyTypeError};
use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Bound;
use crate::py_result_ext::PyResultExt;
use crate::type_object::{HasPyGilRef, PyTypeCheck, PyTypeInfo};
use crate::type_object::{PyTypeCheck, PyTypeInfo};
#[cfg(not(any(PyPy, GraalPy)))]
use crate::types::PySuper;
use crate::types::{PyDict, PyIterator, PyList, PyString, PyTuple, PyType};
use crate::{err, ffi, Py, PyNativeType, Python};
use crate::{err, ffi, Py, Python};
#[cfg(feature = "gil-refs")]
use crate::{err::PyDowncastError, type_object::HasPyGilRef, PyNativeType};
use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::os::raw::c_int;
@ -66,6 +68,7 @@ pyobject_native_type_extract!(PyAny);
pyobject_native_type_sized!(PyAny, ffi::PyObject);
#[cfg(feature = "gil-refs")]
impl PyAny {
/// Returns whether `self` and `other` point to the same object. To compare
/// the equality of two objects (the `==` operator), use [`eq`](PyAny::eq).
@ -942,7 +945,7 @@ impl PyAny {
#[doc(alias = "PyAny")]
pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
/// Returns whether `self` and `other` point to the same object. To compare
/// the equality of two objects (the `==` operator), use [`eq`](PyAny::eq).
/// the equality of two objects (the `==` operator), use [`eq`](PyAnyMethods::eq).
///
/// This is equivalent to the Python expression `self is other`.
fn is<T: AsPyPointer>(&self, other: &T) -> bool;
@ -1589,10 +1592,10 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
/// Downcast this `PyAny` to a concrete Python type or pyclass (but not a subclass of it).
///
/// It is almost always better to use [`PyAny::downcast`] because it accounts for Python
/// It is almost always better to use [`PyAnyMethods::downcast`] because it accounts for Python
/// subtyping. Use this method only when you do not want to allow subtypes.
///
/// The advantage of this method over [`PyAny::downcast`] is that it is faster. The implementation
/// The advantage of this method over [`PyAnyMethods::downcast`] is that it is faster. The implementation
/// of `downcast_exact` uses the equivalent of the Python expression `type(self) is T`, whereas
/// `downcast` uses `isinstance(self, T)`.
///

View File

@ -3,7 +3,9 @@ use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::{Borrowed, Bound};
use crate::py_result_ext::PyResultExt;
use crate::types::any::PyAnyMethods;
use crate::{ffi, AsPyPointer, PyAny, PyNativeType, Python};
#[cfg(feature = "gil-refs")]
use crate::AsPyPointer;
use crate::{ffi, PyAny, PyNativeType, Python};
use std::os::raw::c_char;
use std::slice;

View File

@ -11,7 +11,7 @@ use super::any::PyAnyMethods;
/// Represents a Python `float` object.
///
/// You can usually avoid directly working with this type
/// by using [`ToPyObject`] and [`extract`](PyAny::extract)
/// by using [`ToPyObject`] and [`extract`](PyAnyMethods::extract)
/// with `f32`/`f64`.
#[repr(transparent)]
pub struct PyFloat(PyAny);

View File

@ -1,9 +1,9 @@
use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Borrowed;
use crate::py_result_ext::PyResultExt;
use crate::{ffi, AsPyPointer, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
#[cfg(feature = "gil-refs")]
use crate::{PyDowncastError, PyNativeType};
use crate::{AsPyPointer, PyDowncastError, PyNativeType};
/// A Python iterator object.
///

View File

@ -1,9 +1,9 @@
use crate::err::PyResult;
use crate::ffi_ptr_ext::FfiPtrExt;
use crate::py_result_ext::PyResultExt;
use crate::{ffi, Bound, PyAny};
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ffi, AsPyPointer, Bound, PyAny};
use crate::{AsPyPointer, PyNativeType};
/// Represents a Python `memoryview`.
#[repr(transparent)]

View File

@ -130,7 +130,8 @@ macro_rules! pyobject_native_type_base(
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>)
-> ::std::result::Result<(), ::std::fmt::Error>
{
let s = self.repr().or(::std::result::Result::Err(::std::fmt::Error))?;
use $crate::{PyNativeType, types::{PyAnyMethods, PyStringMethods}};
let s = self.as_borrowed().repr().or(::std::result::Result::Err(::std::fmt::Error))?;
f.write_str(&s.to_string_lossy())
}
}
@ -139,19 +140,20 @@ macro_rules! pyobject_native_type_base(
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>)
-> ::std::result::Result<(), ::std::fmt::Error>
{
use $crate::PyNativeType;
match self.str() {
use $crate::{PyNativeType, types::{PyAnyMethods, PyStringMethods, PyTypeMethods}};
match self.as_borrowed().str() {
::std::result::Result::Ok(s) => return f.write_str(&s.to_string_lossy()),
::std::result::Result::Err(err) => err.write_unraisable_bound(self.py(), ::std::option::Option::Some(&self.as_borrowed())),
}
match self.get_type().name() {
match self.as_borrowed().get_type().name() {
::std::result::Result::Ok(name) => ::std::write!(f, "<unprintable {} object>", name),
::std::result::Result::Err(_err) => f.write_str("<unprintable object>"),
}
}
}
#[cfg(feature = "gil-refs")]
impl<$($generics,)*> $crate::ToPyObject for $name
{
#[inline]
@ -196,6 +198,7 @@ macro_rules! pyobject_native_type_named (
// FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<$($generics,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name {
#[inline]
fn into_py(self, py: $crate::Python<'_>) -> $crate::Py<$name> {
@ -205,6 +208,7 @@ macro_rules! pyobject_native_type_named (
// FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<$($generics,)*> ::std::convert::From<&'_ $name> for $crate::Py<$name> {
#[inline]
fn from(other: &$name) -> Self {
@ -215,6 +219,7 @@ macro_rules! pyobject_native_type_named (
// FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<'a, $($generics,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny {
fn from(ob: &'a $name) -> Self {
unsafe{&*(ob as *const $name as *const $crate::PyAny)}
@ -271,6 +276,7 @@ macro_rules! pyobject_native_type_extract {
($name:ty $(;$generics:ident)*) => {
// FIXME https://github.com/PyO3/pyo3/issues/3903
#[allow(unknown_lints, non_local_definitions)]
#[cfg(feature = "gil-refs")]
impl<'py, $($generics,)*> $crate::FromPyObject<'py> for &'py $name {
#[inline]
fn extract_bound(obj: &$crate::Bound<'py, $crate::PyAny>) -> $crate::PyResult<Self> {

View File

@ -4,7 +4,7 @@ use crate::{ffi, PyAny};
///
/// You can usually avoid directly working with this type
/// by using [`ToPyObject`](crate::conversion::ToPyObject)
/// and [`extract`](PyAny::extract)
/// and [`extract`](super::PyAnyMethods::extract)
/// with the primitive Rust integer types.
#[repr(transparent)]
pub struct PyLong(PyAny);

View File

@ -310,15 +310,6 @@ impl ClassWithFromPyWithMethods {
argument
}
#[classmethod]
#[cfg(feature = "gil-refs")]
fn classmethod_gil_ref(
_cls: &PyType,
#[pyo3(from_py_with = "PyAny::len")] argument: usize,
) -> usize {
argument
}
#[staticmethod]
fn staticmethod(#[pyo3(from_py_with = "get_length")] argument: usize) -> usize {
argument
@ -333,19 +324,15 @@ impl ClassWithFromPyWithMethods {
fn test_pymethods_from_py_with() {
Python::with_gil(|py| {
let instance = Py::new(py, ClassWithFromPyWithMethods {}).unwrap();
let has_gil_refs = cfg!(feature = "gil-refs");
py_run!(
py,
instance
has_gil_refs,
instance,
r#"
arg = {1: 1, 2: 3}
assert instance.instance_method(arg) == 2
assert instance.classmethod(arg) == 2
if has_gil_refs:
assert instance.classmethod_gil_ref(arg) == 2
assert instance.staticmethod(arg) == 2
assert 42 in instance

View File

@ -20,7 +20,7 @@ fn test_compile_errors() {
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
t.compile_fail("tests/ui/reject_generics.rs");
#[cfg(not(feature = "gil-refs"))]
#[cfg(feature = "gil-refs")]
t.compile_fail("tests/ui/deprecations.rs");
t.compile_fail("tests/ui/invalid_closure.rs");
t.compile_fail("tests/ui/pyclass_send.rs");
@ -38,7 +38,13 @@ fn test_compile_errors() {
t.compile_fail("tests/ui/invalid_pymethod_receiver.rs");
t.compile_fail("tests/ui/missing_intopy.rs");
// adding extra error conversion impls changes the output
#[cfg(not(any(windows, feature = "eyre", feature = "anyhow", Py_LIMITED_API)))]
#[cfg(not(any(
windows,
feature = "eyre",
feature = "anyhow",
feature = "gil-refs",
Py_LIMITED_API
)))]
t.compile_fail("tests/ui/invalid_result_conversion.rs");
t.compile_fail("tests/ui/not_send.rs");
t.compile_fail("tests/ui/not_send2.rs");

View File

@ -77,13 +77,6 @@ impl ClassMethod {
Ok(format!("{}.method()!", cls.qualname()?))
}
#[classmethod]
/// Test class method.
#[cfg(feature = "gil-refs")]
fn method_gil_ref(cls: &PyType) -> PyResult<String> {
Ok(format!("{}.method()!", cls.qualname()?))
}
#[classmethod]
fn method_owned(cls: Py<PyType>) -> PyResult<String> {
let qualname = Python::with_gil(|gil| cls.bind(gil).qualname())?;

View File

@ -371,13 +371,6 @@ fn pyfunction_with_module<'py>(module: &Bound<'py, PyModule>) -> PyResult<Bound<
module.name()
}
#[pyfunction]
#[pyo3(pass_module)]
#[cfg(feature = "gil-refs")]
fn pyfunction_with_module_gil_ref(module: &PyModule) -> PyResult<&str> {
module.name()
}
#[pyfunction]
#[pyo3(pass_module)]
fn pyfunction_with_module_owned(
@ -426,28 +419,14 @@ fn pyfunction_with_module_and_args_kwargs<'py>(
.map(|s| (s, args.len(), kwargs.map(|d| d.len())))
}
#[pyfunction]
#[pyo3(pass_module)]
#[cfg(feature = "gil-refs")]
fn pyfunction_with_pass_module_in_attribute(module: &PyModule) -> PyResult<&str> {
module.name()
}
#[pymodule]
fn module_with_functions_with_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(pyfunction_with_module, m)?)?;
#[cfg(feature = "gil-refs")]
m.add_function(wrap_pyfunction!(pyfunction_with_module_gil_ref, m)?)?;
m.add_function(wrap_pyfunction!(pyfunction_with_module_owned, m)?)?;
m.add_function(wrap_pyfunction!(pyfunction_with_module_and_py, m)?)?;
m.add_function(wrap_pyfunction!(pyfunction_with_module_and_arg, m)?)?;
m.add_function(wrap_pyfunction!(pyfunction_with_module_and_default_arg, m)?)?;
m.add_function(wrap_pyfunction!(pyfunction_with_module_and_args_kwargs, m)?)?;
#[cfg(feature = "gil-refs")]
m.add_function(wrap_pyfunction!(
pyfunction_with_pass_module_in_attribute,
m
)?)?;
m.add_function(wrap_pyfunction!(pyfunction_with_module, m)?)?;
Ok(())
}
@ -461,12 +440,6 @@ fn test_module_functions_with_module() {
m,
"m.pyfunction_with_module() == 'module_with_functions_with_module'"
);
#[cfg(feature = "gil-refs")]
py_assert!(
py,
m,
"m.pyfunction_with_module_gil_ref() == 'module_with_functions_with_module'"
);
py_assert!(
py,
m,
@ -489,12 +462,6 @@ fn test_module_functions_with_module() {
"m.pyfunction_with_module_and_args_kwargs(1, x=1, y=2) \
== ('module_with_functions_with_module', 1, 2)"
);
#[cfg(feature = "gil-refs")]
py_assert!(
py,
m,
"m.pyfunction_with_pass_module_in_attribute() == 'module_with_functions_with_module'"
);
});
}

View File

@ -247,9 +247,9 @@ fn mapping() {
}
#[derive(FromPyObject)]
enum SequenceIndex<'a> {
enum SequenceIndex<'py> {
Integer(isize),
Slice(&'a PySlice),
Slice(Bound<'py, PySlice>),
}
#[pyclass]

View File

@ -10,12 +10,6 @@ note: the lint level is defined here
1 | #![deny(deprecated)]
| ^^^^^^^^^^
error: use of deprecated struct `pyo3::PyCell`: `PyCell` was merged into `Bound`, use that instead; see the migration guide for more info
--> tests/ui/deprecations.rs:23:30
|
23 | fn method_gil_ref(_slf: &PyCell<Self>) {}
| ^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
--> tests/ui/deprecations.rs:42:44
|

View File

@ -9,10 +9,10 @@ error[E0277]: the trait bound `PyErr: From<MyError>` is not satisfied
<PyErr as From<std::io::Error>>
<PyErr as From<PyBorrowError>>
<PyErr as From<PyBorrowMutError>>
<PyErr as From<PyDowncastError<'a>>>
<PyErr as From<DowncastError<'_, '_>>>
<PyErr as From<DowncastIntoError<'_>>>
<PyErr as From<NulError>>
<PyErr as From<IntoStringError>>
and $N others
= note: required for `MyError` to implement `Into<PyErr>`
= note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)