diff --git a/CHANGELOG.md b/CHANGELOG.md index 9722cd2d..6929e41a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Clear error indicator when the exception is handled on the Rust side. [#719](https://github.com/PyO3/pyo3/pull/719) * Usage of raw identifiers with `#[pyo3(set)]`. [#745](https://github.com/PyO3/pyo3/pull/745) * Usage of `PyObject` with `#[pyo3(get)]`. [#760](https://github.com/PyO3/pyo3/pull/760) +* `#[pymethods]` used in conjunction with `#[cfg]`. #[769](https://github.com/PyO3/pyo3/pull/769) ### Removed diff --git a/pyo3-derive-backend/src/pyimpl.rs b/pyo3-derive-backend/src/pyimpl.rs index 89e09c53..e62df4f3 100644 --- a/pyo3-derive-backend/src/pyimpl.rs +++ b/pyo3-derive-backend/src/pyimpl.rs @@ -21,11 +21,12 @@ pub fn build_py_methods(ast: &mut syn::ItemImpl) -> syn::Result { } pub fn impl_methods(ty: &syn::Type, impls: &mut Vec) -> syn::Result { - // get method names in impl block let mut methods = Vec::new(); + let mut cfg_attributes = Vec::new(); for iimpl in impls.iter_mut() { if let syn::ImplItem::Method(ref mut meth) = iimpl { methods.push(pymethod::gen_py_method(ty, &mut meth.sig, &mut meth.attrs)?); + cfg_attributes.push(get_cfg_attributes(&meth.attrs)); } } @@ -33,8 +34,18 @@ pub fn impl_methods(ty: &syn::Type, impls: &mut Vec) -> syn::Resu pyo3::inventory::submit! { #![crate = pyo3] { type TyInventory = <#ty as pyo3::class::methods::PyMethodsInventoryDispatch>::InventoryType; - ::new(&[#(#methods),*]) + ::new(&[#( + #(#cfg_attributes)* + #methods + ),*]) } } }) } + +fn get_cfg_attributes(attrs: &[syn::Attribute]) -> Vec<&syn::Attribute> { + attrs + .iter() + .filter(|attr| attr.path.is_ident("cfg")) + .collect() +} diff --git a/tests/test_methods.rs b/tests/test_methods.rs index 153bc2b5..a23942da 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -402,3 +402,54 @@ fn method_with_lifetime() { "assert obj.set_to_list(set((1, 2, 3))) == [1, 2, 3]" ); } + +#[pyclass] +#[cfg(unix)] +struct CfgStruct {} + +#[pyclass] +#[cfg(not(unix))] +struct CfgStruct {} + +#[pymethods] +#[cfg(unix)] +impl CfgStruct { + fn unix_method(&self) -> &str { + "unix" + } + + #[cfg(not(unix))] + fn never_compiled_method(&self) {} +} + +#[pymethods] +#[cfg(not(unix))] +impl CfgStruct { + fn not_unix_method(&self) -> &str { + "not unix" + } + + #[cfg(unix)] + fn never_compiled_method(&self) {} +} + +#[test] +fn test_cfg_attrs() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let inst = Py::new(py, CfgStruct {}).unwrap(); + + #[cfg(unix)] + { + py_assert!(py, inst, "inst.unix_method() == 'unix'"); + py_assert!(py, inst, "not hasattr(inst, 'not_unix_method')"); + } + + #[cfg(not(unix))] + { + py_assert!(py, inst, "not hasattr(inst, 'unix_method')"); + py_assert!(py, inst, "inst.not_unix_method() == 'not unix'"); + } + + py_assert!(py, inst, "not hasattr(inst, 'never_compiled_method')"); +}