feat: Adds the Bound<'_, PyMappingProxy> type#4644
Conversation
Adds in the MappingProxy type.
|
Thanks for the PR! This is in draft status; is there more you want to add before review? |
Nope! Just got busy yesterday and wanted to do a final look through. Please review when ready. |
davidhewitt
left a comment
There was a problem hiding this comment.
Thanks for picking this up; overall this looks close to merge. While I have added a bunch of comments, they're primarily small tweaks where I think the design is relatively clear 😄
| #[inline] | ||
| pub unsafe fn PyDictProxy_Check(op: *mut PyObject) -> c_int { | ||
| PyObject_TypeCheck(op, std::ptr::addr_of_mut!(PyDictProxy_Type)) | ||
| } |
There was a problem hiding this comment.
This function doesn't exist in https://github.com/python/cpython/blob/3.13/Include/descrobject.h (indeed I couldn't find it anywhere). So we shouldn't add this.
| #[inline] | |
| pub unsafe fn PyDictProxy_Check(op: *mut PyObject) -> c_int { | |
| PyObject_TypeCheck(op, std::ptr::addr_of_mut!(PyDictProxy_Type)) | |
| } |
|
|
||
| /// Represents a tuple which can be used as a PyDict item. | ||
| trait PyDictItem<'py> { | ||
| pub trait PyDictItem<'py> { |
There was a problem hiding this comment.
This looks a possibly unintentional change
| pub trait PyDictItem<'py> { | |
| trait PyDictItem<'py> { |
There was a problem hiding this comment.
Removed! For some reason I thought I needed this for one of the tests.
| #checkfunction=ffi::PyDictProxy_Check | ||
| ); |
There was a problem hiding this comment.
I think rather than the ffi function (as discussed, it doesn't seem to exist in CPython), we should just have fn PyDictProxy_Check defined in this file.
| #checkfunction=ffi::PyDictProxy_Check | |
| ); | |
| #checkfunction=PyDictProxy_Check | |
| ); | |
| #[inline] | |
| unsafe fn PyDictProxy_Check(op: *mut PyObject) -> c_int { | |
| ffi::PyObject_TypeCheck(op, std::ptr::addr_of_mut!(PyDictProxy_Type)) | |
| } |
There was a problem hiding this comment.
Also, it looks like subclassing mappingproxy is not allowed so we can probably just do Py_IS_TYPE here.
>>> class F(types.MappingProxyType):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'mappingproxy' is not an acceptable base typeThere was a problem hiding this comment.
Done, I changed the check function to the following:
#[inline]
unsafe fn dict_proxy_check(op: *mut ffi::PyObject) -> c_int {
ffi::Py_IS_TYPE(op, std::ptr::addr_of_mut!(ffi::PyDictProxy_Type))
}| fn copy(&self) -> PyResult<Bound<'_, PyMappingProxy>> { | ||
| let res = self.call_method0("copy")?; | ||
| unsafe { Ok(res.downcast_into_unchecked::<PyMappingProxy>()) } | ||
| } |
There was a problem hiding this comment.
I think the type here is incorrect, it looks like .copy() returns a copy of the underlying mapping, perhaps?
>>> type(types.MappingProxyType({}).copy())
<class 'dict'>There was a problem hiding this comment.
I changed this to return PyMapping instead.
| #[inline] | ||
| fn keys(&self) -> PyResult<Bound<'py, PySequence>> { | ||
| unsafe { | ||
| Ok(ffi::PyMapping_Keys(self.as_ptr()) | ||
| .assume_owned_or_err(self.py())? | ||
| .downcast_into_unchecked()) | ||
| } | ||
| } | ||
|
|
||
| #[inline] | ||
| fn values(&self) -> PyResult<Bound<'py, PySequence>> { | ||
| unsafe { | ||
| Ok(ffi::PyMapping_Values(self.as_ptr()) | ||
| .assume_owned_or_err(self.py())? | ||
| .downcast_into_unchecked()) | ||
| } | ||
| } | ||
|
|
||
| #[inline] | ||
| fn items(&self) -> PyResult<Bound<'py, PySequence>> { | ||
| unsafe { | ||
| Ok(ffi::PyMapping_Items(self.as_ptr()) | ||
| .assume_owned_or_err(self.py())? | ||
| .downcast_into_unchecked()) | ||
| } | ||
| } |
There was a problem hiding this comment.
It looks like since 3.7 (our minimum supported version) these FFI functions are now guaranteed to return lists: https://docs.python.org/3/c-api/mapping.html#c.PyMapping_Keys
So I think we can use PyList as the return type. It would allow for performance gains versus going through the sequence abstraction.
Similarly, would you be willing to update PyMappingMethods in the same way (maybe as a separate PR)?
There was a problem hiding this comment.
I'm open to considering the conversion changes in this file, but these changes might break existing users' code silently. I'm unsure both if it's worth the churn and also what the performance cost might be.
If we move ahead with these we should also include the corresponding changes to the index map and hash brown conversions.
At a minimum I would at like to see these changes split off into a separate PR, although I will be honest that there is a chance we might decide not to have these. Was it critical for your use case?
There was a problem hiding this comment.
Went ahead and removed the conversion changes. It isn't necessary for me, I just had it in there because of the previous PR.
* Addressing more comments * Remove extract_bound. * Remove extract methods.
davidhewitt
left a comment
There was a problem hiding this comment.
This looks great to me, thanks very much for helping get this one finally over the line!
Continuation of #2435 and #3521. Implement the
PyMappingProxytype (calledPyDictProxyin CPython).Resolves #2108.