Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#[pyclass(dict)] makes objects without __dict__ #123

Closed
temoto opened this issue Feb 23, 2018 · 2 comments
Closed

#[pyclass(dict)] makes objects without __dict__ #123

temoto opened this issue Feb 23, 2018 · 2 comments
Labels

Comments

@temoto
Copy link

temoto commented Feb 23, 2018

I tried to mitigate problem of storing &PyObject in pyo3 class struct by going back to Python, using __dict__ instance storage. Documentation mentions single-token attribute to py::class macros. I have studied code that uses this attribute and found it is sophisticated machinery, using special Python C-API construct in PyType header. Respect for special handling of __dict__, AFAIK you could get away with heap allocated PyDict and provide access via getter.

I guess it's some minor scholar mistake again, please point in right direction.

#[py::class(dict)]
struct Hub {
    token: PyToken,
}

#[py::methods]
impl Hub {
    #[new]
    fn __new__(obj: &PyRawObject, py: Python) -> PyResult<()> {
        obj.init(|token| Hub { token: token })
    }
}
% ../venv-27/bin/python -c 'import ext ; print(vars(ext.Hub()))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute

Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64
rustc 1.25.0-nightly (27a046e93 2018-02-18)
Python 2.7.10
setuptools-rust 0.8.3
@konstin konstin added the bug label May 5, 2018
@konstin konstin changed the title #[py::class(dict)] makes objects without __dict__ #[pyclass(dict)] makes objects without __dict__ Nov 24, 2018
@Alexander-N
Copy link
Member

I'd like to work on this, but I would need some hints on what needs to be done.

@konstin
Copy link
Member

konstin commented Mar 13, 2019

As far as I know, tp_dictoffsetin ffi::PyTypeObject needs to be set: https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_dictoffset

Code snippets that should already add __dict__ (but don't work):

pyo3/src/type_object.rs

Lines 323 to 327 in 6c58766

// __dict__ support
if T::FLAGS & PY_TYPE_FLAG_DICT != 0 {
offset -= std::mem::size_of::<*const ffi::PyObject>();
type_object.tp_dictoffset = offset as isize;
}

// insert space for weak ref
let mut has_weakref = false;
let mut has_dict = false;
for f in attr.flags.iter() {
if let syn::Expr::Path(ref epath) = f {
if epath.path == parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_WEAKREF} {
has_weakref = true;
} else if epath.path == parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_DICT} {
has_dict = true;
}
}
}
let weakref = if has_weakref {
quote! {std::mem::size_of::<*const ::pyo3::ffi::PyObject>()}
} else {
quote! {0}
};
let dict = if has_dict {
quote! {std::mem::size_of::<*const ::pyo3::ffi::PyObject>()}
} else {
quote! {0}
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants