Don't export cstr! macro

This commit is contained in:
Daniel Grunwald 2015-04-18 22:20:19 +02:00
parent f8e24a870c
commit 5a303789b9
7 changed files with 109 additions and 43 deletions

View File

@ -5,7 +5,7 @@ use cpython::{PythonObject, ObjectProtocol, PyModule, Python};
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
let sys = PyModule::import(py, cstr!("sys")).unwrap();
let sys = PyModule::import(py, "sys").unwrap();
let path: String = sys.as_object().getattr("version").unwrap().extract().unwrap();
println!("Hello Python {}", path);
}

View File

@ -5,8 +5,8 @@
use cpython::{PyObject, PyResult, PyModule, Python, PyTuple};
py_module_initializer!("hello", inithello, |py, m| {
try!(m.add(cstr!("__doc__"), "Module documentation string"));
try!(m.add(cstr!("run"), py_func!(py, run)));
try!(m.add("__doc__", "Module documentation string"));
try!(m.add("run", py_func!(py, run)));
try!(add_val(py, &m));
Ok(())
});
@ -19,12 +19,12 @@ fn run<'p>(py: Python<'p>, args: &PyTuple<'p>) -> PyResult<'p, PyObject<'p>> {
Ok(py.None())
}
fn val<'p>(py: Python<'p>, args: &PyTuple<'p>) -> PyResult<'p, i32> {
fn val<'p>(_: Python<'p>, _: &PyTuple<'p>) -> PyResult<'p, i32> {
Ok(42)
}
// Workaround for Rust #24561
fn add_val<'p>(py: Python<'p>, m: &PyModule<'p>) -> PyResult<'p, ()> {
m.add(cstr!("val"), py_func!(py, val))
m.add("val", py_func!(py, val))
}

View File

@ -70,16 +70,16 @@ pub trait FromPyObject<'p, 's> {
// This allows using existing python objects in code that generically expects a value
// convertible to a python object.
impl <'p, T> ToPyObject<'p> for T where T: PythonObject<'p> {
type ObjectType = T;
impl <'p> ToPyObject<'p> for PyObject<'p> {
type ObjectType = PyObject<'p>;
#[inline]
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, T> {
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
Ok(self.clone())
}
#[inline]
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, T> {
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
Ok(self)
}
@ -101,7 +101,6 @@ impl <'p, 's, T> FromPyObject<'p, 's> for T where T: PythonObjectWithCheckedDown
// We support FromPyObject and ToPyObject for borrowed python references.
// This allows using existing python objects in code that generically expects a value
// convertible to a python object.
/*
impl <'p, 's, T> ToPyObject<'p> for &'s T where T : ToPyObject<'p> {
type ObjectType = <T as ToPyObject<'p>>::ObjectType;
@ -121,5 +120,5 @@ impl <'p, 's, T> ToPyObject<'p> for &'s T where T : ToPyObject<'p> {
(**self).with_borrowed_ptr(py, f)
}
}
*/

View File

@ -6,17 +6,34 @@
#![feature(utf8_error)] // for translating Utf8Error to python exception
#![allow(unused_imports, dead_code, unused_variables)]
//! Rust bindings to the python interpreter.
//!
//! # Example
//! ```
//! #[macro_use] extern crate cpython;
//!
//! use cpython::{PythonObject, ObjectProtocol, PyModule, Python};
//!
//! fn main() {
//! let gil = Python::acquire_gil();
//! let py = gil.python();
//! let sys = py.import("sys").unwrap();
//! let version: String = sys.get("version").unwrap().extract().unwrap();
//! println!("Hello Python {}", version);
//! }
//! ```
extern crate libc;
extern crate python27_sys as ffi;
pub use ffi::Py_ssize_t;
pub use err::{PyErr, PyResult};
pub use objects::*;
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, ToPythonPointer};
pub use pythonrun::{GILGuard, prepare_freethreaded_python};
pub use conversion::{FromPyObject, ToPyObject};
pub use objectprotocol::{ObjectProtocol};
#[macro_export]
/// Constructs a `&'static CStr` literal.
macro_rules! cstr(
($s: tt) => (
// TODO: verify that $s is a string literal without nuls
@ -33,21 +50,66 @@ mod objects;
mod objectprotocol;
mod pythonrun;
/// Private re-exports for use in macros.
/// Private re-exports for macros. Do not use.
pub mod _detail {
pub use ffi;
pub use libc;
pub use python::ToPythonPointer;
pub use err::from_owned_ptr_or_panic;
}
/// Expands to an `extern "C"` function that allows python to load
/// the rust code as a python extension module.
///
/// The macro takes three arguments:
///
/// 1. The module name as a string literal.
/// 2. The name of the init function as an identifier.
/// The function must be named `init$module_name` so that python 2.7 can load the module.
/// Note: this parameter will be removed in a future version
/// (once Rust supports `concat_ident!` as function name).
/// 3. A function or lambda of type `Fn(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()>`.
/// This function will be called when the module is imported, and is responsible
/// for adding the module's members.
///
/// # Example
/// ```
/// #![crate_type = "dylib"]
/// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyObject, PyTuple};
///
/// py_module_initializer!("example", initexample, |py, m| {
/// try!(m.add("__doc__", "Module documentation string"));
/// try!(m.add("run", py_func!(py, run)));
/// Ok(())
/// });
///
/// fn run<'p>(py: Python<'p>, args: &PyTuple<'p>) -> PyResult<'p, PyObject<'p>> {
/// println!("Rust says: Hello Python!");
/// Ok(py.None())
/// }
/// # fn main() {}
/// ```
/// The code must be compiled into a file `example.so`.
///
/// ```bash
/// rustc example.rs -o example.so
/// ```
/// It can then be imported into python:
///
/// ```python
/// >>> import example
/// >>> example.run()
/// Rust says: Hello Python!
/// ```
///
#[macro_export]
macro_rules! py_module_initializer {
($name: tt, $init_funcname: ident, $init: expr) => {
#[no_mangle]
pub extern "C" fn $init_funcname() {
let py = unsafe { $crate::Python::assume_gil_acquired() };
match $crate::PyModule::_init(py, cstr!($name), $init) {
let name = unsafe { ::std::ffi::CStr::from_ptr(concat!($name, "\0").as_ptr() as *const _) };
match $crate::PyModule::_init(py, name, $init) {
Ok(()) => (),
Err(e) => e.restore()
}
@ -63,13 +125,13 @@ macro_rules! py_func {
-> *mut $crate::_detail::ffi::PyObject {
let py = $crate::Python::assume_gil_acquired();
let args = $crate::PyObject::from_borrowed_ptr(py, args);
let args: &PyTuple = $crate::PythonObject::unchecked_downcast_borrow_from(&args);
let args: &$crate::PyTuple = $crate::PythonObject::unchecked_downcast_borrow_from(&args);
let result = match $f(py, args) {
Ok(val) => $crate::ToPyObject::into_py_object(val, py),
Err(e) => Err(e)
};
match result {
Ok(val) => $crate::_detail::ToPythonPointer::steal_ptr(val),
Ok(val) => $crate::ToPythonPointer::steal_ptr(val),
Err(e) => { e.restore(); ::std::ptr::null_mut() }
}
}
@ -88,14 +150,3 @@ macro_rules! py_func {
})
}
#[test]
fn it_works() {
let gil = Python::acquire_gil();
let py = gil.python();
let sys = PyModule::import(py, cstr!("sys")).unwrap();
let path = sys.as_object().getattr("path").unwrap();
println!("{0}", path);
}

View File

@ -5,22 +5,22 @@ use python::{Python, PythonObject, ToPythonPointer};
use conversion::ToPyObject;
use objects::{PyObject, PyType, PyDict, exc};
use err::{self, PyResult, PyErr};
use std::ffi::CStr;
use std::ffi::{CStr, CString};
pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type);
impl <'p> PyModule<'p> {
/// Create a new module object with the __name__ attribute set to name.
/// Only the modules __doc__ and __name__ attributes are filled in;
/// the caller is responsible for providing a __file__ attribute.
pub fn new(py: Python<'p>, name: &CStr) -> PyResult<'p, PyModule<'p>> {
pub fn new(py: Python<'p>, name: &str) -> PyResult<'p, PyModule<'p>> {
let name = CString::new(name).unwrap();
unsafe {
err::result_cast_from_owned_ptr(py, ffi::PyModule_New(name.as_ptr()))
}
}
/// Import the python module with the specified name.
pub fn import(py: Python<'p>, name: &CStr) -> PyResult<'p, PyModule<'p>> {
pub fn import(py: Python<'p>, name: &str) -> PyResult<'p, PyModule<'p>> {
let name = CString::new(name).unwrap();
unsafe {
err::result_cast_from_owned_ptr(py, ffi::PyImport_ImportModule(name.as_ptr()))
}
@ -68,10 +68,17 @@ impl <'p> PyModule<'p> {
unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.as_ptr())) }
}
/// Convenience function for retrieving a member from the module.
pub fn get(&self, name: &str) -> PyResult<'p, PyObject<'p>> {
use objectprotocol::ObjectProtocol;
self.as_object().getattr(name)
}
/// Adds a member to the module.
/// This is a convenience function which can be used from the module's initialization function.
pub fn add<V>(&self, name: &CStr, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> {
pub fn add<V>(&self, name: &str, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> {
let py = self.python();
let name = CString::new(name).unwrap();
let value = try!(value.into_py_object(py));
let r = unsafe { ffi::PyModule_AddObject(self.as_ptr(), name.as_ptr(), value.steal_ptr()) };
err::error_on_minusone(py, r)

View File

@ -132,35 +132,34 @@ impl<'p> Python<'p> {
result
}
/// Retrieves a reference to the special 'None' value.
/// Gets the python builtin value `None`.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
pub fn None(self) -> PyObject<'p> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_None()) }
}
/// Retrieves a reference to the 'True' constant value.
/// Gets the python builtin value `True`.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
pub fn True(self) -> PyBool<'p> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_True()).unchecked_cast_into::<PyBool>() }
}
/// Retrieves a reference to the 'False' constant value.
/// Gets the python builtin value `False`.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
pub fn False(self) -> PyBool<'p> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_False()).unchecked_cast_into::<PyBool>() }
}
/// Retrieves a reference to the type object for type T.
#[inline]
/// Gets the python type object for type T.
pub fn get_type<T>(self) -> PyType<'p> where T: PythonObjectWithTypeObject<'p> {
T::type_object(self)
}
/// Import the python module with the specified name.
pub fn import(self, name : &CStr) -> PyResult<'p, PyModule<'p>> {
pub fn import(self, name : &str) -> PyResult<'p, PyModule<'p>> {
PyModule::import(self, name)
}
}

View File

@ -6,6 +6,12 @@ use python::Python;
static START: Once = ONCE_INIT;
/// Prepares the use of python in a free-threaded context.
///
/// If the python interpreter is not already initialized, this function
/// will initialize it with disabled signal handling
/// (python will not raise the `KeyboardInterrupt` exception).
/// Python signal handling depends on the notion of a 'main thread', which must be
/// the thread that initializes the python interpreter.
pub fn prepare_freethreaded_python() {
// Protect against race conditions when python is not yet initialized
// and multiple threads concurrently call 'prepare_freethreaded_python()'.
@ -43,8 +49,11 @@ pub struct GILGuard {
gstate: ffi::PyGILState_STATE
}
/// GILGuard is not Send because the GIL must be released
/// by the same thread that acquired it.
impl !Send for GILGuard {}
/// The Drop implementation for GILGuard will release the GIL.
impl Drop for GILGuard {
fn drop(&mut self) {
unsafe { ffi::PyGILState_Release(self.gstate) }
@ -62,6 +71,7 @@ impl GILGuard {
GILGuard { gstate: gstate }
}
/// Retrieves the marker type that proves that the GIL was acquired.
pub fn python<'p>(&'p self) -> Python<'p> {
unsafe { Python::assume_gil_acquired() }
}