From cf689840efe03b5aed71eab6f2e8497a9c1a5863 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Wed, 24 Apr 2019 15:58:26 +0900 Subject: [PATCH] Allow lifetime in pymethods --- CHANGELOG.md | 1 + pyo3-derive-backend/src/pymethod.rs | 14 ++++++++++++-- tests/test_methods.rs | 30 ++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f72725516df..2150a562943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * PyPy support by omerbenamram in [#393](https://github.com/PyO3/pyo3/pull/393) * Have `PyModule` generate an index of its members (`__all__` list). * Allow `slf: PyRef` for pyclass(#419) + * Allow to use lifetime specifiers in `pymethods` ### Changed diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index d68cc39dec9..994ab003ae6 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -40,8 +40,18 @@ pub fn gen_py_method( } fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) { - if !sig.decl.generics.params.is_empty() { - panic!("python method can not be generic: {:?}", name); + for param in &sig.decl.generics.params { + match param { + syn::GenericParam::Lifetime(_) => {} + syn::GenericParam::Type(_) => panic!( + "A Python method can't have a generic type parameter: {}", + name + ), + syn::GenericParam::Const(_) => panic!( + "A Python method can't have a const generic parameter: {}", + name + ), + } } } diff --git a/tests/test_methods.rs b/tests/test_methods.rs index db1759adfa4..0be9b7d3f07 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -1,5 +1,5 @@ use pyo3::prelude::*; -use pyo3::types::{IntoPyDict, PyDict, PyString, PyTuple, PyType}; +use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyString, PyTuple, PyType}; use pyo3::PyRawObject; #[macro_use] @@ -306,3 +306,31 @@ fn meth_doc() { ) .unwrap(); } + +#[pyclass] +struct MethodWithLifeTime {} + +#[pymethods] +impl MethodWithLifeTime { + fn set_to_list<'py>(&self, py: Python<'py>, set: &'py PySet) -> PyResult<&'py PyList> { + let mut items = vec![]; + for _ in 0..set.len() { + items.push(set.pop().unwrap()); + } + let list = PyList::new(py, items); + list.sort()?; + Ok(list) + } +} + +#[test] +fn method_with_lifetime() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let obj = PyRef::new(py, MethodWithLifeTime {}).unwrap(); + py_run!( + py, + obj, + "assert obj.set_to_list(set((1, 2, 3))) == [1, 2, 3]" + ); +}