diff --git a/guide/src/class/protocols.md b/guide/src/class/protocols.md index 4577a510..411978f0 100644 --- a/guide/src/class/protocols.md +++ b/guide/src/class/protocols.md @@ -103,7 +103,7 @@ given signatures should be interpreted as follows: match op { CompareOp::Eq => (self.0 == other.0).into_py(py), CompareOp::Ne => (self.0 != other.0).into_py(py), - _ => py.NotImplemented().into(), + _ => py.NotImplemented(), } } } diff --git a/guide/src/exception.md b/guide/src/exception.md index 56e343f7..e1ce2498 100644 --- a/guide/src/exception.md +++ b/guide/src/exception.md @@ -79,7 +79,7 @@ use pyo3::prelude::*; use pyo3::types::{PyBool, PyList}; Python::with_gil(|py| { - assert!(PyBool::new(py, true).is_instance_of::()); + assert!(PyBool::new_bound(py, true).is_instance_of::()); let list = PyList::new_bound(py, &[1, 2, 3, 4]); assert!(!list.is_instance_of::()); assert!(list.is_instance_of::()); diff --git a/guide/src/migration.md b/guide/src/migration.md index 7d65d397..6a151b99 100644 --- a/guide/src/migration.md +++ b/guide/src/migration.md @@ -82,39 +82,6 @@ Python::with_gil(|py| { # } ``` -### `py.None()`, `py.NotImplemented()` and `py.Ellipsis()` now return typed singletons - -Previously `py.None()`, `py.NotImplemented()` and `py.Ellipsis()` would return `PyObject`. This had a few downsides: - - `PyObject` does not carry static type information - - `PyObject` takes ownership of a reference to the singletons, adding refcounting performance overhead - - `PyObject` is not gil-bound, meaning follow up method calls might again need `py`, causing repetition - -To avoid these downsides, these methods now return typed gil-bound references to the singletons, e.g. `py.None()` returns `&PyNone`. These typed singletons all implement `Into`, so migration is straightforward. - -Before: - -```rust,compile_fail -# use pyo3::prelude::*; -Python::with_gil(|py| { - let a: PyObject = py.None(); - - // let b: &PyAny = py.None().as_ref(py); // or into_ref(py) -}); -``` - -After: - -```rust -# use pyo3::prelude::*; -Python::with_gil(|py| { - // For uses needing a PyObject, add `.into()` - let a: PyObject = py.None().into_py(py); - - // For uses needing &PyAny, remove `.as_ref(py)` - // let b: &PyAny = py.None(); -}); -``` - ### `Iter(A)NextOutput` are deprecated The `__next__` and `__anext__` magic methods can now return any type convertible into Python objects directly just like all other `#[pymethods]`. The `IterNextOutput` used by `__next__` and `IterANextOutput` used by `__anext__` are subsequently deprecated. Most importantly, this change allows returning an awaitable from `__anext__` without non-sensically wrapping it into `Yield` or `Some`. Only the return types `Option` and `Result, E>` are still handled in a special manner where `Some(val)` yields `val` and `None` stops iteration. @@ -433,7 +400,7 @@ fn raise_err() -> anyhow::Result<()> { Err(PyValueError::new_err("original error message").into()) } -# fn main() { +fn main() { Python::with_gil(|py| { let rs_func = wrap_pyfunction!(raise_err, py).unwrap(); pyo3::py_run!( @@ -1212,14 +1179,14 @@ ensure that the Python GIL was held by the current thread). Technically, this wa To migrate, just pass a `py` argument to any calls to these methods. Before: -```rust,ignore +```rust,compile_fail # pyo3::Python::with_gil(|py| { py.None().get_refcnt(); # }) ``` After: -```rust,compile_fail +```rust # pyo3::Python::with_gil(|py| { py.None().get_refcnt(py); # }) diff --git a/guide/src/python_from_rust.md b/guide/src/python_from_rust.md index a5cd624e..99da2e15 100644 --- a/guide/src/python_from_rust.md +++ b/guide/src/python_from_rust.md @@ -474,7 +474,7 @@ class House(object): Ok(_) => { let none = py.None(); house - .call_method1("__exit__", (none, none, none)) + .call_method1("__exit__", (&none, &none, &none)) .unwrap(); } Err(e) => { diff --git a/newsfragments/3578.changed.md b/newsfragments/3578.changed.md deleted file mode 100644 index 53fc9943..00000000 --- a/newsfragments/3578.changed.md +++ /dev/null @@ -1 +0,0 @@ -Change return type of `py.None()`, `py.NotImplemented()`, and `py.Ellipsis()` from `PyObject` to typed singletons (`&PyNone`, `&PyNotImplemented` and `PyEllipsis` respectively). diff --git a/pyo3-benches/benches/bench_gil.rs b/pyo3-benches/benches/bench_gil.rs index 55a5a04a..59b9ff96 100644 --- a/pyo3-benches/benches/bench_gil.rs +++ b/pyo3-benches/benches/bench_gil.rs @@ -8,7 +8,7 @@ fn bench_clean_acquire_gil(b: &mut Bencher<'_>) { } fn bench_dirty_acquire_gil(b: &mut Bencher<'_>) { - let obj: PyObject = Python::with_gil(|py| py.None().into_py(py)); + let obj = Python::with_gil(|py| py.None()); b.iter_batched( || { // Clone and drop an object so that the GILPool has work to do. diff --git a/pyo3-benches/benches/bench_pyobject.rs b/pyo3-benches/benches/bench_pyobject.rs index 169cf1f0..af25d61c 100644 --- a/pyo3-benches/benches/bench_pyobject.rs +++ b/pyo3-benches/benches/bench_pyobject.rs @@ -6,7 +6,7 @@ fn drop_many_objects(b: &mut Bencher<'_>) { Python::with_gil(|py| { b.iter(|| { for _ in 0..1000 { - std::mem::drop(PyObject::from(py.None())); + std::mem::drop(py.None()); } }); }); diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index e2f84949..02024011 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -743,7 +743,7 @@ fn impl_simple_enum( return Ok((self_val == other.__pyo3__int__()).to_object(py)); } - return Ok(::std::convert::Into::into(py.NotImplemented())); + return Ok(py.NotImplemented()); } _pyo3::basic::CompareOp::Ne => { let self_val = self.__pyo3__int__(); @@ -754,9 +754,9 @@ fn impl_simple_enum( return Ok((self_val != other.__pyo3__int__()).to_object(py)); } - return Ok(::std::convert::Into::into(py.NotImplemented())); + return Ok(py.NotImplemented()); } - _ => Ok(::std::convert::Into::into(py.NotImplemented())), + _ => Ok(py.NotImplemented()), } } }; diff --git a/pytests/src/awaitable.rs b/pytests/src/awaitable.rs index 55f1bce4..e1a70b42 100644 --- a/pytests/src/awaitable.rs +++ b/pytests/src/awaitable.rs @@ -37,7 +37,7 @@ impl IterAwaitable { Ok(v) => Err(PyStopIteration::new_err(v)), Err(err) => Err(err), }, - _ => Ok(py.None().into_py(py)), + _ => Ok(py.None()), } } } diff --git a/src/conversion.rs b/src/conversion.rs index 28e15d17..1370fb2a 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -141,7 +141,7 @@ pub trait ToPyObject { /// match self { /// Self::Integer(val) => val.into_py(py), /// Self::String(val) => val.into_py(py), -/// Self::None => py.None().into_py(py), +/// Self::None => py.None(), /// } /// } /// } @@ -266,7 +266,7 @@ where { fn to_object(&self, py: Python<'_>) -> PyObject { self.as_ref() - .map_or_else(|| py.None().into_py(py), |val| val.to_object(py)) + .map_or_else(|| py.None(), |val| val.to_object(py)) } } @@ -275,7 +275,7 @@ where T: IntoPy, { fn into_py(self, py: Python<'_>) -> PyObject { - self.map_or_else(|| py.None().into_py(py), |val| val.into_py(py)) + self.map_or_else(|| py.None(), |val| val.into_py(py)) } } @@ -593,7 +593,6 @@ mod test_no_clone {} #[cfg(test)] mod tests { - use crate::conversion::IntoPy; use crate::{PyObject, Python}; #[allow(deprecated)] @@ -648,13 +647,13 @@ mod tests { assert_eq!(option.as_ptr(), std::ptr::null_mut()); let none = py.None(); - option = Some(none.into_py(py)); + option = Some(none.clone()); - let ref_cnt = none.into_py(py).get_refcnt(py); + let ref_cnt = none.get_refcnt(py); assert_eq!(option.as_ptr(), none.as_ptr()); // Ensure ref count not changed by as_ptr call - assert_eq!(none.into_py(py).get_refcnt(py), ref_cnt); + assert_eq!(none.get_refcnt(py), ref_cnt); }); } } diff --git a/src/conversions/chrono.rs b/src/conversions/chrono.rs index 8d201fb8..0d9a79c7 100644 --- a/src/conversions/chrono.rs +++ b/src/conversions/chrono.rs @@ -566,7 +566,6 @@ fn timezone_utc(py: Python<'_>) -> &PyAny { #[cfg(test)] mod tests { use super::*; - use crate::types::any::PyAnyMethods; use crate::{types::PyTuple, Py}; use std::{cmp::Ordering, panic}; @@ -636,7 +635,7 @@ mod tests { // Test that if a user tries to convert a python's timezone aware datetime into a naive // one, the conversion fails. Python::with_gil(|py| { - let none = py.None(); + let none = py.None().into_ref(py); assert_eq!( none.extract::().unwrap_err().to_string(), "TypeError: 'NoneType' object cannot be converted to 'PyDelta'" diff --git a/src/err/mod.rs b/src/err/mod.rs index 13e154b3..c50e3774 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -219,7 +219,7 @@ impl PyErr { } else { // Assume obj is Type[Exception]; let later normalization handle if this // is not the case - PyErrState::lazy(obj, Option::::None) + PyErrState::lazy(obj, obj.py().None()) }; PyErr::from_state(state) diff --git a/src/ffi/tests.rs b/src/ffi/tests.rs index a3160751..0e0d3688 100644 --- a/src/ffi/tests.rs +++ b/src/ffi/tests.rs @@ -311,20 +311,18 @@ fn test_inc_dec_ref() { #[test] #[cfg(Py_3_12)] fn test_inc_dec_ref_immortal() { - use crate::types::any::PyAnyMethods; - Python::with_gil(|py| { let obj = py.None(); - let ref_count = obj.get_refcnt(); + let ref_count = obj.get_refcnt(py); let ptr = obj.as_ptr(); unsafe { Py_INCREF(ptr) }; - assert_eq!(obj.get_refcnt(), ref_count); + assert_eq!(obj.get_refcnt(py), ref_count); unsafe { Py_DECREF(ptr) }; - assert_eq!(obj.get_refcnt(), ref_count); + assert_eq!(obj.get_refcnt(py), ref_count); }) } diff --git a/src/impl_/pyclass.rs b/src/impl_/pyclass.rs index fa03b81e..2bd39dda 100644 --- a/src/impl_/pyclass.rs +++ b/src/impl_/pyclass.rs @@ -813,7 +813,7 @@ slot_fragment_trait! { // By default `__ne__` will try `__eq__` and invert the result let slf: &PyAny = py.from_borrowed_ptr(slf); let other: &PyAny = py.from_borrowed_ptr(other); - slf.eq(other).map(|is_eq| PyBool::new(py, !is_eq).into_ptr()) + slf.eq(other).map(|is_eq| PyBool::new_bound(py, !is_eq).to_owned().into_ptr()) } } diff --git a/src/instance.rs b/src/instance.rs index 492bef56..793d0e32 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -321,6 +321,14 @@ impl<'a, 'py> Borrowed<'a, 'py, PyAny> { pub(crate) unsafe fn from_ptr_unchecked(py: Python<'py>, ptr: *mut ffi::PyObject) -> Self { Self(NonNull::new_unchecked(ptr), PhantomData, py) } + + /// Converts this `PyAny` to a concrete Python type without checking validity. + /// + /// # Safety + /// Callers must ensure that the type is valid or risk type confusion. + pub(crate) unsafe fn downcast_unchecked(self) -> Borrowed<'a, 'py, T> { + Borrowed(self.0, PhantomData, self.2) + } } impl<'a, 'py, T> From<&'a Bound<'py, T>> for Borrowed<'a, 'py, T> { diff --git a/src/marker.rs b/src/marker.rs index 06fbec7e..55f5cf64 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -698,22 +698,22 @@ impl<'py> Python<'py> { /// Gets the Python builtin value `None`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] - pub fn None(self) -> Borrowed<'py, 'py, PyNone> { - PyNone::get(self) + pub fn None(self) -> PyObject { + PyNone::get(self).into() } /// Gets the Python builtin value `Ellipsis`, or `...`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] - pub fn Ellipsis(self) -> &'py PyEllipsis { - PyEllipsis::get(self) + pub fn Ellipsis(self) -> PyObject { + PyEllipsis::get(self).into() } /// Gets the Python builtin value `NotImplemented`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] - pub fn NotImplemented(self) -> &'py PyNotImplemented { - PyNotImplemented::get(self) + pub fn NotImplemented(self) -> PyObject { + PyNotImplemented::get(self).into() } /// Gets the running Python interpreter version as a string. diff --git a/src/types/any.rs b/src/types/any.rs index 14102d80..61c3c672 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -759,9 +759,9 @@ impl PyAny { /// use pyo3::types::{PyBool, PyLong}; /// /// Python::with_gil(|py| { - /// let b = PyBool::new(py, true); + /// let b = PyBool::new_bound(py, true); /// assert!(b.is_instance_of::()); - /// let any: &PyAny = b.as_ref(); + /// let any: &Bound<'_, PyAny> = b.as_any(); /// /// // `bool` is a subtype of `int`, so `downcast` will accept a `bool` as an `int` /// // but `downcast_exact` will not. @@ -1583,9 +1583,9 @@ pub trait PyAnyMethods<'py> { /// use pyo3::types::{PyBool, PyLong}; /// /// Python::with_gil(|py| { - /// let b = PyBool::new(py, true); + /// let b = PyBool::new_bound(py, true); /// assert!(b.is_instance_of::()); - /// let any: &PyAny = b.as_ref(); + /// let any: &Bound<'_, PyAny> = b.as_any(); /// /// // `bool` is a subtype of `int`, so `downcast` will accept a `bool` as an `int` /// // but `downcast_exact` will not. @@ -2530,7 +2530,7 @@ class SimpleClass: let x = 5.to_object(py).into_ref(py); assert!(x.is_exact_instance_of::()); - let t = PyBool::new(py, true); + let t = PyBool::new_bound(py, true); assert!(t.is_instance_of::()); assert!(!t.is_exact_instance_of::()); assert!(t.is_exact_instance_of::()); @@ -2543,10 +2543,12 @@ class SimpleClass: #[test] fn test_any_is_exact_instance() { Python::with_gil(|py| { - let t = PyBool::new(py, true); - assert!(t.is_instance(py.get_type::()).unwrap()); - assert!(!t.is_exact_instance(py.get_type::())); - assert!(t.is_exact_instance(py.get_type::())); + let t = PyBool::new_bound(py, true); + assert!(t + .is_instance(&py.get_type::().as_borrowed()) + .unwrap()); + assert!(!t.is_exact_instance(&py.get_type::().as_borrowed())); + assert!(t.is_exact_instance(&py.get_type::().as_borrowed())); }); } diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 0decc0b4..c0c4e4ba 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,8 +1,8 @@ #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::{ - exceptions::PyTypeError, ffi, instance::Bound, FromPyObject, IntoPy, PyAny, PyNativeType, - PyObject, PyResult, Python, ToPyObject, + exceptions::PyTypeError, ffi, ffi_ptr_ext::FfiPtrExt, instance::Bound, Borrowed, FromPyObject, + IntoPy, PyAny, PyNativeType, PyObject, PyResult, Python, ToPyObject, }; use super::any::PyAnyMethods; @@ -14,12 +14,33 @@ pub struct PyBool(PyAny); pyobject_native_type!(PyBool, ffi::PyObject, pyobject_native_static_type_object!(ffi::PyBool_Type), #checkfunction=ffi::PyBool_Check); impl PyBool { - /// Depending on `val`, returns `true` or `false`. + /// Deprecated form of [`PyBool::new_bound`] + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`PyBool::new` will be replaced by `PyBool::new_bound` in a future PyO3 version" + ) + )] #[inline] pub fn new(py: Python<'_>, val: bool) -> &PyBool { unsafe { py.from_borrowed_ptr(if val { ffi::Py_True() } else { ffi::Py_False() }) } } + /// Depending on `val`, returns `true` or `false`. + /// + /// # Note + /// This returns a [`Borrowed`] reference to one of Pythons `True` or + /// `False` singletons + #[inline] + pub fn new_bound(py: Python<'_>, val: bool) -> Borrowed<'_, '_, Self> { + unsafe { + if val { ffi::Py_True() } else { ffi::Py_False() } + .assume_borrowed(py) + .downcast_unchecked() + } + } + /// Gets whether this boolean is `true`. #[inline] pub fn is_true(&self) -> bool { @@ -65,7 +86,7 @@ impl ToPyObject for bool { impl IntoPy for bool { #[inline] fn into_py(self, py: Python<'_>) -> PyObject { - PyBool::new(py, self).into() + PyBool::new_bound(py, self).into_py(py) } #[cfg(feature = "experimental-inspect")] @@ -135,27 +156,29 @@ impl FromPyObject<'_> for bool { #[cfg(test)] mod tests { - use crate::types::{PyAny, PyBool}; + use crate::types::any::PyAnyMethods; + use crate::types::boolobject::PyBoolMethods; + use crate::types::PyBool; use crate::Python; use crate::ToPyObject; #[test] fn test_true() { Python::with_gil(|py| { - assert!(PyBool::new(py, true).is_true()); - let t: &PyAny = PyBool::new(py, true).into(); - assert!(t.extract::().unwrap()); - assert!(true.to_object(py).is(PyBool::new(py, true))); + assert!(PyBool::new_bound(py, true).is_true()); + let t = PyBool::new_bound(py, true); + assert!(t.as_any().extract::().unwrap()); + assert!(true.to_object(py).is(&*PyBool::new_bound(py, true))); }); } #[test] fn test_false() { Python::with_gil(|py| { - assert!(!PyBool::new(py, false).is_true()); - let t: &PyAny = PyBool::new(py, false).into(); - assert!(!t.extract::().unwrap()); - assert!(false.to_object(py).is(PyBool::new(py, false))); + assert!(!PyBool::new_bound(py, false).is_true()); + let t = PyBool::new_bound(py, false); + assert!(!t.as_any().extract::().unwrap()); + assert!(false.to_object(py).is(&*PyBool::new_bound(py, false))); }); } } diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 55cd75d5..6303a87d 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -596,7 +596,7 @@ mod tests { #[test] fn test_from_err() { Python::with_gil(|py| { - if let Err(err) = PyByteArray::from_bound(&py.None().as_borrowed()) { + if let Err(err) = PyByteArray::from_bound(py.None().bind(py)) { assert!(err.is_instance_of::(py)); } else { panic!("error"); diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index 1b399a1f..f336140e 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -486,7 +486,7 @@ impl RichComparisons2 { match op { CompareOp::Eq => true.into_py(other.py()), CompareOp::Ne => false.into_py(other.py()), - _ => other.py().NotImplemented().into(), + _ => other.py().NotImplemented(), } } } @@ -556,7 +556,7 @@ mod return_not_implemented { } fn __richcmp__(&self, other: PyRef<'_, Self>, _op: CompareOp) -> PyObject { - other.py().None().into_py(other.py()) + other.py().None() } fn __add__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { diff --git a/tests/test_class_attributes.rs b/tests/test_class_attributes.rs index 0ff0dd6d..b589dd08 100644 --- a/tests/test_class_attributes.rs +++ b/tests/test_class_attributes.rs @@ -190,12 +190,12 @@ fn test_renaming_all_struct_fields() { let struct_class = py.get_type::(); let struct_obj = struct_class.call0().unwrap(); assert!(struct_obj - .setattr("firstField", PyBool::new(py, false)) + .setattr("firstField", PyBool::new_bound(py, false)) .is_ok()); py_assert!(py, struct_obj, "struct_obj.firstField == False"); py_assert!(py, struct_obj, "struct_obj.secondField == 5"); assert!(struct_obj - .setattr("third_field", PyBool::new(py, true)) + .setattr("third_field", PyBool::new_bound(py, true)) .is_ok()); py_assert!(py, struct_obj, "struct_obj.third_field == True"); }); diff --git a/tests/test_class_conversion.rs b/tests/test_class_conversion.rs index a0a16e21..27a8f604 100644 --- a/tests/test_class_conversion.rs +++ b/tests/test_class_conversion.rs @@ -119,7 +119,7 @@ fn test_polymorphic_container_does_not_accept_other_types() { let setattr = |value: PyObject| p.as_ref(py).setattr("inner", value); assert!(setattr(1i32.into_py(py)).is_err()); - assert!(setattr(py.None().into_py(py)).is_err()); + assert!(setattr(py.None()).is_err()); assert!(setattr((1i32, 2i32).into_py(py)).is_err()); }); } diff --git a/tests/test_exceptions.rs b/tests/test_exceptions.rs index b783e887..d6d6b46f 100644 --- a/tests/test_exceptions.rs +++ b/tests/test_exceptions.rs @@ -118,7 +118,7 @@ fn test_write_unraisable() { assert!(object.is_none(py)); let err = PyRuntimeError::new_err("bar"); - err.write_unraisable(py, Some(py.NotImplemented())); + err.write_unraisable(py, Some(py.NotImplemented().as_ref(py))); let (err, object) = capture.borrow_mut(py).capture.take().unwrap(); assert_eq!(err.to_string(), "RuntimeError: bar"); diff --git a/tests/test_frompyobject.rs b/tests/test_frompyobject.rs index c141b3e6..c6f6e148 100644 --- a/tests/test_frompyobject.rs +++ b/tests/test_frompyobject.rs @@ -352,7 +352,7 @@ fn test_enum() { _ => panic!("Expected extracting Foo::TransparentTuple, got {:?}", f), } let none = py.None(); - let f = Foo::extract_bound(none.as_ref()).expect("Failed to extract Foo from int"); + let f = Foo::extract(none.as_ref(py)).expect("Failed to extract Foo from int"); match f { Foo::TransparentStructVar { a } => assert!(a.is_none()), _ => panic!("Expected extracting Foo::TransparentStructVar, got {:?}", f), diff --git a/tests/test_gc.rs b/tests/test_gc.rs index 0f68bf0b..43cdb1b4 100644 --- a/tests/test_gc.rs +++ b/tests/test_gc.rs @@ -89,7 +89,7 @@ impl GcIntegration { fn __clear__(&mut self) { Python::with_gil(|py| { - self.self_ref = py.None().into_py(py); + self.self_ref = py.None(); }); } } @@ -102,7 +102,7 @@ fn gc_integration() { let inst = PyCell::new( py, GcIntegration { - self_ref: py.None().into_py(py), + self_ref: py.None(), dropped: TestDropCall { drop_called: Arc::clone(&drop_called), }, @@ -286,9 +286,7 @@ struct PartialTraverse { impl PartialTraverse { fn new(py: Python<'_>) -> Self { - Self { - member: py.None().into_py(py), - } + Self { member: py.None() } } } @@ -324,9 +322,7 @@ struct PanickyTraverse { impl PanickyTraverse { fn new(py: Python<'_>) -> Self { - Self { - member: py.None().into_py(py), - } + Self { member: py.None() } } } diff --git a/tests/test_no_imports.rs b/tests/test_no_imports.rs index fe49b2d2..df73b9a2 100644 --- a/tests/test_no_imports.rs +++ b/tests/test_no_imports.rs @@ -2,12 +2,10 @@ #![cfg(feature = "macros")] -use pyo3::IntoPy; - #[pyo3::pyfunction] #[pyo3(name = "identity", signature = (x = None))] fn basic_function(py: pyo3::Python<'_>, x: Option) -> pyo3::PyObject { - x.unwrap_or_else(|| py.None().into_py(py)) + x.unwrap_or_else(|| py.None()) } #[pyo3::pymodule]