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
BUG: Fix SystemError when pickling datetime64 array with pickle5 #12748
Conversation
@pierreglaser What are you doing on |
Dynamic/nested scope objects pickling (See this python-dev thread, been working on this for a little while already), feel free to reach out if you are interested! |
I'll note that I get this error after running
The error is still there if I disable all pickling tests, though, so it's probably not pickling-related. |
numpy/core/src/multiarray/methods.c
Outdated
#if PY_VERSION_HEX >= 0x03080000 | ||
pickle_module = PyImport_ImportModule("pickle"); | ||
pickle_module = PyImport_ImportModule("pickle"); | ||
#elif PY_VERSION_HEX < 0x03080000 && PY_VERSION_HEX >= 0x03060000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A nit: you could drop the PY_VERSION_HEX < 0x03080000
here, it's implied by the condition above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right.
((PyObject*)self)->ob_type != &PyArray_Type) || | ||
PyDataType_ISUNSIZED(descr)) { | ||
/* The PickleBuffer class from version 5 of the pickle protocol | ||
* can only be used for arrays backed by a contiguous data buffer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PEP says "PickleBuffer can wrap any kind of buffer, including non-contiguous buffers.". Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only contiguous buffers are correctly handled by the pickle
module, though.
(this is something that should probably be improved in the future, but is non-trivial)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that mentioned in the PEP, pickle docs, or cpython bug tracker?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I have to update the PEP.
del a, DATA, carray | ||
# check for reference leaks (gh-12793) | ||
for ref in refs: | ||
assert ref() is None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mattip, this type of test will fail on pypy, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, yes, I should call gc.collect
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could skip for pypy. These sorts of tests do tend to be fragile.
@pitrou I am curious, what do I need to reproduce that error when running the tests? It seems plausible that is new, or was hidden behind some reference leaks before? |
|
Ah, was wondering if I need a debug build at the least or so, because I cannot reproduce it (am on python 3.7.2). |
I have Python 3.7.2 from Anaconda. Weird. |
Am on arch linux right now, but not quite sure why it should make a difference... I guess that error message does mean the actual integer |
Ok, I bisected the tests manually. The following test is sufficient to reproduce here: def test_array_interface():
# Test scalar coercion within the array interface
class Foo(object):
def __init__(self, value):
self.value = value
self.iface = {'typestr': '=f8'}
def __float__(self):
return float(self.value)
@property
def __array_interface__(self):
return self.iface
f = Foo(0.5)
f.iface['shape'] = (2,)
assert_raises(ValueError, np.array, f) |
@pitrou thanks a lot! I can see the refcount decrase, I guess I just don't reach 0 on my system. EDIT: Or dunno if its that, but I see the error if I run the test often enough anyway. |
The following change seems to solve the issue: diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 63bf5377a..4724b8472 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -2503,6 +2503,7 @@ PyArray_FromInterface(PyObject *origin)
if (ret == NULL) {
goto fail;
}
+ dtype = NULL; /* ref was stolen by PyArray_NewFromDescrAndBase */
if (data == NULL) {
if (PyArray_SIZE(ret) > 1) {
PyErr_SetString(PyExc_ValueError, I'll let someone else handle it, as I don't really know what the surrounding code is doing. |
Dang, should have checked here earlier, just found that as well :). |
Thanks @pitrou. I doubt many know that code well, but I figured the same fix, so that seems like a good sign. |
Is this PR waiting on completion? |
No, it should be ready. |
one very minor nit. We can check after merge if the new test is flaky on PyPy and skip it in a new PR. LGTM. |
9884804
to
7801e07
Compare
Thanks @pitrou . |
…py#12748) * BUG: Fix SystemError when pickling datetime64 array with pickle5 Fixes numpygh-12745 * Fix reference and error handling * Add a test for the fixed reference leak * Fix for PyPy + simplify #if condition * Fix comment
thanks for working on that @pitrou! |
} | ||
else { | ||
PyErr_Format(PyExc_ValueError, | ||
"__reduce_ex__ called with protocol > 5"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we expect this not to work with a later Python pickle protocol?
Check for error when calling the
PickleBuffer
constructor inndarray.__reduce_ex__
,and fall back on the regular
__reduce__
implementation for arrays which don'tsupport taking a buffer.
Also fix some reference leaks.
Fixes gh-12745, gh-12793