Merge pull request #403 from Alexander-N/__dict__

Complete __dict__ support
This commit is contained in:
konstin 2019-03-18 00:51:48 +01:00 committed by GitHub
commit d8dc3a17bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 4 deletions

View file

@ -47,6 +47,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### 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`.
* Fix kwargs support in [#328].
* Add full support for `__dict__` in [#403].
## [0.5.3] - 2019-01-04

View file

@ -104,8 +104,7 @@ python object that can be collected, the `PyGCProtocol` trait has to be implemen
* `weakref` - adds support for python weak references
* `extends=BaseType` - use a custom base class. The base BaseType must implement `PyTypeInfo`.
* `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

View file

@ -27,6 +27,8 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef {
closure: ptr::null_mut(),
};
pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT;
impl Clone for PyGetSetDef {
#[inline]
fn clone(&self) -> PyGetSetDef {

View file

@ -1,5 +1,7 @@
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 std::os::raw::{c_char, c_int, c_void};
use std::ptr;
@ -27,6 +29,14 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef {
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"))]
extern "C" {
pub static mut PyClassMethodDescr_Type: PyTypeObject;

View file

@ -702,6 +702,7 @@ extern "C" {
arg2: *mut PyObject,
arg3: *mut PyObject,
) -> c_int;
pub fn PyObject_GenericGetDict(arg1: *mut PyObject, arg2: *mut c_void) -> *mut PyObject;
pub fn PyObject_GenericSetDict(
arg1: *mut PyObject,
arg2: *mut PyObject,

View file

@ -321,7 +321,8 @@ where
}
// __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>();
type_object.tp_dictoffset = offset as isize;
}
@ -392,6 +393,10 @@ where
// properties
let mut props = py_class_properties::<T>();
if cfg!(Py_3) && has_dict {
props.push(ffi::PyGetSetDef_DICT);
}
if !props.is_empty() {
props.push(ffi::PyGetSetDef_INIT);
type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as *mut _;

View file

@ -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)]
struct WeakRefDunderDictSupport {}