Skip to content

Commit

Permalink
Merge pull request #2448 from davidhewitt/frozen
Browse files Browse the repository at this point in the history
pyclass: switch from immutable to frozen
  • Loading branch information
davidhewitt committed Jun 20, 2022
2 parents 517f4a8 + 2fd5364 commit 920fa93
Show file tree
Hide file tree
Showing 22 changed files with 316 additions and 161 deletions.
5 changes: 3 additions & 2 deletions guide/src/class.md
Expand Up @@ -951,7 +951,9 @@ unsafe impl ::pyo3::type_object::PyTypeInfo for MyClass {
}
}

impl ::pyo3::PyClass for MyClass { }
impl ::pyo3::PyClass for MyClass {
type Frozen = pyo3::pyclass::boolean_struct::False;
}

impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut MyClass {
type Target = ::pyo3::PyRefMut<'a, MyClass>;
Expand All @@ -974,7 +976,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
type Layout = PyCell<MyClass>;
type BaseType = PyAny;
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
type Mutability = pyo3::pycell::Mutable;
type PyClassMutability = pyo3::pycell::MutableClass;
type Dict = ::pyo3::impl_::pyclass::PyClassDummySlot;
type WeakRef = ::pyo3::impl_::pyclass::PyClassDummySlot;
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/attributes.rs
Expand Up @@ -15,6 +15,7 @@ pub mod kw {
syn::custom_keyword!(extends);
syn::custom_keyword!(freelist);
syn::custom_keyword!(from_py_with);
syn::custom_keyword!(frozen);
syn::custom_keyword!(gc);
syn::custom_keyword!(get);
syn::custom_keyword!(item);
Expand All @@ -29,7 +30,6 @@ pub mod kw {
syn::custom_keyword!(transparent);
syn::custom_keyword!(unsendable);
syn::custom_keyword!(weakref);
syn::custom_keyword!(immutable);
}

#[derive(Clone, Debug)]
Expand Down
29 changes: 10 additions & 19 deletions pyo3-macros-backend/src/pyclass.rs
Expand Up @@ -61,7 +61,7 @@ pub struct PyClassPyO3Options {
pub dict: Option<kw::dict>,
pub extends: Option<ExtendsAttribute>,
pub freelist: Option<FreelistAttribute>,
pub immutable: Option<kw::immutable>,
pub frozen: Option<kw::frozen>,
pub mapping: Option<kw::mapping>,
pub module: Option<ModuleAttribute>,
pub name: Option<NameAttribute>,
Expand All @@ -78,7 +78,7 @@ enum PyClassPyO3Option {
Dict(kw::dict),
Extends(ExtendsAttribute),
Freelist(FreelistAttribute),
Immutable(kw::immutable),
Frozen(kw::frozen),
Mapping(kw::mapping),
Module(ModuleAttribute),
Name(NameAttribute),
Expand All @@ -101,8 +101,8 @@ impl Parse for PyClassPyO3Option {
input.parse().map(PyClassPyO3Option::Extends)
} else if lookahead.peek(attributes::kw::freelist) {
input.parse().map(PyClassPyO3Option::Freelist)
} else if lookahead.peek(attributes::kw::immutable) {
input.parse().map(PyClassPyO3Option::Immutable)
} else if lookahead.peek(attributes::kw::frozen) {
input.parse().map(PyClassPyO3Option::Frozen)
} else if lookahead.peek(attributes::kw::mapping) {
input.parse().map(PyClassPyO3Option::Mapping)
} else if lookahead.peek(attributes::kw::module) {
Expand Down Expand Up @@ -160,7 +160,7 @@ impl PyClassPyO3Options {
PyClassPyO3Option::Dict(dict) => set_option!(dict),
PyClassPyO3Option::Extends(extends) => set_option!(extends),
PyClassPyO3Option::Freelist(freelist) => set_option!(freelist),
PyClassPyO3Option::Immutable(immutable) => set_option!(immutable),
PyClassPyO3Option::Frozen(frozen) => set_option!(frozen),
PyClassPyO3Option::Mapping(mapping) => set_option!(mapping),
PyClassPyO3Option::Module(module) => set_option!(module),
PyClassPyO3Option::Name(name) => set_option!(name),
Expand Down Expand Up @@ -713,12 +713,14 @@ impl<'a> PyClassImplsBuilder<'a> {
let cls = self.cls;

quote! {
impl _pyo3::PyClass for #cls { }
impl _pyo3::PyClass for #cls {
type Frozen = <Self::PyClassMutability as _pyo3::pycell::PyClassMutability>::Frozen;
}
}
}
fn impl_extractext(&self) -> TokenStream {
let cls = self.cls;
if self.attr.options.immutable.is_some() {
if self.attr.options.frozen.is_some() {
quote! {
impl<'a> _pyo3::derive_utils::ExtractExt<'a> for &'a #cls
{
Expand Down Expand Up @@ -855,17 +857,7 @@ impl<'a> PyClassImplsBuilder<'a> {

let deprecations = &self.attr.deprecations;

let mutability = if self.attr.options.immutable.is_some() {
quote! {
_pyo3::pycell::Immutable
}
} else {
quote! {
_pyo3::pycell::Mutable
}
};

let class_mutability = if self.attr.options.immutable.is_some() {
let class_mutability = if self.attr.options.frozen.is_some() {
quote! {
ImmutableChild
}
Expand Down Expand Up @@ -907,7 +899,6 @@ impl<'a> PyClassImplsBuilder<'a> {
type BaseType = #base;
type ThreadChecker = #thread_checker;
#inventory
type Mutability = #mutability;
type PyClassMutability = <<#base as _pyo3::impl_::pyclass::PyClassBaseType>::PyClassMutability as _pyo3::pycell::PyClassMutability>::#class_mutability;
type Dict = #dict;
type WeakRef = #weakref;
Expand Down
13 changes: 6 additions & 7 deletions src/class/basic.rs
Expand Up @@ -10,9 +10,8 @@
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)

use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
use crate::{
exceptions, ffi, pyclass::MutablePyClass, FromPyObject, PyAny, PyCell, PyClass, PyObject,
};
use crate::pyclass::boolean_struct::False;
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject};
use std::os::raw::c_int;

/// Basic Python class customization
Expand All @@ -28,14 +27,14 @@ pub trait PyObjectProtocol<'p>: PyClass {

fn __setattr__(&'p mut self, name: Self::Name, value: Self::Value) -> Self::Result
where
Self: PyObjectSetAttrProtocol<'p> + MutablePyClass,
Self: PyObjectSetAttrProtocol<'p> + PyClass<Frozen = False>,
{
unimplemented!()
}

fn __delattr__(&'p mut self, name: Self::Name) -> Self::Result
where
Self: PyObjectDelAttrProtocol<'p> + MutablePyClass,
Self: PyObjectDelAttrProtocol<'p> + PyClass<Frozen = False>,
{
unimplemented!()
}
Expand Down Expand Up @@ -79,12 +78,12 @@ pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
type Name: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<PyObject>;
}
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> + PyClass<Frozen = False> {
type Name: FromPyObject<'p>;
type Value: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> + PyClass<Frozen = False> {
type Name: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}
Expand Down
5 changes: 3 additions & 2 deletions src/class/buffer.rs
Expand Up @@ -6,7 +6,8 @@
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
//! c-api
use crate::callback::IntoPyCallbackOutput;
use crate::{ffi, pyclass::MutablePyClass, PyCell, PyRefMut};
use crate::pyclass::boolean_struct::False;
use crate::{ffi, PyCell, PyClass, PyRefMut};
use std::os::raw::c_int;

/// Buffer protocol interface
Expand All @@ -15,7 +16,7 @@ use std::os::raw::c_int;
/// c-api.
#[allow(unused_variables)]
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
pub trait PyBufferProtocol<'p>: MutablePyClass {
pub trait PyBufferProtocol<'p>: PyClass<Frozen = False> {
// No default implementations so that implementors of this trait provide both methods.

fn bf_getbuffer(
Expand Down
5 changes: 3 additions & 2 deletions src/class/gc.rs
Expand Up @@ -3,14 +3,15 @@

//! Python GC support

use crate::{ffi, pyclass::MutablePyClass, PyCell};
use crate::pyclass::boolean_struct::False;
use crate::{ffi, PyCell, PyClass};
use std::os::raw::{c_int, c_void};

pub use crate::impl_::pymethods::{PyTraverseError, PyVisit};

/// GC support
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
pub trait PyGCProtocol<'p>: MutablePyClass {
pub trait PyGCProtocol<'p>: PyClass<Frozen = False> {
fn __traverse__(&'p self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>;
fn __clear__(&'p mut self);
}
Expand Down
9 changes: 5 additions & 4 deletions src/class/mapping.rs
Expand Up @@ -5,12 +5,13 @@
//! Trait and support implementation for implementing mapping support

use crate::callback::IntoPyCallbackOutput;
use crate::{pyclass::MutablePyClass, FromPyObject, PyClass, PyObject};
use crate::pyclass::boolean_struct::False;
use crate::{FromPyObject, PyClass, PyObject};

/// Mapping interface
#[allow(unused_variables)]
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
pub trait PyMappingProtocol<'p>: PyClass {
pub trait PyMappingProtocol<'p>: PyClass<Frozen = False> {
fn __len__(&'p self) -> Self::Result
where
Self: PyMappingLenProtocol<'p>,
Expand Down Expand Up @@ -52,13 +53,13 @@ pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}

pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> + PyClass<Frozen = False> {
type Key: FromPyObject<'p>;
type Value: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> + PyClass<Frozen = False> {
type Key: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}
Expand Down
31 changes: 16 additions & 15 deletions src/class/number.rs
Expand Up @@ -5,7 +5,8 @@
//! Trait and support implementation for implementing number protocol
use crate::callback::IntoPyCallbackOutput;
use crate::err::PyErr;
use crate::{ffi, pyclass::MutablePyClass, FromPyObject, PyClass, PyObject};
use crate::pyclass::boolean_struct::False;
use crate::{ffi, FromPyObject, PyClass, PyObject};

/// Number interface
#[allow(unused_variables)]
Expand Down Expand Up @@ -461,76 +462,76 @@ pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}

pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
// See https://bugs.python.org/issue36379
type Modulo: FromPyObject<'p>;
}

#[allow(clippy::upper_case_acronyms)]
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

#[allow(clippy::upper_case_acronyms)]
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}
Expand Down
11 changes: 6 additions & 5 deletions src/class/sequence.rs
Expand Up @@ -6,7 +6,8 @@
use crate::callback::IntoPyCallbackOutput;
use crate::conversion::{FromPyObject, IntoPy};
use crate::err::PyErr;
use crate::{exceptions, ffi, pyclass::MutablePyClass, PyAny, PyCell, PyClass, PyObject};
use crate::pyclass::boolean_struct::False;
use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject};
use std::os::raw::c_int;

/// Sequence interface
Expand Down Expand Up @@ -89,13 +90,13 @@ pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> {
type Result: IntoPyCallbackOutput<PyObject>;
}

pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> + PyClass<Frozen = False> {
type Index: FromPyObject<'p> + From<isize>;
type Value: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<()>;
}

pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> + PyClass<Frozen = False> {
type Index: FromPyObject<'p> + From<isize>;
type Result: IntoPyCallbackOutput<()>;
}
Expand All @@ -116,14 +117,14 @@ pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
}

pub trait PySequenceInplaceConcatProtocol<'p>:
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass
PySequenceProtocol<'p> + IntoPy<PyObject> + PyClass<Frozen = False>
{
type Other: FromPyObject<'p>;
type Result: IntoPyCallbackOutput<Self>;
}

pub trait PySequenceInplaceRepeatProtocol<'p>:
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass + 'p
PySequenceProtocol<'p> + IntoPy<PyObject> + PyClass<Frozen = False> + 'p
{
type Index: FromPyObject<'p> + From<isize>;
type Result: IntoPyCallbackOutput<Self>;
Expand Down
6 changes: 3 additions & 3 deletions src/conversion.rs
Expand Up @@ -2,11 +2,11 @@

//! Defines conversions between Rust and Python types.
use crate::err::{self, PyDowncastError, PyResult};
use crate::pyclass::boolean_struct::False;
use crate::type_object::PyTypeInfo;
use crate::types::PyTuple;
use crate::{
ffi, gil, pyclass::MutablePyClass, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef,
PyRefMut, Python,
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
};
use std::ptr::NonNull;

Expand Down Expand Up @@ -375,7 +375,7 @@ where

impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
where
T: MutablePyClass,
T: PyClass<Frozen = False>,
{
fn extract(obj: &'a PyAny) -> PyResult<Self> {
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
Expand Down

0 comments on commit 920fa93

Please sign in to comment.