feature gate APIs using `into_gil_ref` (Part 2) (#4166)
This commit is contained in:
parent
7beb64a8ca
commit
21c02484d0
|
@ -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),
|
||||
# }
|
||||
# );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`).
|
||||
|
||||
|
|
|
@ -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 {})?;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -345,6 +345,7 @@ where
|
|||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
impl<'py, T> FromPyObject<'py> for &'py crate::PyCell<T>
|
||||
where
|
||||
T: PyClass,
|
||||
|
|
|
@ -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")?;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)`.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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'"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -247,9 +247,9 @@ fn mapping() {
|
|||
}
|
||||
|
||||
#[derive(FromPyObject)]
|
||||
enum SequenceIndex<'a> {
|
||||
enum SequenceIndex<'py> {
|
||||
Integer(isize),
|
||||
Slice(&'a PySlice),
|
||||
Slice(Bound<'py, PySlice>),
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue