From 0a270a05839a38da4678c8d7f18e8b3b761a6eea Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 26 Oct 2015 23:52:18 +0100 Subject: [PATCH] Put Python argument at beginning of argument list. Closes #33. --- examples/hello.rs | 6 +- extensions/custom_type.rs | 4 +- extensions/hello.rs | 6 +- extensions/inheritance.rs | 6 +- src/argparse.rs | 35 +++++----- src/conversion.rs | 8 +-- src/err.rs | 14 ++-- src/function.rs | 2 +- src/lib.rs | 48 ++++++------- src/objectprotocol.rs | 26 +++---- src/objects/boolobject.rs | 2 + src/objects/dict.rs | 40 +++++------ src/objects/exc.rs | 4 +- src/objects/list.rs | 49 +++++++------- src/objects/mod.rs | 8 +-- src/objects/module.rs | 26 +++---- src/objects/num.rs | 6 +- src/objects/object.rs | 23 ++++--- src/objects/oldstyle.rs | 6 +- src/objects/sequence.rs | 124 +++++++++++++++++----------------- src/objects/string.rs | 30 ++++---- src/objects/tests.rs | 5 +- src/objects/tuple.rs | 16 +++-- src/objects/typeobject.rs | 11 +-- src/python.rs | 6 +- src/rustobject/method.rs | 23 +++---- src/rustobject/mod.rs | 20 +++--- src/rustobject/tests.rs | 6 +- src/rustobject/typebuilder.rs | 20 +++--- 29 files changed, 292 insertions(+), 288 deletions(-) diff --git a/examples/hello.rs b/examples/hello.rs index 2973a0d0..26070bf5 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -8,11 +8,11 @@ fn main() { let py = gil.python(); let sys = py.import("sys").unwrap(); - let version: String = sys.get("version", py).unwrap().extract(py).unwrap(); + let version: String = sys.get(py, "version").unwrap().extract(py).unwrap(); let os = py.import("os").unwrap(); - let getenv = os.get("getenv", py).unwrap(); - let user: String = getenv.call(("USER",), None, py).unwrap().extract(py).unwrap(); + let getenv = os.get(py, "getenv").unwrap(); + let user: String = getenv.call(py, ("USER",), None).unwrap().extract(py).unwrap(); println!("Hello {}, I'm Python {}", user, version); } diff --git a/extensions/custom_type.rs b/extensions/custom_type.rs index d1a33b72..14493df1 100644 --- a/extensions/custom_type.rs +++ b/extensions/custom_type.rs @@ -7,8 +7,8 @@ use cpython::{Python, PyObject, PyRustObject, PyResult}; py_module_initializer!(custom_type, |py, m| { - try!(m.add("__doc__", "Module documentation string", py)); - try!(m.add_type::("MyType", py) + try!(m.add(py, "__doc__", "Module documentation string")); + try!(m.add_type::(py, "MyType") .add("a", py_method!(a())) .finish()); Ok(()) diff --git a/extensions/hello.rs b/extensions/hello.rs index d63278d5..bed93716 100644 --- a/extensions/hello.rs +++ b/extensions/hello.rs @@ -7,9 +7,9 @@ use cpython::{PyObject, PyResult, Python, PyTuple, PyDict}; py_module_initializer!(hello, |py, m| { - try!(m.add("__doc__", "Module documentation string", py)); - try!(m.add("run", py_fn!(run), py)); - try!(m.add("val", py_fn!(val()), py)); + try!(m.add(py, "__doc__", "Module documentation string")); + try!(m.add(py, "run", py_fn!(run))); + try!(m.add(py, "val", py_fn!(val()))); Ok(()) }); diff --git a/extensions/inheritance.rs b/extensions/inheritance.rs index 0520fc51..3ef3f539 100644 --- a/extensions/inheritance.rs +++ b/extensions/inheritance.rs @@ -5,14 +5,14 @@ #[macro_use] extern crate cpython; py_module_initializer!(inheritance, |py, m| { - try!(m.add("__doc__", "Module documentation string", py)); + try!(m.add(py, "__doc__", "Module documentation string")); let base_class = try!( - m.add_type::<()>("BaseClass", py) + m.add_type::<()>(py, "BaseClass") .doc("Type doc string") .finish()); for i in 1..10 { try!( - m.add_type::<()>(&format!("C{}", i), py) + m.add_type::<()>(py, &format!("C{}", i)) .base(&base_class) .doc(&format!("Derived class #{}", i)) .finish()); diff --git a/src/argparse.rs b/src/argparse.rs index 9e33d835..b02aed4c 100644 --- a/src/argparse.rs +++ b/src/argparse.rs @@ -43,10 +43,10 @@ pub struct ParamDescription<'a> { /// * output: Output array that receives the arguments. /// Must have same length as `params` and must be initialized to `None`. pub fn parse_args( + py: Python, fname: Option<&str>, params: &[ParamDescription], args: &PyTuple, kwargs: Option<&PyDict>, - output: &mut[Option], - py: Python + output: &mut[Option] ) -> PyResult<()> { assert!(params.len() == output.len()); @@ -65,7 +65,7 @@ pub fn parse_args( let mut used_keywords = 0; // Iterate through the parameters and assign values to output: for (i, (p, out)) in params.iter().zip(output).enumerate() { - match kwargs.and_then(|d| d.get_item(p.name, py)) { + match kwargs.and_then(|d| d.get_item(py, p.name)) { Some(kwarg) => { *out = Some(kwarg); used_keywords += 1; @@ -77,7 +77,7 @@ pub fn parse_args( }, None => { if i < nargs { - *out = Some(args.get_item(i, py)); + *out = Some(args.get_item(py, i)); } else { *out = None; if !p.is_optional { @@ -92,7 +92,7 @@ pub fn parse_args( if used_keywords != nkeywords { // check for extraneous keyword arguments for (key, _value) in kwargs.unwrap().items(py) { - let key = try!(PyString::extract(&key, py)); + let key = try!(PyString::extract(py, &key)); if !params.iter().any(|p| p.name == key) { return Err(err::PyErr::new::(py, format!("'{}' is an invalid keyword argument for this function", @@ -106,11 +106,11 @@ pub fn parse_args( #[doc(hidden)] #[macro_export] macro_rules! py_argparse_extract { - ( $iter:expr, $py:ident, ( ) $body:block ) => { $body }; - ( $iter:expr, $py:ident, ( $pname:ident : $ptype:ty ) $body:block) => { - match <$ptype as $crate::ExtractPyObject>::prepare_extract($iter.next().unwrap().as_ref().unwrap(), $py) { + ( $py:ident, $iter:expr, ( ) $body:block ) => { $body }; + ( $py:ident, $iter:expr, ( $pname:ident : $ptype:ty ) $body:block) => { + match <$ptype as $crate::ExtractPyObject>::prepare_extract($py, $iter.next().unwrap().as_ref().unwrap()) { Ok(prepared) => { - match <$ptype as $crate::ExtractPyObject>::extract(&prepared, $py) { + match <$ptype as $crate::ExtractPyObject>::extract($py, &prepared) { Ok($pname) => $body, Err(e) => Err(e) } @@ -118,9 +118,9 @@ macro_rules! py_argparse_extract { Err(e) => Err(e) } }; - ( $iter:expr, $py: ident, ( $pname:ident : $ptype:ty , $($r:tt)+ ) $body:block) => { - py_argparse_extract!($iter, $py, ($pname: $ptype) { - py_argparse_extract!( $iter, $py, ( $($r)* ) $body) + ( $py: ident, $iter:expr, ( $pname:ident : $ptype:ty , $($r:tt)+ ) $body:block) => { + py_argparse_extract!($py, $iter, ($pname: $ptype) { + py_argparse_extract!( $py, $iter, ( $($r)* ) $body) }) } } @@ -133,8 +133,9 @@ macro_rules! py_argparse_snd { /// This macro is used to parse a parameter list into a set of variables. /// -/// Syntax: `py_argparse!(fname, args, kwargs, (parameter-list) { body })` +/// Syntax: `py_argparse!(py, fname, args, kwargs, (parameter-list) { body })` /// +/// * `py`: the `Python` token /// * `fname`: expression of type `Option<&str>`: Name of the function used in error messages. /// * `args`: expression of type `&PyTuple`: The position arguments /// * `kwargs`: expression of type `Option<&PyDict>`: The named arguments @@ -149,7 +150,7 @@ macro_rules! py_argparse_snd { /// If extraction fails, `py_argparse!()` returns a failed `PyResult` without evaluating `body`. #[macro_export] macro_rules! py_argparse { - ($fname:expr, $args:expr, $kwargs:expr, $py:expr, ($( $pname:ident : $ptype:ty ),*) $body:block) => {{ + ($py:expr, $fname:expr, $args:expr, $kwargs:expr, ($( $pname:ident : $ptype:ty ),*) $body:block) => {{ const PARAMS: &'static [$crate::argparse::ParamDescription<'static>] = &[ $( $crate::argparse::ParamDescription { @@ -160,12 +161,12 @@ macro_rules! py_argparse { ]; let py: $crate::Python = $py; let mut output = [$( py_argparse_snd!($pname, None) ),*]; - match $crate::argparse::parse_args($fname, PARAMS, $args, $kwargs, &mut output, py) { + match $crate::argparse::parse_args(py, $fname, PARAMS, $args, $kwargs, &mut output) { Ok(()) => { // We can't use experimental slice pattern syntax in macros //let &[$(ref $pname),*] = &output; let mut iter = output.iter(); - let ret = py_argparse_extract!( iter, py, ( $( $pname : $ptype ),* ) $body ); + let ret = py_argparse_extract!( py, iter, ( $( $pname : $ptype ),* ) $body ); assert!(iter.next() == None); ret }, @@ -185,7 +186,7 @@ mod test { let py = gil_guard.python(); let mut called = false; let tuple = ("abc", 42).to_py_object(py); - py_argparse!(None, &tuple, None, py, (x: &str, y: i32) { + py_argparse!(py, None, &tuple, None, (x: &str, y: i32) { assert_eq!(x, "abc"); assert_eq!(y, 42); called = true; diff --git a/src/conversion.rs b/src/conversion.rs index fb28784d..e329de1d 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -94,9 +94,9 @@ pub trait ToPyObject { pub trait ExtractPyObject<'prepared> : Sized { type Prepared : 'static; - fn prepare_extract<'a, 'p>(obj: &'a PyObject, py: Python<'p>) -> PyResult; + fn prepare_extract<'a, 'p>(py: Python<'p>, obj: &'a PyObject) -> PyResult; - fn extract<'p>(prepared: &'prepared Self::Prepared, py: Python<'p>) -> PyResult; + fn extract<'p>(py: Python<'p>, prepared: &'prepared Self::Prepared) -> PyResult; } impl <'prepared, T> ExtractPyObject<'prepared> for T @@ -105,12 +105,12 @@ where T: PythonObjectWithCheckedDowncast type Prepared = PyObject; #[inline] - fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + fn prepare_extract(py: Python, obj: &PyObject) -> PyResult { Ok(obj.clone_ref(py)) } #[inline] - fn extract(obj: &'prepared Self::Prepared, py: Python) -> PyResult { + fn extract(py: Python, obj: &'prepared Self::Prepared) -> PyResult { Ok(try!(obj.clone_ref(py).cast_into(py))) } } diff --git a/src/err.rs b/src/err.rs index 1dc5c86b..e684cf05 100644 --- a/src/err.rs +++ b/src/err.rs @@ -91,10 +91,10 @@ impl PyErr { pub fn new(py: Python, value: V) -> PyErr where T: PythonObjectWithTypeObject, V: ToPyObject { - PyErr::new_helper(py.get_type::(), value.to_py_object(py).into_object()) + PyErr::new_helper(py, py.get_type::(), value.to_py_object(py).into_object()) } - fn new_helper(ty: PyType, value: PyObject) -> PyErr { + fn new_helper(_py: Python, ty: PyType, value: PyObject) -> PyErr { assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_object().as_ptr()) } != 0); PyErr { ptype: ty.into_object(), @@ -108,11 +108,11 @@ impl PyErr { /// `obj` must be an Python exception instance, the PyErr will use that instance. /// If `obj` is a Python exception type object, the PyErr will (lazily) create a new instance of that type. /// Otherwise, a `TypeError` is created instead. - pub fn from_instance(obj: O, py: Python) -> PyErr where O: PythonObject { - PyErr::from_instance_helper(obj.into_object(), py) + pub fn from_instance(py: Python, obj: O) -> PyErr where O: PythonObject { + PyErr::from_instance_helper(py, obj.into_object()) } - fn from_instance_helper(obj: PyObject, py: Python) -> PyErr { + fn from_instance_helper(py: Python, obj: PyObject) -> PyErr { if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 { PyErr { ptype: unsafe { PyObject::from_borrowed_ptr(py, ffi::PyExceptionInstance_Class(obj.as_ptr())) }, @@ -162,7 +162,7 @@ impl PyErr { /// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass. /// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match. #[inline] - pub fn matches(&self, exc: &PyObject, _py: Python) -> bool { + pub fn matches(&self, _py: Python, exc: &PyObject) -> bool { unsafe { ffi::PyErr_GivenExceptionMatches(self.ptype.as_ptr(), exc.as_ptr()) != 0 } } @@ -175,7 +175,7 @@ impl PyErr { } // This is safe as long as normalized() doesn't unwind due to a panic. } - + /// Helper function for normalizing the error by deconstructing and reconstructing the PyErr. /// Must not panic for safety in normalize() fn into_normalized(self, py: Python) -> PyErr { diff --git a/src/function.rs b/src/function.rs index 9c350771..83cf06d6 100644 --- a/src/function.rs +++ b/src/function.rs @@ -91,7 +91,7 @@ macro_rules! py_fn { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), py, + match py_argparse!(py, Some(stringify!($f)), &args, kwargs.as_ref(), ( $($pname : $ptype),* ) { $f( py, $($pname),* ) }) { Ok(val) => { diff --git a/src/lib.rs b/src/lib.rs index 0db0c7a9..8ecd0b34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ #![feature(filling_drop)] // necessary to avoid segfault with unsafe_no_drop_flag #![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)] // because some imports are only necessary with python 2.x or 3.x @@ -31,28 +30,25 @@ //! In Python, all objects are implicitly reference counted. //! In rust, we will use the `PyObject` type to represent a reference to a Python object. //! +//! The method `clone_ref()` (from trait `PyClone`) can be used to create additional +//! references to the same Python object. +//! //! Because all Python objects potentially have multiple owners, the concept -//! concept of rust mutability does not apply to Python objects. +//! concept of Rust mutability does not apply to Python objects. //! As a result, this API will allow mutating Python objects even if they are not stored -//! in a mutable rust variable. +//! in a mutable Rust variable. //! //! The Python interpreter uses a global interpreter lock (GIL) //! to ensure thread-safety. -//! This API uses the lifetime parameter `PyObject<'p>` to ensure that Python objects cannot -//! be accessed without holding the GIL. -//! Throughout this library, the lifetime `'p` always refers to the lifetime of the Python interpreter. +//! This API uses a zero-sized `struct Python<'p>` as a token to indicate +//! that a function can assume that the GIL is held. //! -//! When accessing existing objects, the lifetime on `PyObject<'p>` is sufficient to ensure that the GIL -//! is held by the current code. But we also need to ensure that the GIL is held when creating new objects. -//! For this purpose, this library uses the marker type `Python<'p>`, -//! which acts like a reference to the whole Python interpreter. -//! -//! You can obtain a `Python<'p>` instance by acquiring the GIL, or by calling `Python()` -//! on any existing Python object. +//! You obtain a `Python` instance by acquiring the GIL, +//! and have to pass it into all operations that call into the Python runtime. //! //! # Error Handling -//! The vast majority of operations in this library will return `PyResult<'p, ...>`. -//! This is an alias for the type `Result<..., PyErr<'p>>`. +//! The vast majority of operations in this library will return `PyResult<...>`. +//! This is an alias for the type `Result<..., PyErr>`. //! //! A `PyErr` represents a Python exception. Errors within the rust-cpython library are //! also exposed as Python exceptions. @@ -66,14 +62,14 @@ //! //! fn main() { //! let gil = Python::acquire_gil(); -//! let py = gil.python(); +//! let py = gil.python(); // obtain `Python` token //! //! let sys = py.import("sys").unwrap(); -//! let version: String = sys.get("version", py).unwrap().extract(py).unwrap(); +//! let version: String = sys.get(py, "version").unwrap().extract(py).unwrap(); //! //! let os = py.import("os").unwrap(); -//! let getenv = os.get("getenv", py).unwrap(); -//! let user: String = getenv.call(("USER",), None, py).unwrap().extract(py).unwrap(); +//! let getenv = os.get(py, "getenv").unwrap(); +//! let user: String = getenv.call(py, ("USER",), None).unwrap().extract(py).unwrap(); //! //! println!("Hello {}, I'm Python {}", user, version); //! } @@ -142,7 +138,7 @@ pub mod _detail { /// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope /// of the referenced variable. - /// This is useful in macros to ensure that type inference doesn't set 'p == 'static. + /// This is useful in macros to ensure that type inference doesn't set `'p` == `'static`. #[inline] pub unsafe fn bounded_assume_gil_acquired<'p, T>(_bound: &'p T) -> super::Python<'p> { super::Python::assume_gil_acquired() @@ -154,12 +150,8 @@ pub mod _detail { /// /// Macro syntax: `py_module_initializer!($name, |$py, $m| $body)` /// -/// 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, ()>`. +/// 1. `name`: The module name as a Rust identifier. +/// 2. A lambda of type `Fn(Python, &PyModule) -> PyResult<()>`. /// This function will be called when the module is imported, and is responsible /// for adding the module's members. /// @@ -172,8 +164,8 @@ pub mod _detail { /// use cpython::{Python, PyResult, PyObject}; /// /// py_module_initializer!(example, |py, m| { -/// try!(m.add("__doc__", "Module documentation string", py)); -/// try!(m.add("run", py_fn!(run()), py)); +/// try!(m.add(py, "__doc__", "Module documentation string")); +/// try!(m.add(py, "run", py_fn!(run()))); /// Ok(()) /// }); /// diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 77a9ecfe..4a0066da 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -30,7 +30,7 @@ pub trait ObjectProtocol : PythonObject { /// Determines whether this object has the given attribute. /// This is equivalent to the Python expression 'hasattr(self, attr_name)'. #[inline] - fn hasattr(&self, attr_name: N, py: Python) -> PyResult where N: ToPyObject { + fn hasattr(&self, py: Python, attr_name: N) -> PyResult where N: ToPyObject { attr_name.with_borrowed_ptr(py, |attr_name| unsafe { Ok(ffi::PyObject_HasAttr(self.as_ptr(), attr_name) != 0) }) @@ -39,7 +39,7 @@ pub trait ObjectProtocol : PythonObject { /// Retrieves an attribute value. /// This is equivalent to the Python expression 'self.attr_name'. #[inline] - fn getattr(&self, attr_name: N, py: Python) -> PyResult where N: ToPyObject { + fn getattr(&self, py: Python, attr_name: N) -> PyResult where N: ToPyObject { attr_name.with_borrowed_ptr(py, |attr_name| unsafe { err::result_from_owned_ptr(py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name)) @@ -49,7 +49,7 @@ pub trait ObjectProtocol : PythonObject { /// Sets an attribute value. /// This is equivalent to the Python expression 'self.attr_name = value'. #[inline] - fn setattr(&self, attr_name: N, value: V, py: Python) -> PyResult<()> + fn setattr(&self, py: Python, attr_name: N, value: V) -> PyResult<()> where N: ToPyObject, V: ToPyObject { attr_name.with_borrowed_ptr(py, move |attr_name| @@ -62,7 +62,7 @@ pub trait ObjectProtocol : PythonObject { /// Deletes an attribute. /// This is equivalent to the Python expression 'del self.attr_name'. #[inline] - fn delattr(&self, attr_name: N, py: Python) -> PyResult<()> where N: ToPyObject { + fn delattr(&self, py: Python, attr_name: N) -> PyResult<()> where N: ToPyObject { attr_name.with_borrowed_ptr(py, |attr_name| unsafe { err::error_on_minusone(py, ffi::PyObject_DelAttr(self.as_ptr(), attr_name)) @@ -72,7 +72,7 @@ pub trait ObjectProtocol : PythonObject { /// Compares two Python objects. /// This is equivalent to the Python expression 'cmp(self, other)'. #[cfg(feature="python27-sys")] - fn compare(&self, other: O, py: Python) -> PyResult where O: ToPyObject { + fn compare(&self, py: Python, other: O) -> PyResult where O: ToPyObject { other.with_borrowed_ptr(py, |other| unsafe { let mut result : libc::c_int = -1; try!(err::error_on_minusone(py, @@ -126,7 +126,7 @@ pub trait ObjectProtocol : PythonObject { /// Calls the object. /// This is equivalent to the Python expression: 'self(*args, **kwargs)' #[inline] - fn call(&self, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + fn call(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult where A: ToPyObject { args.with_borrowed_ptr(py, |args| unsafe { @@ -137,10 +137,10 @@ pub trait ObjectProtocol : PythonObject { /// Calls a method on the object. /// This is equivalent to the Python expression: 'self.name(*args, **kwargs)' #[inline] - fn call_method(&self, name: &str, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + fn call_method(&self, py: Python, name: &str, args: A, kwargs: Option<&PyDict>) -> PyResult where A: ToPyObject { - try!(self.getattr(name, py)).call(args, kwargs, py) + try!(self.getattr(py, name)).call(py, args, kwargs) } /// Retrieves the hash code of the object. @@ -181,7 +181,7 @@ pub trait ObjectProtocol : PythonObject { /// This is equivalent to the Python expression: 'self[key]' #[inline] - fn get_item(&self, key: K, py: Python) -> PyResult where K: ToPyObject { + fn get_item(&self, py: Python, key: K) -> PyResult where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { err::result_from_owned_ptr(py, ffi::PyObject_GetItem(self.as_ptr(), key)) @@ -191,7 +191,7 @@ pub trait ObjectProtocol : PythonObject { /// Sets an item value. /// This is equivalent to the Python expression 'self[key] = value'. #[inline] - fn set_item(&self, key: K, value: V, py: Python) -> PyResult<()> where K: ToPyObject, V: ToPyObject { + fn set_item(&self, py: Python, key: K, value: V) -> PyResult<()> where K: ToPyObject, V: ToPyObject { key.with_borrowed_ptr(py, move |key| value.with_borrowed_ptr(py, |value| unsafe { err::error_on_minusone(py, @@ -202,14 +202,14 @@ pub trait ObjectProtocol : PythonObject { /// Deletes an item. /// This is equivalent to the Python expression 'del self[key]'. #[inline] - fn del_item(&self, key: K, py: Python) -> PyResult<()> where K: ToPyObject { + fn del_item(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { err::error_on_minusone(py, ffi::PyObject_DelItem(self.as_ptr(), key)) }) } -/* /// Takes an object and returns an iterator for it. +/* TODO /// Takes an object and returns an iterator for it. /// This is typically a new iterator but if the argument /// is an iterator, this returns itself. #[cfg(feature="python27-sys")] @@ -248,7 +248,7 @@ mod test { use std; use python::{Python, PythonObject}; use conversion::ToPyObject; - use objects::{/*PySequence, */PyList, PyTuple}; + use objects::{PyList, PyTuple}; #[test] fn test_debug_string() { diff --git a/src/objects/boolobject.rs b/src/objects/boolobject.rs index 0dcf5d62..882b6b76 100644 --- a/src/objects/boolobject.rs +++ b/src/objects/boolobject.rs @@ -48,3 +48,5 @@ extract!(obj to bool; py => { Ok(try!(obj.cast_as::(py)).is_true()) }); +// TODO: mod tests + diff --git a/src/objects/dict.rs b/src/objects/dict.rs index 3c5573f0..572f39b7 100644 --- a/src/objects/dict.rs +++ b/src/objects/dict.rs @@ -61,7 +61,7 @@ impl PyDict { /// Determine if the dictionary contains the specified key. /// This is equivalent to the Python expression `key in self`. - pub fn contains(&self, key: K, py: Python) -> PyResult where K: ToPyObject { + pub fn contains(&self, py: Python, key: K) -> PyResult where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { match ffi::PyDict_Contains(self.0.as_ptr(), key) { 1 => Ok(true), @@ -73,7 +73,7 @@ impl PyDict { /// Gets an item from the dictionary. /// Returns None if the item is not present, or if an error occurs. - pub fn get_item(&self, key: K, py: Python) -> Option where K: ToPyObject { + pub fn get_item(&self, py: Python, key: K) -> Option where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { PyObject::from_borrowed_ptr_opt(py, ffi::PyDict_GetItem(self.0.as_ptr(), key)) @@ -82,7 +82,7 @@ impl PyDict { /// Sets an item value. /// This is equivalent to the Python expression `self[key] = value`. - pub fn set_item(&self, key: K, value: V, py: Python) -> PyResult<()> where K: ToPyObject, V: ToPyObject { + pub fn set_item(&self, py: Python, key: K, value: V) -> PyResult<()> where K: ToPyObject, V: ToPyObject { key.with_borrowed_ptr(py, move |key| value.with_borrowed_ptr(py, |value| unsafe { err::error_on_minusone(py, @@ -92,7 +92,7 @@ impl PyDict { /// Deletes an item. /// This is equivalent to the Python expression `del self[key]`. - pub fn del_item(&self, key: K, py: Python) -> PyResult<()> where K: ToPyObject { + pub fn del_item(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { err::error_on_minusone(py, ffi::PyDict_DelItem(self.0.as_ptr(), key)) @@ -135,7 +135,7 @@ impl ToPyObject for collections::HashMap fn to_py_object(&self, py: Python) -> PyDict { let dict = PyDict::new(py); for (key, value) in self { - dict.set_item(key, value, py).unwrap(); + dict.set_item(py, key, value).unwrap(); }; dict } @@ -150,7 +150,7 @@ impl ToPyObject for collections::BTreeMap fn to_py_object(&self, py: Python) -> PyDict { let dict = PyDict::new(py); for (key, value) in self { - dict.set_item(key, value, py).unwrap(); + dict.set_item(py, key, value).unwrap(); }; dict } @@ -183,8 +183,8 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert_eq!(true, dict.contains(7i32, py).unwrap()); - assert_eq!(false, dict.contains(8i32, py).unwrap()); + assert_eq!(true, dict.contains(py, 7i32).unwrap()); + assert_eq!(false, dict.contains(py, 8i32).unwrap()); } #[test] @@ -194,8 +194,8 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert_eq!(32, dict.get_item(7i32, py).unwrap().extract::(py).unwrap()); - assert_eq!(None, dict.get_item(8i32, py)); + assert_eq!(32, dict.get_item(py, 7i32).unwrap().extract::(py).unwrap()); + assert_eq!(None, dict.get_item(py, 8i32)); } #[test] @@ -205,10 +205,10 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.set_item(7i32, 42i32, py).is_ok()); // change - assert!(dict.set_item(8i32, 123i32, py).is_ok()); // insert - assert_eq!(42i32, dict.get_item(7i32, py).unwrap().extract::(py).unwrap()); - assert_eq!(123i32, dict.get_item(8i32, py).unwrap().extract::(py).unwrap()); + assert!(dict.set_item(py, 7i32, 42i32).is_ok()); // change + assert!(dict.set_item(py, 8i32, 123i32).is_ok()); // insert + assert_eq!(42i32, dict.get_item(py, 7i32).unwrap().extract::(py).unwrap()); + assert_eq!(123i32, dict.get_item(py, 8i32).unwrap().extract::(py).unwrap()); } #[test] @@ -218,8 +218,8 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.set_item(7i32, 42i32, py).is_ok()); // change - assert!(dict.set_item(8i32, 123i32, py).is_ok()); // insert + assert!(dict.set_item(py, 7i32, 42i32).is_ok()); // change + assert!(dict.set_item(py, 8i32, 123i32).is_ok()); // insert assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated! assert_eq!(None, v.get(&8i32)); } @@ -232,9 +232,9 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.del_item(7i32, py).is_ok()); + assert!(dict.del_item(py, 7i32).is_ok()); assert_eq!(0, dict.len(py)); - assert_eq!(None, dict.get_item(7i32, py)); + assert_eq!(None, dict.get_item(py, 7i32)); } #[test] @@ -244,13 +244,13 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.del_item(7i32, py).is_ok()); // change + assert!(dict.del_item(py, 7i32).is_ok()); // change assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated! } /* #[test] - fn test_items_list() { +TODO fn test_items_list() { let gil = Python::acquire_gil(); let py = gil.python(); let mut v = HashMap::new(); diff --git a/src/objects/exc.rs b/src/objects/exc.rs index baad70ac..6e055100 100644 --- a/src/objects/exc.rs +++ b/src/objects/exc.rs @@ -37,7 +37,7 @@ macro_rules! exc_type( impl PythonObjectWithCheckedDowncast for $name { #[inline] - fn downcast_from<'p>(obj : PyObject, py: Python<'p>) + fn downcast_from<'p>(py: Python<'p>, obj : PyObject) -> Result<$name, PythonObjectDowncastError<'p>> { unsafe { @@ -50,7 +50,7 @@ macro_rules! exc_type( } #[inline] - fn downcast_borrow_from<'a, 'p>(obj: &'a PyObject, py: Python<'p>) + fn downcast_borrow_from<'a, 'p>(py: Python<'p>, obj: &'a PyObject) -> Result<&'a $name, PythonObjectDowncastError<'p>> { unsafe { diff --git a/src/objects/list.rs b/src/objects/list.rs index 2ea30f17..43ef84e7 100644 --- a/src/objects/list.rs +++ b/src/objects/list.rs @@ -52,7 +52,8 @@ impl PyList { /// Gets the item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: usize, py: Python) -> PyObject { + pub fn get_item(&self, py: Python, index: usize) -> PyObject { + // TODO: do we really want to panic here? assert!(index < self.len(py)); unsafe { PyObject::from_borrowed_ptr(py, ffi::PyList_GetItem(self.0.as_ptr(), index as Py_ssize_t)) @@ -62,7 +63,7 @@ impl PyList { /// Sets the item at the specified index. /// /// Panics if the index is out of range. - pub fn set_item(&self, index: usize, item: PyObject, _py: Python) { + pub fn set_item(&self, _py: Python, index: usize, item: PyObject) { let r = unsafe { ffi::PyList_SetItem(self.0.as_ptr(), index as Py_ssize_t, item.steal_ptr()) }; assert!(r == 0); } @@ -70,7 +71,7 @@ impl PyList { /// Inserts an item at the specified index. /// /// Panics if the index is out of range. - pub fn insert_item(&self, index: usize, item: PyObject, _py: Python) { + pub fn insert_item(&self, _py: Python, index: usize, item: PyObject) { let r = unsafe { ffi::PyList_Insert(self.0.as_ptr(), index as Py_ssize_t, item.as_ptr()) }; assert!(r == 0); } @@ -98,7 +99,7 @@ impl <'a, 'p> IntoIterator for &'a PyList { } /// Used by `impl IntoIterator for &PyList`. -pub struct PyListIterator<'p> { +TODO pub struct PyListIterator<'p> { list: PyList, index: usize } @@ -143,20 +144,20 @@ impl <'prepared, T> ExtractPyObject<'prepared> for Vec { type Prepared = Vec; - fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + fn prepare_extract(py: Python, obj: &PyObject) -> PyResult { let list = try!(obj.cast_as::(py)); let len = list.len(py); let mut v = Vec::with_capacity(len); for i in 0 .. len { - v.push(try!(T::prepare_extract(&list.get_item(i, py), py))); + v.push(try!(T::prepare_extract(py, &list.get_item(py, i)))); } Ok(v) } - fn extract(prepared: &'prepared Self::Prepared, py: Python) -> PyResult> { + fn extract(py: Python, prepared: &'prepared Self::Prepared) -> PyResult> { let mut v = Vec::with_capacity(prepared.len()); for prepared_elem in prepared { - v.push(try!(T::extract(prepared_elem, py))); + v.push(try!(T::extract(py, prepared_elem))); } Ok(v) } @@ -184,10 +185,10 @@ mod test { let py = gil.python(); let v = vec![2, 3, 5, 7]; let list = v.to_py_object(py); - assert_eq!(2, list.get_item(0, py).extract::(py).unwrap()); - assert_eq!(3, list.get_item(1, py).extract::(py).unwrap()); - assert_eq!(5, list.get_item(2, py).extract::(py).unwrap()); - assert_eq!(7, list.get_item(3, py).extract::(py).unwrap()); + assert_eq!(2, list.get_item(py, 0).extract::(py).unwrap()); + assert_eq!(3, list.get_item(py, 1).extract::(py).unwrap()); + assert_eq!(5, list.get_item(py, 2).extract::(py).unwrap()); + assert_eq!(7, list.get_item(py, 3).extract::(py).unwrap()); } #[test] @@ -197,9 +198,9 @@ mod test { let v = vec![2, 3, 5, 7]; let list = v.to_py_object(py); let val = 42i32.to_py_object(py).into_object(); - assert_eq!(2, list.get_item(0, py).extract::(py).unwrap()); - list.set_item(0, val, py); - assert_eq!(42, list.get_item(0, py).extract::(py).unwrap()); + assert_eq!(2, list.get_item(py, 0).extract::(py).unwrap()); + list.set_item(py, 0, val); + assert_eq!(42, list.get_item(py, 0).extract::(py).unwrap()); } #[test] @@ -210,16 +211,16 @@ mod test { let list = v.to_py_object(py); let val = 42i32.to_py_object(py).into_object(); assert_eq!(4, list.len(py)); - assert_eq!(2, list.get_item(0, py).extract::(py).unwrap()); - list.insert_item(0, val, py); + assert_eq!(2, list.get_item(py, 0).extract::(py).unwrap()); + list.insert_item(py, 0, val); assert_eq!(5, list.len(py)); - assert_eq!(42, list.get_item(0, py).extract::(py).unwrap()); - assert_eq!(2, list.get_item(1, py).extract::(py).unwrap()); + assert_eq!(42, list.get_item(py, 0).extract::(py).unwrap()); + assert_eq!(2, list.get_item(py, 1).extract::(py).unwrap()); } /* #[test] - fn test_iter() { + fn test_iter() { TODO let gil = Python::acquire_gil(); let py = gil.python(); let v = vec![2, 3, 5, 7]; @@ -246,14 +247,14 @@ mod test { assert_eq!(idx, v.len()); } */ - - /*#[test] + + #[test] fn test_extract() { let gil = Python::acquire_gil(); let py = gil.python(); let v = vec![2, 3, 5, 7]; let list = v.to_py_object(py); - let v2 = list.into_object().extract::>().unwrap(); + let v2 = list.into_object().extract::>(py).unwrap(); assert_eq!(v, v2); - }*/ + } } diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 22892b7c..ebc69c7a 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -102,7 +102,7 @@ macro_rules! pyobject_newtype( impl ::python::PythonObjectWithCheckedDowncast for $name { #[inline] - fn downcast_from<'p>(obj: ::objects::object::PyObject, py: ::python::Python<'p>) -> Result<$name, ::python::PythonObjectDowncastError<'p>> { + fn downcast_from<'p>(py: ::python::Python<'p>, obj: ::objects::object::PyObject) -> Result<$name, ::python::PythonObjectDowncastError<'p>> { unsafe { if ::ffi::$checkfunction(obj.as_ptr()) != 0 { Ok($name(obj)) @@ -113,7 +113,7 @@ macro_rules! pyobject_newtype( } #[inline] - fn downcast_borrow_from<'a, 'p>(obj: &'a ::objects::object::PyObject, py: ::python::Python<'p>) -> Result<&'a $name, ::python::PythonObjectDowncastError<'p>> { + fn downcast_borrow_from<'a, 'p>(py: ::python::Python<'p>, obj: &'a ::objects::object::PyObject) -> Result<&'a $name, ::python::PythonObjectDowncastError<'p>> { unsafe { if ::ffi::$checkfunction(obj.as_ptr()) != 0 { Ok(::std::mem::transmute(obj)) @@ -144,11 +144,11 @@ macro_rules! extract( type Prepared = PyObject; #[inline] - fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + fn prepare_extract(py: Python, obj: &PyObject) -> PyResult { Ok(::python::PyClone::clone_ref(obj, py)) } - fn extract($obj: &'prepared PyObject, $py: Python) -> PyResult { + fn extract($py: Python, $obj: &'prepared PyObject) -> PyResult { $body } } diff --git a/src/objects/module.rs b/src/objects/module.rs index 77f0096c..dfcbe47f 100644 --- a/src/objects/module.rs +++ b/src/objects/module.rs @@ -57,14 +57,14 @@ impl PyModule { } } - unsafe fn str_from_ptr<'a>(&'a self, ptr: *const c_char, py: Python) -> PyResult<&'a str> { - if ptr == std::ptr::null() { + unsafe fn str_from_ptr<'a>(&'a self, py: Python, ptr: *const c_char) -> PyResult<&'a str> { + if ptr.is_null() { Err(PyErr::fetch(py)) } else { let slice = CStr::from_ptr(ptr).to_bytes(); match std::str::from_utf8(slice) { Ok(s) => Ok(s), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, slice, e)), py)) + Err(e) => Err(PyErr::from_instance(py, try!(exc::UnicodeDecodeError::new_utf8(py, slice, e)))) } } } @@ -73,35 +73,35 @@ impl PyModule { /// /// May fail if the module does not have a `__name__` attribute. pub fn name<'a>(&'a self, py: Python) -> PyResult<&'a str> { - unsafe { self.str_from_ptr(ffi::PyModule_GetName(self.0.as_ptr()), py) } + unsafe { self.str_from_ptr(py, ffi::PyModule_GetName(self.0.as_ptr())) } } /// Gets the module filename. /// /// May fail if the module does not have a `__file__` attribute. pub fn filename<'a>(&'a self, py: Python) -> PyResult<&'a str> { - unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.0.as_ptr()), py) } + unsafe { self.str_from_ptr(py, ffi::PyModule_GetFilename(self.0.as_ptr())) } } /// Gets a member from the module. /// This is equivalent to the Python expression: `getattr(module, name)` - pub fn get(&self, name: &str, py: Python) -> PyResult { - self.as_object().getattr(name, py) + pub fn get(&self, py: Python, name: &str) -> PyResult { + self.as_object().getattr(py, name) } /// Calls a function in the module. /// This is equivalent to the Python expression: `getattr(module, name)(*args, **kwargs)` - pub fn call(&self, name: &str, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + pub fn call(&self, py: Python, name: &str, args: A, kwargs: Option<&PyDict>) -> PyResult where A: ToPyObject { - try!(self.as_object().getattr(name, py)).call(args, kwargs, py) + try!(self.as_object().getattr(py, name)).call(py, args, kwargs) } /// Adds a member to the module. /// /// This is a convenience function which can be used from the module's initialization function. - pub fn add(&self, name: &str, value: V, py: Python) -> PyResult<()> where V: ToPyObject { - self.as_object().setattr(name, value, py) + pub fn add(&self, py: Python, name: &str, value: V) -> PyResult<()> where V: ToPyObject { + self.as_object().setattr(py, name, value) } /// Adds a new extension type to the module. @@ -109,9 +109,9 @@ impl PyModule { /// This is a convenience function that creates a new `PyRustTypeBuilder` and /// sets `new_type.__module__` to this module's name. /// The new type will be added to this module when `finish()` is called on the builder. - pub fn add_type<'p, T>(&self, name: &str, py: Python<'p>) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T> + pub fn add_type<'p, T>(&self, py: Python<'p>, name: &str) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T> where T: 'static + Send { - ::rustobject::typebuilder::new_typebuilder_for_module(self, name, py) + ::rustobject::typebuilder::new_typebuilder_for_module(py, self, name) } } diff --git a/src/objects/num.rs b/src/objects/num.rs index 2971373e..0fc5e359 100644 --- a/src/objects/num.rs +++ b/src/objects/num.rs @@ -196,12 +196,12 @@ macro_rules! int_convert_u64_or_i64 ( type Prepared = PyObject; #[inline] - fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + fn prepare_extract(py: Python, obj: &PyObject) -> PyResult { Ok(obj.clone_ref(py)) } #[cfg(feature="python27-sys")] - fn extract(obj: &'prepared PyObject, py: Python) -> PyResult<$rust_type> { + fn extract(py: Python, obj: &'prepared PyObject) -> PyResult<$rust_type> { let ptr = obj.as_ptr(); unsafe { @@ -220,7 +220,7 @@ macro_rules! int_convert_u64_or_i64 ( } #[cfg(feature="python3-sys")] - fn extract(obj: &'prepared PyObject, py: Python) -> PyResult<$rust_type> { + fn extract(py: Python, obj: &'prepared PyObject) -> PyResult<$rust_type> { let ptr = obj.as_ptr(); unsafe { if ffi::PyLong_Check(ptr) != 0 { diff --git a/src/objects/object.rs b/src/objects/object.rs index 7b2458e4..420724cb 100644 --- a/src/objects/object.rs +++ b/src/objects/object.rs @@ -25,17 +25,20 @@ use err::PyResult; /// Represents a reference to a Python object. /// /// Python objects are reference counted. -/// Calling `clone()` on a `PyObject` will return a new reference to the same object +/// Calling `clone_ref()` on a `PyObject` will return a new reference to the same object /// (thus incrementing the reference count). -/// The `Drop` implementation will decrement the reference count. +/// The `Drop` implementation will automatically decrement the reference count. +/// You can also call `release_ref()` to explicitly decrement the reference count. +/// This is slightly faster than relying on automatic drop, because `release_ref` +/// does not need to check whether the GIL needs to be acquired. /// /// `PyObject` can be used with all Python objects, since all python types /// derive from `object`. This crate also contains other, more specific types /// that serve as references to Python objects (e.g. `PyTuple` for Python tuples, etc.). /// -/// You can convert from any Python object to `PyObject` by calling `as_object()` or `into_object` +/// You can convert from any Python object to `PyObject` by calling `as_object()` or `into_object()` /// from the [PythonObject trait](trait.PythonObject.html). -/// In the other direction, you can call `cast_as` or `cast_into` +/// In the other direction, you can call `cast_as()` or `cast_into()` /// on `PyObject` to convert to more specific object types. /// /// Most of the interesting methods are provided by the [ObjectProtocol trait](trait.ObjectProtocol.html). @@ -85,12 +88,12 @@ impl PythonObject for PyObject { impl PythonObjectWithCheckedDowncast for PyObject { #[inline] - fn downcast_from<'p>(obj: PyObject, _py: Python<'p>) -> Result> { + fn downcast_from<'p>(_py: Python<'p>, obj: PyObject) -> Result> { Ok(obj) } #[inline] - fn downcast_borrow_from<'a, 'p>(obj: &'a PyObject, _py: Python<'p>) -> Result<&'a PyObject, PythonObjectDowncastError<'p>> { + fn downcast_borrow_from<'a, 'p>(_py: Python<'p>, obj: &'a PyObject) -> Result<&'a PyObject, PythonObjectDowncastError<'p>> { Ok(obj) } } @@ -209,7 +212,7 @@ impl PyObject { pub fn cast_into<'p, T>(self, py: Python<'p>) -> Result> where T: PythonObjectWithCheckedDowncast { - PythonObjectWithCheckedDowncast::downcast_from(self, py) + PythonObjectWithCheckedDowncast::downcast_from(py, self) } /// Casts the PyObject to a concrete Python object type. @@ -229,7 +232,7 @@ impl PyObject { pub fn cast_as<'s, 'p, T>(&'s self, py: Python<'p>) -> Result<&'s T, PythonObjectDowncastError<'p>> where T: PythonObjectWithCheckedDowncast { - PythonObjectWithCheckedDowncast::downcast_borrow_from(self, py) + PythonObjectWithCheckedDowncast::downcast_borrow_from(py, self) } /// Extracts some type from the Python object. @@ -238,8 +241,8 @@ impl PyObject { pub fn extract(&self, py: Python) -> PyResult where T: for<'prep> ::conversion::ExtractPyObject<'prep> { - let prepared = try!(::prepare_extract(self, py)); - ::extract(&prepared, py) + let prepared = try!(::prepare_extract(py, self)); + ::extract(py, &prepared) } } diff --git a/src/objects/oldstyle.rs b/src/objects/oldstyle.rs index 213dfa75..9158c0b8 100644 --- a/src/objects/oldstyle.rs +++ b/src/objects/oldstyle.rs @@ -40,13 +40,13 @@ pyobject_newtype!(PyInstance, PyInstance_Check, PyInstance_Type); impl PyClass { /// Return true if self is a subclass of base. - pub fn is_subclass_of(&self, base: &PyClass, _py: Python) -> bool { + pub fn is_subclass_of(&self, _py: Python, base: &PyClass) -> bool { unsafe { ffi::PyClass_IsSubclass(self.as_ptr(), base.as_ptr()) != 0 } } /// Create a new instance of the class. /// The parameters args and kw are used as the positional and keyword parameters to the object’s constructor. - pub fn create_instance(&self, args: T, kw: Option<&PyDict>, py: Python) -> PyResult + pub fn create_instance(&self, py: Python, args: T, kw: Option<&PyDict>) -> PyResult where T: ToPyObject { args.with_borrowed_ptr(py, |args| unsafe { @@ -57,7 +57,7 @@ impl PyClass { /// Create a new instance of a specific class without calling its constructor. /// The dict parameter will be used as the object’s __dict__. - pub fn create_instance_raw(&self, dict: &PyDict, py: Python) -> PyResult { + pub fn create_instance_raw(&self, py: Python, dict: &PyDict) -> PyResult { unsafe { err::result_cast_from_owned_ptr(py, ffi::PyInstance_NewRaw(self.as_ptr(), dict.as_object().as_ptr())) diff --git a/src/objects/sequence.rs b/src/objects/sequence.rs index 853a3b14..c0eef63f 100644 --- a/src/objects/sequence.rs +++ b/src/objects/sequence.rs @@ -43,7 +43,7 @@ impl PySequence { /// Return the concatenation of o1 and o2. Equivalent to python `o1 + o2` #[inline] - pub fn concat(&self, other: &PySequence, py: Python) -> PyResult { + pub fn concat(&self, py: Python, other: &PySequence) -> PyResult { unsafe { err::result_from_owned_ptr(py, ffi::PySequence_Concat(self.as_ptr(), other.as_ptr())) } @@ -53,7 +53,7 @@ impl PySequence { /// Equivalent to python `o * count` /// NB: Python accepts negative counts; it returns an empty Sequence. #[inline] - pub fn repeat(&self, count: isize, py: Python) -> PyResult { + pub fn repeat(&self, py: Python, count: isize) -> PyResult { unsafe { err::result_from_owned_ptr(py, ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t)) } @@ -61,7 +61,7 @@ impl PySequence { /// Return the concatenation of o1 and o2 on success. Equivalent to python `o1 += o2` #[inline] - pub fn in_place_concat(&self, other: &PySequence, py: Python) -> PyResult { + pub fn in_place_concat(&self, py: Python, other: &PySequence) -> PyResult { unsafe { result_from_owned_ptr(py, ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr())) } @@ -71,7 +71,7 @@ impl PySequence { /// Equivalent to python `o *= count` /// NB: Python accepts negative counts; it empties the Sequence. #[inline] - pub fn in_place_repeat(&self, count: isize, py: Python) -> PyResult { + pub fn in_place_repeat(&self, py: Python, count: isize) -> PyResult { unsafe { result_from_owned_ptr(py, ffi::PySequence_InPlaceRepeat(self.as_ptr(), count as Py_ssize_t)) @@ -80,7 +80,7 @@ impl PySequence { /// Return the ith element of the Sequence. Equivalent to python `o[index]` #[inline] - pub fn get_item(&self, index: isize, py: Python) -> PyResult { + pub fn get_item(&self, py: Python, index: isize) -> PyResult { unsafe { result_from_owned_ptr(py, ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t)) @@ -90,7 +90,7 @@ impl PySequence { /// Return the slice of sequence object o between begin and end. /// This is the equivalent of the Python expression `o[begin:end]` #[inline] - pub fn get_slice(&self, begin : isize, end : isize, py: Python) -> PyResult { + pub fn get_slice(&self, py: Python, begin : isize, end : isize) -> PyResult { unsafe { result_from_owned_ptr(py, ffi::PySequence_GetSlice(self.as_ptr(), begin as Py_ssize_t, end as Py_ssize_t)) @@ -100,7 +100,7 @@ impl PySequence { /// Assign object v to the ith element of o. /// Equivalent to Python statement `o[i] = v` #[inline] - pub fn set_item(&self, i: isize, v: &PyObject, py: Python) -> PyResult<()> { + pub fn set_item(&self, py: Python, i: isize, v: &PyObject) -> PyResult<()> { unsafe { err::error_on_minusone(py, ffi::PySequence_SetItem(self.as_ptr(), i as Py_ssize_t, v.as_ptr())) @@ -110,7 +110,7 @@ impl PySequence { /// Delete the ith element of object o. /// Python statement `del o[i]` #[inline] - pub fn del_item(&self, i: isize, py: Python) -> PyResult<()> { + pub fn del_item(&self, py: Python, i: isize) -> PyResult<()> { unsafe { err::error_on_minusone(py, ffi::PySequence_DelItem(self.as_ptr(), i as Py_ssize_t)) @@ -120,7 +120,7 @@ impl PySequence { /// Assign the sequence object v to the slice in sequence object o from i1 to i2. /// This is the equivalent of the Python statement `o[i1:i2] = v` #[inline] - pub fn set_slice(&self, i1: isize, i2: isize, v: &PyObject, py: Python) -> PyResult<()> { + pub fn set_slice(&self, py: Python, i1: isize, i2: isize, v: &PyObject) -> PyResult<()> { unsafe { err::error_on_minusone(py, ffi::PySequence_SetSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr())) @@ -130,7 +130,7 @@ impl PySequence { /// Delete the slice in sequence object o from i1 to i2. /// equivalent of the Python statement `del o[i1:i2]` #[inline] - pub fn del_slice(&self, i1: isize, i2: isize, py: Python) -> PyResult<()> { + pub fn del_slice(&self, py: Python, i1: isize, i2: isize) -> PyResult<()> { unsafe { err::error_on_minusone(py, ffi::PySequence_DelSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t)) @@ -140,7 +140,7 @@ impl PySequence { /// Return the number of occurrences of value in o, that is, return the number of keys for /// which `o[key] == value` #[inline] - pub fn count(&self, value: V, py: Python) -> PyResult + pub fn count(&self, py: Python, value: V) -> PyResult where V: ToPyObject { let r = value.with_borrowed_ptr(py, |ptr| unsafe { @@ -155,7 +155,7 @@ impl PySequence { /// Determine if o contains value. this is equivalent to the Python expression `value in o` #[inline] - pub fn contains(&self, value: V, py: Python) -> PyResult + pub fn contains(&self, py: Python, value: V) -> PyResult where V: ToPyObject { let r = value.with_borrowed_ptr(py, |ptr| unsafe { @@ -171,7 +171,7 @@ impl PySequence { /// Return the first index i for which o[i] == value. /// This is equivalent to the Python expression `o.index(value)` #[inline] - pub fn index(&self, value: V, py: Python) -> PyResult + pub fn index(&self, py: Python, value: V) -> PyResult where V: ToPyObject { let r = value.with_borrowed_ptr(py, |ptr| unsafe { @@ -233,7 +233,7 @@ impl <'p> Iterator for PySequenceIterator<'p> { // can't report any errors in underlying size check so we panic. let len = self.sequence.len(self.py).unwrap(); if self.index < len { - match self.sequence.get_item(self.index, self.py) { + match self.sequence.get_item(self.py, self.index) { Ok(item) => { self.index += 1; Some(item) @@ -277,7 +277,7 @@ mod test { assert_eq!(0, seq.len(py).unwrap()); let needle = 7i32.to_py_object(py).into_object(); - assert_eq!(false, seq.contains(&needle, py).unwrap()); + assert_eq!(false, seq.contains(py, &needle).unwrap()); } #[test] @@ -289,13 +289,13 @@ mod test { assert_eq!(6, seq.len(py).unwrap()); let bad_needle = 7i32.to_py_object(py).into_object(); - assert_eq!(false, seq.contains(&bad_needle, py).unwrap()); + assert_eq!(false, seq.contains(py, &bad_needle).unwrap()); let good_needle = 8i32.to_py_object(py).into_object(); - assert_eq!(true, seq.contains(&good_needle, py).unwrap()); + assert_eq!(true, seq.contains(py, &good_needle).unwrap()); let type_coerced_needle = 8f32.to_py_object(py).into_object(); - assert_eq!(true, seq.contains(&type_coerced_needle, py).unwrap()); + assert_eq!(true, seq.contains(py, &type_coerced_needle).unwrap()); } #[test] @@ -304,18 +304,18 @@ mod test { let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - assert_eq!(1, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert_eq!(1, seq.get_item(1, py).unwrap().extract::(py).unwrap()); - assert_eq!(2, seq.get_item(2, py).unwrap().extract::(py).unwrap()); - assert_eq!(3, seq.get_item(3, py).unwrap().extract::(py).unwrap()); - assert_eq!(5, seq.get_item(4, py).unwrap().extract::(py).unwrap()); - assert_eq!(8, seq.get_item(5, py).unwrap().extract::(py).unwrap()); - assert_eq!(8, seq.get_item(-1, py).unwrap().extract::(py).unwrap()); - assert_eq!(5, seq.get_item(-2, py).unwrap().extract::(py).unwrap()); - assert_eq!(3, seq.get_item(-3, py).unwrap().extract::(py).unwrap()); - assert_eq!(2, seq.get_item(-4, py).unwrap().extract::(py).unwrap()); - assert_eq!(1, seq.get_item(-5, py).unwrap().extract::(py).unwrap()); - assert!(seq.get_item(10, py).is_err()); + assert_eq!(1, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert_eq!(1, seq.get_item(py, 1).unwrap().extract::(py).unwrap()); + assert_eq!(2, seq.get_item(py, 2).unwrap().extract::(py).unwrap()); + assert_eq!(3, seq.get_item(py, 3).unwrap().extract::(py).unwrap()); + assert_eq!(5, seq.get_item(py, 4).unwrap().extract::(py).unwrap()); + assert_eq!(8, seq.get_item(py, 5).unwrap().extract::(py).unwrap()); + assert_eq!(8, seq.get_item(py, -1).unwrap().extract::(py).unwrap()); + assert_eq!(5, seq.get_item(py, -2).unwrap().extract::(py).unwrap()); + assert_eq!(3, seq.get_item(py, -3).unwrap().extract::(py).unwrap()); + assert_eq!(2, seq.get_item(py, -4).unwrap().extract::(py).unwrap()); + assert_eq!(1, seq.get_item(py, -5).unwrap().extract::(py).unwrap()); + assert!(seq.get_item(py, 10).is_err()); } // fn test_get_slice() {} @@ -328,21 +328,21 @@ mod test { let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - assert!(seq.del_item(10, py).is_err()); - assert_eq!(1, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert!(seq.del_item(0, py).is_ok()); - assert_eq!(1, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert!(seq.del_item(0, py).is_ok()); - assert_eq!(2, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert!(seq.del_item(0, py).is_ok()); - assert_eq!(3, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert!(seq.del_item(0, py).is_ok()); - assert_eq!(5, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert!(seq.del_item(0, py).is_ok()); - assert_eq!(8, seq.get_item(0, py).unwrap().extract::(py).unwrap()); - assert!(seq.del_item(0, py).is_ok()); + assert!(seq.del_item(py, 10).is_err()); + assert_eq!(1, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(py, 0).is_ok()); + assert_eq!(1, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(py, 0).is_ok()); + assert_eq!(2, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(py, 0).is_ok()); + assert_eq!(3, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(py, 0).is_ok()); + assert_eq!(5, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(py, 0).is_ok()); + assert_eq!(8, seq.get_item(py, 0).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(py, 0).is_ok()); assert_eq!(0, seq.len(py).unwrap()); - assert!(seq.del_item(0, py).is_err()); + assert!(seq.del_item(py, 0).is_err()); } #[test] @@ -351,12 +351,12 @@ mod test { let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - assert_eq!(0, seq.index(1i32, py).unwrap()); - assert_eq!(2, seq.index(2i32, py).unwrap()); - assert_eq!(3, seq.index(3i32, py).unwrap()); - assert_eq!(4, seq.index(5i32, py).unwrap()); - assert_eq!(5, seq.index(8i32, py).unwrap()); - assert!(seq.index(42i32, py).is_err()); + assert_eq!(0, seq.index(py, 1i32).unwrap()); + assert_eq!(2, seq.index(py, 2i32).unwrap()); + assert_eq!(3, seq.index(py, 3i32).unwrap()); + assert_eq!(4, seq.index(py, 5i32).unwrap()); + assert_eq!(5, seq.index(py, 8i32).unwrap()); + assert!(seq.index(py, 42i32).is_err()); } #[test] @@ -365,17 +365,17 @@ mod test { let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - assert_eq!(2, seq.count(1i32, py).unwrap()); - assert_eq!(1, seq.count(2i32, py).unwrap()); - assert_eq!(1, seq.count(3i32, py).unwrap()); - assert_eq!(1, seq.count(5i32, py).unwrap()); - assert_eq!(1, seq.count(8i32, py).unwrap()); - assert_eq!(0, seq.count(42i32, py).unwrap()); + assert_eq!(2, seq.count(py, 1i32).unwrap()); + assert_eq!(1, seq.count(py, 2i32).unwrap()); + assert_eq!(1, seq.count(py, 3i32).unwrap()); + assert_eq!(1, seq.count(py, 5i32).unwrap()); + assert_eq!(1, seq.count(py, 8i32).unwrap()); + assert_eq!(0, seq.count(py, 42i32).unwrap()); } /* #[test] - fn test_seq_iter() { + fn test_seq_iter() { TODO let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; @@ -411,10 +411,10 @@ mod test { let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); let bad_needle = "blurst".to_py_object(py); - assert_eq!(false, seq.contains(bad_needle, py).unwrap()); + assert_eq!(false, seq.contains(py, bad_needle).unwrap()); let good_needle = "worst".to_py_object(py); - assert_eq!(true, seq.contains(good_needle, py).unwrap()); + assert_eq!(true, seq.contains(py, good_needle).unwrap()); } #[test] @@ -423,7 +423,7 @@ mod test { let py = gil.python(); let v : Vec = vec![1, 2, 3]; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - let concat_seq = seq.concat(&seq, py).unwrap().cast_into::(py).unwrap(); + let concat_seq = seq.concat(py, &seq).unwrap().cast_into::(py).unwrap(); assert_eq!(6, concat_seq.len(py).unwrap()); let concat_v : Vec = vec![1, 2, 3, 1, 2, 3]; for (el, cc) in seq.into_iter(py).zip(concat_v) { @@ -437,7 +437,7 @@ mod test { let py = gil.python(); let v = "string"; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - let concat_seq = seq.concat(&seq, py).unwrap().cast_into::(py).unwrap(); + let concat_seq = seq.concat(py, &seq).unwrap().cast_into::(py).unwrap(); assert_eq!(12, concat_seq.len(py).unwrap()); /*let concat_v = "stringstring".to_owned(); for (el, cc) in seq.into_iter(py).zip(concat_v.chars()) { @@ -451,7 +451,7 @@ mod test { let py = gil.python(); let v = vec!["foo", "bar"]; let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - let repeat_seq = seq.repeat(3, py).unwrap().cast_into::(py).unwrap(); + let repeat_seq = seq.repeat(py, 3).unwrap().cast_into::(py).unwrap(); assert_eq!(6, repeat_seq.len(py).unwrap()); let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"]; for (el, rpt) in seq.into_iter(py).zip(repeated.iter()) { diff --git a/src/objects/string.rs b/src/objects/string.rs index 4b7e0616..f5ff2174 100644 --- a/src/objects/string.rs +++ b/src/objects/string.rs @@ -99,7 +99,7 @@ impl PyUnicode { }; match str::from_utf8(bytes.as_slice(py)) { Ok(s) => Ok(Cow::Owned(s.to_owned())), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, bytes.as_slice(py), e)), py)) + Err(e) => Err(PyErr::from_instance(py, try!(exc::UnicodeDecodeError::new_utf8(py, bytes.as_slice(py), e)))) } } @@ -137,7 +137,7 @@ impl PyUnicode { let bytes = try!(self.to_utf8_bytes(py)); match str::from_utf8(bytes) { Ok(s) => Ok(Cow::Borrowed(s)), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, bytes, e)), py)) + Err(e) => Err(PyErr::from_instance(py, try!(exc::UnicodeDecodeError::new_utf8(py, bytes, e)))) } } @@ -164,7 +164,7 @@ impl PyString { /// Returns `TypeError` if the input is not one of the accepted types. /// Returns `UnicodeDecodeError` if the input is not valid unicode. #[cfg(feature="python27-sys")] - pub fn extract<'a>(o: &'a PyObject, py: Python) -> PyResult> { + pub fn extract<'a>(py: Python, o: &'a PyObject) -> PyResult> { if let Ok(s) = o.cast_as::(py) { s.to_string(py) } else if let Ok(u) = o.cast_as::(py) { @@ -184,7 +184,7 @@ impl PyString { /// Returns `TypeError` if the input is not one of the accepted types. /// Any invalid code points are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python27-sys")] - pub fn extract_lossy<'a>(o: &'a PyObject, py: Python) -> PyResult> { + pub fn extract_lossy<'a>(py: Python, o: &'a PyObject) -> PyResult> { if let Ok(s) = o.cast_as::(py) { Ok(s.to_string_lossy(py)) } else if let Ok(u) = o.cast_as::(py) { @@ -204,7 +204,7 @@ impl PyString { /// Returns `TypeError` if the input is not one of the accepted types. /// Returns `UnicodeDecodeError` if the input is not valid unicode. #[cfg(feature="python3-sys")] - pub fn extract<'a>(o: &'a PyObject, py: Python) -> PyResult> { + pub fn extract<'a>(py: Python, o: &'a PyObject) -> PyResult> { if let Ok(u) = o.cast_as::(py) { u.to_string(py) } else { @@ -222,7 +222,7 @@ impl PyString { /// Returns `TypeError` if the input is not one of the accepted types. /// Any invalid code points are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python3-sys")] - pub fn extract_lossy<'a>(o: &'a PyObject, py: Python) -> PyResult> { + pub fn extract_lossy<'a>(py: Python, o: &'a PyObject) -> PyResult> { if let Ok(u) = o.cast_as::(py) { Ok(u.to_string_lossy(py)) } else { @@ -243,7 +243,7 @@ impl PyString { pub fn to_string(&self, py: Python) -> PyResult> { match str::from_utf8(self.as_slice(py)) { Ok(s) => Ok(Cow::Borrowed(s)), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, self.as_slice(py), e)), py)) + Err(e) => Err(PyErr::from_instance(py, try!(exc::UnicodeDecodeError::new_utf8(py, self.as_slice(py), e)))) } } @@ -312,14 +312,14 @@ impl ToPyObject for String { /// Accepts Python `str` and `unicode` objects. /// In Python 2.7, `str` is expected to be UTF-8 encoded. extract!(obj to String; py => { - PyString::extract(obj, py).map(|s| s.into_owned()) + PyString::extract(py, obj).map(|s| s.into_owned()) }); /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. /// In Python 2.7, `str` is expected to be UTF-8 encoded. extract!(obj to Cow<'prepared, str>; py => { - PyString::extract(obj, py) + PyString::extract(py, obj) }); enum PreparedString { @@ -330,18 +330,18 @@ enum PreparedString { impl <'prepared> ExtractPyObject<'prepared> for &'prepared str { type Prepared = PreparedString; - fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { - match try!(PyString::extract(obj, py)) { + fn prepare_extract(py: Python, obj: &PyObject) -> PyResult { + match try!(PyString::extract(py, obj)) { Cow::Owned(s) => Ok(PreparedString::Extracted(s)), Cow::Borrowed(_) => Ok(PreparedString::BorrowFrom(obj.clone_ref(py))) } } - fn extract(prepared: &'prepared PreparedString, py: Python) -> PyResult { + fn extract(py: Python, prepared: &'prepared PreparedString) -> PyResult { match *prepared { PreparedString::Extracted(ref s) => Ok(s), PreparedString::BorrowFrom(ref obj) => { - match try!(PyString::extract(obj, py)) { + match try!(PyString::extract(py, obj)) { Cow::Owned(_) => panic!("Failed to borrow from python object"), Cow::Borrowed(s) => Ok(s) } @@ -370,8 +370,8 @@ mod test { let py = gil.python(); let s = "Hello Python"; let py_string = s.to_py_object(py).into_object(); - let prepared = <&str>::prepare_extract(&py_string, py).unwrap(); - assert_eq!(s, <&str>::extract(&prepared, py).unwrap()); + let prepared = <&str>::prepare_extract(py, &py_string).unwrap(); + assert_eq!(s, <&str>::extract(py, &prepared).unwrap()); } } diff --git a/src/objects/tests.rs b/src/objects/tests.rs index 11efb0eb..fc0c9233 100644 --- a/src/objects/tests.rs +++ b/src/objects/tests.rs @@ -19,6 +19,7 @@ use {Python, PyDict, ToPyObject, PyInt}; use std::collections::{BTreeMap, HashMap}; +// TODO: move these tests into the dict module #[test] fn test_hashmap_to_python() { let gil = Python::acquire_gil(); @@ -30,7 +31,7 @@ fn test_hashmap_to_python() { let py_map = map.to_py_object(py); assert!(py_map.len(py) == 1); - assert!( py_map.get_item(1, py).unwrap().extract::(py).unwrap() == 1); + assert!( py_map.get_item(py, 1).unwrap().extract::(py).unwrap() == 1); } #[test] @@ -44,6 +45,6 @@ fn test_btreemap_to_python() { let py_map = map.to_py_object(py); assert!(py_map.len(py) == 1); - assert!( py_map.get_item(1, py).unwrap().extract::(py).unwrap() == 1); + assert!( py_map.get_item(py, 1).unwrap().extract::(py).unwrap() == 1); } diff --git a/src/objects/tuple.rs b/src/objects/tuple.rs index 2bc68df1..07ee91b2 100644 --- a/src/objects/tuple.rs +++ b/src/objects/tuple.rs @@ -53,7 +53,7 @@ impl PyTuple { /// Gets the length of the tuple. #[inline] pub fn len(&self) -> usize { - // Safe despite not taking a `Python`, because tuples are immutable. + // Safe despite not taking a `Python` token, because tuples are immutable. unsafe { // non-negative Py_ssize_t should always fit into Rust uint ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize @@ -63,7 +63,9 @@ impl PyTuple { /// Gets the item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: usize, py: Python) -> PyObject { + pub fn get_item(&self, py: Python, index: usize) -> PyObject { + // TODO: reconsider whether we should panic + // It's quite inconsistent that this method takes `Python` when `len()` does not. assert!(index < self.len()); unsafe { PyObject::from_borrowed_ptr(py, ffi::PyTuple_GET_ITEM(self.0.as_ptr(), index as Py_ssize_t)) @@ -84,8 +86,10 @@ impl PyTuple { } } +// TODO impl Index for PyTuple + /* -impl IntoIterator for PyTuple { +impl IntoIterator for PyTuple { TODO type Item = PyObject; type IntoIter = PyTupleIterator; @@ -140,7 +144,7 @@ impl <'p> ExactSizeIterator for PyTupleIterator<'p> { } */ -fn wrong_tuple_length(t: &PyTuple, expected_length: usize, py: Python) -> PyErr { +fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr { let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len()); PyErr::new_lazy_init(py.get_type::(), Some(msg.to_py_object(py).into_object())) } @@ -203,7 +207,7 @@ tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D), /// let gil_guard = cpython::Python::acquire_gil(); /// let py = gil_guard.python(); /// let os = py.import("os").unwrap(); -/// let pid = os.call("get_pid", cpython::NoArgs, None, py); +/// let pid = os.call(py, "get_pid", cpython::NoArgs, None); /// ``` #[derive(Copy, Clone, Debug)] pub struct NoArgs; @@ -224,7 +228,7 @@ extract!(obj to NoArgs; py => { if t.len() == 0 { Ok(NoArgs) } else { - Err(wrong_tuple_length(t, 0, py)) + Err(wrong_tuple_length(py, t, 0)) } }); diff --git a/src/objects/typeobject.rs b/src/objects/typeobject.rs index 04d2b890..b914dd96 100644 --- a/src/objects/typeobject.rs +++ b/src/objects/typeobject.rs @@ -35,28 +35,29 @@ impl PyType { } /// Retrieves the PyType instance for the given FFI pointer. + /// This increments the reference count on the type object. /// Undefined behavior if the pointer is NULL or invalid. #[inline] pub unsafe fn from_type_ptr(py: Python, p: *mut ffi::PyTypeObject) -> PyType { PyObject::from_borrowed_ptr(py, p as *mut ffi::PyObject).unchecked_cast_into::() } - /// Return true if self is a subtype of b. + /// Return true if `self` is a subtype of `b`. #[inline] - pub fn is_subtype_of(&self, b : &PyType, _: Python) -> bool { + pub fn is_subtype_of(&self, _: Python, b : &PyType) -> bool { unsafe { ffi::PyType_IsSubtype(self.as_type_ptr(), b.as_type_ptr()) != 0 } } - /// Return true if obj is an instance of self. + /// Return true if `obj` is an instance of `self`. #[inline] - pub fn is_instance(&self, obj : &PyObject, _: Python) -> bool { + pub fn is_instance(&self, _: Python, obj : &PyObject) -> bool { unsafe { ffi::PyObject_TypeCheck(obj.as_ptr(), self.as_type_ptr()) != 0 } } /// Calls the type object, thus creating a new instance. /// This is equivalent to the Python expression: `self(*args, **kwargs)` #[inline] - pub fn call(&self, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + pub fn call(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult where A: ToPyObject { args.with_borrowed_ptr(py, |args| unsafe { diff --git a/src/python.rs b/src/python.rs index 51dbe92a..23806936 100644 --- a/src/python.rs +++ b/src/python.rs @@ -61,10 +61,10 @@ pub struct PythonObjectDowncastError<'p>(pub Python<'p>); /// Trait implemented by Python object types that allow a checked downcast. pub trait PythonObjectWithCheckedDowncast : PythonObject { /// Cast from PyObject to a concrete Python object type. - fn downcast_from<'p>(PyObject, Python<'p>) -> Result>; + fn downcast_from<'p>(Python<'p>, PyObject) -> Result>; /// Cast from PyObject to a concrete Python object type. - fn downcast_borrow_from<'a, 'p>(&'a PyObject, Python<'p>) -> Result<&'a Self, PythonObjectDowncastError<'p>>; + fn downcast_borrow_from<'a, 'p>(Python<'p>, &'a PyObject) -> Result<&'a Self, PythonObjectDowncastError<'p>>; } /// Trait implemented by Python object types that have a corresponding type object. @@ -318,7 +318,7 @@ mod test { let d = PyDict::new(py); - d.set_item("foo", 13, py).unwrap(); + d.set_item(py, "foo", 13).unwrap(); // Inject our own local namespace let v: i32 = py.eval("foo + 29", None, Some(&d)).unwrap().extract(py).unwrap(); diff --git a/src/rustobject/method.rs b/src/rustobject/method.rs index 7e185747..62d9231e 100644 --- a/src/rustobject/method.rs +++ b/src/rustobject/method.rs @@ -54,8 +54,8 @@ use err; /// let multiplier_type = PyRustTypeBuilder::::new(py, "Multiplier") /// .add("mul", py_method!(mul(arg: i32))) /// .finish().unwrap(); -/// let obj = multiplier_type.create_instance(3, (), py).into_object(); -/// let result = obj.call_method("mul", &(4,), None, py).unwrap().extract::(py).unwrap(); +/// let obj = multiplier_type.create_instance(py, 3, ()).into_object(); +/// let result = obj.call_method(py, "mul", &(4,), None).unwrap().extract::(py).unwrap(); /// assert_eq!(result, 12); /// } /// ``` @@ -127,7 +127,7 @@ macro_rules! py_method { None => None }; let ret: $crate::PyResult<_> = - py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), py, + py_argparse!(py, Some(stringify!($f)), &args, kwargs.as_ref(), ( $($pname : $ptype),* ) { $f( py, &slf, $($pname),* ) }); $crate::PyDrop::release_ref(kwargs, py); $crate::PyDrop::release_ref(args, py); @@ -233,7 +233,7 @@ pub mod py_method_impl { impl TypeMember for MethodDescriptor where T: PythonObject { #[inline] - fn to_descriptor(&self, ty: &PyType, _name: &str, py: Python) -> PyObject { + fn to_descriptor(&self, py: Python, ty: &PyType, _name: &str) -> PyObject { unsafe { err::from_owned_ptr_or_panic(py, ffi::PyDescr_NewMethod(ty.as_type_ptr(), self.0)) @@ -250,7 +250,7 @@ impl TypeMember for MethodDescriptor where T: PythonObject { /// Creates a Python class method descriptor that invokes a Rust function. /// /// As arguments, takes the name of a rust function with the signature -/// `fn(&PyType, &PyTuple, Python) -> PyResult` +/// `fn(Python, &PyType, &PyTuple, Option<&PyDict>) -> PyResult` /// for some `T` that implements `ToPyObject`. /// /// Returns a type that implements `typebuilder::TypeMember>` @@ -261,9 +261,8 @@ impl TypeMember for MethodDescriptor where T: PythonObject { /// #![feature(plugin)] /// #![plugin(interpolate_idents)] /// #[macro_use] extern crate cpython; -/// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol, -/// PyTuple, PyType, PyRustTypeBuilder, NoArgs}; -/// use cpython::{exc}; +/// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, +/// PyRustTypeBuilder, NoArgs}; /// /// fn method(py: Python) -> PyResult { /// Ok(42) @@ -275,7 +274,7 @@ impl TypeMember for MethodDescriptor where T: PythonObject { /// let my_type = PyRustTypeBuilder::::new(py, "MyType") /// .add("method", py_class_method!(method())) /// .finish().unwrap(); -/// let result = my_type.as_object().call_method("method", NoArgs, None, py).unwrap(); +/// let result = my_type.as_object().call_method(py, "method", NoArgs, None).unwrap(); /// assert_eq!(42, result.extract::(py).unwrap()); /// } /// ``` @@ -298,7 +297,7 @@ macro_rules! py_class_method { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - let ret: $crate::PyResult<_> = $f(&slf, &args, kwargs.as_ref(), py); + let ret: $crate::PyResult<_> = $f(py, &slf, &args, kwargs.as_ref()); $crate::PyDrop::release_ref(kwargs, py); $crate::PyDrop::release_ref(args, py); $crate::PyDrop::release_ref(slf, py); @@ -349,7 +348,7 @@ macro_rules! py_class_method { None => None }; let ret: $crate::PyResult<_> = - py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), py, + py_argparse!(py, Some(stringify!($f)), &args, kwargs.as_ref(), ( $($pname : $ptype),* ) { $f( py, $($pname),* ) }); $crate::PyDrop::release_ref(kwargs, py); $crate::PyDrop::release_ref(args, py); @@ -394,7 +393,7 @@ pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDes impl TypeMember for ClassMethodDescriptor where T: PythonObject { #[inline] - fn to_descriptor(&self, ty: &PyType, _name: &str, py: Python) -> PyObject { + fn to_descriptor(&self, py: Python, ty: &PyType, _name: &str) -> PyObject { unsafe { err::from_owned_ptr_or_panic(py, ffi::PyDescr_NewClassMethod(ty.as_type_ptr(), self.0)) diff --git a/src/rustobject/mod.rs b/src/rustobject/mod.rs index 5bc86c5b..98c2d307 100644 --- a/src/rustobject/mod.rs +++ b/src/rustobject/mod.rs @@ -40,12 +40,12 @@ pub trait PythonBaseObject : PythonObject { /// and initializes it using init_val. /// `ty` must be derived from the Self type, and the resulting object /// must be of type `ty`. - unsafe fn alloc(ty: &PyType, init_val: Self::InitType, py: Python) -> PyResult; + unsafe fn alloc(py: Python, ty: &PyType, init_val: Self::InitType) -> PyResult; /// Calls the rust destructor for the object and frees the memory /// (usually by calling ptr->ob_type->tp_free). /// This function is used as tp_dealloc implementation. - unsafe fn dealloc(ptr: *mut ffi::PyObject, py: Python); + unsafe fn dealloc(py: Python, ptr: *mut ffi::PyObject); } impl PythonBaseObject for PyObject { @@ -56,12 +56,12 @@ impl PythonBaseObject for PyObject { type InitType = (); - unsafe fn alloc(ty: &PyType, _init_val: (), py: Python) -> PyResult { + unsafe fn alloc(py: Python, ty: &PyType, _init_val: ()) -> PyResult { let ptr = ffi::PyType_GenericAlloc(ty.as_type_ptr(), 0); err::result_from_owned_ptr(py, ptr) } - unsafe fn dealloc(ptr: *mut ffi::PyObject, _py: Python) { + unsafe fn dealloc(_py: Python, ptr: *mut ffi::PyObject) { // Unfortunately, there is no PyType_GenericFree, so // we have to manually un-do the work of PyType_GenericAlloc: let ty = ffi::Py_TYPE(ptr); @@ -130,17 +130,17 @@ impl PythonBaseObject for PyRustObject where T: 'static + Send, B: type InitType = (T, B::InitType); - unsafe fn alloc(ty: &PyType, (val, base_val): Self::InitType, py: Python) -> PyResult { - let obj = try!(B::alloc(ty, base_val, py)); + unsafe fn alloc(py: Python, ty: &PyType, (val, base_val): Self::InitType) -> PyResult { + let obj = try!(B::alloc(py, ty, base_val)); let offset = PyRustObject::::offset() as isize; ptr::write((obj.as_object().as_ptr() as *mut u8).offset(offset) as *mut T, val); Ok(Self::unchecked_downcast_from(obj.into_object())) } - unsafe fn dealloc(obj: *mut ffi::PyObject, py: Python) { + unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) { let offset = PyRustObject::::offset() as isize; ptr::read_and_drop((obj as *mut u8).offset(offset) as *mut T); - B::dealloc(obj, py) + B::dealloc(py, obj) } } @@ -204,9 +204,9 @@ pub struct PyRustType where T: 'static + Send, B: PythonBaseObj impl PyRustType where T: 'static + Send, B: PythonBaseObject { /// Creates a PyRustObject instance from a value. - pub fn create_instance(&self, val: T, base_val: B::InitType, py: Python) -> PyRustObject { + pub fn create_instance(&self, py: Python, val: T, base_val: B::InitType) -> PyRustObject { unsafe { - PythonBaseObject::alloc(&self.type_obj, (val, base_val), py).unwrap() + PythonBaseObject::alloc(py, &self.type_obj, (val, base_val)).unwrap() } } } diff --git a/src/rustobject/tests.rs b/src/rustobject/tests.rs index ad89b29b..d8ebee1c 100644 --- a/src/rustobject/tests.rs +++ b/src/rustobject/tests.rs @@ -37,7 +37,7 @@ fn rustobject_calls_drop() { let t = PyRustTypeBuilder::::new(py, "TypeWithDrop").finish().unwrap(); let drop_called = Arc::new(AtomicBool::new(false)); - let inst = t.create_instance(MyObj { drop_called: drop_called.clone() }, (), py); + let inst = t.create_instance(py, MyObj { drop_called: drop_called.clone() }, ()); assert!(drop_called.load(Ordering::Relaxed) == false); drop(inst); assert!(drop_called.load(Ordering::Relaxed) == true); @@ -49,7 +49,7 @@ fn no_init_from_python() { let gil = Python::acquire_gil(); let py = gil.python(); let t = PyRustTypeBuilder::::new(py, "MyType").finish().unwrap(); - assert!(t.call(&NoArgs, None, py).is_err()); + assert!(t.call(py, &NoArgs, None).is_err()); } @@ -61,7 +61,7 @@ fn heaptype_refcount() { // TODO: investigate why the refcnt isn't 1. //assert_eq!(1, t.as_object().get_refcnt()); let old_refcnt = t.as_object().get_refcnt(py); - let inst = t.create_instance(1, (), py); + let inst = t.create_instance(py, 1, ()); assert_eq!(old_refcnt + 1, t.as_object().get_refcnt(py)); drop(inst); assert_eq!(old_refcnt, t.as_object().get_refcnt(py)); diff --git a/src/rustobject/typebuilder.rs b/src/rustobject/typebuilder.rs index 448067a0..43a80e32 100644 --- a/src/rustobject/typebuilder.rs +++ b/src/rustobject/typebuilder.rs @@ -68,7 +68,7 @@ pub struct PyRustTypeBuilder<'p, T, B = PyObject> where T: 'static + Send, B: Py phantom: marker::PhantomData<&'p (B, T)> } -pub fn new_typebuilder_for_module<'p, T>(m: &PyModule, name: &str, py: Python<'p>) -> PyRustTypeBuilder<'p, T> +pub fn new_typebuilder_for_module<'p, T>(py: Python<'p>, m: &PyModule, name: &str) -> PyRustTypeBuilder<'p, T> where T: 'static + Send { let b = PyRustTypeBuilder::new(py, name); PyRustTypeBuilder { target_module: Some(m.clone_ref(py)), .. b } @@ -86,7 +86,7 @@ unsafe extern "C" fn tp_dealloc_callback(obj: *mut ffi::PyObject) where T: 'static + Send, B: PythonBaseObject { abort_on_panic!({ let py = Python::assume_gil_acquired(); - PyRustObject::::dealloc(obj, py) + PyRustObject::::dealloc(py, obj) }); } @@ -213,7 +213,7 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa pub fn add(mut self, name: &str, val: M) -> Self where M: TypeMember> { self.can_change_base = false; - self.dict().set_item(name, val.to_descriptor(&self.type_obj, name, self.py), self.py).unwrap(); + self.dict().set_item(self.py, name, val.to_descriptor(self.py, &self.type_obj, name)).unwrap(); self } @@ -241,11 +241,11 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa if let Some(m) = self.target_module { // Set module name for new type if let Ok(mod_name) = m.name(py) { - try!(self.type_obj.as_object().setattr("__module__", mod_name, py)); + try!(self.type_obj.as_object().setattr(py, "__module__", mod_name)); } // Register the new type in the target module let name = unsafe { PyObject::from_borrowed_ptr(py, (*self.ht).ht_name) }; - try!(m.dict(py).set_item(name, self.type_obj.as_object(), py)); + try!(m.dict(py).set_item(py, name, self.type_obj.as_object())); } Ok(PyRustType { type_obj: self.type_obj, @@ -278,13 +278,13 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa self.py, &self.name, PyRustObject::::size(), self.flags, &mut self.slots) }); for (name, member) in self.members { - let descr = member.to_descriptor(&type_obj, &name, self.py); - try!(type_obj.as_object().setattr(name, descr, self.py)); + let descr = member.to_descriptor(self.py, &type_obj, &name); + try!(type_obj.as_object().setattr(self.py, name, descr)); } if let Some(m) = self.target_module { // Set module name for new type if let Ok(mod_name) = m.name(self.py) { - try!(type_obj.as_object().setattr("__module__", mod_name, self.py)); + try!(type_obj.as_object().setattr(self.py, "__module__", mod_name)); } // Register the new type in the target module unsafe { @@ -353,7 +353,7 @@ unsafe fn create_type_from_slots<'p>( pub trait TypeMember where T: PythonObject { /// Convert the type member into a python object /// that can be stored in the type dict. - fn to_descriptor(&self, ty: &PyType, name: &str, py: Python) -> PyObject; + fn to_descriptor(&self, py: Python, ty: &PyType, name: &str) -> PyObject; /// Put the type member into a box with lifetime `'p` so that /// it can be used at a later point in time. @@ -367,7 +367,7 @@ pub trait TypeMember where T: PythonObject { impl TypeMember for S where T: PythonObject, S: ToPyObject { #[inline] - fn to_descriptor(&self, _ty: &PyType, _name: &str, py: Python) -> PyObject { + fn to_descriptor(&self, py: Python, _ty: &PyType, _name: &str) -> PyObject { self.to_py_object(py).into_object() }