various cleanups
This commit is contained in:
parent
7631f0a6c1
commit
8227ce81e2
|
@ -5,9 +5,9 @@
|
|||
//! Python argument parsing
|
||||
|
||||
use ffi;
|
||||
use err::PyResult;
|
||||
use python::{Python, PyDowncastFrom};
|
||||
use objects::{PyObjectRef, PyTuple, PyDict, PyString, exc};
|
||||
use err::{self, PyResult};
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Description of a python parameter; used for `parse_args()`.
|
||||
|
@ -33,12 +33,10 @@ pub fn parse_args<'p>(fname: Option<&str>, params: &[ParamDescription],
|
|||
accept_args: bool, accept_kwargs: bool,
|
||||
output: &mut[Option<&'p PyObjectRef>]) -> PyResult<()>
|
||||
{
|
||||
|
||||
|
||||
let nargs = args.len();
|
||||
let nkeywords = kwargs.map_or(0, |d| d.len());
|
||||
if !accept_args && (nargs + nkeywords > params.len()) {
|
||||
return Err(err::PyErr::new::<exc::TypeError, _>(
|
||||
return Err(exc::TypeError::new(
|
||||
format!("{}{} takes at most {} argument{} ({} given)",
|
||||
fname.unwrap_or("function"),
|
||||
if fname.is_some() { "()" } else { "" },
|
||||
|
@ -55,14 +53,14 @@ pub fn parse_args<'p>(fname: Option<&str>, params: &[ParamDescription],
|
|||
*out = Some(kwarg);
|
||||
used_keywords += 1;
|
||||
if i < nargs {
|
||||
return Err(err::PyErr::new::<exc::TypeError, _>(
|
||||
return Err(exc::TypeError::new(
|
||||
format!("Argument given by name ('{}') and position ({})", p.name, i+1)));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if p.kw_only {
|
||||
if !p.is_optional {
|
||||
return Err(err::PyErr::new::<exc::TypeError, _>(
|
||||
return Err(exc::TypeError::new(
|
||||
format!("Required argument ('{}') is keyword only argument", p.name)));
|
||||
}
|
||||
*out = None;
|
||||
|
@ -72,7 +70,7 @@ pub fn parse_args<'p>(fname: Option<&str>, params: &[ParamDescription],
|
|||
} else {
|
||||
*out = None;
|
||||
if !p.is_optional {
|
||||
return Err(err::PyErr::new::<exc::TypeError, _>(
|
||||
return Err(exc::TypeError::new(
|
||||
format!("Required argument ('{}') (pos {}) not found", p.name, i+1)));
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +83,7 @@ pub fn parse_args<'p>(fname: Option<&str>, params: &[ParamDescription],
|
|||
let item = PyTuple::downcast_from(item)?;
|
||||
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, _>(
|
||||
return Err(exc::TypeError::new(
|
||||
format!("'{}' is an invalid keyword argument for this function", key)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ 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();
|
||||
return Err(exc::BufferError::new("Slice length does not match buffer length."));
|
||||
}
|
||||
if !T::is_compatible_format(self.format()) || mem::size_of::<T>() != self.item_size() {
|
||||
return incompatible_format_error();
|
||||
|
@ -480,7 +480,7 @@ impl PyBuffer {
|
|||
return buffer_readonly_error();
|
||||
}
|
||||
if mem::size_of_val(source) != self.len_bytes() {
|
||||
return slice_length_error();
|
||||
return Err(exc::BufferError::new("Slice length does not match buffer length."));
|
||||
}
|
||||
if !T::is_compatible_format(self.format()) || mem::size_of::<T>() != self.item_size() {
|
||||
return incompatible_format_error();
|
||||
|
@ -504,16 +504,12 @@ impl PyBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
fn slice_length_error() -> PyResult<()> {
|
||||
Err(err::PyErr::new::<exc::BufferError, _>("Slice length does not match buffer length."))
|
||||
}
|
||||
|
||||
fn incompatible_format_error() -> PyResult<()> {
|
||||
Err(err::PyErr::new::<exc::BufferError, _>("Slice type is incompatible with buffer format."))
|
||||
Err(exc::BufferError::new("Slice type is incompatible with buffer format."))
|
||||
}
|
||||
|
||||
fn buffer_readonly_error() -> PyResult<()> {
|
||||
Err(err::PyErr::new::<exc::BufferError, _>("Cannot write to read-only buffer."))
|
||||
Err(exc::BufferError::new("Cannot write to read-only buffer."))
|
||||
}
|
||||
|
||||
impl Drop for PyBuffer {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! Utilities for a Python callable object that invokes a Rust function.
|
||||
|
||||
use std::os::raw::c_int;
|
||||
use std::{any, ptr, isize};
|
||||
use std::{ptr, isize};
|
||||
|
||||
use err::PyResult;
|
||||
use ffi::{self, Py_hash_t};
|
||||
|
@ -150,10 +150,3 @@ pub unsafe fn cb_convert<C, T>(_c: C, py: Python, value: PyResult<T>) -> C::R
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn handle_panic(_py: Python, _panic: &any::Any) {
|
||||
unsafe {
|
||||
ffi::PyErr_SetString(ffi::PyExc_SystemError, "Rust panic\0".as_ptr() as *const i8);
|
||||
}
|
||||
}
|
||||
|
|
166
src/err.rs
166
src/err.rs
|
@ -58,22 +58,21 @@ macro_rules! py_exception {
|
|||
pub fn new<T: $crate::ToPyObject + 'static>(args: T) -> $crate::PyErr {
|
||||
$crate::PyErr::new::<$name, T>(args)
|
||||
}
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn type_object() -> *mut $crate::ffi::PyTypeObject {
|
||||
#[allow(non_upper_case_globals)]
|
||||
static mut type_object: *mut $crate::ffi::PyTypeObject =
|
||||
static mut TYPE_OBJECT: *mut $crate::ffi::PyTypeObject =
|
||||
0 as *mut $crate::ffi::PyTypeObject;
|
||||
|
||||
unsafe {
|
||||
if type_object.is_null() {
|
||||
if TYPE_OBJECT.is_null() {
|
||||
let gil = $crate::Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
type_object = $crate::PyErr::new_type(
|
||||
TYPE_OBJECT = $crate::PyErr::new_type(
|
||||
py, concat!(stringify!($module), ".", stringify!($name)),
|
||||
Some(py.get_type::<$base>()), None);
|
||||
}
|
||||
type_object
|
||||
TYPE_OBJECT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,76 +187,6 @@ impl PyErr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets whether an error is present in the Python interpreter's global state.
|
||||
#[inline]
|
||||
pub fn occurred(_: Python) -> bool {
|
||||
unsafe { !ffi::PyErr_Occurred().is_null() }
|
||||
}
|
||||
|
||||
/// Creates a new exception type with the given name, which must be of the form
|
||||
/// `<module>.<ExceptionName>`, as required by `PyErr_NewException`.
|
||||
///
|
||||
/// `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<'p>(_: Python<'p>, name: &str, base: Option<&PyType>, dict: Option<PyObject>)
|
||||
-> *mut ffi::PyTypeObject
|
||||
{
|
||||
let base: *mut ffi::PyObject = match base {
|
||||
None => std::ptr::null_mut(),
|
||||
Some(obj) => obj.as_ptr()
|
||||
};
|
||||
|
||||
let dict: *mut ffi::PyObject = match dict {
|
||||
None => std::ptr::null_mut(),
|
||||
Some(obj) => obj.as_ptr(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let null_terminated_name = CString::new(name)
|
||||
.expect("Failed to initialize nul terminated exception name");
|
||||
ffi::PyErr_NewException(
|
||||
null_terminated_name.as_ptr() as *mut c_char, base, dict) as *mut ffi::PyTypeObject
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(_: 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(ptype, pvalue, ptraceback)
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
<exc::SystemError as PyTypeObject>::type_object()
|
||||
} else {
|
||||
Py::from_owned_ptr(ptype)
|
||||
},
|
||||
pvalue: pvalue,
|
||||
ptraceback: PyObject::from_owned_ptr_or_opt(Python::assume_gil_acquired(), ptraceback),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new PyErr.
|
||||
///
|
||||
/// `obj` must be an Python exception instance, the PyErr will use that instance.
|
||||
|
@ -289,6 +218,76 @@ impl PyErr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets whether an error is present in the Python interpreter's global state.
|
||||
#[inline]
|
||||
pub fn occurred(_: Python) -> bool {
|
||||
unsafe { !ffi::PyErr_Occurred().is_null() }
|
||||
}
|
||||
|
||||
/// 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(_: 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(ptype, pvalue, ptraceback)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new exception type with the given name, which must be of the form
|
||||
/// `<module>.<ExceptionName>`, as required by `PyErr_NewException`.
|
||||
///
|
||||
/// `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<'p>(_: Python<'p>, name: &str, base: Option<&PyType>, dict: Option<PyObject>)
|
||||
-> *mut ffi::PyTypeObject
|
||||
{
|
||||
let base: *mut ffi::PyObject = match base {
|
||||
None => std::ptr::null_mut(),
|
||||
Some(obj) => obj.as_ptr()
|
||||
};
|
||||
|
||||
let dict: *mut ffi::PyObject = match dict {
|
||||
None => std::ptr::null_mut(),
|
||||
Some(obj) => obj.as_ptr(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let null_terminated_name = CString::new(name)
|
||||
.expect("Failed to initialize nul terminated exception name");
|
||||
ffi::PyErr_NewException(
|
||||
null_terminated_name.as_ptr() as *mut c_char, base, dict) as *mut ffi::PyTypeObject
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
<exc::SystemError as PyTypeObject>::type_object()
|
||||
} else {
|
||||
Py::from_owned_ptr(ptype)
|
||||
},
|
||||
pvalue: pvalue,
|
||||
ptraceback: PyObject::from_owned_ptr_or_opt(Python::assume_gil_acquired(), ptraceback),
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a standard traceback to sys.stderr.
|
||||
pub fn print(self, py: Python) {
|
||||
self.restore(py);
|
||||
|
@ -322,7 +321,8 @@ impl PyErr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Normalizes the error. This ensures that the exception value is an instance of the exception type.
|
||||
/// Normalizes the error. This ensures that the exception value is an instance
|
||||
/// of the exception type.
|
||||
pub fn normalize(&mut self, py: Python) {
|
||||
// The normalization helper function involves temporarily moving out of the &mut self,
|
||||
// which requires some unsafe trickery:
|
||||
|
@ -352,11 +352,6 @@ impl PyErr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Retrieves the exception type.
|
||||
pub fn get_type(&self, py: Python) -> Py<PyType> {
|
||||
self.ptype.clone_ref(py)
|
||||
}
|
||||
|
||||
/// Retrieves the exception instance for this error.
|
||||
/// This method takes `mut self` because the error might need
|
||||
/// to be normalized in order to create the exception instance.
|
||||
|
@ -410,13 +405,6 @@ impl PyErr {
|
|||
ptraceback: t,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release(self, py: Python) {
|
||||
#[allow(unused_variables)]
|
||||
let PyErr { ptype, pvalue, ptraceback } = self;
|
||||
py.release(ptype);
|
||||
py.release(ptraceback);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PyErr {
|
||||
|
|
|
@ -15,7 +15,7 @@ use python::{Python, ToPyPointer, IntoPyPointer};
|
|||
#[derive(Debug)]
|
||||
pub struct PyObject(*mut ffi::PyObject);
|
||||
|
||||
// `PyObject` is thread-safe, because any python related operations require a Python<'p> token.
|
||||
// `PyObject` is thread-safe, any python related operations require a Python<'p> token.
|
||||
unsafe impl Send for PyObject {}
|
||||
unsafe impl Sync for PyObject {}
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ pub trait ObjectProtocol {
|
|||
/// Casts the PyObject to a concrete Python object type.
|
||||
fn cast_as<'a, D>(&'a self) -> Option<&'a D>
|
||||
where D: PyDowncastFrom,
|
||||
&'a PyObjectRef: std::convert::From<&'a Self>;
|
||||
&'a PyObjectRef: std::convert::From<&'a Self>;
|
||||
|
||||
/// Extracts some type from the Python object.
|
||||
/// This is a wrapper function around `FromPyObject::extract()`.
|
||||
|
|
Loading…
Reference in a new issue