Skip to content

Commit 558549e

Browse files
committed
pyproto: split into new feature
1 parent 6db7dd7 commit 558549e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2089
-1347
lines changed

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,17 @@ serde_json = "1.0.61"
5252
pyo3-build-config = { path = "pyo3-build-config", version = "0.15.1", features = ["resolve-config"] }
5353

5454
[features]
55-
default = ["macros"]
55+
default = ["macros", "pyproto"]
5656

5757
# Enables macros: #[pyclass], #[pymodule], #[pyfunction] etc.
5858
macros = ["pyo3-macros", "indoc", "unindent"]
5959

6060
# Enables multiple #[pymethods] per #[pyclass]
6161
multiple-pymethods = ["inventory", "pyo3-macros/multiple-pymethods"]
6262

63+
# Enables deprecated #[pyproto] macro
64+
pyproto = ["pyo3-macros/pyproto"]
65+
6366
# Use this feature when building an extension module.
6467
# It tells the linker to keep the python symbols unresolved,
6568
# so that the module can also be used with statically linked python interpreters.
@@ -83,7 +86,7 @@ nightly = []
8386

8487
# Activates all additional features
8588
# This is mostly intended for testing purposes - activating *all* of these isn't particularly useful.
86-
full = ["macros", "multiple-pymethods", "num-bigint", "num-complex", "hashbrown", "serde", "indexmap", "eyre", "anyhow"]
89+
full = ["macros", "pyproto", "multiple-pymethods", "num-bigint", "num-complex", "hashbrown", "serde", "indexmap", "eyre", "anyhow"]
8790

8891
[[bench]]
8992
name = "bench_call"

Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
ALL_ADDITIVE_FEATURES = macros multiple-pymethods num-bigint num-complex hashbrown serde indexmap eyre anyhow
44
COVERAGE_PACKAGES = --package pyo3 --package pyo3-build-config --package pyo3-macros-backend --package pyo3-macros
55

6-
list_all_additive_features:
7-
@echo $(ALL_ADDITIVE_FEATURES)
8-
96
test: lint test_py
107
cargo test
118
cargo test --features="abi3"

guide/src/class.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -849,17 +849,17 @@ impl pyo3::IntoPy<PyObject> for MyClass {
849849
}
850850
}
851851

852-
impl pyo3::class::impl_::PyClassImpl for MyClass {
852+
impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
853853
const DOC: &'static str = "Class for demonstration\u{0}";
854854
const IS_GC: bool = false;
855855
const IS_BASETYPE: bool = false;
856856
const IS_SUBCLASS: bool = false;
857857
type Layout = PyCell<MyClass>;
858858
type BaseType = PyAny;
859-
type ThreadChecker = pyo3::class::impl_::ThreadCheckerStub<MyClass>;
859+
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
860860

861861
fn for_each_method_def(visitor: &mut dyn FnMut(&[pyo3::class::PyMethodDefType])) {
862-
use pyo3::class::impl_::*;
862+
use pyo3::impl_::pyclass::*;
863863
let collector = PyClassImplCollector::<MyClass>::new();
864864
visitor(collector.py_methods());
865865
visitor(collector.py_class_descriptors());
@@ -870,23 +870,23 @@ impl pyo3::class::impl_::PyClassImpl for MyClass {
870870
visitor(collector.number_protocol_methods());
871871
}
872872
fn get_new() -> Option<pyo3::ffi::newfunc> {
873-
use pyo3::class::impl_::*;
873+
use pyo3::impl_::pyclass::*;
874874
let collector = PyClassImplCollector::<Self>::new();
875875
collector.new_impl()
876876
}
877877
fn get_alloc() -> Option<pyo3::ffi::allocfunc> {
878-
use pyo3::class::impl_::*;
878+
use pyo3::impl_::pyclass::*;
879879
let collector = PyClassImplCollector::<Self>::new();
880880
collector.alloc_impl()
881881
}
882882
fn get_free() -> Option<pyo3::ffi::freefunc> {
883-
use pyo3::class::impl_::*;
883+
use pyo3::impl_::pyclass::*;
884884
let collector = PyClassImplCollector::<Self>::new();
885885
collector.free_impl()
886886
}
887887
fn for_each_proto_slot(visitor: &mut dyn FnMut(&[pyo3::ffi::PyType_Slot])) {
888888
// Implementation which uses dtolnay specialization to load all slots.
889-
use pyo3::class::impl_::*;
889+
use pyo3::impl_::pyclass::*;
890890
let collector = PyClassImplCollector::<Self>::new();
891891
visitor(collector.object_protocol_slots());
892892
visitor(collector.number_protocol_slots());

guide/src/features.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ Most users should only need a single `#[pymethods]` per `#[pyclass]`. In additio
6565

6666
See [the `#[pyclass]` implementation details](class.md#implementation-details) for more information.
6767

68+
### `pyproto`
69+
70+
This feature enables the `#[pyproto]` macro, which is an alternative (older, soon-to-be-deprecated) to `#[pymethods]` for defining magic methods such as `__eq__`.
71+
72+
> This feature is enabled by default. To disable it, set `default-features = false` for the `pyo3` entry in your Cargo.toml.
73+
6874
### `nightly`
6975

7076
The `nightly` feature needs the nightly Rust compiler. This allows PyO3 to use Rust's unstable specialization feature to apply the following optimizations:

pyo3-macros-backend/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ pyo3-build-config = { path = "../pyo3-build-config", version = "0.15.1", feature
2222
version = "1"
2323
default-features = false
2424
features = ["derive", "parsing", "printing", "clone-impls", "full", "extra-traits"]
25+
26+
[features]
27+
pyproto = []

pyo3-macros-backend/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@
99
mod utils;
1010

1111
mod attributes;
12+
#[cfg(feature = "pyproto")]
1213
mod defs;
1314
mod deprecations;
1415
mod frompyobject;
1516
mod konst;
1617
mod method;
1718
mod module;
1819
mod params;
20+
#[cfg(feature = "pyproto")]
1921
mod proto_method;
2022
mod pyclass;
2123
mod pyfunction;
2224
mod pyimpl;
2325
mod pymethod;
26+
#[cfg(feature = "pyproto")]
2427
mod pyproto;
2528
mod wrap;
2629

@@ -29,6 +32,7 @@ pub use module::{process_functions_in_module, pymodule_impl, PyModuleOptions};
2932
pub use pyclass::{build_py_class, build_py_enum, PyClassArgs};
3033
pub use pyfunction::{build_py_function, PyFunctionOptions};
3134
pub use pyimpl::{build_py_methods, PyClassMethodsType};
35+
#[cfg(feature = "pyproto")]
3236
pub use pyproto::build_py_proto;
3337
pub use utils::get_doc;
3438
pub use wrap::{wrap_pyfunction_impl, wrap_pymodule_impl, WrapPyFunctionArgs};

pyo3-macros-backend/src/method.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -566,23 +566,23 @@ impl<'a> FnSpec<'a> {
566566
let doc = &self.doc;
567567
match self.convention {
568568
CallingConvention::Noargs => quote! {
569-
_pyo3::class::methods::PyMethodDef::noargs(
569+
_pyo3::impl_::pymethods::PyMethodDef::noargs(
570570
#python_name,
571-
_pyo3::class::methods::PyCFunction(#wrapper),
571+
_pyo3::impl_::pymethods::PyCFunction(#wrapper),
572572
#doc,
573573
)
574574
},
575575
CallingConvention::Fastcall => quote! {
576-
_pyo3::class::methods::PyMethodDef::fastcall_cfunction_with_keywords(
576+
_pyo3::impl_::pymethods::PyMethodDef::fastcall_cfunction_with_keywords(
577577
#python_name,
578-
_pyo3::class::methods::PyCFunctionFastWithKeywords(#wrapper),
578+
_pyo3::impl_::pymethods::PyCFunctionFastWithKeywords(#wrapper),
579579
#doc,
580580
)
581581
},
582582
CallingConvention::Varargs => quote! {
583-
_pyo3::class::methods::PyMethodDef::cfunction_with_keywords(
583+
_pyo3::impl_::pymethods::PyMethodDef::cfunction_with_keywords(
584584
#python_name,
585-
_pyo3::class::methods::PyCFunctionWithKeywords(#wrapper),
585+
_pyo3::impl_::pymethods::PyCFunctionWithKeywords(#wrapper),
586586
#doc,
587587
)
588588
},

pyo3-macros-backend/src/pyclass.rs

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -511,11 +511,11 @@ fn unit_variants_as_descriptors<'a>(
511511
.map(|var| gen_py_const(&cls_type, &variant_to_attribute(var)));
512512

513513
quote! {
514-
impl _pyo3::class::impl_::PyClassDescriptors<#cls>
515-
for _pyo3::class::impl_::PyClassImplCollector<#cls>
514+
impl _pyo3::impl_::pyclass::PyClassDescriptors<#cls>
515+
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
516516
{
517-
fn py_class_descriptors(self) -> &'static [_pyo3::class::methods::PyMethodDefType] {
518-
static METHODS: &[_pyo3::class::methods::PyMethodDefType] = &[#(#py_methods),*];
517+
fn py_class_descriptors(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
518+
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#py_methods),*];
519519
METHODS
520520
}
521521
}
@@ -574,11 +574,11 @@ fn impl_descriptors(
574574
.collect::<syn::Result<_>>()?;
575575

576576
Ok(quote! {
577-
impl _pyo3::class::impl_::PyClassDescriptors<#cls>
578-
for _pyo3::class::impl_::PyClassImplCollector<#cls>
577+
impl _pyo3::impl_::pyclass::PyClassDescriptors<#cls>
578+
for _pyo3::impl_::pyclass::PyClassImplCollector<#cls>
579579
{
580-
fn py_class_descriptors(self) -> &'static [_pyo3::class::methods::PyMethodDefType] {
581-
static METHODS: &[_pyo3::class::methods::PyMethodDefType] = &[#(#py_methods),*];
580+
fn py_class_descriptors(self) -> &'static [_pyo3::impl_::pymethods::PyMethodDefType] {
581+
static METHODS: &[_pyo3::impl_::pymethods::PyMethodDefType] = &[#(#py_methods),*];
582582
METHODS
583583
}
584584
}
@@ -676,7 +676,7 @@ impl<'a> PyClassImplsBuilder<'a> {
676676
};
677677

678678
let base_nativetype = if attr.has_extends {
679-
quote! { <Self::BaseType as _pyo3::class::impl_::PyClassBaseType>::BaseNativeType }
679+
quote! { <Self::BaseType as _pyo3::impl_::pyclass::PyClassBaseType>::BaseNativeType }
680680
} else {
681681
quote! { _pyo3::PyAny }
682682
};
@@ -749,13 +749,13 @@ impl<'a> PyClassImplsBuilder<'a> {
749749
};
750750

751751
let thread_checker = if self.attr.has_unsendable {
752-
quote! { _pyo3::class::impl_::ThreadCheckerImpl<#cls> }
752+
quote! { _pyo3::impl_::pyclass::ThreadCheckerImpl<#cls> }
753753
} else if self.attr.has_extends {
754754
quote! {
755-
_pyo3::class::impl_::ThreadCheckerInherited<#cls, <#cls as _pyo3::class::impl_::PyClassImpl>::BaseType>
755+
_pyo3::impl_::pyclass::ThreadCheckerInherited<#cls, <#cls as _pyo3::impl_::pyclass::PyClassImpl>::BaseType>
756756
}
757757
} else {
758-
quote! { _pyo3::class::impl_::ThreadCheckerStub<#cls> }
758+
quote! { _pyo3::impl_::pyclass::ThreadCheckerStub<#cls> }
759759
};
760760

761761
let (for_each_py_method, methods_protos, inventory, inventory_class) = match self
@@ -775,22 +775,51 @@ impl<'a> PyClassImplsBuilder<'a> {
775775
);
776776
(
777777
quote! {
778-
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::class::impl_::PyClassImpl>::Inventory>() {
779-
visitor(_pyo3::class::impl_::PyClassInventory::methods(inventory));
778+
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
779+
visitor(_pyo3::impl_::pyclass::PyClassInventory::methods(inventory));
780780
}
781781
},
782782
quote! {
783-
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::class::impl_::PyClassImpl>::Inventory>() {
784-
visitor(_pyo3::class::impl_::PyClassInventory::slots(inventory));
783+
for inventory in _pyo3::inventory::iter::<<Self as _pyo3::impl_::pyclass::PyClassImpl>::Inventory>() {
784+
visitor(_pyo3::impl_::pyclass::PyClassInventory::slots(inventory));
785785
}
786786
},
787787
Some(quote! { type Inventory = #inventory_class_name; }),
788788
Some(define_inventory_class(&inventory_class_name)),
789789
)
790790
}
791791
};
792+
793+
let pyproto_method_visitors = if cfg!(feature = "pyproto") {
794+
Some(quote! {
795+
visitor(collector.object_protocol_methods());
796+
visitor(collector.async_protocol_methods());
797+
visitor(collector.descr_protocol_methods());
798+
visitor(collector.mapping_protocol_methods());
799+
visitor(collector.number_protocol_methods());
800+
})
801+
} else {
802+
None
803+
};
804+
805+
let pyproto_proto_visitors = if cfg!(feature = "pyproto") {
806+
Some(quote! {
807+
visitor(collector.object_protocol_slots());
808+
visitor(collector.number_protocol_slots());
809+
visitor(collector.iter_protocol_slots());
810+
visitor(collector.gc_protocol_slots());
811+
visitor(collector.descr_protocol_slots());
812+
visitor(collector.mapping_protocol_slots());
813+
visitor(collector.sequence_protocol_slots());
814+
visitor(collector.async_protocol_slots());
815+
visitor(collector.buffer_protocol_slots());
816+
})
817+
} else {
818+
None
819+
};
820+
792821
quote! {
793-
impl _pyo3::class::impl_::PyClassImpl for #cls {
822+
impl _pyo3::impl_::pyclass::PyClassImpl for #cls {
794823
const DOC: &'static str = #doc;
795824
const IS_GC: bool = #is_gc;
796825
const IS_BASETYPE: bool = #is_basetype;
@@ -802,48 +831,36 @@ impl<'a> PyClassImplsBuilder<'a> {
802831
#inventory
803832

804833
fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::class::PyMethodDefType])) {
805-
use _pyo3::class::impl_::*;
834+
use _pyo3::impl_::pyclass::*;
806835
let collector = PyClassImplCollector::<Self>::new();
807836
#for_each_py_method;
808837
visitor(collector.py_class_descriptors());
809-
visitor(collector.object_protocol_methods());
810-
visitor(collector.async_protocol_methods());
811-
visitor(collector.descr_protocol_methods());
812-
visitor(collector.mapping_protocol_methods());
813-
visitor(collector.number_protocol_methods());
838+
#pyproto_method_visitors
814839
}
815840
fn get_new() -> ::std::option::Option<_pyo3::ffi::newfunc> {
816-
use _pyo3::class::impl_::*;
841+
use _pyo3::impl_::pyclass::*;
817842
let collector = PyClassImplCollector::<Self>::new();
818843
collector.new_impl()
819844
}
820845
fn get_alloc() -> ::std::option::Option<_pyo3::ffi::allocfunc> {
821-
use _pyo3::class::impl_::*;
846+
use _pyo3::impl_::pyclass::*;
822847
let collector = PyClassImplCollector::<Self>::new();
823848
collector.alloc_impl()
824849
}
825850
fn get_free() -> ::std::option::Option<_pyo3::ffi::freefunc> {
826-
use _pyo3::class::impl_::*;
851+
use _pyo3::impl_::pyclass::*;
827852
let collector = PyClassImplCollector::<Self>::new();
828853
collector.free_impl()
829854
}
830855

831856
fn for_each_proto_slot(visitor: &mut dyn ::std::ops::FnMut(&[_pyo3::ffi::PyType_Slot])) {
832857
// Implementation which uses dtolnay specialization to load all slots.
833-
use _pyo3::class::impl_::*;
858+
use _pyo3::impl_::pyclass::*;
834859
let collector = PyClassImplCollector::<Self>::new();
835860
// This depends on Python implementation detail;
836861
// an old slot entry will be overriden by newer ones.
837862
visitor(collector.py_class_default_slots());
838-
visitor(collector.object_protocol_slots());
839-
visitor(collector.number_protocol_slots());
840-
visitor(collector.iter_protocol_slots());
841-
visitor(collector.gc_protocol_slots());
842-
visitor(collector.descr_protocol_slots());
843-
visitor(collector.mapping_protocol_slots());
844-
visitor(collector.sequence_protocol_slots());
845-
visitor(collector.async_protocol_slots());
846-
visitor(collector.buffer_protocol_slots());
863+
#pyproto_proto_visitors
847864
#methods_protos
848865
}
849866

@@ -861,7 +878,7 @@ impl<'a> PyClassImplsBuilder<'a> {
861878

862879
self.attr.freelist.as_ref().map_or(quote!{}, |freelist| {
863880
quote! {
864-
impl _pyo3::class::impl_::PyClassWithFreeList for #cls {
881+
impl _pyo3::impl_::pyclass::PyClassWithFreeList for #cls {
865882
#[inline]
866883
fn get_free_list(_py: _pyo3::Python<'_>) -> &mut _pyo3::impl_::freelist::FreeList<*mut _pyo3::ffi::PyObject> {
867884
static mut FREELIST: *mut _pyo3::impl_::freelist::FreeList<*mut _pyo3::ffi::PyObject> = 0 as *mut _;
@@ -875,17 +892,17 @@ impl<'a> PyClassImplsBuilder<'a> {
875892
}
876893
}
877894

878-
impl _pyo3::class::impl_::PyClassAllocImpl<#cls> for _pyo3::class::impl_::PyClassImplCollector<#cls> {
895+
impl _pyo3::impl_::pyclass::PyClassAllocImpl<#cls> for _pyo3::impl_::pyclass::PyClassImplCollector<#cls> {
879896
#[inline]
880897
fn alloc_impl(self) -> ::std::option::Option<_pyo3::ffi::allocfunc> {
881-
::std::option::Option::Some(_pyo3::class::impl_::alloc_with_freelist::<#cls>)
898+
::std::option::Option::Some(_pyo3::impl_::pyclass::alloc_with_freelist::<#cls>)
882899
}
883900
}
884901

885-
impl _pyo3::class::impl_::PyClassFreeImpl<#cls> for _pyo3::class::impl_::PyClassImplCollector<#cls> {
902+
impl _pyo3::impl_::pyclass::PyClassFreeImpl<#cls> for _pyo3::impl_::pyclass::PyClassImplCollector<#cls> {
886903
#[inline]
887904
fn free_impl(self) -> ::std::option::Option<_pyo3::ffi::freefunc> {
888-
::std::option::Option::Some(_pyo3::class::impl_::free_with_freelist::<#cls>)
905+
::std::option::Option::Some(_pyo3::impl_::pyclass::free_with_freelist::<#cls>)
889906
}
890907
}
891908
}
@@ -928,7 +945,7 @@ fn define_inventory_class(inventory_class_name: &syn::Ident) -> TokenStream {
928945
}
929946
}
930947

931-
impl _pyo3::class::impl_::PyClassInventory for #inventory_class_name {
948+
impl _pyo3::impl_::pyclass::PyClassInventory for #inventory_class_name {
932949
fn methods(&'static self) -> &'static [_pyo3::class::PyMethodDefType] {
933950
self.methods
934951
}

0 commit comments

Comments
 (0)