Skip to content

Commit a584ce1

Browse files
committed
release py objects aftre use
1 parent 84f5578 commit a584ce1

18 files changed

+186
-66
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ log = "0.3"
2626
libc = "0.2"
2727
num-traits = "0.1"
2828
pyo3cls = { path = "pyo3cls" }
29+
backtrace = "0.3"
2930

3031
[build-dependencies]
3132
regex = "0.2"

pyo3cls/src/py_class.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,11 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
5353
let ptr = <#cls as _pyo3::python::ToPyPointer>::as_ptr(self);
5454
let repr = unsafe {
5555
_pyo3::PyString::downcast_from_ptr(
56-
py, _pyo3::ffi::PyObject_Repr(ptr))
57-
.map_err(|_| std::fmt::Error)?
56+
py, _pyo3::ffi::PyObject_Repr(ptr)).map_err(|_| std::fmt::Error)?
5857
};
59-
f.write_str(&repr.to_string_lossy(py))
58+
let result = f.write_str(&repr.to_string_lossy(py));
59+
py.release(repr);
60+
result
6061
}
6162
}
6263

@@ -66,10 +67,11 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
6667
let ptr = <#cls as _pyo3::python::ToPyPointer>::as_ptr(self);
6768
let str_obj = unsafe {
6869
_pyo3::PyString::downcast_from_ptr(
69-
py, _pyo3::ffi::PyObject_Str(ptr))
70-
.map_err(|_| std::fmt::Error)?
70+
py, _pyo3::ffi::PyObject_Str(ptr)).map_err(|_| std::fmt::Error)?
7171
};
72-
f.write_str(&str_obj.to_string_lossy(py))
72+
let result = f.write_str(&str_obj.to_string_lossy(py));
73+
py.release(str_obj);
74+
result
7375
}
7476
}
7577
})

pyo3cls/src/py_method.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,23 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens
4747
{
4848
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
4949
_pyo3::callback::cb_meth(LOCATION, |py| {
50+
//println!("METH {:?} =====: {:?} {:?} {:?}", LOCATION, slf, args, kwargs);
5051
let slf = #cls::from_borrowed_ptr(slf);
5152
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
5253
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
5354

54-
let result: #output = {
55-
#body
55+
let result = {
56+
let result: #output = {
57+
#body
58+
};
59+
_pyo3::callback::cb_convert(
60+
_pyo3::callback::PyObjectCallbackConverter, py, result)
5661
};
62+
py.release(kwargs);
63+
py.release(args);
5764
py.release(slf);
58-
_pyo3::callback::cb_convert(
59-
_pyo3::callback::PyObjectCallbackConverter, py, result)
65+
//println!("METH {:?} =====", LOCATION);
66+
result
6067
})
6168
}
6269
}
@@ -237,16 +244,24 @@ fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
237244
];
238245

239246
let mut output = [#(#placeholders),*];
240-
match _pyo3::argparse::parse_args(py, Some(LOCATION), PARAMS, &args,
241-
kwargs.as_ref(), #accept_args, #accept_kwargs,
242-
&mut output) {
247+
let result = match _pyo3::argparse::parse_args(
248+
py, Some(LOCATION), PARAMS, &args,
249+
kwargs.as_ref(), #accept_args, #accept_kwargs, &mut output)
250+
{
243251
Ok(_) => {
244252
let mut _iter = output.iter();
245253

246254
#body
247255
},
248256
Err(err) => Err(err)
257+
};
258+
for p in output.iter_mut() {
259+
if let Some(ob) = p.take() {
260+
py.release(ob);
261+
}
249262
}
263+
264+
result
250265
}
251266
}
252267

@@ -260,7 +275,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
260275

261276
if spec.is_args(&name) {
262277
quote! {
263-
match <#ty as _pyo3::FromPyObject>::extract(py, &args.into())
278+
match <#ty as _pyo3::FromPyObject>::extract(py, args.as_ref())
264279
{
265280
Ok(#name) => {
266281
#body

pyo3cls/src/py_ptr.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,13 @@ pub fn build_ptr(cls: syn::Ident, ast: &mut syn::DeriveInput) -> Tokens {
2323
type Target = #ptr;
2424

2525
fn to_inst_ptr(&self) -> #ptr {
26-
let token = _pyo3::PyObjectWithToken::token(self);
27-
let ptr = self.as_ptr();
28-
29-
#ptr(unsafe{_pyo3::PyPtr::from_borrowed_ptr(ptr)})
26+
#ptr(unsafe{_pyo3::PyPtr::from_borrowed_ptr(self.as_ptr())})
3027
}
3128
unsafe fn from_owned_ptr(ptr: *mut _pyo3::ffi::PyObject) -> #ptr {
32-
std::mem::transmute(ptr)
29+
#ptr(_pyo3::PyPtr::from_owned_ptr(ptr))
3330
}
3431
unsafe fn from_borrowed_ptr(ptr: *mut _pyo3::ffi::PyObject) -> #ptr {
35-
_pyo3::ffi::Py_INCREF(ptr);
36-
std::mem::transmute(ptr)
32+
#ptr(_pyo3::PyPtr::from_borrowed_ptr(ptr))
3733
}
3834
}
3935

@@ -64,6 +60,11 @@ pub fn build_ptr(cls: syn::Ident, ast: &mut syn::DeriveInput) -> Tokens {
6460
&self.0
6561
}
6662
}
63+
impl std::ops::DerefMut for #ptr {
64+
fn deref_mut(&mut self) -> &mut Self::Target {
65+
&mut self.0
66+
}
67+
}
6768
impl _pyo3::PyClone for #ptr {
6869
fn clone_ref(&self, _py: _pyo3::Python) -> #ptr {
6970
#ptr(unsafe{ _pyo3::PyPtr::from_borrowed_ptr(self.as_ptr()) })

src/argparse.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ pub fn parse_args<'p>(py: Python<'p>,
7272
if i < nargs {
7373
return Err(err::PyErr::new::<exc::TypeError, _>(
7474
py,
75-
format!("Argument given by name ('{}') and position ({})",
76-
p.name, i+1)));
75+
format!("Argument given by name ('{}') and position ({})", p.name, i+1)));
7776
}
7877
},
7978
None => {
@@ -347,6 +346,8 @@ macro_rules! py_argparse_raw {
347346
let args: $crate::PyTuple = $crate::PyTuple::from_borrowed_ptr($py, $args);
348347
let kwargs: Option<$crate::PyDict> = $crate::argparse::get_kwargs($py, $kwargs);
349348
let ret = py_argparse_impl!($py, $fname, &args, kwargs.as_ref(), $body, $plist);
349+
$py.release(kwargs);
350+
$py.release(args);
350351
ret
351352
}};
352353
}

src/conversion.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ impl<'source, T> FromPyObject<'source> for &'source T
161161
}
162162
}
163163

164-
impl <'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source> {
164+
impl <'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source>
165+
{
165166
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self>
166167
{
167168
if obj.as_ptr() == unsafe { ffi::Py_None() } {

src/err.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,13 @@ impl PyErr {
339339
ptraceback: self.ptraceback.clone_ref(py),
340340
}
341341
}
342+
343+
pub fn release(self, py: Python) {
344+
let PyErr { ptype, pvalue, ptraceback } = self;
345+
py.release(ptype);
346+
py.release(pvalue);
347+
py.release(ptraceback);
348+
}
342349
}
343350

344351
/// Converts `PyDowncastError` to Python `TypeError`.

src/fmt.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ impl fmt::Debug for PyPtr {
1414
// TODO: we shouldn't use fmt::Error when repr() fails
1515
let r = self.as_object(py);
1616
let repr_obj = try!(r.repr(py).map_err(|_| fmt::Error));
17-
f.write_str(&repr_obj.to_string_lossy(py))
17+
let result = f.write_str(&repr_obj.to_string_lossy(py));
18+
py.release(repr_obj);
19+
result
1820
}
1921
}
2022

