Skip to content

Commit

Permalink
Merge pull request #403 from Alexander-N/__dict__
Browse files Browse the repository at this point in the history
Complete __dict__ support
  • Loading branch information
konstin committed Mar 17, 2019
2 parents 88924a3 + 5a3466d commit d8dc3a1
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 1 addition & 2 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions src/ffi2/descrobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 11 additions & 1 deletion src/ffi3/descrobject.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/ffi3/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion src/type_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 _;
Expand Down
16 changes: 16 additions & 0 deletions tests/test_dunder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand Down

0 comments on commit d8dc3a1

Please sign in to comment.