2017-06-22 08:04:37 +00:00
|
|
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
|
|
|
|
|
|
|
use std;
|
|
|
|
|
2018-07-30 21:01:46 +00:00
|
|
|
use conversion::{
|
|
|
|
FromPyObject, IntoPyObject, IntoPyTuple, PyTryFrom, ToBorrowedObject, ToPyObject,
|
|
|
|
};
|
|
|
|
use err::{PyDowncastError, PyErr, PyResult};
|
2017-06-22 08:04:37 +00:00
|
|
|
use ffi;
|
2017-06-23 03:56:09 +00:00
|
|
|
use instance::{AsPyRef, PyObjectWithToken};
|
2018-08-25 18:47:30 +00:00
|
|
|
use python::{IntoPyPointer, Python, ToPyPointer};
|
2018-07-30 21:01:46 +00:00
|
|
|
use pythonrun;
|
2018-09-21 21:32:48 +00:00
|
|
|
use types::{PyDict, PyObjectRef, PyTuple};
|
2017-06-22 08:04:37 +00:00
|
|
|
|
2017-07-18 17:13:50 +00:00
|
|
|
/// Safe wrapper around unsafe `*mut ffi::PyObject` pointer.
|
2017-06-22 08:04:37 +00:00
|
|
|
#[derive(Debug)]
|
2018-08-11 15:35:03 +00:00
|
|
|
#[repr(transparent)]
|
2017-06-23 03:56:09 +00:00
|
|
|
pub struct PyObject(*mut ffi::PyObject);
|
2017-06-22 08:04:37 +00:00
|
|
|
|
2017-07-27 03:29:07 +00:00
|
|
|
// `PyObject` is thread-safe, any python related operations require a Python<'p> token.
|
2017-06-23 03:56:09 +00:00
|
|
|
unsafe impl Send for PyObject {}
|
|
|
|
unsafe impl Sync for PyObject {}
|
2017-06-22 08:04:37 +00:00
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
impl PyObject {
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Creates a `PyObject` instance for the given FFI pointer.
|
|
|
|
/// This moves ownership over the pointer into the `PyObject`.
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Undefined behavior if the pointer is NULL or invalid.
|
|
|
|
#[inline]
|
2017-06-23 03:56:09 +00:00
|
|
|
pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
|
2018-07-30 21:01:46 +00:00
|
|
|
debug_assert!(
|
|
|
|
!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
|
|
|
|
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr))
|
|
|
|
);
|
2017-06-23 03:56:09 +00:00
|
|
|
PyObject(ptr)
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Creates a `PyObject` instance for the given FFI pointer.
|
|
|
|
/// Panics if the pointer is `null`.
|
|
|
|
/// Undefined behavior if the pointer is invalid.
|
2017-06-22 08:04:37 +00:00
|
|
|
#[inline]
|
2018-07-30 21:01:46 +00:00
|
|
|
pub unsafe fn from_owned_ptr_or_panic(py: Python, ptr: *mut ffi::PyObject) -> PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
::err::panic_after_error();
|
|
|
|
} else {
|
2017-06-23 20:27:18 +00:00
|
|
|
PyObject::from_owned_ptr(py, ptr)
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Construct `PyObject` from the result of a Python FFI call that
|
2017-06-22 08:04:37 +00:00
|
|
|
/// returns a new reference (owned pointer).
|
|
|
|
/// Returns `Err(PyErr)` if the pointer is `null`.
|
2018-07-30 21:01:46 +00:00
|
|
|
pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<PyObject> {
|
2017-06-22 08:04:37 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
Err(PyErr::fetch(py))
|
|
|
|
} else {
|
2017-12-26 21:41:27 +00:00
|
|
|
Ok(PyObject::from_owned_ptr(py, ptr))
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Construct `PyObject` from the result of a Python FFI call that
|
2017-06-22 08:04:37 +00:00
|
|
|
/// returns a new reference (owned pointer).
|
|
|
|
/// Returns `None` if the pointer is `null`.
|
2018-07-30 21:01:46 +00:00
|
|
|
pub unsafe fn from_owned_ptr_or_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
|
2017-06-22 08:04:37 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
2017-12-26 21:41:27 +00:00
|
|
|
Some(PyObject::from_owned_ptr(py, ptr))
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Creates a `PyObject` instance for the given Python FFI pointer.
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Calls Py_INCREF() on the ptr.
|
|
|
|
/// Undefined behavior if the pointer is NULL or invalid.
|
|
|
|
#[inline]
|
2017-06-23 03:56:09 +00:00
|
|
|
pub unsafe fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
|
2018-07-30 21:01:46 +00:00
|
|
|
debug_assert!(
|
|
|
|
!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
|
|
|
|
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr))
|
|
|
|
);
|
2017-06-22 08:04:37 +00:00
|
|
|
ffi::Py_INCREF(ptr);
|
2017-06-23 03:56:09 +00:00
|
|
|
PyObject(ptr)
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Creates a `PyObject` instance for the given Python FFI pointer.
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Calls Py_INCREF() on the ptr.
|
|
|
|
/// Returns `Err(PyErr)` if the pointer is `null`.
|
2018-07-30 21:01:46 +00:00
|
|
|
pub unsafe fn from_borrowed_ptr_or_err(
|
|
|
|
py: Python,
|
|
|
|
ptr: *mut ffi::PyObject,
|
|
|
|
) -> PyResult<PyObject> {
|
2017-06-22 08:04:37 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
Err(PyErr::fetch(py))
|
|
|
|
} else {
|
2017-12-26 21:41:27 +00:00
|
|
|
Ok(PyObject::from_borrowed_ptr(py, ptr))
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 20:27:18 +00:00
|
|
|
/// Creates a `PyObject` instance for the given Python FFI pointer.
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Calls Py_INCREF() on the ptr.
|
|
|
|
/// Returns `None` if the pointer is `null`.
|
2018-07-30 21:01:46 +00:00
|
|
|
pub unsafe fn from_borrowed_ptr_or_opt(
|
|
|
|
py: Python,
|
|
|
|
ptr: *mut ffi::PyObject,
|
|
|
|
) -> Option<PyObject> {
|
2017-06-22 08:04:37 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
2017-12-26 21:41:27 +00:00
|
|
|
Some(PyObject::from_borrowed_ptr(py, ptr))
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the reference count of the ffi::PyObject pointer.
|
|
|
|
pub fn get_refcnt(&self) -> isize {
|
|
|
|
unsafe { ffi::Py_REFCNT(self.0) }
|
|
|
|
}
|
|
|
|
|
2017-07-18 17:13:50 +00:00
|
|
|
/// Clone self, Calls Py_INCREF() on the ptr.
|
|
|
|
pub fn clone_ref(&self, py: Python) -> Self {
|
2018-07-30 21:01:46 +00:00
|
|
|
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
2017-07-18 17:13:50 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Returns whether the object is considered to be None.
|
|
|
|
/// This is equivalent to the Python expression: 'is None'
|
|
|
|
pub fn is_none(&self) -> bool {
|
|
|
|
unsafe { ffi::Py_None() == self.as_ptr() }
|
|
|
|
}
|
|
|
|
|
2017-06-29 05:23:55 +00:00
|
|
|
/// Returns whether the object is considered to be true.
|
|
|
|
/// This is equivalent to the Python expression: 'not not self'
|
|
|
|
pub fn is_true(&self, py: Python) -> PyResult<bool> {
|
|
|
|
let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
|
|
|
|
if v == -1 {
|
|
|
|
Err(PyErr::fetch(py))
|
|
|
|
} else {
|
|
|
|
Ok(v != 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Casts the PyObject to a concrete Python object type.
|
2018-08-11 15:35:03 +00:00
|
|
|
pub fn cast_as<D>(&self, py: Python) -> Result<&D, PyDowncastError>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
2018-08-11 15:35:03 +00:00
|
|
|
D: PyTryFrom,
|
2017-06-22 08:04:37 +00:00
|
|
|
{
|
2017-07-29 06:19:00 +00:00
|
|
|
D::try_from(self.as_ref(py))
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Extracts some type from the Python object.
|
|
|
|
/// This is a wrapper function around `FromPyObject::extract()`.
|
2018-07-30 21:01:46 +00:00
|
|
|
pub fn extract<'p, D>(&'p self, py: Python) -> PyResult<D>
|
|
|
|
where
|
|
|
|
D: FromPyObject<'p>,
|
2017-06-22 08:04:37 +00:00
|
|
|
{
|
|
|
|
FromPyObject::extract(self.as_ref(py))
|
|
|
|
}
|
|
|
|
|
2017-07-19 20:01:59 +00:00
|
|
|
/// Retrieves an attribute value.
|
|
|
|
/// This is equivalent to the Python expression 'self.attr_name'.
|
|
|
|
pub fn getattr<N>(&self, py: Python, attr_name: N) -> PyResult<PyObject>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
|
|
|
N: ToPyObject,
|
2017-07-19 20:01:59 +00:00
|
|
|
{
|
|
|
|
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
|
2018-07-30 21:01:46 +00:00
|
|
|
PyObject::from_owned_ptr_or_err(py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
|
2017-07-19 20:01:59 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
/// Calls the object.
|
|
|
|
/// This is equivalent to the Python expression: 'self(*args, **kwargs)'
|
2018-08-25 18:47:30 +00:00
|
|
|
pub fn call<A>(&self, py: Python, args: A, kwargs: Option<PyDict>) -> PyResult<PyObject>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
|
|
|
A: IntoPyTuple,
|
2017-06-23 03:56:09 +00:00
|
|
|
{
|
2017-08-03 22:01:52 +00:00
|
|
|
let args = args.into_tuple(py).into_ptr();
|
2018-08-26 19:35:53 +00:00
|
|
|
let kwargs = kwargs.into_ptr();
|
2017-06-23 03:56:09 +00:00
|
|
|
let result = unsafe {
|
2018-08-26 19:35:53 +00:00
|
|
|
PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(self.as_ptr(), args, kwargs))
|
2017-06-23 03:56:09 +00:00
|
|
|
};
|
2018-08-26 19:35:53 +00:00
|
|
|
unsafe {
|
|
|
|
ffi::Py_XDECREF(args);
|
|
|
|
ffi::Py_XDECREF(kwargs);
|
|
|
|
}
|
2017-06-23 03:56:09 +00:00
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2017-08-12 03:17:09 +00:00
|
|
|
/// Calls the object without arguments.
|
|
|
|
/// This is equivalent to the Python expression: 'self()'
|
2018-07-30 21:01:46 +00:00
|
|
|
pub fn call0(&self, py: Python) -> PyResult<PyObject> {
|
2018-08-26 19:35:53 +00:00
|
|
|
self.call(py, PyTuple::empty(py), None)
|
2017-08-12 03:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Calls the object.
|
|
|
|
/// This is equivalent to the Python expression: 'self(*args)'
|
|
|
|
pub fn call1<A>(&self, py: Python, args: A) -> PyResult<PyObject>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
|
|
|
A: IntoPyTuple,
|
2017-08-12 03:17:09 +00:00
|
|
|
{
|
2018-08-26 19:35:53 +00:00
|
|
|
self.call(py, args, None)
|
2017-08-12 03:17:09 +00:00
|
|
|
}
|
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
/// Calls a method on the object.
|
|
|
|
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
|
2018-08-26 19:35:53 +00:00
|
|
|
pub fn call_method<A>(
|
2018-07-30 21:01:46 +00:00
|
|
|
&self,
|
|
|
|
py: Python,
|
|
|
|
name: &str,
|
|
|
|
args: A,
|
2018-08-26 19:35:53 +00:00
|
|
|
kwargs: Option<PyDict>,
|
2018-07-30 21:01:46 +00:00
|
|
|
) -> PyResult<PyObject>
|
|
|
|
where
|
|
|
|
A: IntoPyTuple,
|
2017-06-23 03:56:09 +00:00
|
|
|
{
|
|
|
|
name.with_borrowed_ptr(py, |name| unsafe {
|
2017-08-03 22:01:52 +00:00
|
|
|
let args = args.into_tuple(py).into_ptr();
|
2018-08-25 18:47:30 +00:00
|
|
|
let kwargs = kwargs.into_ptr();
|
2017-06-23 03:56:09 +00:00
|
|
|
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
|
2018-09-24 02:49:52 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
return Err(PyErr::fetch(py));
|
|
|
|
}
|
2018-07-30 21:01:46 +00:00
|
|
|
let result = PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(ptr, args, kwargs));
|
2017-07-19 13:35:59 +00:00
|
|
|
ffi::Py_DECREF(ptr);
|
2018-08-26 19:35:53 +00:00
|
|
|
ffi::Py_XDECREF(args);
|
|
|
|
ffi::Py_XDECREF(kwargs);
|
2017-06-23 03:56:09 +00:00
|
|
|
result
|
|
|
|
})
|
2017-08-12 03:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Calls a method on the object.
|
|
|
|
/// This is equivalent to the Python expression: 'self.name()'
|
2018-07-30 21:01:46 +00:00
|
|
|
pub fn call_method0(&self, py: Python, name: &str) -> PyResult<PyObject> {
|
2018-08-26 19:35:53 +00:00
|
|
|
self.call_method(py, name, PyTuple::empty(py), None)
|
2017-08-12 03:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Calls a method on the object.
|
|
|
|
/// This is equivalent to the Python expression: 'self.name(*args)'
|
|
|
|
pub fn call_method1<A>(&self, py: Python, name: &str, args: A) -> PyResult<PyObject>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
|
|
|
A: IntoPyTuple,
|
2017-08-12 03:17:09 +00:00
|
|
|
{
|
2018-08-26 19:35:53 +00:00
|
|
|
self.call_method(py, name, args, None)
|
2017-06-23 03:56:09 +00:00
|
|
|
}
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
|
2017-06-24 15:28:31 +00:00
|
|
|
impl AsPyRef<PyObjectRef> for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
#[inline]
|
2017-06-24 15:28:31 +00:00
|
|
|
fn as_ref(&self, _py: Python) -> &PyObjectRef {
|
2018-07-30 21:01:46 +00:00
|
|
|
unsafe { &*(self as *const _ as *mut PyObjectRef) }
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
#[inline]
|
2018-08-21 21:51:13 +00:00
|
|
|
fn as_mut(&mut self, _py: Python) -> &mut PyObjectRef {
|
2018-07-30 21:01:46 +00:00
|
|
|
unsafe { &mut *(self as *const _ as *mut PyObjectRef) }
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:01:46 +00:00
|
|
|
impl ToPyObject for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
#[inline]
|
2018-08-26 19:35:53 +00:00
|
|
|
fn to_object(&self, py: Python) -> PyObject {
|
2018-07-30 21:01:46 +00:00
|
|
|
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
2017-07-26 08:11:00 +00:00
|
|
|
}
|
2017-06-22 08:04:37 +00:00
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
impl ToPyPointer for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Gets the underlying FFI pointer, returns a borrowed pointer.
|
|
|
|
#[inline]
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
impl<'a> ToPyPointer for &'a PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Gets the underlying FFI pointer, returns a borrowed pointer.
|
|
|
|
#[inline]
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
impl IntoPyPointer for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Gets the underlying FFI pointer, returns a owned pointer.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
fn into_ptr(self) -> *mut ffi::PyObject {
|
|
|
|
let ptr = self.0;
|
2018-08-26 19:35:53 +00:00
|
|
|
std::mem::forget(self); // Avoid Drop
|
2017-06-22 08:04:37 +00:00
|
|
|
ptr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 03:56:09 +00:00
|
|
|
impl PartialEq for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
#[inline]
|
2017-06-23 03:56:09 +00:00
|
|
|
fn eq(&self, o: &PyObject) -> bool {
|
2017-06-22 08:04:37 +00:00
|
|
|
self.0 == o.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:01:46 +00:00
|
|
|
impl IntoPyObject for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
#[inline]
|
2017-06-23 20:27:18 +00:00
|
|
|
fn into_object(self, _py: Python) -> PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:01:46 +00:00
|
|
|
impl<'a> FromPyObject<'a> for PyObject {
|
2017-06-23 03:56:09 +00:00
|
|
|
#[inline]
|
|
|
|
/// Extracts `Self` from the source `PyObject`.
|
2018-07-30 21:01:46 +00:00
|
|
|
fn extract(ob: &'a PyObjectRef) -> PyResult<Self> {
|
|
|
|
unsafe { Ok(PyObject::from_borrowed_ptr(ob.py(), ob.as_ptr())) }
|
2017-06-23 03:56:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-22 08:04:37 +00:00
|
|
|
/// Dropping a `PyObject` instance decrements the reference count on the object by 1.
|
2017-06-23 03:56:09 +00:00
|
|
|
impl Drop for PyObject {
|
2017-06-22 08:04:37 +00:00
|
|
|
fn drop(&mut self) {
|
2018-07-30 21:01:46 +00:00
|
|
|
unsafe {
|
|
|
|
pythonrun::register_pointer(self.0);
|
|
|
|
}
|
2017-06-22 08:04:37 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-24 02:49:52 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::PyObject;
|
|
|
|
use python::Python;
|
|
|
|
use types::PyDict;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_call_for_non_existing_method() {
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
let py = gil.python();
|
|
|
|
let obj: PyObject = PyDict::new(py).into();
|
|
|
|
assert!(obj.call_method0(py, "asdf").is_err());
|
2018-09-26 23:11:13 +00:00
|
|
|
assert!(
|
|
|
|
obj.call_method(py, "nonexistent_method", (1,), None)
|
|
|
|
.is_err()
|
|
|
|
);
|
2018-09-24 02:49:52 +00:00
|
|
|
assert!(obj.call_method0(py, "nonexistent_method").is_err());
|
|
|
|
assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err());
|
|
|
|
}
|
|
|
|
}
|