@@ -25,7 +27,9 @@ impl fmt::Display for PyPtr {
2527

2628
// TODO: we shouldn't use fmt::Error when repr() fails
2729
let r = self.as_object(py);
28-
let repr_obj = try!(r.str(py).map_err(|_| fmt::Error));
29-
f.write_str(&repr_obj.to_string_lossy(py))
30+
let str_obj = try!(r.str(py).map_err(|_| fmt::Error));
31+
let result = f.write_str(&str_obj.to_string_lossy(py));
32+
py.release(str_obj);
33+
result
3034
}
3135
}

src/function.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,11 @@ macro_rules! py_fn_impl {
115115
-> *mut $crate::ffi::PyObject
116116
{
117117
$crate::callback::handle(
118-
stringify!($f), $crate::callback::PyObjectCallbackConverter,
119-
|py| {
118+
stringify!($f), $crate::callback::PyObjectCallbackConverter, |py|
119+
{
120120
py_argparse_raw!(py, Some(stringify!($f)), args, kwargs,
121-
[ $( { $pname : $ptype = $detail } )* ]
122-
{
123-
$f(py $(, $pname )* )
124-
})
121+
[ $( { $pname : $ptype = $detail } )* ]
122+
{ $f(py $(, $pname )* ) })
125123
})
126124
}
127125
unsafe {

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
//! ```
5555
5656
extern crate libc;
57+
extern crate backtrace;
5758
#[macro_use] extern crate log;
5859

5960
#[allow(unused_imports)]

src/objects/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,30 +201,34 @@ macro_rules! pyobject_nativetype(
201201
{
202202
use $crate::python::PyDowncastInto;
203203

204-
let gil = $crate::Python::acquire_gil();
205-
let py = gil.python();
204+
let gil = $crate::Python::acquire_gil();
205+
let py = gil.python();
206206

207207
let s = unsafe { $crate::PyString::downcast_from_ptr(
208208
py, $crate::ffi::PyObject_Repr(
209209
$crate::python::ToPyPointer::as_ptr(self))) };
210210
let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
211-
f.write_str(&repr_obj.to_string_lossy(py))
211+
let result = f.write_str(&repr_obj.to_string_lossy(py));
212+
py.release(repr_obj);
213+
result
212214
}
213215
}
214216

215217
impl $crate::std::fmt::Display for $name {
216218
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
217219
-> Result<(), $crate::std::fmt::Error>
218220
{
219-
let gil = $crate::Python::acquire_gil();
220-
let py = gil.python();
221+
let gil = $crate::Python::acquire_gil();
222+
let py = gil.python();
221223
use $crate::python::PyDowncastInto;
222224

223225
let s = unsafe { $crate::PyString::downcast_from_ptr(
224226
py, $crate::ffi::PyObject_Str(
225227
$crate::python::ToPyPointer::as_ptr(self))) };
226228
let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
227-
f.write_str(&str_obj.to_string_lossy(py))
229+
let result = f.write_str(&str_obj.to_string_lossy(py));
230+
py.release(str_obj);
231+
result
228232
}
229233
}
230234
);

src/objects/module.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,16 @@ impl<'p> PyModule {
112112
} else {
113113
// automatically initialize the class
114114
let name = self.name(py)?;
115-
::typeob::initialize_type::<T>(py, Some(name), type_name, ty)
116-
.expect(
117-
format!("An error occurred while initializing class {}",
118-
<T as ::typeob::PyTypeInfo>::type_name()).as_ref());
115+
let to = ::typeob::initialize_type::<T>(py, Some(name), type_name, ty)
116+
.expect(format!("An error occurred while initializing class {}",
117+
<T as ::typeob::PyTypeInfo>::type_name()).as_ref());
118+
py.release(to);
119119
unsafe { PyType::from_type_ptr(py, ty) }
120120
};
121121

