update PyType

This commit is contained in:
Nikolay Kim 2017-06-21 15:11:32 -07:00
parent 7cf8e1ab80
commit af663e0f80
10 changed files with 88 additions and 83 deletions

View File

@ -97,41 +97,21 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
}
}
impl std::fmt::Debug for #cls {
impl<'a> std::fmt::Debug for &'a #cls {
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let py = _pyo3::PyObjectWithToken::token(self);
let ptr = <#cls as _pyo3::ToPyPointer>::as_ptr(self);
unsafe {
let repr = PyObject::from_borrowed_ptr(
py, _pyo3::ffi::PyObject_Repr(ptr));
use pyo3::ObjectProtocol2;
let result = {
let s = _pyo3::PyString::downcast_from(py, &repr);
let s = try!(s.map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
};
py.release(repr);
result
}
let s = try!(ObjectProtocol2::repr(self).map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
impl std::fmt::Display for #cls {
impl<'a> std::fmt::Display for &'a #cls {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let py = _pyo3::PyObjectWithToken::token(self);
let ptr = <#cls as _pyo3::ToPyPointer>::as_ptr(self);
unsafe {
let repr = PyObject::from_borrowed_ptr(
py, _pyo3::ffi::PyObject_Str(ptr));
use pyo3::ObjectProtocol2;
let result = {
let s = _pyo3::PyString::downcast_from(py, &repr);
let s = try!(s.map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
};
py.release(repr);
result
}
let s = try!(ObjectProtocol2::str(self).map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
})

View File

@ -6,9 +6,10 @@ use std::error::Error;
use libc;
use ffi;
use python::{ToPyPointer, IntoPyPointer, Python, PyDowncastInto, PyClone};
use python::{ToPyPointer, IntoPyPointer, Python, PyDowncastFrom, PyClone};
use objects::{PyObject, PyType, exc};
use typeob::{PyTypeObject};
use token::Py;
use typeob::PyTypeObject;
use conversion::{ToPyObject, IntoPyTuple, IntoPyObject};
/**
@ -76,7 +77,7 @@ macro_rules! py_exception {
}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::Python<'p>) -> &'p $crate::PyType {
unsafe { $crate::PyType::from_type_ptr(py, $name::type_object(py)) }
}
}
@ -90,7 +91,7 @@ macro_rules! py_exception {
#[derive(Debug)]
pub struct PyErr {
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
pub ptype: PyType,
pub ptype: Py<PyType>,
/// The value of the exception.
///
/// This can be either an instance of `ptype`,
@ -140,8 +141,8 @@ impl PyErr {
///
/// `base` can be an existing exception type to subclass, or a tuple of classes
/// `dict` specifies an optional dictionary of class variables and methods
pub fn new_type(py: Python, name: &str, base: Option<PyType>, dict: Option<PyObject>)
-> PyType
pub fn new_type<'p>(py: Python<'p>,
name: &str, base: Option<&PyType>, dict: Option<PyObject>) -> &'p PyType
{
let base: *mut ffi::PyObject = match base {
None => std::ptr::null_mut(),
@ -183,19 +184,19 @@ impl PyErr {
// and because we mustn't panic in normalize().
PyErr {
ptype: if ptype.is_null() {
py.get_type::<exc::SystemError>()
py.get_type::<exc::SystemError>().into()
} else {
PyObject::from_owned_ptr(py, ptype).unchecked_cast_into::<PyType>()
PyType::from_type_ptr(py, ptype as *mut ffi::PyTypeObject).into()
},
pvalue: PyObject::from_owned_ptr_or_opt(py, pvalue),
ptraceback: PyObject::from_owned_ptr_or_opt(py, ptraceback)
}
}
fn new_helper(_py: Python, ty: PyType, value: PyObject) -> PyErr {
fn new_helper(_py: Python, ty: &PyType, value: PyObject) -> PyErr {
assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } != 0);
PyErr {
ptype: ty,
ptype: ty.into(),
pvalue: Some(value),
ptraceback: None
}
@ -211,23 +212,24 @@ impl PyErr {
}
fn from_instance_helper<'p>(py: Python, obj: PyObject) -> PyErr {
if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 {
let ptr = obj.as_ptr();
if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 {
PyErr {
ptype: unsafe { PyObject::from_borrowed_ptr(
py, ffi::PyExceptionInstance_Class(obj.as_ptr()))
.unchecked_cast_into::<PyType>() },
ptype: unsafe { PyType::from_type_ptr(py, ptr as *mut ffi::PyTypeObject).into() },
pvalue: Some(obj),
ptraceback: None
}
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErr {
ptype: PyType::downcast_into(py, obj).expect("Failed to downcast into PyType"),
ptype: PyType::downcast_from(py, &obj)
.expect("Failed to downcast into PyType").into(),
pvalue: None,
ptraceback: None
}
} else {
PyErr {
ptype: py.get_type::<exc::TypeError>(),
ptype: py.get_type::<exc::TypeError>().into(),
pvalue: Some("exceptions must derive from BaseException".into_object(py)),
ptraceback: None
}
@ -238,9 +240,9 @@ impl PyErr {
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
/// `value` is the exception instance, or a tuple of arguments to pass to the exception constructor.
#[inline]
pub fn new_lazy_init(exc: PyType, value: Option<PyObject>) -> PyErr {
pub fn new_lazy_init(exc: &PyType, value: Option<PyObject>) -> PyErr {
PyErr {
ptype: exc,
ptype: exc.into(),
pvalue: value,
ptraceback: None
}
@ -254,7 +256,7 @@ impl PyErr {
where A: IntoPyTuple
{
PyErr {
ptype: exc.clone_ref(py),
ptype: exc.into(),
pvalue: Some(args.into_tuple(py).into()),
ptraceback: None
}
@ -307,7 +309,7 @@ impl PyErr {
}
/// Retrieves the exception type.
pub fn get_type(&self, py: Python) -> PyType {
pub fn get_type(&self, py: Python) -> Py<PyType> {
self.ptype.clone_ref(py)
}

View File

@ -120,7 +120,7 @@ pub trait ObjectProtocol {
/// Gets the Python type object for this object's type.
#[inline]
fn get_type(&self, py: Python) -> PyType;
fn get_type<'p>(&self, py: Python<'p>) -> &'p PyType;
fn get_refcnt(&self) -> isize;
}
@ -383,7 +383,7 @@ impl<T> ObjectProtocol for T where T: ToPyPointer {
/// Gets the Python type object for this object's type.
#[inline]
fn get_type(&self, py: Python) -> PyType {
fn get_type<'p>(&self, py: Python<'p>) -> &'p PyType {
unsafe {
PyType::from_type_ptr(py, (*self.as_ptr()).ob_type)
}

View File

@ -117,7 +117,7 @@ pub trait ObjectProtocol2 {
fn iter<'p>(&'p self) -> PyResult<PyIterator<'p>>;
/// Gets the Python type object for this object's type.
fn get_type(&self) -> PyType;
fn get_type(&self) -> &PyType;
fn get_refcnt(&self) -> isize;
@ -388,7 +388,7 @@ impl<'a, T> ObjectProtocol2 for &'a T where T: PyObjectWithToken + ToPyPointer {
/// Gets the Python type object for this object's type.
#[inline]
fn get_type(&self) -> PyType {
fn get_type(&self) -> &PyType {
unsafe {
PyType::from_type_ptr(self.token(), (*self.as_ptr()).ob_type)
}

View File

@ -24,7 +24,7 @@ macro_rules! exc_type(
fn init_type(_py: Python) {}
#[inline]
fn type_object(py: $crate::python::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::python::Python<'p>) -> &'p $crate::PyType {
unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) }
}
}

View File

@ -109,7 +109,7 @@ macro_rules! pyobject_nativetype(
fn init_type(_py: Python) {}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::Python<'p>) -> &'p $crate::PyType {
unsafe { $crate::PyType::from_type_ptr(py, &mut $crate::ffi::$typeobject) }
}
}
@ -293,6 +293,11 @@ macro_rules! pyobject_nativetype2(
unsafe{$crate::std::mem::transmute(self)}
}
}
impl<'a> $crate::std::convert::From<&'a $name> for &'a $crate::PyObject {
fn from(ob: &'a $name) -> Self {
unsafe{$crate::std::mem::transmute(ob)}
}
}
impl $crate::PyObjectWithToken for $name {
#[inline]
fn token<'p>(&'p self) -> $crate::Python<'p> {
@ -395,7 +400,7 @@ macro_rules! pyobject_nativetype2(
fn init_type(_py: Python) {}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::Python<'p>) -> &'p $crate::PyType {
unsafe { $crate::PyType::from_type_ptr(py, &mut $crate::ffi::$typeobject) }
}
}

View File

@ -10,13 +10,13 @@ use pointers::PyPtr;
use python::{Python, ToPyPointer};
use objects::PyObject;
use err::{PyErr, PyResult};
use token::PyObjectWithToken;
use typeob::PyTypeObject;
/// Represents a reference to a Python type object.
pub struct PyType(PyPtr);
pyobject_convert!(PyType);
pyobject_nativetype!(PyType, PyType_Type, PyType_Check);
pyobject_nativetype2!(PyType, PyType_Type, PyType_Check);
impl PyType {
@ -30,26 +30,28 @@ impl PyType {
/// This increments the reference count on the type object.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_type_ptr(_py: Python, p: *mut ffi::PyTypeObject) -> PyType {
PyType(PyPtr::from_borrowed_ptr(p as *mut ffi::PyObject))
pub unsafe fn from_type_ptr<'p>(py: Python<'p>, p: *mut ffi::PyTypeObject) -> &'p PyType
{
py.unchecked_cast_from_borrowed_ptr::<PyType>(p as *mut ffi::PyObject)
}
/// Gets the name of the PyType.
pub fn name<'a>(&'a self, _py: Python) -> Cow<'a, str> {
pub fn name<'a>(&'a self) -> Cow<'a, str> {
unsafe {
CStr::from_ptr((*self.as_type_ptr()).tp_name).to_string_lossy()
}
}
/// Check whether `self` is subclass of type `T` like Python `issubclass` function
pub fn is_subclass<T>(&self, py: Python) -> PyResult<bool>
pub fn is_subclass<T>(&self) -> PyResult<bool>
where T: PyTypeObject
{
let result = unsafe {
ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object(py).as_ptr())
ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object(self.token()).as_ptr())
};
if result == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else if result == 1 {
Ok(true)
} else {
@ -58,12 +60,12 @@ impl PyType {
}
// Check whether `obj` is an instance of `self`
pub fn is_instance<T: ToPyPointer>(&self, py: Python, obj: &T) -> PyResult<bool> {
pub fn is_instance<T: ToPyPointer>(&self, obj: &T) -> PyResult<bool> {
let result = unsafe {
ffi::PyObject_IsInstance(obj.as_ptr(), self.as_ptr())
};
if result == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else if result == 1 {
Ok(true)
} else {

View File

@ -195,7 +195,7 @@ impl<'p> Python<'p> {
}
/// Gets the Python type object for type T.
pub fn get_type<T>(self) -> PyType where T: PyTypeObject {
pub fn get_type<T>(self) -> &'p PyType where T: PyTypeObject {
T::type_object(self)
}
@ -261,7 +261,7 @@ impl<'p> Python<'p> {
/// Check whether `obj` is an instance of type `T` like Python `isinstance` function
pub fn is_instance<T: PyTypeObject>(self, obj: &PyObject) -> PyResult<bool> {
T::type_object(self).is_instance(self, obj)
T::type_object(self).is_instance(obj)
}
/// Check whether type `T` is subclass of type `U` like Python `issubclass` function
@ -269,7 +269,7 @@ impl<'p> Python<'p> {
where T: PyTypeObject,
U: PyTypeObject
{
T::type_object(self).is_subclass::<U>(self)
T::type_object(self).is_subclass::<U>()
}
}
@ -297,6 +297,14 @@ impl<'p> Python<'p> {
<D as PyDowncastFrom>::unchecked_downcast_from(self, p)
}
pub unsafe fn unchecked_cast_from_borrowed_ptr<D>(self, ptr: *mut ffi::PyObject) -> &'p D
where D: PyDowncastFrom
{
let obj = PyObject::from_borrowed_ptr(self, ptr);
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::unchecked_downcast_from(self, p)
}
pub fn unchecked_cast_from_ptr_or_err<D>(self, ptr: *mut ffi::PyObject) -> PyResult<&'p D>
where D: PyDowncastFrom
{
@ -343,15 +351,15 @@ mod test {
assert_eq!(v, 2);
}
/*#[test]
#[test]
fn test_is_instance() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(py.is_instance::<PyBool>(py.True().as_ob_ref(py)).unwrap());
assert!(py.is_instance::<PyBool>(py.True().into()).unwrap());
let list = PyList::new(py, &[1, 2, 3, 4]);
assert!(!py.is_instance::<PyBool>(list.as_ref()).unwrap());
assert!(py.is_instance::<PyList>(list.as_ref()).unwrap());
}*/
}
#[test]
fn test_is_subclass() {

View File

@ -130,7 +130,7 @@ pub trait PyTypeObject {
fn init_type(py: Python);
/// Retrieves the type object for this Python object type.
fn type_object(py: Python) -> PyType;
fn type_object<'p>(py: Python<'p>) -> &'p PyType;
}
@ -152,7 +152,7 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
}
#[inline]
default fn type_object(py: Python) -> PyType {
default fn type_object<'p>(py: Python<'p>) -> &'p PyType {
<T as PyTypeObject>::init_type(py);
unsafe { PyType::from_type_ptr(py, <T as PyTypeInfo>::type_object()) }
@ -160,9 +160,11 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
}
pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str,
type_description: &'static str, type_object: &mut ffi::PyTypeObject)
-> PyResult<PyType>
pub fn initialize_type<'p, T>(py: Python<'p>,
module_name: Option<&str>,
type_name: &str,
type_description: &'static str,
type_object: &mut ffi::PyTypeObject) -> PyResult<&'p PyType>
where T: PyObjectAlloc<T> + PyTypeInfo
{
// type name

View File

@ -59,10 +59,16 @@ struct ClassWithDocs { }
#[test]
fn class_with_docstr() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<ClassWithDocs>();
py_run!(py, typeobj, "assert typeobj.__doc__ == 'Line1\\nLine2\\n Line3'");
{
let gil = Python::acquire_gil();
let py = gil.python();
println!("TEST1");
let typeobj = py.get_type::<ClassWithDocs>();
println!("TEST2");
py_run!(py, typeobj, "assert typeobj.__doc__ == 'Line1\\nLine2\\n Line3'");
println!("TEST3");
}
println!("TEST4");
}
#[py::class(name=CustomName)]
@ -283,7 +289,7 @@ impl ClassMethod {
#[classmethod]
fn method(cls: &PyType, py: Python) -> PyResult<String> {
Ok(format!("{}.method()!", cls.name(py)))
Ok(format!("{}.method()!", cls.name()))
}
}
@ -306,7 +312,7 @@ struct ClassMethodWithArgs{token: PyToken}
impl ClassMethodWithArgs {
#[classmethod]
fn method(cls: &PyType, py: Python, input: &PyString) -> PyResult<String> {
Ok(format!("{}.method({})", cls.name(py), input))
Ok(format!("{}.method({})", cls.name(), input))
}
}
@ -1042,7 +1048,7 @@ impl<'p> PyContextProtocol<'p> for ContextManager {
}
fn __exit__(&mut self, py: Python,
ty: Option<PyType>,
ty: Option<&'p PyType>,
value: Option<PyObject>,
traceback: Option<PyObject>) -> PyResult<bool> {
self.exit_called = true;