Merge pull request #403 from Alexander-N/__dict__
Complete __dict__ support
This commit is contained in:
commit
d8dc3a17bd
|
@ -47,6 +47,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* A soudness hole where every instances of a `#[pyclass]` struct was considered to be part of a python object, even though you can create instances that are not part of the python heap. This was fixed through `PyRef` and `PyRefMut`.
|
* A soudness hole where every instances of a `#[pyclass]` struct was considered to be part of a python object, even though you can create instances that are not part of the python heap. This was fixed through `PyRef` and `PyRefMut`.
|
||||||
|
* Fix kwargs support in [#328].
|
||||||
|
* Add full support for `__dict__` in [#403].
|
||||||
|
|
||||||
## [0.5.3] - 2019-01-04
|
## [0.5.3] - 2019-01-04
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,7 @@ python object that can be collected, the `PyGCProtocol` trait has to be implemen
|
||||||
* `weakref` - adds support for python weak references
|
* `weakref` - adds support for python weak references
|
||||||
* `extends=BaseType` - use a custom base class. The base BaseType must implement `PyTypeInfo`.
|
* `extends=BaseType` - use a custom base class. The base BaseType must implement `PyTypeInfo`.
|
||||||
* `subclass` - Allows Python classes to inherit from this class
|
* `subclass` - Allows Python classes to inherit from this class
|
||||||
* `dict` - adds `__dict__` support, the instances of this type have a dictionary containing instance variables. (Incomplete, see [#123](https://github.com/PyO3/pyo3/issues/123))
|
* `dict` - adds `__dict__` support, the instances of this type have a dictionary containing instance variables.
|
||||||
|
|
||||||
|
|
||||||
## Constructor
|
## Constructor
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef {
|
||||||
closure: ptr::null_mut(),
|
closure: ptr::null_mut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT;
|
||||||
|
|
||||||
impl Clone for PyGetSetDef {
|
impl Clone for PyGetSetDef {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> PyGetSetDef {
|
fn clone(&self) -> PyGetSetDef {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::ffi3::methodobject::PyMethodDef;
|
use crate::ffi3::methodobject::PyMethodDef;
|
||||||
use crate::ffi3::object::{PyObject, PyTypeObject};
|
use crate::ffi3::object::{
|
||||||
|
PyObject, PyObject_GenericGetDict, PyObject_GenericSetDict, PyTypeObject,
|
||||||
|
};
|
||||||
use crate::ffi3::structmember::PyMemberDef;
|
use crate::ffi3::structmember::PyMemberDef;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -27,6 +29,14 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef {
|
||||||
closure: ptr::null_mut(),
|
closure: ptr::null_mut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef {
|
||||||
|
name: "__dict__\0".as_ptr() as *mut c_char,
|
||||||
|
get: Some(PyObject_GenericGetDict),
|
||||||
|
set: Some(PyObject_GenericSetDict),
|
||||||
|
doc: ptr::null_mut(),
|
||||||
|
closure: ptr::null_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub static mut PyClassMethodDescr_Type: PyTypeObject;
|
pub static mut PyClassMethodDescr_Type: PyTypeObject;
|
||||||
|
|
|
@ -702,6 +702,7 @@ extern "C" {
|
||||||
arg2: *mut PyObject,
|
arg2: *mut PyObject,
|
||||||
arg3: *mut PyObject,
|
arg3: *mut PyObject,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
pub fn PyObject_GenericGetDict(arg1: *mut PyObject, arg2: *mut c_void) -> *mut PyObject;
|
||||||
pub fn PyObject_GenericSetDict(
|
pub fn PyObject_GenericSetDict(
|
||||||
arg1: *mut PyObject,
|
arg1: *mut PyObject,
|
||||||
arg2: *mut PyObject,
|
arg2: *mut PyObject,
|
||||||
|
|
|
@ -321,7 +321,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// __dict__ support
|
// __dict__ support
|
||||||
if T::FLAGS & PY_TYPE_FLAG_DICT != 0 {
|
let has_dict = T::FLAGS & PY_TYPE_FLAG_DICT != 0;
|
||||||
|
if has_dict {
|
||||||
offset -= std::mem::size_of::<*const ffi::PyObject>();
|
offset -= std::mem::size_of::<*const ffi::PyObject>();
|
||||||
type_object.tp_dictoffset = offset as isize;
|
type_object.tp_dictoffset = offset as isize;
|
||||||
}
|
}
|
||||||
|
@ -392,6 +393,10 @@ where
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
let mut props = py_class_properties::<T>();
|
let mut props = py_class_properties::<T>();
|
||||||
|
|
||||||
|
if cfg!(Py_3) && has_dict {
|
||||||
|
props.push(ffi::PyGetSetDef_DICT);
|
||||||
|
}
|
||||||
if !props.is_empty() {
|
if !props.is_empty() {
|
||||||
props.push(ffi::PyGetSetDef_INIT);
|
props.push(ffi::PyGetSetDef_INIT);
|
||||||
type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as *mut _;
|
type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as *mut _;
|
||||||
|
|
|
@ -453,6 +453,22 @@ fn dunder_dict_support() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(Py_3)]
|
||||||
|
#[test]
|
||||||
|
fn access_dunder_dict() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
let inst = PyRef::new(py, DunderDictSupport {}).unwrap();
|
||||||
|
py_run!(
|
||||||
|
py,
|
||||||
|
inst,
|
||||||
|
r#"
|
||||||
|
inst.a = 1
|
||||||
|
assert inst.__dict__ == {'a': 1}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[pyclass(weakref, dict)]
|
#[pyclass(weakref, dict)]
|
||||||
struct WeakRefDunderDictSupport {}
|
struct WeakRefDunderDictSupport {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue