fix ptr borrowing PyTuple::get_item

This commit is contained in:
Nikolay Kim 2017-05-29 18:36:44 -07:00
parent 4232caf3a3
commit 61b8bd0695
12 changed files with 68 additions and 35 deletions

View file

@ -47,7 +47,7 @@ macro_rules! py_exception {
($module: ident, $name: ident, $base: ty) => { ($module: ident, $name: ident, $base: ty) => {
pub struct $name; pub struct $name;
pyobject_nativetype!($name); // pyobject_nativetype!($name);
impl $name { impl $name {
pub fn new<'p, T: $crate::ToPyObject>(py: $crate::Python<'p>, args: T) -> $crate::PyErr { pub fn new<'p, T: $crate::ToPyObject>(py: $crate::Python<'p>, args: T) -> $crate::PyErr {
@ -59,13 +59,14 @@ macro_rules! py_exception {
#[inline] #[inline]
fn type_object<'p>(py: $crate::Python<'p>) -> $crate::PyType<'p> { fn type_object<'p>(py: $crate::Python<'p>) -> $crate::PyType<'p> {
unsafe { unsafe {
#[allow(non_upper_case_globals)]
static mut type_object: *mut $crate::ffi::PyTypeObject = 0 as *mut $crate::ffi::PyTypeObject; static mut type_object: *mut $crate::ffi::PyTypeObject = 0 as *mut $crate::ffi::PyTypeObject;
if type_object.is_null() { if type_object.is_null() {
type_object = $crate::PyErr::new_type( type_object = $crate::PyErr::new_type(
py, py,
concat!(stringify!($module), ".", stringify!($name)), concat!(stringify!($module), ".", stringify!($name)),
Some(py.get_type::<$base>()), None); Some(py.get_type::<$base>()), None).as_type_ptr();
} }
$crate::PyType::from_type_ptr(py, type_object) $crate::PyType::from_type_ptr(py, type_object)
@ -133,7 +134,7 @@ impl PyErr {
/// `base` can be an existing exception type to subclass, or a tuple of classes /// `base` can be an existing exception type to subclass, or a tuple of classes
/// `dict` specifies an optional dictionary of class variables and methods /// `dict` specifies an optional dictionary of class variables and methods
pub fn new_type<'p>(py: Python<'p>, name: &str, pub fn new_type<'p>(py: Python<'p>, name: &str,
base: Option<PyObject<'p>>, dict: Option<PyObject<'p>>) -> PyType<'p> { base: Option<PyType<'p>>, dict: Option<PyObject<'p>>) -> PyType<'p> {
let base: *mut ffi::PyObject = match base { let base: *mut ffi::PyObject = match base {
None => std::ptr::null_mut(), None => std::ptr::null_mut(),
Some(obj) => obj.into_ptr() Some(obj) => obj.into_ptr()
@ -334,17 +335,6 @@ impl PyErr {
} }
} }
/*impl PyClone for PyErr {
fn clone_ref(&self, py: Python) -> PyErr {
PyErr {
ptype: self.ptype.clone_ref(py),
pvalue: self.pvalue.clone_ref(py),
ptraceback: self.ptraceback.clone_ref(py)
}
}
}*/
/// Converts `PyDowncastError` to Python `TypeError`. /// Converts `PyDowncastError` to Python `TypeError`.
impl <'p> std::convert::From<PyDowncastError<'p>> for PyErr { impl <'p> std::convert::From<PyDowncastError<'p>> for PyErr {
fn from(err: PyDowncastError<'p>) -> PyErr { fn from(err: PyDowncastError<'p>) -> PyErr {

View file

@ -90,7 +90,7 @@ macro_rules! py_method_def {
/// let gil = Python::acquire_gil(); /// let gil = Python::acquire_gil();
/// let py = gil.python(); /// let py = gil.python();
/// let dict = PyDict::new(py); /// let dict = PyDict::new(py);
/// dict.set_item(py, "multiply", py_fn!(py, multiply(lhs: i32, rhs: i32))).unwrap(); /// dict.set_item("multiply", py_fn!(py, multiply(lhs: i32, rhs: i32))).unwrap();
/// py.run("print(multiply(6, 7))", None, Some(&dict)).unwrap(); /// py.run("print(multiply(6, 7))", None, Some(&dict)).unwrap();
/// } /// }
/// ``` /// ```

View file

@ -42,11 +42,11 @@
//! //!
//! fn hello(py: Python) -> PyResult<()> { //! fn hello(py: Python) -> PyResult<()> {
//! let sys = py.import("sys")?; //! let sys = py.import("sys")?;
//! let version: String = sys.get(py, "version")?.extract(py)?; //! let version: String = sys.get("version")?.extract()?;
//! //!
//! let locals = PyDict::new(py); //! let locals = PyDict::new(py);
//! locals.set_item("os", py.import("os")?)?; //! locals.set_item("os", py.import("os")?)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?; //! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract()?;
//! //!
//! println!("Hello {}, I'm Python {}", user, version); //! println!("Hello {}, I'm Python {}", user, version);
//! Ok(()) //! Ok(())
@ -145,14 +145,14 @@ pub use std::os::raw::*;
/// use pyo3::{Python, PyResult, PyObject}; /// use pyo3::{Python, PyResult, PyObject};
/// ///
/// py_module_init!(hello, PyInit_hello, |py, m| { /// py_module_init!(hello, PyInit_hello, |py, m| {
/// m.add(py, "__doc__", "Module documentation string")?; /// m.add("__doc__", "Module documentation string")?;
/// m.add(py, "run", py_fn!(py, run()))?; /// m.add("run", py_fn!(py, run()))?;
/// Ok(()) /// Ok(())
/// }); /// });
/// ///
/// fn run(py: Python) -> PyResult<PyObject> { /// fn run(py: Python) -> PyResult<PyObject> {
/// println!("Rust says: Hello Python!"); /// println!("Rust says: Hello Python!");
/// Ok(py.None()) /// Ok(py.None().into_object(py))
/// } /// }
/// # fn main() {} /// # fn main() {}
/// ``` /// ```

View file

@ -119,6 +119,8 @@ pub trait ObjectProtocol<'p> {
// /// This is typically a new iterator but if the argument // /// This is typically a new iterator but if the argument
// /// is an iterator, this returns itself. // /// is an iterator, this returns itself.
// fn iter<'a>(&'a self) -> PyResult<Py<'p, ::objects::PyIterator<'a>>>; // fn iter<'a>(&'a self) -> PyResult<Py<'p, ::objects::PyIterator<'a>>>;
fn get_refcnt(&self) -> isize;
} }
@ -371,6 +373,10 @@ impl<'p, T> ObjectProtocol<'p> for T where T: PythonObjectWithGilToken<'p> + ToP
//pub fn iter<'a>(&'a self) -> PyResult<Py<'p, ::objects::PyIterator<'a>>> { //pub fn iter<'a>(&'a self) -> PyResult<Py<'p, ::objects::PyIterator<'a>>> {
// Py::from_owned_ptr_or_err(self.py(), ffi::PyObject_GetIter(self.as_ptr())) // Py::from_owned_ptr_or_err(self.py(), ffi::PyObject_GetIter(self.as_ptr()))
//} //}
fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
}
} }

View file

@ -32,6 +32,7 @@ impl<'p> PyByteArray<'p> {
/// Creates a new Python bytearray object /// Creates a new Python bytearray object
/// from other PyObject, that implements the buffer protocol. /// from other PyObject, that implements the buffer protocol.
pub fn from(src: &'p PyObject<'p>) -> PyResult<PyByteArray<'p>> { pub fn from(src: &'p PyObject<'p>) -> PyResult<PyByteArray<'p>> {
println!("FROM: {:?} {}", src.as_ptr(), src.get_refcnt());
let res = unsafe {ffi::PyByteArray_FromObject(src.as_ptr())}; let res = unsafe {ffi::PyByteArray_FromObject(src.as_ptr())};
if res != ptr::null_mut() { if res != ptr::null_mut() {
Ok(unsafe{ PyByteArray( Ok(unsafe{ PyByteArray(
@ -77,7 +78,7 @@ impl<'p> PyByteArray<'p> {
mod test { mod test {
use ::ToPyObject; use ::ToPyObject;
use exc; use exc;
use python::Python; use python::{Python, ToPythonPointer};
use typeob::PyTypeObject; use typeob::PyTypeObject;
use objects::PyByteArray; use objects::PyByteArray;
@ -100,6 +101,7 @@ mod test {
assert_eq!(20, bytearray.len()); assert_eq!(20, bytearray.len());
let none = py.None(); let none = py.None();
println!("NONE: {:?} {}", none.as_ptr(), none.get_refcnt());
if let Err(mut err) = PyByteArray::from(none.as_object(py)) { if let Err(mut err) = PyByteArray::from(none.as_object(py)) {
assert!(exc::TypeError::type_object(py).is_instance(&err.instance(py))) assert!(exc::TypeError::type_object(py).is_instance(&err.instance(py)))
} else { } else {

View file

@ -8,7 +8,7 @@ use std::os::raw::c_char;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use ::pptr; use ::pptr;
use conversion::ToPyTuple; use conversion::{ToPyObject, ToPyTuple};
use pyptr::PyPtr; use pyptr::PyPtr;
use python::{ToPythonPointer, Python}; use python::{ToPythonPointer, Python};
use token::PythonObjectWithGilToken; use token::PythonObjectWithGilToken;
@ -89,6 +89,19 @@ impl<'p> PyModule<'p> {
self.getattr(name)?.call(args, kwargs) self.getattr(name)?.call(args, kwargs)
} }
/// Gets a member from the module.
/// This is equivalent to the Python expression: `getattr(module, name)`
pub fn get(&self, name: &str) -> PyResult<PyObject> {
self.getattr(name)
}
/// Adds a member to the module.
///
/// This is a convenience function which can be used from the module's initialization function.
pub fn add<V>(&self, name: &str, value: V) -> PyResult<()> where V: ToPyObject {
self.setattr(name, value)
}
/// Adds a new extension type to the module. /// Adds a new extension type to the module.
/// ///
/// This is a convenience function that initializes the `class`, /// This is a convenience function that initializes the `class`,

View file

@ -88,6 +88,11 @@ impl<'p> PyObject<'p> {
{ {
::conversion::FromPyObject::extract(&self) ::conversion::FromPyObject::extract(&self)
} }
pub fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.0.as_ptr()) }
}
} }
impl<'p> PartialEq for PyObject<'p> { impl<'p> PartialEq for PyObject<'p> {

View file

@ -62,7 +62,7 @@ impl<'p> PyTuple<'p> {
// It's quite inconsistent that this method takes `Python` when `len()` does not. // It's quite inconsistent that this method takes `Python` when `len()` does not.
assert!(index < self.len()); assert!(index < self.len());
unsafe { unsafe {
PyObject::from_owned_ptr( PyObject::from_borrowed_ptr(
self.gil(), ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t)) self.gil(), ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
} }
} }
@ -89,7 +89,7 @@ impl<'p> PyTuple<'p> {
impl<'a> ToPyTuple for PyTuple<'a> { impl<'a> ToPyTuple for PyTuple<'a> {
fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> { fn to_py_tuple<'p>(&self, py: Python<'p>) -> PyTuple<'p> {
unsafe { PyTuple(pptr::from_owned_ptr_or_panic(py, self.0.as_ptr())) } unsafe { PyTuple(pptr::from_borrowed_ptr(py, self.0.as_ptr())) }
} }
} }

View file

@ -1,8 +1,10 @@
// Copyright (c) 2017-present PyO3 Project and Contributors // Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use ffi; use ffi;
use err::{PyErr, PyResult}; use err::{PyErr, PyResult};
use python::{Python, ToPythonPointer}; use python::{Python, PyDowncastInto, ToPythonPointer};
use typeob::{PyTypeInfo, PyObjectAlloc}; use typeob::{PyTypeInfo, PyObjectAlloc};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -176,3 +178,21 @@ impl<'p> Drop for pptr<'p> {
unsafe { ffi::Py_DECREF(self.1); } unsafe { ffi::Py_DECREF(self.1); }
} }
} }
impl<'p> std::fmt::Debug for pptr<'p> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let repr = unsafe { ::PyString::downcast_from_owned_ptr(
self.0, ffi::PyObject_Repr(self.1)) };
let repr = repr.map_err(|_| std::fmt::Error)?;
f.write_str(&repr.to_string_lossy())
}
}
impl<'p> std::fmt::Display for pptr<'p> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let ob = unsafe { ::PyString::downcast_from_owned_ptr(
self.0, ffi::PyObject_Str(self.1)) };
let ob = ob.map_err(|_| std::fmt::Error)?;
f.write_str(&ob.to_string_lossy())
}
}

View file

@ -113,6 +113,7 @@ impl<T> PyPtr<T> {
/// Converts PyPtr<T> -> &PyObject<'p>. /// Converts PyPtr<T> -> &PyObject<'p>.
#[inline] #[inline]
pub fn as_object<'p>(&self, _py: Python<'p>) -> &PyObject<'p> { pub fn as_object<'p>(&self, _py: Python<'p>) -> &PyObject<'p> {
unsafe {ffi::Py_INCREF(self.inner)};
unsafe { std::mem::transmute(self) } unsafe { std::mem::transmute(self) }
} }

View file

@ -443,6 +443,7 @@ fn string_methods() {
#[py::class] #[py::class]
struct Comparisons { struct Comparisons {
val: i32, val: i32,
#[token]
token: PythonToken<Comparisons>, token: PythonToken<Comparisons>,
} }
@ -451,7 +452,6 @@ impl PyObjectProtocol for Comparisons {
fn __hash__(&self, py: Python) -> PyResult<usize> { fn __hash__(&self, py: Python) -> PyResult<usize> {
Ok(self.val as usize) Ok(self.val as usize)
} }
fn __bool__(&self, py: Python) -> PyResult<bool> { fn __bool__(&self, py: Python) -> PyResult<bool> {
Ok(self.val != 0) Ok(self.val != 0)
} }
@ -994,16 +994,12 @@ fn context_manager() {
assert!(c.exit_called); assert!(c.exit_called);
c.exit_called = false; c.exit_called = false;
py_expect_exception!(
//TODO: re-enable py, c, "with c as x:\n raise NotImplementedError",
NotImplementedError);
//py_expect_exception!( assert!(c.exit_called);
// py, c, "with c as x:\n raise NotImplementedError",
// NotImplementedError);
//assert!(c.exit_called);
} }
#[py::class] #[py::class]
struct ClassWithProperties { struct ClassWithProperties {
num: i32, num: i32,