Skip to content

Commit

Permalink
Merge pull request #1292 from davidhewitt/python-deprecations
Browse files Browse the repository at this point in the history
python: deprecate some redundant methods
  • Loading branch information
kngwyu authored Nov 23, 2020
2 parents e0c7d82 + 7ca126c commit 6465766
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 91 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Change `Debug` and `Display` impls for `PyException` to be consistent with `PyAny`. [#1275](https://github.com/PyO3/pyo3/pull/1275)
- Change `Debug` impl of `PyErr` to output more helpful information (acquiring the GIL if necessary). [#1275](https://github.com/PyO3/pyo3/pull/1275)
- Rename `PyTypeInfo::is_instance` and `PyTypeInfo::is_exact_instance` to `PyTypeInfo::is_type_of` and `PyTypeInfo::is_exact_type_of`. [#1278](https://github.com/PyO3/pyo3/pull/1278)
- Deprecate `Python::is_instance`, `Python::is_subclass`, `Python::release`, and `Python::xdecref`. [#1292](https://github.com/PyO3/pyo3/pull/1292)

### Removed
- Remove deprecated ffi definitions `PyUnicode_AsUnicodeCopy`, `PyUnicode_GetMax`, `_Py_CheckRecursionLimit`, `PyObject_AsCharBuffer`, `PyObject_AsReadBuffer`, `PyObject_CheckReadBuffer` and `PyObject_AsWriteBuffer`, which will be removed in Python 3.10. [#1217](https://github.com/PyO3/pyo3/pull/1217)
Expand Down
189 changes: 98 additions & 91 deletions src/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,6 @@ impl Python<'_> {
}

impl<'p> Python<'p> {
/// Retrieves a Python instance under the assumption that the GIL is already
/// acquired at this point, and stays acquired for the lifetime `'p`.
///
/// Because the output lifetime `'p` is not connected to any input parameter,
/// care must be taken that the compiler infers an appropriate lifetime for `'p`
/// when calling this function.
///
/// # Safety
/// The lifetime `'p` must be shorter than the period you *assume* that you have GIL.
/// I.e., `Python<'static>` is always *really* unsafe.
#[inline]
pub unsafe fn assume_gil_acquired() -> Python<'p> {
Python(PhantomData)
}

/// Acquires the global interpreter lock, which allows access to the Python runtime.
///
/// If the Python runtime is not already initialized, this function will initialize it.
Expand Down Expand Up @@ -303,24 +288,6 @@ impl<'p> Python<'p> {
PyModule::import(self, name)
}

/// Checks whether `obj` is an instance of type `T`.
///
/// This is equivalent to the Python `isinstance` function.
pub fn is_instance<T: PyTypeObject, V: AsPyPointer>(self, obj: &V) -> PyResult<bool> {
T::type_object(self).is_instance(obj)
}

/// Checks whether type `T` is subclass of type `U`.
///
/// This is equivalent to the Python `issubclass` function.
pub fn is_subclass<T, U>(self) -> PyResult<bool>
where
T: PyTypeObject,
U: PyTypeObject,
{
T::type_object(self).is_subclass::<U>()
}

/// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
Expand All @@ -335,64 +302,6 @@ impl<'p> Python<'p> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_NotImplemented()) }
}

/// Create a new pool for managing PyO3's owned references.
///
/// When this `GILPool` is dropped, all PyO3 owned references created after this `GILPool` will
/// all have their Python reference counts decremented, potentially allowing Python to drop
/// the corresponding Python objects.
///
/// Typical usage of PyO3 will not need this API, as `Python::acquire_gil` automatically
/// creates a `GILPool` where appropriate.
///
/// Advanced uses of PyO3 which perform long-running tasks which never free the GIL may need
/// to use this API to clear memory, as PyO3 usually does not clear memory until the GIL is
/// released.
///
/// # Example
/// ```rust
/// # use pyo3::prelude::*;
/// let gil = Python::acquire_gil();
/// let py = gil.python();
///
/// // Some long-running process like a webserver, which never releases the GIL.
/// loop {
/// // Create a new pool, so that PyO3 can clear memory at the end of the loop.
/// let pool = unsafe { py.new_pool() };
///
/// // It is recommended to *always* immediately set py to the pool's Python, to help
/// // avoid creating references with invalid lifetimes.
/// let py = unsafe { pool.python() };
///
/// // do stuff...
/// # break; // Exit the loop so that doctest terminates!
/// }
/// ```
///
/// # Safety
/// Extreme care must be taken when using this API, as misuse can lead to accessing invalid
/// memory. In addition, the caller is responsible for guaranteeing that the GIL remains held
/// for the entire lifetime of the returned `GILPool`.
///
/// Two best practices are required when using this API:
/// - From the moment `new_pool()` is called, only the `Python` token from the returned
/// `GILPool` (accessible using `.python()`) should be used in PyO3 APIs. All other older
/// `Python` tokens with longer lifetimes are unsafe to use until the `GILPool` is dropped,
/// because they can be used to create PyO3 owned references which have lifetimes which
/// outlive the `GILPool`.
/// - Similarly, methods on existing owned references will implicitly refer back to the
/// `Python` token which that reference was originally created with. If the returned values
/// from these methods are owned references they will inherit the same lifetime. As a result,
/// Rust's lifetime rules may allow them to outlive the `GILPool`, even though this is not
/// safe for reasons discussed above. Care must be taken to never access these return values
/// after the `GILPool` is dropped, unless they are converted to `Py<T>` *before* the pool
/// is dropped.
#[inline]
pub unsafe fn new_pool(self) -> GILPool {
GILPool::new()
}
}

