Skip to content

BUG: fix handling of copy keyword argument when calling __array__ #25922

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

Merged
merged 3 commits into from
Mar 4, 2024

Conversation

ngoldbaum
Copy link
Member

Closes #25916.

This applies @rgommers draft changes from the issue description and adds a couple more fixes on top.

  • Replaces internal usages of never_copy with copy that can be -1 (corresponding to None), 0 (False), and 1 (True). This allows the array coercion machinery and PyArray_FromArrayAttr_int to support passing copy=True (although right now that will never happen).

  • Only passes a copy keyword if copy is not the default value.

  • Fixes a bug in checking for the error message

  • Removes an incorrect usage of Py_SetRef (sorry about suggesting that in the first place 😬 )

  • Fixes some reference counting issues

  • Tests that the old deprecated calling convention still works.

@ngoldbaum ngoldbaum requested a review from mtsokol March 3, 2024 23:24
@ngoldbaum ngoldbaum added this to the 2.0.0 release milestone Mar 3, 2024
@ngoldbaum
Copy link
Member Author

ngoldbaum commented Mar 3, 2024

@oscarbenjamin it looks like there are still some sympy test failures with this PR applied, but I think they'll be fixed once scipy is updated (the failures have tracebacks that end in scipy).

FAILED sympy/physics/control/tests/test_control_plots.py::test_pole_zero - assert False
FAILED sympy/physics/quantum/tests/test_identitysearch.py::test_is_scalar_sparse_matrix - ValueError: Unable to avoid copy while creating an array from given array.
FAILED sympy/physics/quantum/tests/test_identitysearch.py::test_is_reducible - ValueError: Unable to avoid copy while creating an array from given array.
FAILED sympy/physics/quantum/tests/test_identitysearch.py::test_bfs_identity_search - ValueError: Unable to avoid copy while creating an array from given array.
FAILED sympy/physics/quantum/tests/test_identitysearch.py::test_bfs_identity_search_xfail - ValueError: Unable to avoid copy while creating an array from given array.
FAILED sympy/solvers/tests/test_simplex.py::test_lp - ImportError: cannot import name '_np' from 'sympy.solvers.inequalities' (/Users/goldbaum/D...
FAILED sympy/utilities/tests/test_lambdify.py::test_scipy_sparse_matrix - ValueError: Unable to avoid copy while creating an array.

(although not sure what's up with test_control_plots and test_simplex).

I tried testing scipy with this PR applied, but it looks like scipy isn't buildable at the moment because of the descr->f removal.

@oscarbenjamin
Copy link

Thanks @ngoldbaum. If changes are needed on SymPy's end then that's fine and I can make them. For now though perhaps the test failures in sympy are some measure of potential breakage that could be caused for other code.

@charris
Copy link
Member

charris commented Mar 4, 2024

Not clear what is going on with the Linux SIMD tests / without optimizations, I think copy should be recognized as a keyword and it didn't fail before. Maybe the problem is with something else called with the keyword.

@ngoldbaum
Copy link
Member Author

I can't reproduce that failure locally, but I see that it's running on python 3.12-dev, which seems odd now that python 3.12 is out. Let's see what happens if I use the release python version.

@ngoldbaum
Copy link
Member Author

Hmm, nope. I just tried running python 3.12.1 and I can reproduce this there though. I guess an API changed...

@ngoldbaum
Copy link
Member Author

It looks like on Python 3.12, the exception object you get back from PyErr_Fetch doesn't pass PyUnicode_Check, so I updated the implementation to explicitly convert the exception object into a string, which seems to work on 3.11 and 3.12. Hopefully that makes all the CI happy.

@ngoldbaum
Copy link
Member Author

(we should probably add more CI coverage on python 3.12 if that's the only runner on that version)

@charris charris merged commit 95684b6 into numpy:main Mar 4, 2024
@charris
Copy link
Member

charris commented Mar 4, 2024

Thanks Nathan, good sleuthing.

I guess an API changed

Nasty. But I guess we can understand :)

@rgommers
Copy link
Member

rgommers commented Mar 4, 2024

Thanks a lot for the quick fix Nathan!

return NULL;
}
}

Py_DECREF(kwargs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have Py_DECREF(args); next to kwargs? Similarly to:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is the only comment that I have.

Comment on lines +14 to +21
NumPy will pass ``copy`` to the ``__array__`` special method in situations where
it would be set to a non-default value (e.g. in a call to
``np.asarray(some_object, copy=False)``). Currently, if an
unexpected keyword argument error is raised after this, NumPy will print a
warning and re-try without the ``copy`` keyword argument. Implementations of
objects implementing the ``__array__`` protocol should accept a ``copy`` keyword
argument with the same meaning as when passed to `numpy.array` or
`numpy.asarray`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to move it to a new issue, but thinking through how to update some __array__ implementations, I am wondering: what are the expectations from numpy how an __array__ implementations handles this keyword fully or partially?

When copy=True is being passed, does numpy assume that the __array__ implementation already made that copy? But what if the implementation defers dtype casting to numpy (which is currently possible), then it might be a waste to already copy up front?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question. Worth a new issue indeed I think.

But what if the implementation defers dtype casting to numpy (which is currently possible)

Deprecated though, right? The signature should already have included the dtype keyword, even though it was still working to not have that.

then it might be a waste to already copy up front?

What we want to achieve I think is that only a single copy is ever made. We can have two now in many cases, because the other library may copy from its internal implementation into an array, and then numpy will make another copy. The only way to get it right is for the other library to do the copy if copy=True, and for numpy not to do so if the method call including copy=True succeeded.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #25941, in case you want to move over your comments as well

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

Successfully merging this pull request may close these issues.

__array__ copy keyword changes incomplete
7 participants