-
Notifications
You must be signed in to change notification settings - Fork 113
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
Interface for making a PyArray
non-writeable
#456
Comments
A minor follow-up: I think a method on impl<T, D> PyReadwriteArray<T, D> {
pub fn make_nonwriteable(self) {
// SAFETY: the array pointer is known to be non-null. We are consuming the only
// possible extant mutable view on the data, so cannot invalidate any accessible
// mutable view.
unsafe {
(*self.as_array_ptr()).flags &= !npyffi::flags::NPY_ARRAY_WRITEABLE;
}
}
} might work? Happy to PR and add a bit of documentation around it, if so. |
We have a |
I'm trying to return the I could copy the data into a Numpy array on access, or write a custom type that implements much of the array interface I want to provide users easy access to (it's all the magic operator methods in particular, since the ufunc protocols are easy enough), I'm just trying to reduce runtime / boilerplate code. |
It looks to me like |
You can presumably also do something like |
Sorry if I'm missing some of your point here - I'm not trying to enforce immutability within Rust, I'm trying to enforce it from Python. I can't allow Python space to write into the data buffer. I can pass underlying Give or take, in pure Python, I'm doing something like this: import numpy
class A:
def __init__(self):
# This is my data. In Rust, it's some other slice type.
self._buffer = b"\x00" * 256
def view(self):
# This wraps the data in an `ndarray` that forbids mutations.
return numpy.frombuffer(self._buffer, dtype=numpy.uint8)
a = A()
assert not a.view().flags.writeable
# This will raise an ValueError because it's read-only.
a.view()[0] = 1 So the underlying data buffer isn't an |
Ah sorry, this is entirely my mistake causing the confusion. We used to set the flag, but after the borrow strategy was changed in #258 we stopped doing that. In which case I think the API you propose above in Do we think there are any other alternatives for the name? I briefly thought about |
Oh yeah, returning a For naming, I was somewhat avoiding "readonly" because of the clash with I couldn't think if there's any other conventions in rust-numpy or PyO3 for that kind of "modification beyond the borrowed lifetime" implication. I can write up a PR, and we can play with the name in that, if anything comes to mind? |
Sounds good to me, thanks 👍 |
Fixed by #462 - thanks for the merge! |
I'm using
PyArray::from_borrowed_array_bound
to expose an immutable data buffer from a Rust struct to Python space via Numpy. The type needs to uphold some invariants about its internal data, which means I want to prevent Numpy from allowing writes, so I'm trying to unset theWRITEABLE
flag before returning the object from Rust space.Currently, I'm doing something like this:
I'm not certain that I'm entirely correct in doing this in the first place. If I am, then my second
unsafe
block feels like it could have a safe abstraction wrapping it? If I understand correctly, if we can assert/verify that there are no existingPyReadwriteArray
s taken out on the underlying memory in Rust space (which I haven't done explicitly here, since I only just created the array object), then removing theWRITEABLE
flag should be a safe operation.Please correct me if I've made soundness errors here. If I haven't, could we potentially add methods like
nonwriteable
/try_nonwriteable
that unset this flag in a safe manner?The text was updated successfully, but these errors were encountered: