Skip to content

Commit

Permalink
Merge pull request #291 from PyO3/exception_macros
Browse files Browse the repository at this point in the history
Refactor the exception macros
  • Loading branch information
konstin authored Dec 1, 2018
2 parents 27b4c8a + 9102f2e commit 790a103
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 250 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

* Renamed `add_function` to `add_wrapped` as it now also supports modules.
* Renamed `#[pymodinit]` to `#[pymodule]`.
* Renamed `py_exception` to `create_exception` and refactored the error macros.

### Removed

Expand Down
9 changes: 5 additions & 4 deletions guide/src/exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

## Define a new exception

You can use the `py_exception!` macro to define a new exception type:
You can use the `create_exception!` macro to define a new exception type:

```rust
#[macro_use] extern crate pyo3;

py_exception!(module, MyError, pyo3::exceptions::Exception);
create_exception!(module, MyError, pyo3::exceptions::Exception);
```

* `module` is the name of the containing module.
Expand All @@ -20,8 +20,9 @@ For example:

use pyo3::Python;
use pyo3::types::PyDict;
use pyo3::exceptions::Exception;

py_exception!(mymodule, CustomError, pyo3::exceptions::Exception);
create_exception!(mymodule, CustomError, Exception);

fn main() {
let gil = Python::acquire_gil();
Expand Down Expand Up @@ -61,7 +62,7 @@ PyErr::from_instance(py, err).restore(py);

If rust type exists for exception, then it is possible to use `new` method.
For example each standard exception defined in `exc` module
has corresponding rust type, exceptions defined by `py_exception!` and `import_exception!` macro
has corresponding rust type, exceptions defined by `create_exception!` and `import_exception!` macro
have rust type as well.

```rust
Expand Down
4 changes: 2 additions & 2 deletions pyo3cls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use syn::parse::Parser;
use syn::punctuated::Punctuated;

#[proc_macro_attribute]
pub fn mod2init(
pub fn pymodule2(
attr: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
Expand Down Expand Up @@ -46,7 +46,7 @@ pub fn mod2init(
}

#[proc_macro_attribute]
pub fn mod3init(
pub fn pymodule3(
attr: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
Expand Down
109 changes: 7 additions & 102 deletions src/err.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use libc;
use std;
use std::error::Error;
use std::ffi::CString;
use std::io;
use std::os::raw::c_char;

use crate::conversion::{IntoPyObject, ToBorrowedObject, ToPyObject};
use crate::ffi;
Expand All @@ -13,101 +7,12 @@ use crate::object::PyObject;
use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::typeob::PyTypeObject;
use crate::types::{exceptions, PyObjectRef, PyType};

/// Defines a new exception type.
///
/// # Syntax
/// `py_exception!(module, MyError, pyo3::exceptions::Exception)`
///
/// * `module` is the name of the containing module.
/// * `MyError` is the name of the new exception type.
/// * `pyo3::exceptions::Exception` is the name of the base type
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate pyo3;
///
/// use pyo3::Python;
/// use pyo3::types::PyDict;
///
/// py_exception!(mymodule, CustomError, pyo3::exceptions::Exception);
///
/// fn main() {
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let ctx = PyDict::new(py);
///
/// ctx.set_item("CustomError", py.get_type::<CustomError>()).unwrap();
///
/// py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"",
/// None, Some(&ctx)).unwrap();
/// py.run("assert CustomError('oops').args == ('oops',)", None, Some(ctx)).unwrap();
/// }
/// ```
#[macro_export]
macro_rules! py_exception {
($module: ident, $name: ident, $base: ty) => {
pub struct $name;

impl std::convert::From<$name> for $crate::PyErr {
fn from(_err: $name) -> $crate::PyErr {
$crate::PyErr::new::<$name, _>(())
}
}

impl<T> std::convert::Into<$crate::PyResult<T>> for $name {
fn into(self) -> $crate::PyResult<T> {
$crate::PyErr::new::<$name, _>(()).into()
}
}

impl $name {
pub fn py_err<T: $crate::ToPyObject + 'static>(args: T) -> $crate::PyErr {
$crate::PyErr::new::<$name, T>(args)
}
pub fn into<R, T: $crate::ToPyObject + 'static>(args: T) -> $crate::PyResult<R> {
$crate::PyErr::new::<$name, T>(args).into()
}
#[inline]
fn 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() {
let gil = $crate::Python::acquire_gil();
let py = gil.python();

TYPE_OBJECT = $crate::PyErr::new_type(
py,
concat!(stringify!($module), ".", stringify!($name)),
Some(py.get_type::<$base>()),
None,
);
}
TYPE_OBJECT
}
}
}

impl $crate::typeob::PyTypeObject for $name {
#[inline]
fn init_type() {
let _ = $name::type_object();
}

#[inline]
fn type_object() -> $crate::Py<$crate::types::PyType> {
unsafe {
$crate::Py::from_borrowed_ptr(
$name::type_object() as *const _ as *mut $crate::ffi::PyObject
)
}
}
}
};
}
use libc::c_int;
use std;
use std::error::Error;
use std::ffi::CString;
use std::io;
use std::os::raw::c_char;

/// Represents a `PyErr` value
pub enum PyErrValue {
Expand Down Expand Up @@ -607,7 +512,7 @@ pub fn panic_after_error() -> ! {

/// Returns Ok if the error code is not -1.
#[inline]
pub fn error_on_minusone(py: Python, result: libc::c_int) -> PyResult<()> {
pub fn error_on_minusone(py: Python, result: c_int) -> PyResult<()> {
if result != -1 {
Ok(())
} else {
Expand Down
66 changes: 35 additions & 31 deletions src/ffi3/object.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::ffi3::pyport::{Py_hash_t, Py_ssize_t};
use std::mem;
use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void};
use std::ptr;

Expand All @@ -24,7 +25,7 @@ pub const PyObject_HEAD_INIT: PyObject = PyObject {
#[cfg(not(py_sys_config = "Py_TRACE_REFS"))]
pub const PyObject_HEAD_INIT: PyObject = PyObject {
ob_refcnt: 1,
ob_type: ::std::ptr::null_mut(),
ob_type: ptr::null_mut(),
};

#[repr(C)]
Expand Down Expand Up @@ -87,6 +88,7 @@ pub type objobjargproc =
#[cfg(not(Py_LIMITED_API))]
mod bufferinfo {
use crate::ffi3::pyport::Py_ssize_t;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};

#[repr(C)]
Expand All @@ -108,7 +110,7 @@ mod bufferinfo {
impl Default for Py_buffer {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}

Expand Down Expand Up @@ -198,7 +200,9 @@ mod typeobject {
mod typeobject {
use crate::ffi3::pyport::Py_ssize_t;
use crate::ffi3::{self, object};
use std::mem;
use std::os::raw::{c_char, c_uint, c_ulong, c_void};
use std::ptr;

#[repr(C)]
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -244,7 +248,7 @@ mod typeobject {
impl Default for PyNumberMethods {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}
macro_rules! as_expr {
Expand Down Expand Up @@ -320,17 +324,17 @@ mod typeobject {
impl Default for PySequenceMethods {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}
pub const PySequenceMethods_INIT: PySequenceMethods = PySequenceMethods {
sq_length: None,
sq_concat: None,
sq_repeat: None,
sq_item: None,
was_sq_slice: ::std::ptr::null_mut(),
was_sq_slice: ptr::null_mut(),
sq_ass_item: None,
was_sq_ass_slice: ::std::ptr::null_mut(),
was_sq_ass_slice: ptr::null_mut(),
sq_contains: None,
sq_inplace_concat: None,
sq_inplace_repeat: None,
Expand All @@ -346,7 +350,7 @@ mod typeobject {
impl Default for PyMappingMethods {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}
pub const PyMappingMethods_INIT: PyMappingMethods = PyMappingMethods {
Expand All @@ -365,7 +369,7 @@ mod typeobject {
impl Default for PyAsyncMethods {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}
pub const PyAsyncMethods_INIT: PyAsyncMethods = PyAsyncMethods {
Expand All @@ -383,7 +387,7 @@ mod typeobject {
impl Default for PyBufferProcs {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}
pub const PyBufferProcs_INIT: PyBufferProcs = PyBufferProcs {
Expand Down Expand Up @@ -462,37 +466,37 @@ mod typeobject {
ob_base: ffi3::object::PyObject_HEAD_INIT,
ob_size: 0
},
tp_name: ::std::ptr::null(),
tp_name: ptr::null(),
tp_basicsize: 0,
tp_itemsize: 0,
tp_dealloc: None,
tp_print: None,
tp_getattr: None,
tp_setattr: None,
$tp_as_async: ::std::ptr::null_mut(),
$tp_as_async: ptr::null_mut(),
tp_repr: None,
tp_as_number: ::std::ptr::null_mut(),
tp_as_sequence: ::std::ptr::null_mut(),
tp_as_mapping: ::std::ptr::null_mut(),
tp_as_number: ptr::null_mut(),
tp_as_sequence: ptr::null_mut(),
tp_as_mapping: ptr::null_mut(),
tp_hash: None,
tp_call: None,
tp_str: None,
tp_getattro: None,
tp_setattro: None,
tp_as_buffer: ::std::ptr::null_mut(),
tp_as_buffer: ptr::null_mut(),
tp_flags: ffi3::object::Py_TPFLAGS_DEFAULT,
tp_doc: ::std::ptr::null(),
tp_doc: ptr::null(),
tp_traverse: None,
tp_clear: None,
tp_richcompare: None,
tp_weaklistoffset: 0,
tp_iter: None,
tp_iternext: None,
tp_methods: ::std::ptr::null_mut(),
tp_members: ::std::ptr::null_mut(),
tp_getset: ::std::ptr::null_mut(),
tp_base: ::std::ptr::null_mut(),
tp_dict: ::std::ptr::null_mut(),
tp_methods: ptr::null_mut(),
tp_members: ptr::null_mut(),
tp_getset: ptr::null_mut(),
tp_base: ptr::null_mut(),
tp_dict: ptr::null_mut(),
tp_descr_get: None,
tp_descr_set: None,
tp_dictoffset: 0,
Expand All @@ -501,11 +505,11 @@ mod typeobject {
tp_new: None,
tp_free: None,
tp_is_gc: None,
tp_bases: ::std::ptr::null_mut(),
tp_mro: ::std::ptr::null_mut(),
tp_cache: ::std::ptr::null_mut(),
tp_subclasses: ::std::ptr::null_mut(),
tp_weaklist: ::std::ptr::null_mut(),
tp_bases: ptr::null_mut(),
tp_mro: ptr::null_mut(),
tp_cache: ptr::null_mut(),
tp_subclasses: ptr::null_mut(),
tp_weaklist: ptr::null_mut(),
tp_del: None,
tp_version_tag: 0,
$($tail)*
Expand All @@ -522,8 +526,8 @@ mod typeobject {
tp_allocs: 0,
tp_frees: 0,
tp_maxalloc: 0,
tp_prev: ::std::ptr::null_mut(),
tp_next: ::std::ptr::null_mut(),
tp_prev: ptr::null_mut(),
tp_next: ptr::null_mut(),
)
}
}
Expand Down Expand Up @@ -556,7 +560,7 @@ mod typeobject {
impl Default for PyHeapTypeObject {
#[inline]
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}

Expand All @@ -582,7 +586,7 @@ pub struct PyType_Slot {

impl Default for PyType_Slot {
fn default() -> PyType_Slot {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}

Expand All @@ -598,7 +602,7 @@ pub struct PyType_Spec {

impl Default for PyType_Spec {
fn default() -> PyType_Spec {
unsafe { ::std::mem::zeroed() }
unsafe { mem::zeroed() }
}
}

Expand Down
Loading

0 comments on commit 790a103

Please sign in to comment.