122-
self.setattr(py, type_name, ty)
122+
self.setattr(py, type_name, &ty)?;
123+
124+
py.release(ty);
125+
Ok(())
123126
}
124127
}

src/objects/object.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ impl PyObject {
111111

112112
pub fn get_refcnt(&self) -> isize {
113113
unsafe { ffi::Py_REFCNT(self.0.as_ptr()) }
114+
}
114115

116+
#[inline]
117+
pub unsafe fn drop_ref(&mut self) {
118+
self.0.drop_ref();
115119
}
116120
}
117121

src/objects/tuple.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ impl PyTuple {
6767
}
6868
}
6969

70+
/// Gets the item at the specified index.
71+
/// Panics if the index is out of range.
72+
pub fn into_item(self, py: Python, index: usize) -> PyObject {
73+
assert!(index < self.len(py));
74+
let result = unsafe {
75+
PyObject::from_borrowed_ptr(
76+
py, ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
77+
};
78+
py.release(self);
79+
result
80+
}
81+
7082
#[inline]
7183
pub fn as_slice<'a>(&'a self, py: Python) -> &'a [PyObject] {
7284
// This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
@@ -95,7 +107,11 @@ impl IntoPyTuple for PyTuple {
95107

96108
impl<'a> IntoPyTuple for &'a str {
97109
fn into_tuple(self, py: Python) -> PyTuple {
98-
PyTuple::new(py, &[py_coerce_expr!(self.to_object(py))])
110+
unsafe {
111+
let ptr = ffi::PyTuple_New(1);
112+
ffi::PyTuple_SetItem(ptr, 0, self.into_object(py).into_ptr());
113+
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr))
114+
}
99115
}
100116
}
101117

@@ -109,24 +125,31 @@ fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr
109125
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => {
110126
impl <$($T: ToPyObject),+> ToPyObject for ($($T,)+) {
111127
fn to_object(&self, py: Python) -> PyObject {
112-
PyTuple::new(py, &[
113-
$(py_coerce_expr!(self.$n.to_object(py)),)+
114-
]).into()
128+
unsafe {
129+
let ptr = ffi::PyTuple_New($length);
130+
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.to_object(py).into_ptr());)+;
131+
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr)).into()
132+
}
115133
}
116134
}
117135
impl <$($T: IntoPyObject),+> IntoPyObject for ($($T,)+) {
118136
fn into_object(self, py: Python) -> PyObject {
119-
PyTuple::new(py, &[
120-
$(py_coerce_expr!(self.$n.into_object(py)),)+
121-
]).into()
137+
unsafe {
138+
let ptr = ffi::PyTuple_New($length);
139+
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_object(py).into_ptr());)+;
140+
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr)).into()
141+
}
122142
}
123143
}
124144

125145
impl <$($T: IntoPyObject),+> IntoPyTuple for ($($T,)+) {
126146
fn into_tuple(self, py: Python) -> PyTuple {
127-
PyTuple::new(py, &[
128-
$(py_coerce_expr!(self.$n.into_object(py)),)+
129-
])
147+
unsafe {
148+
let ptr = ffi::PyTuple_New($length);
149+
$(py_coerce_expr!(
150+
ffi::PyTuple_SetItem(ptr, $n, self.$n.into_object(py).into_ptr()));)+;
151+
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr))
152+
}
130153
}
131154
}
132155

@@ -232,7 +255,7 @@ mod test {
232255
fn test_len() {
233256
let gil = Python::acquire_gil();
234257
let py = gil.python();
235-
let tuple = PyTuple::downcast_into(py, (1, 2, 3).to_object(py).into_object(py)).unwrap();
258+
let tuple = PyTuple::downcast_into(py, (1, 2, 3).to_object(py)).unwrap();
236259
assert_eq!(3, tuple.len(py));
237260
assert_eq!((1, 2, 3), tuple.into_object(py).extract(py).unwrap());
238261
}

0 commit comments

Comments
 (0)