Refactor implementation. Drop parameter from constructor

This commit is contained in:
Nikolay Kim 2017-07-26 01:11:00 -07:00
parent 86252cda4c
commit a120bbf15e
34 changed files with 371 additions and 261 deletions

View File

@ -1,13 +1,15 @@
Changes
-------
0.1.x (xx-xx-2017)
0.2.x (xx-xx-2017)
^^^^^^^^^^^^^^^^^^
* Added weakref support #56
* Allow to add gc support without implementing PyGCProtocol #57
* Refactor `PyErr` implementation. Drop `py` parameter from constructor.
0.1.0 (07-23-2017)
^^^^^^^^^^^^^^^^^^

View File

@ -1,6 +1,6 @@
[package]
name = "pyo3"
version = "0.1.1"
version = "0.2.0"
description = "Bindings to Python"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3"]
readme = "README.md"

View File

@ -64,6 +64,8 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
fn to_object<'p>(&self, py: _pyo3::Python<'p>) -> _pyo3::PyObject {
unsafe { _pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl _pyo3::ToBorrowedObject for #cls {
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: _pyo3::Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
@ -76,6 +78,8 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
fn to_object<'p>(&self, py: _pyo3::Python<'p>) -> _pyo3::PyObject {
unsafe { _pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<'a> _pyo3::ToBorrowedObject for &'a mut #cls {
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: _pyo3::Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R

View File

@ -358,7 +358,7 @@ pub fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
];
let mut _output = [#(#placeholders),*];
match _pyo3::argparse::parse_args(_py, Some(_LOCATION), _PARAMS, &_args,
match _pyo3::argparse::parse_args(Some(_LOCATION), _PARAMS, &_args,
_kwargs, #accept_args, #accept_kwargs, &mut _output)
{
Ok(_) => {

View File

@ -28,8 +28,7 @@ pub struct ParamDescription<'a> {
/// * kwargs: Keyword arguments
/// * output: Output array that receives the arguments.
/// Must have same length as `params` and must be initialized to `None`.
pub fn parse_args<'p>(py: Python<'p>,
fname: Option<&str>, params: &[ParamDescription],
pub fn parse_args<'p>(fname: Option<&str>, params: &[ParamDescription],
args: &'p PyTuple, kwargs: Option<&'p PyDict>,
accept_args: bool, accept_kwargs: bool,
output: &mut[Option<&'p PyObjectRef>]) -> PyResult<()>
@ -40,7 +39,6 @@ pub fn parse_args<'p>(py: Python<'p>,
let nkeywords = kwargs.map_or(0, |d| d.len());
if !accept_args && (nargs + nkeywords > params.len()) {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
format!("{}{} takes at most {} argument{} ({} given)",
fname.unwrap_or("function"),
if fname.is_some() { "()" } else { "" },
@ -58,7 +56,6 @@ pub fn parse_args<'p>(py: Python<'p>,
used_keywords += 1;
if i < nargs {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
format!("Argument given by name ('{}') and position ({})", p.name, i+1)));
}
},
@ -66,8 +63,7 @@ pub fn parse_args<'p>(py: Python<'p>,
if p.kw_only {
if !p.is_optional {
return Err(err::PyErr::new::<exc::TypeError, _>(
py, format!(
"Required argument ('{}') is keyword only argument", p.name)));
format!("Required argument ('{}') is keyword only argument", p.name)));
}
*out = None;
}
@ -77,9 +73,7 @@ pub fn parse_args<'p>(py: Python<'p>,
*out = None;
if !p.is_optional {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
format!("Required argument ('{}') (pos {}) not found",
p.name, i+1)));
format!("Required argument ('{}') (pos {}) not found", p.name, i+1)));
}
}
}
@ -92,7 +86,6 @@ pub fn parse_args<'p>(py: Python<'p>,
let key = PyString::downcast_from(item.get_item(0))?.to_string()?;
if !params.iter().any(|p| p.name == key) {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
format!("'{}' is an invalid keyword argument for this function", key)));
}
}

View File

@ -394,10 +394,10 @@ impl PyBuffer {
fn copy_to_slice_impl<T: Element+Copy>(&self, py: Python, target: &mut [T], fort: u8) -> PyResult<()> {
if mem::size_of_val(target) != self.len_bytes() {
return slice_length_error(py);
return slice_length_error();
}
if !T::is_compatible_format(self.format()) || mem::size_of::<T>() != self.item_size() {
return incompatible_format_error(py);
return incompatible_format_error();
}
unsafe {
err::error_on_minusone(py, ffi::PyBuffer_ToContiguous(
@ -427,7 +427,7 @@ impl PyBuffer {
fn to_vec_impl<T: Element+Copy>(&self, py: Python, fort: u8) -> PyResult<Vec<T>> {
if !T::is_compatible_format(self.format()) || mem::size_of::<T>() != self.item_size() {
incompatible_format_error(py)?;
incompatible_format_error()?;
unreachable!();
}
let item_count = self.item_count();
@ -477,13 +477,13 @@ impl PyBuffer {
fn copy_from_slice_impl<T: Element+Copy>(&self, py: Python, source: &[T], fort: u8) -> PyResult<()> {
if self.readonly() {
return buffer_readonly_error(py);
return buffer_readonly_error();
}
if mem::size_of_val(source) != self.len_bytes() {
return slice_length_error(py);
return slice_length_error();
}
if !T::is_compatible_format(self.format()) || mem::size_of::<T>() != self.item_size() {
return incompatible_format_error(py);
return incompatible_format_error();
}
unsafe {
err::error_on_minusone(py, ffi::PyBuffer_FromContiguous(
@ -504,19 +504,16 @@ impl PyBuffer {
}
}
fn slice_length_error(py: Python) -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>(
py, "Slice length does not match buffer length."))
fn slice_length_error() -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>("Slice length does not match buffer length."))
}
fn incompatible_format_error(py: Python) -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>(
py, "Slice type is incompatible with buffer format."))
fn incompatible_format_error() -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>("Slice type is incompatible with buffer format."))
}
fn buffer_readonly_error(py: Python) -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>(
py, "Cannot write to read-only buffer."))
fn buffer_readonly_error() -> PyResult<()> {
Err(err::PyErr::new::<exc::BufferError, _>("Cannot write to read-only buffer."))
}
impl Drop for PyBuffer {

View File

@ -5,11 +5,11 @@
use std::os::raw::c_int;
use std::{any, ptr, isize};
use python::{Python, IntoPyPointer};
use objects::exc;
use conversion::IntoPyObject;
use err::PyResult;
use ffi::{self, Py_hash_t};
use err::{PyErr, PyResult};
use python::{Python, IntoPyPointer};
use objects::exc::OverflowError;
use conversion::IntoPyObject;
pub trait CallbackConverter<S> {
@ -62,8 +62,7 @@ impl CallbackConverter<usize> for LenResultConverter {
if val <= (isize::MAX as usize) {
val as isize
} else {
PyErr::new_lazy_init(
py.get_type::<exc::OverflowError>(), None).restore(py);
OverflowError::new(()).restore(py);
-1
}
}

View File

@ -365,7 +365,7 @@ impl<T> PyObjectRichcmpProtocolImpl for T
let slf = py.cast_from_borrowed_ptr::<T>(slf);
let arg = py.cast_from_borrowed_ptr::<PyObjectRef>(arg);
let res = match extract_op(py, op) {
let res = match extract_op(op) {
Ok(op) => match arg.extract() {
Ok(arg) =>
slf.__richcmp__(arg, op).into(),
@ -388,7 +388,7 @@ impl<T> PyObjectRichcmpProtocolImpl for T
}
fn extract_op(py: Python, op: c_int) -> PyResult<CompareOp> {
fn extract_op(op: c_int) -> PyResult<CompareOp> {
match op {
ffi::Py_LT => Ok(CompareOp::Lt),
ffi::Py_LE => Ok(CompareOp::Le),
@ -396,8 +396,7 @@ fn extract_op(py: Python, op: c_int) -> PyResult<CompareOp> {
ffi::Py_NE => Ok(CompareOp::Ne),
ffi::Py_GT => Ok(CompareOp::Gt),
ffi::Py_GE => Ok(CompareOp::Ge),
_ => Err(PyErr::new_lazy_init(
py.get_type::<exc::ValueError>(),
Some("tp_richcompare called with invalid comparison operator".into_object(py))))
_ => Err(PyErr::new::<exc::ValueError, _>(
"tp_richcompare called with invalid comparison operator"))
}
}

View File

@ -294,7 +294,7 @@ macro_rules! py_func_set{
if value.is_null() {
let e = $crate::PyErr::new::<exc::NotImplementedError, _>(
py, format!("Subscript deletion not supported by {:?}", stringify!(T)));
format!("Subscript deletion not supported by {:?}", stringify!(T)));
e.restore(py);
-1
} else {
@ -356,8 +356,7 @@ macro_rules! py_func_del{
}
} else {
let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Subscript assignment not supported by {:?}",
stringify!(T)));
format!("Subscript assignment not supported by {:?}", stringify!(T)));
e.restore(py);
-1
}

View File

@ -222,7 +222,6 @@ impl<T> PySequenceSetItemProtocolImpl for T
if value.is_null() {
let e = PyErr::new::<exc::NotImplementedError, _>(
py,
format!("Item deletion not supported by {:?}", stringify!(T)));
e.restore(py);
-1
@ -283,7 +282,7 @@ impl<T> PySequenceDelItemProtocolImpl for T
}
} else {
let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Item assignment not supported by {:?}", stringify!(T)));
format!("Item assignment not supported by {:?}", stringify!(T)));
e.restore(py);
-1
}

View File

@ -16,13 +16,23 @@ pub trait ToPyObject {
/// Converts self into a Python object.
fn to_object(&self, py: Python) -> PyObject;
}
pub trait ToBorrowedObject: ToPyObject {
/// Converts self into a Python object and calls the specified closure
/// on the native FFI pointer underlying the Python object.
///
/// May be more efficient than `to_py_object` because it does not need
/// May be more efficient than `to_object` because it does not need
/// to touch any reference counts when the input object already is a Python object.
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R;
}
impl<T> ToBorrowedObject for T where T: ToPyObject {
#[inline]
default fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
let obj = self.to_object(py);
@ -38,14 +48,16 @@ pub trait IntoPyObject {
/// Converts self into a Python object. (Consumes self)
#[inline]
fn into_object(self, py: Python) -> PyObject
where Self: Sized;
fn into_object(self, py: Python) -> PyObject;
}
/// Conversion trait that allows various objects to be converted into `PyTuple` object.
pub trait IntoPyTuple {
/// Converts self into a PyTuple object.
fn to_tuple(&self, py: Python) -> Py<PyTuple>;
/// Converts self into a PyTuple object.
fn into_tuple(self, py: Python) -> Py<PyTuple>;
@ -104,12 +116,15 @@ impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
fn to_object(&self, py: Python) -> PyObject {
<T as ToPyObject>::to_object(*self, py)
}
}
impl <'a, T: ?Sized> ToBorrowedObject for &'a T where T: ToBorrowedObject {
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
<T as ToPyObject>::with_borrowed_ptr(*self, py, f)
<T as ToBorrowedObject>::with_borrowed_ptr(*self, py, f)
}
}

View File

@ -12,7 +12,7 @@ use PyObject;
use objects::{PyObjectRef, PyType, exc};
use instance::Py;
use typeob::PyTypeObject;
use conversion::{ToPyObject, IntoPyTuple, IntoPyObject};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyTuple};
/**
Defines a new exception type.
@ -49,11 +49,15 @@ macro_rules! py_exception {
($module: ident, $name: ident, $base: ty) => {
pub struct $name;
// pyobject_nativetype!($name);
impl std::convert::From<$name> for $crate::PyErr {
fn from(_err: $name) -> $crate::PyErr {
$crate::PyErr::new::<$name, _>(())
}
}
impl $name {
pub fn new<T: $crate::IntoPyObject>(py: $crate::Python, args: T) -> $crate::PyErr {
$crate::PyErr::new::<$name, T>(py, args)
pub fn new<T: $crate::ToPyObject + 'static>(args: T) -> $crate::PyErr {
$crate::PyErr::new::<$name, T>(args)
}
#[inline(always)]
fn type_object() -> *mut $crate::ffi::PyTypeObject {
@ -95,8 +99,16 @@ macro_rules! py_exception {
}
}
/// Represents a PyErr value
pub enum PyErrValue {
None,
Value(PyObject),
ToErr(Box<ToPyErr>),
ToObject(Box<ToPyObject>),
ToTuple(Box<IntoPyTuple>),
}
/// Represents a Python exception that was raised.
#[derive(Debug)]
pub struct PyErr {
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
pub ptype: Py<PyType>,
@ -106,7 +118,7 @@ pub struct PyErr {
/// a tuple of arguments to be passed to `ptype`'s constructor,
/// or a single argument to be passed to `ptype`'s constructor.
/// Call `PyErr::instance()` to get the exception instance in all cases.
pub pvalue: Option<PyObject>,
pub pvalue: PyErrValue,
/// The `PyTraceBack` object associated with the error.
pub ptraceback: Option<PyObject>,
}
@ -117,7 +129,7 @@ pub type PyResult<T> = Result<T, PyErr>;
/// Marker type that indicates an error while downcasting
pub struct PyDowncastError<'p>(pub Python<'p>, pub Option<&'p str>);
pub struct PyDowncastError;
impl PyErr {
@ -131,11 +143,46 @@ impl PyErr {
/// Panics if `T` is not a python class derived from `BaseException`.
///
/// Example:
/// `return Err(PyErr::new::<exc::TypeError, _>(py, "Error message"));`
pub fn new<T, V>(py: Python, value: V) -> PyErr
where T: PyTypeObject, V: IntoPyObject
/// `return Err(PyErr::new::<exc::TypeError, _>("Error message"));`
pub fn new<T, V>(value: V) -> PyErr
where T: PyTypeObject, V: ToPyObject + 'static
{
PyErr::new_helper(py, py.get_type::<T>(), value.into_object(py))
let ty = T::type_object();
assert_ne!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) }, 0);
PyErr {
ptype: ty,
pvalue: PyErrValue::ToObject(Box::new(value)),
ptraceback: None,
}
}
/// Construct a new error, with the usual lazy initialization of Python exceptions.
/// `exc` is the exception type; usually one of the standard exceptions
/// like `exc::RuntimeError::type_info()`.
/// `args` is the a tuple of arguments to pass to the exception constructor.
pub fn from_type<A>(exc: Py<PyType>, args: A) -> PyErr
where A: IntoPyTuple + 'static
{
PyErr {
ptype: exc,
pvalue: PyErrValue::ToTuple(Box::new(args)),
ptraceback: None,
}
}
/// Creates a new PyErr of type `T`.
pub fn from_value<T>(value: PyErrValue) -> PyErr
where T: PyTypeObject
{
let ty = T::type_object();
assert_ne!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) }, 0);
PyErr {
ptype: ty,
pvalue: value,
ptraceback: None,
}
}
/// Gets whether an error is present in the Python interpreter's global state.
@ -173,39 +220,38 @@ impl PyErr {
/// Retrieves the current error from the Python interpreter's global state.
/// The error is cleared from the Python interpreter.
/// If no error is set, returns a `SystemError`.
pub fn fetch(py: Python) -> PyErr {
pub fn fetch(_: Python) -> PyErr {
unsafe {
let mut ptype : *mut ffi::PyObject = std::ptr::null_mut();
let mut pvalue : *mut ffi::PyObject = std::ptr::null_mut();
let mut ptraceback : *mut ffi::PyObject = std::ptr::null_mut();
ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
PyErr::new_from_ffi_tuple(ptype, pvalue, ptraceback)
}
}
unsafe fn new_from_ffi_tuple(py: Python,
ptype: *mut ffi::PyObject,
unsafe fn new_from_ffi_tuple(ptype: *mut ffi::PyObject,
pvalue: *mut ffi::PyObject,
ptraceback: *mut ffi::PyObject) -> PyErr {
// Note: must not panic to ensure all owned pointers get acquired correctly,
// and because we mustn't panic in normalize().
let pvalue = if let Some(obj) =
PyObject::from_owned_ptr_or_opt(Python::assume_gil_acquired(), pvalue)
{
PyErrValue::Value(obj)
} else {
PyErrValue::None
};
PyErr {
ptype: if ptype.is_null() {
py.get_type::<exc::SystemError>().into()
<exc::SystemError as PyTypeObject>::type_object()
} else {
Py::from_owned_ptr(ptype)
},
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 {
assert_ne!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) }, 0);
PyErr {
ptype: ty.into(),
pvalue: Some(value),
ptraceback: None
pvalue: pvalue,
ptraceback: PyObject::from_owned_ptr_or_opt(Python::assume_gil_acquired(), ptraceback),
}
}
@ -215,60 +261,31 @@ impl PyErr {
/// If `obj` is a Python exception type object, the PyErr will (lazily) create a new
/// instance of that type.
/// Otherwise, a `TypeError` is created instead.
pub fn from_instance<O>(py: Python, obj: O) -> PyErr where O: IntoPyObject {
PyErr::from_instance_helper(py, obj.into_object(py))
}
fn from_instance_helper(py: Python, obj: PyObject) -> PyErr {
pub fn from_instance(obj: &PyObjectRef) -> PyErr {
let ptr = obj.as_ptr();
if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 {
PyErr {
ptype: unsafe { Py::from_borrowed_ptr( ffi::PyExceptionInstance_Class(ptr)) },
pvalue: Some(obj),
ptraceback: None
pvalue: PyErrValue::Value(obj.into()),
ptraceback: None,
}
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErr {
ptype: unsafe { Py::from_borrowed_ptr(ptr) },
pvalue: None,
ptraceback: None
pvalue: PyErrValue::None,
ptraceback: None,
}
} else {
PyErr {
ptype: py.get_type::<exc::TypeError>().into(),
pvalue: Some("exceptions must derive from BaseException".into_object(py)),
ptraceback: None
ptype: exc::TypeError::type_object(),
pvalue: PyErrValue::ToObject(
Box::new("exceptions must derive from BaseException")),
ptraceback: None,
}
}
}
/// Construct a new error, with the usual lazy initialization of Python exceptions.
/// `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 {
PyErr {
ptype: exc.into(),
pvalue: value,
ptraceback: None
}
}
/// Construct a new error, with the usual lazy initialization of Python exceptions.
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
/// `args` is the a tuple of arguments to pass to the exception constructor.
#[inline]
pub fn new_err<A>(py: Python, exc: &PyType, args: A) -> PyErr
where A: IntoPyTuple
{
PyErr {
ptype: exc.into(),
pvalue: Some(args.into_tuple(py).into()),
ptraceback: None
}
}
/// Print a standard traceback to sys.stderr.
pub fn print(self, py: Python) {
self.restore(py);
@ -285,7 +302,7 @@ impl PyErr {
/// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass.
/// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match.
pub fn matches<T>(&self, py: Python, exc: T) -> bool
where T: ToPyObject
where T: ToBorrowedObject
{
exc.with_borrowed_ptr(py, |exc| unsafe {
ffi::PyErr_GivenExceptionMatches(self.ptype.as_ptr(), exc) != 0
@ -306,12 +323,20 @@ impl PyErr {
/// Must not panic for safety in normalize()
fn into_normalized(self, py: Python) -> PyErr {
let PyErr { ptype, pvalue, ptraceback } = self;
let mut pvalue = match pvalue {
PyErrValue::None => std::ptr::null_mut(),
PyErrValue::Value(ob) => ob.into_ptr(),
PyErrValue::ToErr(ob) => ob.exc_arguments(py).into_ptr(),
PyErrValue::ToObject(ob) => ob.to_object(py).into_ptr(),
PyErrValue::ToTuple(ob) => ob.to_tuple(py).into_ptr(),
};
let mut ptype = ptype.into_ptr();
let mut pvalue = pvalue.into_ptr();
let mut ptraceback = ptraceback.into_ptr();
unsafe {
ffi::PyErr_NormalizeException(&mut ptype, &mut pvalue, &mut ptraceback);
PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback)
PyErr::new_from_ffi_tuple(ptype, pvalue, ptraceback)
}
}
@ -321,38 +346,51 @@ impl PyErr {
}
/// Retrieves the exception instance for this error.
/// This method takes `&mut self` because the error might need
/// This method takes `mut self` because the error might need
/// to be normalized in order to create the exception instance.
pub fn instance(&mut self, py: Python) -> PyObject {
self.normalize(py);
pub fn instance(mut self, py: Python) -> PyObject {
&self.normalize(py);
match self.pvalue {
Some(ref instance) => instance.clone_ref(py),
None => py.None(),
PyErrValue::Value(ref instance) => instance.clone_ref(py),
_ => py.None(),
}
}
/// Writes the error back to the Python interpreter's global state.
/// This is the opposite of `PyErr::fetch()`.
#[inline]
pub fn restore(self, _py: Python) {
pub fn restore(self, py: Python) {
let PyErr { ptype, pvalue, ptraceback } = self;
let pvalue = match pvalue {
PyErrValue::None => std::ptr::null_mut(),
PyErrValue::Value(ob) => ob.into_ptr(),
PyErrValue::ToErr(ob) => ob.exc_arguments(py).into_ptr(),
PyErrValue::ToObject(ob) => ob.to_object(py).into_ptr(),
PyErrValue::ToTuple(ob) => ob.to_tuple(py).into_ptr(),
};
unsafe {
ffi::PyErr_Restore(ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr())
ffi::PyErr_Restore(ptype.into_ptr(), pvalue, ptraceback.into_ptr())
}
}
/// Issue a warning message.
/// May return a PyErr if warnings-as-errors is enabled.
pub fn warn(py: Python, category: &PyObjectRef, message: &str, stacklevel: i32) -> PyResult<()> {
let message = CString::new(message).map_err(|e| e.to_pyerr(py))?;
let message = CString::new(message)?;
unsafe {
error_on_minusone(py, ffi::PyErr_WarnEx(
category.as_ptr(), message.as_ptr(), stacklevel as ffi::Py_ssize_t))
}
}
pub fn clone_ref(&self, py: Python) -> PyErr {
let v = if let Some(ref val) = self.pvalue { Some(val.clone_ref(py))} else { None };
pub fn clone_ref(&mut self, py: Python) -> PyErr {
&self.normalize(py);
let v = match self.pvalue {
PyErrValue::Value(ref instance) => PyErrValue::Value(instance.clone_ref(py)),
_ => PyErrValue::None,
};
let t = if let Some(ref val) = self.ptraceback { Some(val.clone_ref(py))} else { None };
PyErr {
ptype: self.ptype.clone_ref(py),
@ -362,21 +400,27 @@ impl PyErr {
}
pub fn release(self, py: Python) {
#[allow(unused_variables)]
let PyErr { ptype, pvalue, ptraceback } = self;
py.release(ptype);
py.release(pvalue);
py.release(ptraceback);
}
}
/// Converts `PyDowncastError` to Python `TypeError`.
impl <'p> std::convert::From<PyDowncastError<'p>> for PyErr {
fn from(err: PyDowncastError<'p>) -> PyErr {
PyErr::new_lazy_init(err.0.get_type::<exc::TypeError>(), None)
impl std::fmt::Debug for PyErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str(format!("PyErr {{ type: {:?} }}", self.ptype).as_str())
}
}
impl <'p> std::fmt::Debug for PyDowncastError<'p> {
/// Converts `PyDowncastError` to Python `TypeError`.
impl std::convert::From<PyDowncastError> for PyErr {
fn from(_err: PyDowncastError) -> PyErr {
PyErr::new::<exc::TypeError, _>(())
}
}
impl <'p> std::fmt::Debug for PyDowncastError {
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str("PyDowncastError")
}
@ -392,14 +436,22 @@ impl std::convert::From<PyErr> for std::io::Error {
/// Converts into `PyErr`
pub trait ToPyErr {
fn to_pyerr(&self, Python) -> PyErr;
fn exc_arguments(&self, Python) -> PyObject;
}
macro_rules! impl_to_pyerr {
($err: ty, $pyexc: ty) => {
impl $crate::ToPyErr for $err {
fn to_pyerr(&self, py: $crate::Python) -> PyErr {
PyErr::new::<$pyexc, _>(py, self.description())
fn exc_arguments(&self, py: $crate::Python) -> PyObject {
self.description().to_object(py)
}
}
impl $crate::std::convert::From<$err> for $crate::PyErr {
fn from(err: $err) -> $crate::PyErr {
$crate::PyErr::from_value::<exc::ValueError>(
$crate::err::PyErrValue::ToErr(Box::new(err))
)
}
}
}
@ -407,43 +459,59 @@ macro_rules! impl_to_pyerr {
#[cfg(Py_3)]
/// Create `OSError` from `io::Error`
impl ToPyErr for io::Error {
fn to_pyerr(&self, py: Python) -> PyErr {
let tp = match self.kind() {
io::ErrorKind::BrokenPipe => py.get_type::<exc::BrokenPipeError>(),
io::ErrorKind::ConnectionRefused => py.get_type::<exc::ConnectionRefusedError>(),
io::ErrorKind::ConnectionAborted => py.get_type::<exc::ConnectionAbortedError>(),
io::ErrorKind::ConnectionReset => py.get_type::<exc::ConnectionResetError>(),
io::ErrorKind::Interrupted => py.get_type::<exc::InterruptedError>(),
io::ErrorKind::NotFound => py.get_type::<exc::FileNotFoundError>(),
io::ErrorKind::WouldBlock => py.get_type::<exc::BlockingIOError>(),
io::ErrorKind::TimedOut => py.get_type::<exc::TimeoutError>(),
_ => py.get_type::<exc::OSError>(),
};
let errno = self.raw_os_error().unwrap_or(0);
let errdesc = self.description();
PyErr::new_err(py, tp, (errno, errdesc))
impl std::convert::From<io::Error> for PyErr {
fn from(err: io::Error) -> PyErr {
match err.kind() {
io::ErrorKind::BrokenPipe =>
PyErr::from_value::<exc::BrokenPipeError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::ConnectionRefused =>
PyErr::from_value::<exc::ConnectionRefusedError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::ConnectionAborted =>
PyErr::from_value::<exc::ConnectionAbortedError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::ConnectionReset =>
PyErr::from_value::<exc::ConnectionResetError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::Interrupted =>
PyErr::from_value::<exc::InterruptedError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::NotFound =>
PyErr::from_value::<exc::FileNotFoundError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::WouldBlock =>
PyErr::from_value::<exc::BlockingIOError>(PyErrValue::ToErr(Box::new(err))),
io::ErrorKind::TimedOut =>
PyErr::from_value::<exc::TimeoutError>(PyErrValue::ToErr(Box::new(err))),
_ =>
PyErr::from_value::<exc::OSError>(PyErrValue::ToErr(Box::new(err))),
}
}
}
#[cfg(not(Py_3))]
/// Create `OSError` from `io::Error`
impl std::convert::From<io::Error> for PyErr {
fn from(err: io::Error) -> PyErr {
PyErr::from_value::<exc::OSError>(PyErrValue::ToErr(Box::new(err)))
}
}
/// Extract `errno` and `errdesc` from from `io::Error`
impl ToPyErr for io::Error {
fn to_pyerr(&self, py: Python) -> PyErr {
fn exc_arguments(&self, py: Python) -> PyObject {
let errno = self.raw_os_error().unwrap_or(0);
let errdesc = self.description();
let errdesc = self.description().to_owned();
(errno, errdesc).to_object(py)
}
}
PyErr::new_err(py, &py.get_type::<exc::OSError>(), (errno, errdesc))
impl<W: 'static + Send + std::fmt::Debug> std::convert::From<std::io::IntoInnerError<W>> for PyErr
{
fn from(err: std::io::IntoInnerError<W>) -> PyErr {
PyErr::from_value::<exc::OSError>(PyErrValue::ToErr(Box::new(err)))
}
}
impl<W: Send + std::fmt::Debug> ToPyErr for std::io::IntoInnerError<W> {
fn to_pyerr(&self, py: Python) -> PyErr {
PyErr::new::<exc::OSError, _>(py, self.description())
fn exc_arguments(&self, py: Python) -> PyObject {
self.description().to_object(py)
}
}
@ -483,7 +551,8 @@ mod tests {
fn set_typeerror() {
let gil = Python::acquire_gil();
let py = gil.python();
PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), None).restore(py);
let err: PyErr = exc::TypeError.into();
err.restore(py);
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py));
}

View File

@ -325,8 +325,7 @@ impl<'a, T> std::convert::From<&'a mut T> for PyObject
impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
{
fn downcast_into<I>(py: Python, ob: I)
-> Result<Self, PyDowncastError>
fn downcast_into<I>(_py: Python, ob: I) -> Result<Self, PyDowncastError>
where I: IntoPyPointer
{
unsafe{
@ -335,20 +334,20 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
Ok(Py::from_owned_ptr(ptr))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
Err(PyDowncastError)
}
}
}
fn downcast_into_from_ptr(py: Python, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError>
fn downcast_into_from_ptr(_py: Python, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError>
{
unsafe{
if T::is_instance(ptr) {
Ok(Py::from_owned_ptr(ptr))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
Err(PyDowncastError)
}
}
}

View File

@ -150,7 +150,7 @@ pub mod ffi {
pub use ffi3::*;
}
pub use err::{PyErr, PyResult, PyDowncastError, ToPyErr};
pub use err::{PyErr, PyErrValue, PyResult, PyDowncastError, ToPyErr};
pub use objects::*;
pub use objectprotocol::ObjectProtocol;
pub use object::PyObject;
@ -158,7 +158,8 @@ pub use python::{Python, ToPyPointer, IntoPyPointer,
PyMutDowncastFrom, PyDowncastFrom, PyDowncastInto};
pub use pythonrun::{GILGuard, GILPool, prepare_freethreaded_python, prepare_pyo3_library};
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, IntoPyTuple};
pub use conversion::{FromPyObject, RefFromPyObject,
ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple};
pub mod class;
pub use class::*;

View File

@ -7,7 +7,7 @@ use pythonrun;
use err::{PyErr, PyResult};
use instance::{AsPyRef, PyObjectWithToken};
use objects::{PyObjectRef, PyDict};
use conversion::{ToPyObject, IntoPyObject, IntoPyTuple, FromPyObject};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyObject, IntoPyTuple, FromPyObject};
use python::{Python, ToPyPointer, IntoPyPointer};
@ -230,7 +230,9 @@ impl ToPyObject for PyObject
fn to_object<'p>(&self, py: Python<'p>) -> PyObject {
unsafe {PyObject::from_borrowed_ptr(py, self.as_ptr())}
}
}
impl ToBorrowedObject for PyObject {
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R

View File

@ -9,7 +9,7 @@ use err::{self, PyErr, PyResult};
use python::{Python, ToPyPointer, PyDowncastFrom};
use object::PyObject;
use objects::{PyObjectRef, PyDict, PyString, PyIterator, PyType};
use conversion::{ToPyObject, IntoPyTuple, FromPyObject};
use conversion::{ToPyObject, ToBorrowedObject, IntoPyTuple, FromPyObject};
use instance::PyObjectWithToken;
@ -27,7 +27,7 @@ pub trait ObjectProtocol {
/// Sets an attribute value.
/// This is equivalent to the Python expression 'self.attr_name = value'.
fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
where N: ToPyObject, V: ToPyObject;
where N: ToBorrowedObject, V: ToBorrowedObject;
/// Deletes an attribute.
/// This is equivalent to the Python expression 'del self.attr_name'.
@ -102,16 +102,16 @@ pub trait ObjectProtocol {
fn len(&self) -> PyResult<usize>;
/// This is equivalent to the Python expression: 'self[key]'
fn get_item<K>(&self, key: K) -> PyResult<&PyObjectRef> where K: ToPyObject;
fn get_item<K>(&self, key: K) -> PyResult<&PyObjectRef> where K: ToBorrowedObject;
/// Sets an item value.
/// This is equivalent to the Python expression 'self[key] = value'.
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where K: ToPyObject, V: ToPyObject;
where K: ToBorrowedObject, V: ToBorrowedObject;
/// Deletes an item.
/// This is equivalent to the Python expression 'del self[key]'.
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject;
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToBorrowedObject;
/// Takes an object and returns an iterator for it.
/// This is typically a new iterator but if the argument
@ -163,7 +163,7 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
#[inline]
fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
where N: ToPyObject, V: ToPyObject
where N: ToBorrowedObject, V: ToBorrowedObject
{
attr_name.with_borrowed_ptr(
self.py(), move |attr_name|
@ -203,7 +203,8 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
} else if result < 0 {
return Err(PyErr::fetch(py));
}
Err(PyErr::new::<::exc::TypeError, _>(py, "ObjectProtocol::compare(): All comparisons returned false"))
Err(::exc::TypeError::new(
"ObjectProtocol::compare(): All comparisons returned false"))
}
other.with_borrowed_ptr(self.py(), |other| unsafe {
@ -308,7 +309,7 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
}
#[inline]
fn get_item<K>(&self, key: K) -> PyResult<&PyObjectRef> where K: ToPyObject {
fn get_item<K>(&self, key: K) -> PyResult<&PyObjectRef> where K: ToBorrowedObject {
key.with_borrowed_ptr(self.py(), |key| unsafe {
self.py().cast_from_ptr_or_err(
ffi::PyObject_GetItem(self.as_ptr(), key))
@ -317,7 +318,7 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
#[inline]
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where K: ToPyObject, V: ToPyObject
where K: ToBorrowedObject, V: ToBorrowedObject
{
key.with_borrowed_ptr(
self.py(), move |key|
@ -328,7 +329,7 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
}
#[inline]
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject {
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToBorrowedObject {
key.with_borrowed_ptr(self.py(), |key| unsafe {
err::error_on_minusone(
self.py(), ffi::PyObject_DelItem(self.as_ptr(), key))

View File

@ -2,7 +2,7 @@
use ffi;
use object::PyObject;
use python::{ToPyPointer, Python, PyDowncastFrom};
use conversion::{ToPyObject, IntoPyObject};
use conversion::{ToPyObject, IntoPyObject, ToBorrowedObject};
/// Represents a Python `bool`.
pub struct PyBool(PyObject);
@ -36,7 +36,9 @@ impl ToPyObject for bool {
py, if *self { ffi::Py_True() } else { ffi::Py_False() })
}
}
}
impl ToBorrowedObject for bool {
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R

View File

@ -98,7 +98,7 @@ mod test {
assert_eq!(20, bytearray.len());
let none = py.None();
if let Err(mut err) = PyByteArray::from(py, &none) {
if let Err(err) = PyByteArray::from(py, &none) {
assert!(py.is_instance::<exc::TypeError, _>(&err.instance(py)).unwrap())
} else {
panic!("error");

View File

@ -8,7 +8,7 @@ use ffi;
use object::PyObject;
use instance::PyObjectWithToken;
use python::{Python, ToPyPointer};
use conversion::ToPyObject;
use conversion::{ToPyObject, ToBorrowedObject};
use objects::{PyObjectRef, PyList};
use err::{self, PyResult, PyErr};
@ -52,7 +52,7 @@ impl PyDict {
/// Determine if the dictionary contains the specified key.
/// This is equivalent to the Python expression `key in self`.
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject {
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToBorrowedObject {
key.with_borrowed_ptr(self.py(), |key| unsafe {
match ffi::PyDict_Contains(self.as_ptr(), key) {
1 => Ok(true),
@ -64,7 +64,7 @@ impl PyDict {
/// Gets an item from the dictionary.
/// Returns None if the item is not present, or if an error occurs.
pub fn get_item<K>(&self, key: K) -> Option<&PyObjectRef> where K: ToPyObject {
pub fn get_item<K>(&self, key: K) -> Option<&PyObjectRef> where K: ToBorrowedObject {
key.with_borrowed_ptr(self.py(), |key| unsafe {
self.py().cast_from_borrowed_ptr_or_opt(
ffi::PyDict_GetItem(self.as_ptr(), key))
@ -86,7 +86,7 @@ impl PyDict {
/// Deletes an item.
/// This is equivalent to the Python expression `del self[key]`.
pub fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject
pub fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToBorrowedObject
{
key.with_borrowed_ptr(self.py(), |key| unsafe {
err::error_on_minusone(

View File

@ -9,7 +9,7 @@ use std::{self, mem, ops};
use std::ffi::CStr;
use ffi;
use object::PyObject;
use objects::PyObjectRef;
use python::{Python, ToPyPointer};
use err::PyResult;
use super::PyTuple;
@ -18,8 +18,16 @@ macro_rules! exc_type(
($name:ident, $exc_name:ident) => (
pub struct $name;
// pyobject_newtype!($name);
impl std::convert::From<$name> for $crate::PyErr {
fn from(_err: $name) -> $crate::PyErr {
$crate::PyErr::new::<$name, _>(())
}
}
impl $name {
pub fn new<V: $crate::ToPyObject + 'static>(value: V) -> $crate::PyErr {
$crate::PyErr::new::<$name, V>(value)
}
}
impl $crate::typeob::PyTypeObject for $name {
#[inline(always)]
fn init_type() {}
@ -116,12 +124,12 @@ exc_type!(WindowsError, PyExc_WindowsError);
impl UnicodeDecodeError {
pub fn new(py: Python, encoding: &CStr, input: &[u8],
range: ops::Range<usize>, reason: &CStr) -> PyResult<PyObject> {
pub fn new_err<'p>(py: Python<'p>, encoding: &CStr, input: &[u8],
range: ops::Range<usize>, reason: &CStr) -> PyResult<&'p PyObjectRef> {
unsafe {
let input: &[c_char] = mem::transmute(input);
PyObject::from_owned_ptr_or_err(
py, ffi::PyUnicodeDecodeError_Create(
py.cast_from_ptr_or_err(
ffi::PyUnicodeDecodeError_Create(
encoding.as_ptr(),
input.as_ptr(),
input.len() as ffi::Py_ssize_t,
@ -131,11 +139,12 @@ impl UnicodeDecodeError {
}
}
pub fn new_utf8(py: Python, input: &[u8], err: std::str::Utf8Error)
-> PyResult<PyObject>
pub fn new_utf8<'p>(py: Python<'p>, input: &[u8], err: std::str::Utf8Error)
-> PyResult<&'p PyObjectRef>
{
let pos = err.valid_up_to();
UnicodeDecodeError::new(py, cstr!("utf-8"), input, pos .. pos+1, cstr!("invalid utf-8"))
UnicodeDecodeError::new_err(
py, cstr!("utf-8"), input, pos .. pos+1, cstr!("invalid utf-8"))
}
}

View File

@ -17,8 +17,7 @@ pub struct PyIterator<'p>(&'p PyObjectRef);
impl <'p> PyIterator<'p> {
/// Constructs a `PyIterator` from a Python iterator object.
pub fn from_object<T>(py: Python<'p>, obj: T)
-> Result<PyIterator<'p>, PyDowncastError<'p>>
pub fn from_object<T>(py: Python<'p>, obj: T) -> Result<PyIterator<'p>, PyDowncastError>
where T: IntoPyPointer
{
unsafe {
@ -27,7 +26,7 @@ impl <'p> PyIterator<'p> {
Ok(PyIterator(py.cast_from_ptr(ptr)))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
Err(PyDowncastError)
}
}
}

View File

@ -8,7 +8,7 @@ use instance::PyObjectWithToken;
use object::PyObject;
use objects::PyObjectRef;
use python::{Python, ToPyPointer, IntoPyPointer};
use conversion::{ToPyObject, IntoPyObject};
use conversion::{ToPyObject, IntoPyObject, ToBorrowedObject};
/// Represents a Python `list`.
pub struct PyList(PyObject);
@ -77,7 +77,7 @@ impl PyList {
}
/// Appends an item at the list.
pub fn append<I>(&self, item: I) -> PyResult<()> where I: ToPyObject
pub fn append<I>(&self, item: I) -> PyResult<()> where I: ToBorrowedObject
{
item.with_borrowed_ptr(self.py(), |item| unsafe {
err::error_on_minusone(
@ -88,7 +88,7 @@ impl PyList {
/// Inserts an item at the specified index.
///
/// Panics if the index is out of range.
pub fn insert<I>(&self, index: isize, item: I) -> PyResult<()> where I: ToPyObject
pub fn insert<I>(&self, index: isize, item: I) -> PyResult<()> where I: ToBorrowedObject
{
item.with_borrowed_ptr(self.py(), |item| unsafe {
err::error_on_minusone(
@ -148,7 +148,7 @@ impl <T> ToPyObject for Vec<T> where T: ToPyObject {
}
impl <T> IntoPyObject for Vec<T> where T: IntoPyObject {
impl <T> IntoPyObject for Vec<T> where T: IntoPyObject + ToPyObject {
fn into_object(self, py: Python) -> PyObject {
unsafe {

View File

@ -61,12 +61,11 @@ macro_rules! pyobject_downcast(
/// Extracts `Self` from the source `PyObject`.
fn extract(ob: &'a $crate::PyObjectRef) -> $crate::PyResult<Self>
{
use instance::PyObjectWithToken;
unsafe {
if $crate::ffi::$checkfunction(ob.as_ptr()) != 0 {
Ok($crate::std::mem::transmute(ob))
} else {
Err($crate::PyDowncastError(ob.py(), None).into())
Err($crate::PyDowncastError.into())
}
}
}
@ -168,7 +167,10 @@ macro_rules! pyobject_nativetype(
fn to_object(&self, py: $crate::Python) -> $crate::PyObject {
unsafe {$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())}
}
}
impl $crate::ToBorrowedObject for $name
{
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
where F: FnOnce(*mut $crate::ffi::PyObject) -> R

View File

@ -14,7 +14,7 @@ use python::{Python, ToPyPointer};
use objects::{PyObjectRef, PyDict, PyType, exc};
use objectprotocol::ObjectProtocol;
use instance::PyObjectWithToken;
use err::{PyResult, PyErr, ToPyErr};
use err::{PyResult, PyErr};
/// Represents a Python `module` object.
@ -27,7 +27,7 @@ pyobject_nativetype!(PyModule, PyModule_Type, PyModule_Check);
impl PyModule {
/// Create a new module object with the `__name__` attribute set to name.
pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
let name = CString::new(name).map_err(|e| e.to_pyerr(py))?;
let name = CString::new(name)?;
unsafe {
py.cast_from_ptr_or_err(
ffi::PyModule_New(name.as_ptr()))
@ -36,7 +36,7 @@ impl PyModule {
/// Import the Python module with the specified name.
pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
let name = CString::new(name).map_err(|e| e.to_pyerr(py))?;
let name = CString::new(name)?;
unsafe {
py.cast_from_ptr_or_err(
ffi::PyImport_ImportModule(name.as_ptr()))
@ -60,8 +60,7 @@ impl PyModule {
match std::str::from_utf8(slice) {
Ok(s) => Ok(s),
Err(e) => Err(PyErr::from_instance(
self.py(),
try!(exc::UnicodeDecodeError::new_utf8(self.py(), slice, e))))
exc::UnicodeDecodeError::new_utf8(self.py(), slice, e)?))
}
}
}

View File

@ -86,7 +86,7 @@ macro_rules! int_fits_c_long(
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(obj.py()))
None => Err(exc::OverflowError.into())
}
});
)
@ -110,7 +110,7 @@ macro_rules! int_fits_larger_int(
let val = try!(obj.extract::<$larger_type>());
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(obj.py()))
None => Err(exc::OverflowError.into())
}
});
)
@ -162,7 +162,7 @@ macro_rules! int_convert_u64_or_i64 (
} else if ffi::PyInt_Check(ptr) != 0 {
match cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
Some(v) => Ok(v),
None => Err(overflow_error(obj.py()))
None => Err(exc::OverflowError.into())
}
} else {
let num = PyObject::from_owned_ptr_or_err(
@ -206,10 +206,6 @@ int_fits_larger_int!(usize, u64);
// u64 has a manual implementation as it never fits into signed long
int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong);
fn overflow_error(py: Python) -> PyErr {
PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
}
#[cfg(test)]
mod test {

View File

@ -50,7 +50,7 @@ macro_rules! int_fits_c_long(
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(obj.py()))
None => Err(exc::OverflowError.into())
}
});
)
@ -62,7 +62,7 @@ macro_rules! int_fits_larger_int(
impl ToPyObject for $rust_type {
#[inline]
fn to_object(&self, py: Python) -> PyObject {
(*self as $larger_type).to_object(py)
(*self as $larger_type).into_object(py)
}
}
impl IntoPyObject for $rust_type {
@ -74,7 +74,7 @@ macro_rules! int_fits_larger_int(
let val = try!(obj.extract::<$larger_type>());
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(obj.py()))
None => Err(exc::OverflowError.into())
}
});
)
@ -160,9 +160,6 @@ int_fits_larger_int!(usize, u64);
// u64 has a manual implementation as it never fits into signed long
int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong);
fn overflow_error(py: Python) -> PyErr {
PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
}
#[cfg(test)]
mod test {

View File

@ -6,7 +6,7 @@ use err::{self, PyErr, PyResult};
use object::PyObject;
use instance::PyObjectWithToken;
use python::{ToPyPointer, PyDowncastFrom};
use conversion::{FromPyObject, ToPyObject};
use conversion::{FromPyObject, ToBorrowedObject};
use objects::{PyObjectRef, PyList, PyTuple};
use objectprotocol::ObjectProtocol;
@ -101,7 +101,7 @@ impl PySequence {
/// Assign object v to the ith element of o.
/// Equivalent to Python statement `o[i] = v`
#[inline]
pub fn set_item<I>(&self, i: isize, item: I) -> PyResult<()> where I: ToPyObject {
pub fn set_item<I>(&self, i: isize, item: I) -> PyResult<()> where I: ToBorrowedObject {
unsafe {
item.with_borrowed_ptr(self.py(), |item| {
err::error_on_minusone(
@ -145,7 +145,7 @@ impl PySequence {
/// Return the number of occurrences of value in o, that is, return the number of keys for
/// which `o[key] == value`
#[inline]
pub fn count<V>(&self, value: V) -> PyResult<usize> where V: ToPyObject
pub fn count<V>(&self, value: V) -> PyResult<usize> where V: ToBorrowedObject
{
let r = value.with_borrowed_ptr(self.py(), |ptr| unsafe {
ffi::PySequence_Count(self.as_ptr(), ptr)
@ -157,9 +157,9 @@ impl PySequence {
}
}
/// Determine if o contains value. this is equivalent to the Python expression `value in o`
/// Determine if o contains value. this is equivalent to the Python expression `value in o`
#[inline]
pub fn contains<V>(&self, value: V) -> PyResult<bool> where V: ToPyObject
pub fn contains<V>(&self, value: V) -> PyResult<bool> where V: ToBorrowedObject
{
let r = value.with_borrowed_ptr(self.py(), |ptr| unsafe {
ffi::PySequence_Contains(self.as_ptr(), ptr)
@ -174,7 +174,7 @@ impl PySequence {
/// Return the first index i for which o[i] == value.
/// This is equivalent to the Python expression `o.index(value)`
#[inline]
pub fn index<V>(&self, value: V) -> PyResult<usize> where V: ToPyObject
pub fn index<V>(&self, value: V) -> PyResult<usize> where V: ToBorrowedObject
{
let r = value.with_borrowed_ptr(self.py(), |ptr| unsafe {
ffi::PySequence_Index(self.as_ptr(), ptr)

View File

@ -5,7 +5,7 @@ use std::{hash, collections};
use ffi;
use python::{Python, ToPyPointer};
use object::PyObject;
use conversion::ToPyObject;
use conversion::{ToPyObject, ToBorrowedObject};
use instance::{AsPyRef, Py, PyObjectWithToken};
use err::{self, PyResult, PyErr};
@ -129,7 +129,7 @@ impl PyFrozenSet {
/// Determine if the set contains the specified key.
/// This is equivalent to the Python expression `key in self`.
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject {
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToBorrowedObject {
key.with_borrowed_ptr(self.py(), |key| unsafe {
match ffi::PySet_Contains(self.as_ptr(), key) {
1 => Ok(true),

View File

@ -52,7 +52,8 @@ impl <'a> PyStringData<'a> {
PyStringData::Utf8(data) => {
match str::from_utf8(data) {
Ok(s) => Ok(Cow::Borrowed(s)),
Err(e) => Err(PyErr::from_instance(py, try!(exc::UnicodeDecodeError::new_utf8(py, data, e))))
Err(e) => Err(PyErr::from_instance(
exc::UnicodeDecodeError::new_utf8(py, data, e)?))
}
}
PyStringData::Latin1(data) => {
@ -69,10 +70,10 @@ impl <'a> PyStringData<'a> {
match String::from_utf16(data) {
Ok(s) => Ok(Cow::Owned(s)),
Err(_) => Err(PyErr::from_instance(
py, try!(exc::UnicodeDecodeError::new(
exc::UnicodeDecodeError::new_err(
py, cstr!("utf-16"),
utf16_bytes(data), 0 .. 2*data.len(), cstr!("invalid utf-16")))
))
utf16_bytes(data), 0 .. 2*data.len(), cstr!("invalid utf-16"))?)
)
}
},
PyStringData::Utf32(data) => {
@ -82,10 +83,10 @@ impl <'a> PyStringData<'a> {
match data.iter().map(|&u| char::from_u32(u)).collect() {
Some(s) => Ok(Cow::Owned(s)),
None => Err(PyErr::from_instance(
py, try!(exc::UnicodeDecodeError::new(
exc::UnicodeDecodeError::new_err(
py, cstr!("utf-32"),
utf32_bytes(data), 0 .. 4*data.len(), cstr!("invalid utf-32")))
))
utf32_bytes(data), 0 .. 4*data.len(), cstr!("invalid utf-32"))?)
)
}
}
}

View File

@ -101,18 +101,32 @@ impl PyTuple {
}
impl<'a> IntoPyTuple for &'a PyTuple {
fn to_tuple(&self, _py: Python) -> Py<PyTuple> {
let t: Py<PyTuple> = (*self).into();
t
}
fn into_tuple(self, _py: Python) -> Py<PyTuple> {
self.into()
}
}
impl IntoPyTuple for Py<PyTuple> {
fn to_tuple(&self, py: Python) -> Py<PyTuple> {
self.clone_ref(py)
}
fn into_tuple(self, _py: Python) -> Py<PyTuple> {
self
}
}
impl<'a> IntoPyTuple for &'a str {
fn to_tuple(&self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New(1);
ffi::PyTuple_SetItem(ptr, 0, ToPyObject::to_object(self, py).into_ptr());
Py::from_owned_ptr_or_panic(ptr)
}
}
fn into_tuple(self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New(1);
@ -122,11 +136,10 @@ impl<'a> IntoPyTuple for &'a str {
}
}
fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr {
fn wrong_tuple_length(t: &PyTuple, expected_length: usize) -> PyErr {
let msg = format!("Expected tuple of length {}, but got tuple of length {}.",
expected_length, t.len());
PyErr::new_lazy_init(
py.get_type::<exc::ValueError>(), Some(msg.into_object(py)))
exc::ValueError::new(msg)
}
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => {
@ -149,7 +162,14 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
}
}
impl <$($T: IntoPyObject),+> IntoPyTuple for ($($T,)+) {
impl <$($T: ToPyObject + IntoPyObject),+> IntoPyTuple for ($($T,)+) {
fn to_tuple(&self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, ToPyObject::to_object(&self.$n, py).into_ptr());)+;
Py::from_owned_ptr_or_panic(ptr)
}
}
fn into_tuple(self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New($length);
@ -169,7 +189,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
$( try!(slice[$n].extract::<$T>(obj.py())), )+
))
} else {
Err(wrong_tuple_length(obj.py(), t, $length))
Err(wrong_tuple_length(t, $length))
}
}
}
@ -213,8 +233,8 @@ impl ToPyObject for NoArgs {
}
}
impl IntoPyObject for NoArgs
{
impl IntoPyObject for NoArgs {
fn into_object(self, py: Python) -> PyObject {
PyTuple::empty(py).into()
}
@ -223,6 +243,10 @@ impl IntoPyObject for NoArgs
/// Converts `NoArgs` to an empty Python tuple.
impl IntoPyTuple for NoArgs {
fn to_tuple(&self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
fn into_tuple(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
@ -231,6 +255,10 @@ impl IntoPyTuple for NoArgs {
/// Converts `()` to an empty Python tuple.
impl IntoPyTuple for () {
fn to_tuple(&self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
fn into_tuple(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
@ -244,7 +272,7 @@ pyobject_extract!(py, obj to NoArgs => {
if t.len() == 0 {
Ok(NoArgs)
} else {
Err(wrong_tuple_length(obj.py(), t, 0))
Err(wrong_tuple_length(t, 0))
}
});

View File

@ -9,10 +9,10 @@ use std::os::raw::c_int;
use ffi;
use typeob::{PyTypeInfo, PyTypeObject, PyObjectAlloc};
use instance::{Py, PyToken, PyObjectWithToken, AsPyRef};
use instance::{Py, PyToken, AsPyRef};
use object::PyObject;
use objects::{PyObjectRef, PyType, PyDict, PyModule};
use err::{PyErr, PyResult, PyDowncastError, ToPyErr};
use err::{PyErr, PyResult, PyDowncastError};
use pythonrun::{self, GILGuard};
@ -46,7 +46,7 @@ pub trait PyDowncastFrom : Sized {
if let Some(ob) = Self::try_downcast_from(ob) {
Ok(ob)
} else {
Err(PyDowncastError(ob.py(), None))
Err(PyDowncastError)
}
}
@ -55,7 +55,7 @@ pub trait PyDowncastFrom : Sized {
if let Some(ob) = Self::try_exact_downcast_from(ob) {
Ok(ob)
} else {
Err(PyDowncastError(ob.py(), None))
Err(PyDowncastError)
}
}
@ -82,8 +82,7 @@ pub trait PyMutDowncastFrom : Sized {
if let Some(o) = Self::try_mut_downcast_from(ob) {
return Ok(o)
} else {
let py = unsafe { Python::assume_gil_acquired() };
Err(PyDowncastError(py, None))
Err(PyDowncastError)
}
}
@ -92,8 +91,7 @@ pub trait PyMutDowncastFrom : Sized {
if let Some(ob) = Self::try_mut_exact_downcast_from(ob) {
Ok(ob)
} else {
let py = unsafe { Python::assume_gil_acquired() };
Err(PyDowncastError(py, None))
Err(PyDowncastError)
}
}
}
@ -107,7 +105,7 @@ pub trait PyDowncastInto : Sized {
/// Cast from ffi::PyObject to a concrete Python object type.
fn downcast_into_from_ptr(py: Python, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError>;
-> Result<Self, PyDowncastError>;
/// Cast from ffi::PyObject to a concrete Python object type.
fn unchecked_downcast_into<I>(I) -> Self where I: IntoPyPointer;
@ -210,7 +208,7 @@ impl<'p> Python<'p> {
/// If `locals` is `None`, it defaults to the value of `globals`.
fn run_code(self, code: &str, start: c_int,
globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<&'p PyObjectRef> {
let code = CString::new(code).map_err(|e| e.to_pyerr(self))?;
let code = CString::new(code)?;
unsafe {
let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _);
@ -303,7 +301,7 @@ impl<'p> Python<'p> {
impl<'p> Python<'p> {
/// Register object in release pool, and try to downcast to specific type.
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError<'p>>
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError>
where T: PyDowncastFrom
{
unsafe {

View File

@ -20,7 +20,7 @@ impl class::PyBufferProtocol for TestClass {
fn bf_getbuffer(&self, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
if view.is_null() {
return Err(PyErr::new::<exc::BufferError, _>(self.py(), "View is null"))
return Err(PyErr::new::<exc::BufferError, _>("View is null"))
}
unsafe {
@ -28,7 +28,7 @@ impl class::PyBufferProtocol for TestClass {
}
if (flags & ffi::PyBUF_WRITABLE) == ffi::PyBUF_WRITABLE {
return Err(PyErr::new::<exc::BufferError, _>(self.py(), "Object is not writable"))
return Err(PyErr::new::<exc::BufferError, _>("Object is not writable"))
}
let bytes = &self.vec;

View File

@ -656,7 +656,7 @@ impl PySequenceProtocol for Sequence {
fn __getitem__(&self, key: isize) -> PyResult<isize> {
if key == 5 {
return Err(PyErr::new::<exc::IndexError, NoArgs>(self.py(), NoArgs));
return Err(PyErr::new::<exc::IndexError, NoArgs>(NoArgs));
}
Ok(key)
}

View File

@ -40,7 +40,7 @@ impl<'p> PyMappingProtocol<'p> for Test
return Ok("int".into_object(self.py()))
}
}
Err(PyErr::new::<exc::ValueError, _>(self.py(), "error"))
Err(PyErr::new::<exc::ValueError, _>("error"))
}
}