impl<'p> Python<'p> {
/// Registers the object in the release pool, and tries to downcast to specific type.
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError<'p>>
where
Expand Down Expand Up @@ -479,8 +388,32 @@ impl<'p> Python<'p> {
FromPyPointer::from_borrowed_ptr_or_opt(self, ptr)
}

/// Checks whether `obj` is an instance of type `T`.
///
/// This is equivalent to the Python `isinstance` function.
#[deprecated(since = "0.13.0", note = "Please use obj.is_instance::<T>() instead")]
pub fn is_instance<T: PyTypeObject, V: AsPyPointer>(self, obj: &V) -> PyResult<bool> {
T::type_object(self).is_instance(obj)
}

/// Checks whether type `T` is subclass of type `U`.
///
/// This is equivalent to the Python `issubclass` function.
#[deprecated(
since = "0.13.0",
note = "Please use T::type_object(py).is_subclass::<U>() instead"
)]
pub fn is_subclass<T, U>(self) -> PyResult<bool>
where
T: PyTypeObject,
U: PyTypeObject,
{
T::type_object(self).is_subclass::<U>()
}

/// Releases a PyObject reference.
#[inline]
#[deprecated(since = "0.13.0", note = "Please just drop ob instead")]
pub fn release<T>(self, ob: T)
where
T: IntoPyPointer,
Expand All @@ -495,6 +428,7 @@ impl<'p> Python<'p> {

/// Releases a `ffi::PyObject` pointer.
#[inline]
#[deprecated(since = "0.13.0", note = "Please just drop obj instead")]
pub fn xdecref<T: IntoPyPointer>(self, ptr: T) {
unsafe { ffi::Py_XDECREF(ptr.into_ptr()) };
}
Expand All @@ -518,6 +452,77 @@ impl<'p> Python<'p> {
Ok(())
}
}

/// Retrieves a Python instance under the assumption that the GIL is already
/// acquired at this point, and stays acquired for the lifetime `'p`.
///
/// Because the output lifetime `'p` is not connected to any input parameter,
/// care must be taken that the compiler infers an appropriate lifetime for `'p`
/// when calling this function.
///
/// # Safety
/// The lifetime `'p` must be shorter than the period you *assume* that you have GIL.
/// I.e., `Python<'static>` is always *really* unsafe.
#[inline]
pub unsafe fn assume_gil_acquired() -> Python<'p> {
Python(PhantomData)
}

/// Create a new pool for managing PyO3's owned references.
///
/// When this `GILPool` is dropped, all PyO3 owned references created after this `GILPool` will
/// all have their Python reference counts decremented, potentially allowing Python to drop
/// the corresponding Python objects.
///
/// Typical usage of PyO3 will not need this API, as `Python::acquire_gil` automatically
/// creates a `GILPool` where appropriate.
///
/// Advanced uses of PyO3 which perform long-running tasks which never free the GIL may need
/// to use this API to clear memory, as PyO3 usually does not clear memory until the GIL is
/// released.
///
/// # Example
/// ```rust
/// # use pyo3::prelude::*;
/// let gil = Python::acquire_gil();
/// let py = gil.python();
///
/// // Some long-running process like a webserver, which never releases the GIL.
/// loop {
/// // Create a new pool, so that PyO3 can clear memory at the end of the loop.
/// let pool = unsafe { py.new_pool() };
///
/// // It is recommended to *always* immediately set py to the pool's Python, to help
/// // avoid creating references with invalid lifetimes.
/// let py = unsafe { pool.python() };
///
/// // do stuff...
/// # break; // Exit the loop so that doctest terminates!
/// }
/// ```
///
/// # Safety
/// Extreme care must be taken when using this API, as misuse can lead to accessing invalid
/// memory. In addition, the caller is responsible for guaranteeing that the GIL remains held
/// for the entire lifetime of the returned `GILPool`.
///
/// Two best practices are required when using this API:
/// - From the moment `new_pool()` is called, only the `Python` token from the returned
/// `GILPool` (accessible using `.python()`) should be used in PyO3 APIs. All other older
/// `Python` tokens with longer lifetimes are unsafe to use until the `GILPool` is dropped,
/// because they can be used to create PyO3 owned references which have lifetimes which
/// outlive the `GILPool`.
/// - Similarly, methods on existing owned references will implicitly refer back to the
/// `Python` token which that reference was originally created with. If the returned values
/// from these methods are owned references they will inherit the same lifetime. As a result,
/// Rust's lifetime rules may allow them to outlive the `GILPool`, even though this is not
/// safe for reasons discussed above. Care must be taken to never access these return values
/// after the `GILPool` is dropped, unless they are converted to `Py<T>` *before* the pool
/// is dropped.
#[inline]
pub unsafe fn new_pool(self) -> GILPool {
GILPool::new()
}
}

#[cfg(test)]
Expand Down Expand Up @@ -567,6 +572,7 @@ mod test {
}

#[test]
#[allow(deprecated)]
fn test_is_instance() {
let gil = Python::acquire_gil();
let py = gil.python();
Expand All @@ -579,6 +585,7 @@ mod test {
}

#[test]
#[allow(deprecated)]
fn test_is_subclass() {
let gil = Python::acquire_gil();
let py = gil.python();
Expand Down

0 comments on commit 6465766

Please sign in to comment.