Don't export cstr! macro
This commit is contained in:
parent
f8e24a870c
commit
5a303789b9
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
|
87
src/lib.rs
87
src/lib.rs
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 module’s __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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
|
@ -61,7 +70,8 @@ impl GILGuard {
|
|||
let gstate = unsafe { ffi::PyGILState_Ensure() }; // acquire GIL
|
||||
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() }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue