Skip to content

Commit

Permalink
feature gate PyCell (#4177)
Browse files Browse the repository at this point in the history
* feature gate `PyCell`

* feature gate `HasPyGilRef` completely

* bump version
  • Loading branch information
Icxolu authored May 12, 2024
1 parent 57500d9 commit 10152a7
Show file tree
Hide file tree
Showing 30 changed files with 220 additions and 98 deletions.
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3"
version = "0.21.2"
version = "0.22.0-dev"
description = "Bindings to Python interpreter"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
readme = "README.md"
Expand All @@ -20,10 +20,10 @@ libc = "0.2.62"
memoffset = "0.9"

# ffi bindings to the python interpreter, split into a separate crate so they can be used independently
pyo3-ffi = { path = "pyo3-ffi", version = "=0.21.2" }
pyo3-ffi = { path = "pyo3-ffi", version = "=0.22.0-dev" }

# support crates for macros feature
pyo3-macros = { path = "pyo3-macros", version = "=0.21.2", optional = true }
pyo3-macros = { path = "pyo3-macros", version = "=0.22.0-dev", optional = true }
indoc = { version = "2.0.1", optional = true }
unindent = { version = "0.2.1", optional = true }

Expand Down Expand Up @@ -62,7 +62,7 @@ rayon = "1.6.1"
futures = "0.3.28"

[build-dependencies]
pyo3-build-config = { path = "pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] }
pyo3-build-config = { path = "pyo3-build-config", version = "=0.22.0-dev", features = ["resolve-config"] }

[features]
default = ["macros"]
Expand Down Expand Up @@ -106,7 +106,7 @@ generate-import-lib = ["pyo3-ffi/generate-import-lib"]
auto-initialize = []

# Allows use of the deprecated "GIL Refs" APIs.
gil-refs = []
gil-refs = ["pyo3-macros/gil-refs"]

# Enables `Clone`ing references to Python objects `Py<T>` which panics if the GIL is not held.
py-clone = []
Expand Down
1 change: 1 addition & 0 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,7 @@ struct MyClass {
impl pyo3::types::DerefToPyAny for MyClass {}

# #[allow(deprecated)]
# #[cfg(feature = "gil-refs")]
unsafe impl pyo3::type_object::HasPyGilRef for MyClass {
type AsRefTarget = pyo3::PyCell<Self>;
}
Expand Down
3 changes: 1 addition & 2 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1609,7 +1609,7 @@ For more, see [the constructor section](class.md#constructor) of this guide.
<details>
<summary><small>Click to expand</small></summary>

PyO3 0.9 introduces [`PyCell`], which is a [`RefCell`]-like object wrapper
PyO3 0.9 introduces `PyCell`, which is a [`RefCell`]-like object wrapper
for ensuring Rust's rules regarding aliasing of references are upheld.
For more detail, see the
[Rust Book's section on Rust's rules of references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references)
Expand Down Expand Up @@ -1788,7 +1788,6 @@ impl PySequenceProtocol for ByteSequence {

[`FromPyObject`]: {{#PYO3_DOCS_URL}}/pyo3/conversion/trait.FromPyObject.html
[`PyAny`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html
[`PyCell`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyCell.html
[`PyBorrowMutError`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyBorrowMutError.html
[`PyRef`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRef.html
[`PyRefMut`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRef.html
Expand Down
2 changes: 1 addition & 1 deletion pyo3-build-config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3-build-config"
version = "0.21.2"
version = "0.22.0-dev"
description = "Build configuration for the PyO3 ecosystem"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
keywords = ["pyo3", "python", "cpython", "ffi"]
Expand Down
4 changes: 2 additions & 2 deletions pyo3-ffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3-ffi"
version = "0.21.2"
version = "0.22.0-dev"
description = "Python-API bindings for the PyO3 ecosystem"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
keywords = ["pyo3", "python", "cpython", "ffi"]
Expand Down Expand Up @@ -38,7 +38,7 @@ abi3-py312 = ["abi3", "pyo3-build-config/abi3-py312"]
generate-import-lib = ["pyo3-build-config/python3-dll-a"]

[build-dependencies]
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] }
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.22.0-dev", features = ["resolve-config"] }

[lints]
workspace = true
5 changes: 3 additions & 2 deletions pyo3-macros-backend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3-macros-backend"
version = "0.21.2"
version = "0.22.0-dev"
description = "Code generation for PyO3 package"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
keywords = ["pyo3", "python", "cpython", "ffi"]
Expand All @@ -16,7 +16,7 @@ edition = "2021"
[dependencies]
heck = "0.5"
proc-macro2 = { version = "1", default-features = false }
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] }
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.22.0-dev", features = ["resolve-config"] }
quote = { version = "1", default-features = false }

[dependencies.syn]
Expand All @@ -29,3 +29,4 @@ workspace = true

[features]
experimental-async = []
gil-refs = []
7 changes: 6 additions & 1 deletion pyo3-macros-backend/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ fn process_functions_in_module(options: &PyModuleOptions, func: &mut syn::ItemFn
let Ctx { pyo3_path } = ctx;
let mut stmts: Vec<syn::Stmt> = Vec::new();

#[cfg(feature = "gil-refs")]
let imports = quote!(use #pyo3_path::{PyNativeType, types::PyModuleMethods};);
#[cfg(not(feature = "gil-refs"))]
let imports = quote!(use #pyo3_path::types::PyModuleMethods;);

for mut stmt in func.block.stmts.drain(..) {
if let syn::Stmt::Item(Item::Fn(func)) = &mut stmt {
if let Some(pyfn_args) = get_pyfn_attr(&mut func.attrs)? {
Expand All @@ -394,7 +399,7 @@ fn process_functions_in_module(options: &PyModuleOptions, func: &mut syn::ItemFn
#wrapped_function
{
#[allow(unknown_lints, unused_imports, redundant_imports)]
use #pyo3_path::{PyNativeType, types::PyModuleMethods};
#imports
#module_name.as_borrowed().add_function(#pyo3_path::wrap_pyfunction!(#name, #module_name.as_borrowed())?)?;
}
};
Expand Down
10 changes: 9 additions & 1 deletion pyo3-macros-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1307,11 +1307,19 @@ fn impl_pytypeinfo(
quote! { ::core::option::Option::None }
};

quote! {
#[cfg(feature = "gil-refs")]
let has_py_gil_ref = quote! {
#[allow(deprecated)]
unsafe impl #pyo3_path::type_object::HasPyGilRef for #cls {
type AsRefTarget = #pyo3_path::PyCell<Self>;
}
};

#[cfg(not(feature = "gil-refs"))]
let has_py_gil_ref = TokenStream::new();

quote! {
#has_py_gil_ref

unsafe impl #pyo3_path::type_object::PyTypeInfo for #cls {
const NAME: &'static str = #cls_name;
Expand Down
5 changes: 3 additions & 2 deletions pyo3-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3-macros"
version = "0.21.2"
version = "0.22.0-dev"
description = "Proc macros for PyO3 package"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
keywords = ["pyo3", "python", "cpython", "ffi"]
Expand All @@ -17,12 +17,13 @@ proc-macro = true
multiple-pymethods = []
experimental-async = ["pyo3-macros-backend/experimental-async"]
experimental-declarative-modules = []
gil-refs = ["pyo3-macros-backend/gil-refs"]

[dependencies]
proc-macro2 = { version = "1", default-features = false }
quote = "1"
syn = { version = "2", features = ["full", "extra-traits"] }
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.21.2" }
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.22.0-dev" }

[lints]
workspace = true
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[tool.towncrier]
filename = "CHANGELOG.md"
version = "0.21.2"
version = "0.22.0-dev"
start_string = "<!-- towncrier release notes start -->\n"
template = ".towncrier.template.md"
title_format = "## [{version}] - {project_date}"
Expand Down
7 changes: 3 additions & 4 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ use crate::inspect::types::TypeInfo;
use crate::pyclass::boolean_struct::False;
use crate::types::any::PyAnyMethods;
use crate::types::PyTuple;
use crate::{
ffi, Borrowed, Bound, Py, PyAny, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
};
use crate::{ffi, Borrowed, Bound, Py, PyAny, PyClass, PyObject, PyRef, PyRefMut, Python};
#[cfg(feature = "gil-refs")]
use {
crate::{
err::{self, PyDowncastError},
gil,
gil, PyNativeType,
},
std::ptr::NonNull,
};
Expand Down Expand Up @@ -221,6 +219,7 @@ pub trait FromPyObject<'py>: Sized {
///
/// Implementors are encouraged to implement `extract_bound` and leave this method as the
/// default implementation, which will forward calls to `extract_bound`.
#[cfg(feature = "gil-refs")]
fn extract(ob: &'py PyAny) -> PyResult<Self> {
Self::extract_bound(&ob.as_borrowed())
}
Expand Down
9 changes: 7 additions & 2 deletions src/err/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ use crate::panic::PanicException;
use crate::type_object::PyTypeInfo;
use crate::types::any::PyAnyMethods;
use crate::types::{string::PyStringMethods, typeobject::PyTypeMethods, PyTraceback, PyType};
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{
exceptions::{self, PyBaseException},
ffi,
};
use crate::{Borrowed, IntoPy, Py, PyAny, PyNativeType, PyObject, Python, ToPyObject};
use crate::{Borrowed, IntoPy, Py, PyAny, PyObject, Python, ToPyObject};
use std::borrow::Cow;
use std::cell::UnsafeCell;
use std::ffi::CString;
Expand Down Expand Up @@ -47,11 +49,13 @@ pub type PyResult<T> = Result<T, PyErr>;

/// Error that indicates a failure to convert a PyAny to a more specific Python type.
#[derive(Debug)]
#[cfg(feature = "gil-refs")]
pub struct PyDowncastError<'a> {
from: &'a PyAny,
to: Cow<'static, str>,
}

#[cfg(feature = "gil-refs")]
impl<'a> PyDowncastError<'a> {
/// Create a new `PyDowncastError` representing a failure to convert the object
/// `from` into the type named in `to`.
Expand All @@ -64,7 +68,6 @@ impl<'a> PyDowncastError<'a> {

/// Compatibility API to convert the Bound variant `DowncastError` into the
/// gil-ref variant
#[cfg(feature = "gil-refs")]
pub(crate) fn from_downcast_err(DowncastError { from, to }: DowncastError<'a, 'a>) -> Self {
#[allow(deprecated)]
let from = unsafe { from.py().from_borrowed_ptr(from.as_ptr()) };
Expand Down Expand Up @@ -1012,8 +1015,10 @@ impl<'a> std::convert::From<PyDowncastError<'a>> for PyErr {
}
}

#[cfg(feature = "gil-refs")]
impl<'a> std::error::Error for PyDowncastError<'a> {}

#[cfg(feature = "gil-refs")]
impl<'a> std::fmt::Display for PyDowncastError<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
display_downcast_error(f, &self.from.as_borrowed(), &self.to)
Expand Down
1 change: 1 addition & 0 deletions src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ macro_rules! import_exception_bound {

// FIXME remove this: was necessary while `PyTypeInfo` requires `HasPyGilRef`,
// should change in 0.22.
#[cfg(feature = "gil-refs")]
unsafe impl $crate::type_object::HasPyGilRef for $name {
type AsRefTarget = $crate::PyAny;
}
Expand Down
1 change: 1 addition & 0 deletions src/impl_/deprecations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct NotAGilRef<T>(std::marker::PhantomData<T>);

pub trait IsGilRef {}

#[cfg(feature = "gil-refs")]
impl<T: crate::PyNativeType> IsGilRef for &'_ T {}

impl<T> GilRefs<T> {
Expand Down
10 changes: 8 additions & 2 deletions src/impl_/pyclass.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{
exceptions::{PyAttributeError, PyNotImplementedError, PyRuntimeError, PyValueError},
ffi,
Expand All @@ -7,8 +9,7 @@ use crate::{
pyclass_init::PyObjectInit,
types::any::PyAnyMethods,
types::PyBool,
Borrowed, Py, PyAny, PyClass, PyErr, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo,
Python,
Borrowed, Py, PyAny, PyClass, PyErr, PyMethodDefType, PyResult, PyTypeInfo, Python,
};
use std::{
borrow::Cow,
Expand Down Expand Up @@ -168,7 +169,12 @@ pub trait PyClassImpl: Sized + 'static {

/// The closest native ancestor. This is `PyAny` by default, and when you declare
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
#[cfg(feature = "gil-refs")]
type BaseNativeType: PyTypeInfo + PyNativeType;
/// The closest native ancestor. This is `PyAny` by default, and when you declare
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
#[cfg(not(feature = "gil-refs"))]
type BaseNativeType: PyTypeInfo;

/// This handles following two situations:
/// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing.
Expand Down
Loading

0 comments on commit 10152a7

Please sign in to comment.