py_module_initializer! for python 3

This commit is contained in:
Daniel Grunwald 2015-05-24 20:06:08 +02:00
parent db47455904
commit 8c8779e3fb
9 changed files with 115 additions and 30 deletions

View File

@ -4,8 +4,8 @@ env:
global:
- secure: g4kCg8twONwKPquuJmYrvGjo2n0lNtWTbyzFOITNn8FgCxNK2j38Qc9/UhErTR3g3rDjVzsTHZ8FTH7TJZrOK1Nzz90tJG6JHqUv77ufkcBlxgwwjilOz84uQhkDTMpLitMEeQDLEynKeWbxrjtc5LIpjEkxOPk5eiqwzKRN14c=
script:
- cargo build --verbose
- cargo test --verbose
- make test extensions PY=2
- make test extensions PY=3
# 'cargo doc' is broken due to https://github.com/rust-lang/cargo/issues/1622
# - cargo doc --verbose

View File

@ -23,8 +23,9 @@ exclude = [
build = "build.rs"
[dependencies]
libc="*"
num="*"
libc = "*"
num = "*"
interpolate_idents = "*"
# These features are both optional, but you must pick one to
# indicate which python ffi you are trying to bind to.

View File

@ -1,18 +1,29 @@
.PHONY: default build test doc extensions clean
ifndef PY
PY=3
endif
ifeq ($(PY),2)
FEATURES=--features python27-sys --no-default-features
endif
ifeq ($(PY),3)
FEATURES=--features python3-sys --no-default-features
endif
default: test extensions
build:
cargo build
cargo build $(FEATURES)
test: build
cargo test
cargo test $(FEATURES)
doc: build
cargo doc --no-deps
cargo doc --no-deps $(FEATURES)
extensions: build
make -C extensions/
make -C extensions/ PY=$(PY)
clean:
rm -r target

View File

@ -3,6 +3,10 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst
.PHONY: all clean
ifndef PY
PY=3
endif
all:
clean:
@ -13,15 +17,16 @@ clean:
stamps:
mkdir stamps
stamps/rust-cpython: $(call rwildcard,../src,*.rs) Makefile | stamps
cd .. && cargo build
stamps/rust-cpython-$(PY): $(call rwildcard,../src,*.rs) Makefile | stamps
-rm stamps/rust-cpython-*
cd .. && make build PY=$(PY)
touch $@
%.so: %.rs stamps/rust-cpython
%.so: %.rs stamps/rust-cpython-$(PY)
rustc $< -L $(TARGETDIR) -L $(TARGETDIR)/deps -o $@
hello.out: hello.so
python -c "import hello; hello.run(hello.val())" 2>&1 | tee $@
python$(PY) -c "import hello; hello.run(hello.val())" 2>&1 | tee $@
all: stamps/test-hello
stamps/test-hello: hello.out

View File

@ -1,10 +1,12 @@
#![crate_type = "dylib"]
#![feature(plugin)]
#![plugin(interpolate_idents)]
#[macro_use] extern crate cpython;
use cpython::{PyObject, PyResult, PyModule, Python, PyTuple};
py_module_initializer!("hello", inithello, |py, m| {
py_module_initializer!(hello, |py, m| {
try!(m.add("__doc__", "Module documentation string"));
try!(m.add("run", py_func!(py, run)));
try!(add_val(py, &m));

View File

@ -40,11 +40,13 @@ pub struct PyModuleDef_Base {
impl ::std::clone::Clone for PyModuleDef_Base {
fn clone(&self) -> PyModuleDef_Base { *self }
}
impl ::std::default::Default for PyModuleDef_Base {
fn default() -> PyModuleDef_Base {
unsafe { ::std::mem::zeroed() }
}
}
pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base {
ob_base: PyObject_HEAD_INIT,
m_init: None,
m_index: 0,
m_copy: 0 as *mut PyObject
};
#[repr(C)]
#[derive(Copy)]
@ -62,7 +64,5 @@ pub struct PyModuleDef {
impl ::std::clone::Clone for PyModuleDef {
fn clone(&self) -> PyModuleDef { *self }
}
impl ::std::default::Default for PyModuleDef {
fn default() -> PyModuleDef { unsafe { ::std::mem::zeroed() } }
}

View File

@ -13,6 +13,20 @@ pub struct PyObject {
pub ob_type: *mut PyTypeObject,
}
#[cfg(py_sys_config="Py_TRACE_REFS")]
pub const PyObject_HEAD_INIT: PyObject = PyObject {
_ob_next: 0 as *mut PyObject,
_ob_prev: 0 as *mut PyObject,
ob_refcnt: 1,
ob_type: 0 as *mut PyTypeObject
};
#[cfg(not(py_sys_config="Py_TRACE_REFS"))]
pub const PyObject_HEAD_INIT: PyObject = PyObject {
ob_refcnt: 1,
ob_type: 0 as *mut PyTypeObject
};
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyVarObject {

View File

@ -22,6 +22,8 @@
#![feature(optin_builtin_traits)] // for opting out of Sync/Send
#![feature(slice_patterns)] // for tuple_conversion macros
#![feature(utf8_error)] // for translating Utf8Error to python exception
#![feature(plugin)]
#![plugin(interpolate_idents)]
#![allow(unused_imports, unused_variables)]
//! Rust bindings to the python interpreter.
@ -129,10 +131,12 @@ pub mod _detail {
/// # Example
/// ```
/// #![crate_type = "dylib"]
/// #![feature(plugin)]
/// #![plugin(interpolate_idents)]
/// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyObject, PyTuple};
///
/// py_module_initializer!("example", initexample, |py, m| {
/// py_module_initializer!(example, |py, m| {
/// try!(m.add("__doc__", "Module documentation string"));
/// try!(m.add("run", py_func!(py, run)));
/// Ok(())
@ -158,18 +162,55 @@ pub mod _detail {
/// ```
///
#[macro_export]
#[cfg(feature="python27-sys")]
macro_rules! py_module_initializer {
($name: tt, $init_funcname: ident, $init: expr) => {
#[no_mangle]
pub extern "C" fn $init_funcname() {
($name: ident, $init: expr) => ( interpolate_idents! {
#[[no_mangle]]
#[allow(non_snake_case)]
pub extern "C" fn [ init $name ]() {
let py = unsafe { $crate::Python::assume_gil_acquired() };
let name = unsafe { ::std::ffi::CStr::from_ptr(concat!($name, "\0").as_ptr() as *const _) };
let name = unsafe { ::std::ffi::CStr::from_ptr(concat!(stringify!($name), "\0").as_ptr() as *const _) };
match $crate::PyModule::_init(py, name, $init) {
Ok(()) => (),
Err(e) => e.restore()
}
}
}
})
}
#[macro_export]
#[cfg(feature="python3-sys")]
macro_rules! py_module_initializer {
($name: ident, $init: expr) => ( interpolate_idents! {
#[[no_mangle]]
#[allow(non_snake_case)]
pub extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject {
let py = unsafe { $crate::Python::assume_gil_acquired() };
static mut module_def: $crate::_detail::ffi::PyModuleDef = $crate::_detail::ffi::PyModuleDef {
m_base: $crate::_detail::ffi::PyModuleDef_HEAD_INIT,
m_name: 0 as *const _,
m_doc: 0 as *const _,
m_size: 0, // we don't use per-module state
m_methods: 0 as *mut _,
m_reload: None,
m_traverse: None,
m_clear: None,
m_free: None
};
// We can't convert &'static str to *const c_char within a static initializer,
// so we'll do it here in the module initialization:
unsafe {
module_def.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
}
match $crate::PyModule::_init(py, unsafe { &mut module_def }, $init) {
Ok(m) => $crate::ToPythonPointer::steal_ptr(m),
Err(e) => {
e.restore();
return ::std::ptr::null_mut();
}
}
}
})
}
/// Creates a python callable object that invokes a Rust function.

View File

@ -47,13 +47,24 @@ impl <'p> PyModule<'p> {
// Helper method for module_initializer!() macro, do not use directly!
#[doc(hidden)]
#[cfg(feature="python27-sys")]
pub fn _init<F, R>(py: Python<'p>, name: &CStr, init: F) -> PyResult<'p, R>
where F: FnOnce(Python<'p>, PyModule<'p>) -> PyResult<'p, R> {
pub fn _init<F>(py: Python<'p>, name: &CStr, init: F) -> PyResult<'p, ()>
where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
let module = try!(unsafe {
err::result_from_borrowed_ptr(py, ffi::Py_InitModule(name.as_ptr(), std::ptr::null_mut()))
});
let module = try!(module.cast_into::<PyModule>());
init(py, module)
init(py, &module)
}
#[doc(hidden)]
#[cfg(feature="python3-sys")]
pub fn _init<F>(py: Python<'p>, def: *mut ffi::PyModuleDef, init: F) -> PyResult<'p, PyModule<'p>>
where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
let module: PyModule = try!(unsafe {
err::result_cast_from_owned_ptr(py, ffi::PyModule_Create(def))
});
try!(init(py, &module));
Ok(module)
}
/// Return the dictionary object that implements modules namespace;