Skip to content

BUG: resolve incompatibilities in units and utils.masked with numpy 2.4 (dev)#18821

Merged
mhvk merged 4 commits intoastropy:mainfrom
neutrinoceros:compat/numpy-2.4
Nov 5, 2025
Merged

BUG: resolve incompatibilities in units and utils.masked with numpy 2.4 (dev)#18821
mhvk merged 4 commits intoastropy:mainfrom
neutrinoceros:compat/numpy-2.4

Conversation

@neutrinoceros
Copy link
Copy Markdown
Contributor

@neutrinoceros neutrinoceros commented Nov 3, 2025

Description

xref: numpy/numpy#30068
xref: numpy/numpy#30143

At the time of opening, the test in units that I'm patching still fails against numpy-dev, where the current failure mode bisects to the same PR (specifically, 41cebd0f891f54d3090d4544d3f7a932ec0d4782, which is the first commit there), and may indicate an actual regression. Though, I suspect the remaining problem is more likely to be on our side.
I haven't figured it out yet, but here's the error I'm getting:

>       assert out3 == expected2
E       AssertionError: assert '[0.0, 1.0, 2.0]' == '[0.0 Jy, 1.0 Jy, 2.0 Jy]'
E
E         - [0.0 Jy, 1.0 Jy, 2.0 Jy]
E         ?     ---     ---     ---
E         + [0.0, 1.0, 2.0]

These incompatibilities are expected to show up in CI with numpy's next nightly, ~2 days from now.
I'm hoping to figure out the remaining problem ahead of that.

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 3, 2025

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@neutrinoceros neutrinoceros changed the title BUG: resolve incompatibilities in units and utils.masked with numpy 2.4 (dev) BUG: resolve incompatibilities in units and utils.masked with numpy 2.4 (dev) Nov 3, 2025
# also work around this by passing on a formatter (as is done in Angle).
# So, we do nothing if the formatter argument is present and has the
# relevant formatter for our dtype.
formatter = args[6] if len(args) >= 7 else kwargs.get("formatter")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this was a subtle one. The fact that argument positions where hard coded made it hard to find. Instead of branching explicitly on numpy's version, I rewrote this to dynamically compute the position at runtime. However, I'm intentionally leaving import inspect as a "lazy" import because importing this module is noticeable in the context of a CLI's starting time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do you mean that formatter is no longer the sixth positional argument? That seems really weird (and a bug!) Or am I missing something?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is exactly what I mean, and why positional-allowed arguments are basically impossible to deprecate/remove without breaking someone else's code.

import inspect

sig = inspect.signature(np.array2string)
formatter_arg_pos = list(sig.parameters).index("formatter") - 1
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

note to reviewers (which I assume would be @mhvk): I don't understand why this -1 is needed, but empirically, that's what works.

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

I found the remaining issue (this was significantly harder to find). I also included a third commit, which is a purely internal refactor and doesn't fix any known issue per-se, but should reduce the "attack surface" for the kind of incompatibilities I'm solving here, so hopefully it makes sense to include it here.

@neutrinoceros neutrinoceros marked this pull request as ready for review November 3, 2025 10:50
@astrofrog astrofrog modified the milestones: v7.1.2, v7.2.0 Nov 3, 2025
@astrofrog astrofrog added backport-v7.2.x on-merge: backport to v7.2.x and removed backport-v7.1.x labels Nov 3, 2025
args = (self.ma, None, None, None, ", ", "", np._NoValue, {"int": hex})
else:
args = (self.ma, None, None, None, ", ", "", {"int": hex})
out3 = np.array2string(*args)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Maybe this part of the test should actually be removed: it seems redundant with in depth signature introspection tests, and it clearly has a maintenance cost of its own. Anyway, that's merely a suggestion for a follow up, but I think it's out of scope here.

@pllim
Copy link
Copy Markdown
Member

pllim commented Nov 3, 2025

What about these 2 failures?

FAILED astropy/units/tests/test_quantity_non_ufuncs.py::TestStringFunctions::test_array2string - IndexError: tuple index out of range
FAILED astropy/utils/masked/tests/test_function_helpers.py::TestFunctionHelpersSignatureCompatibility::test_all_arguments_reexposed[array2string-array2string] - AssertionError: argument 'style' isn't re-exposed as positional
assert 'formatter' == 'style'

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

That's expected. As often, I'm ahead of nightlies, so it will not pass allowed-failure until Wednesday, by which point it will be required

Copy link
Copy Markdown
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

I think this looks good but I wonder if even independently of numpy we should just insist formatter is given as a keyword argument... I don't like inspecting the call signature to find the position - really, positions should not be allowed to change.

# also work around this by passing on a formatter (as is done in Angle).
# So, we do nothing if the formatter argument is present and has the
# relevant formatter for our dtype.
formatter = args[6] if len(args) >= 7 else kwargs.get("formatter")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do you mean that formatter is no longer the sixth positional argument? That seems really weird (and a bug!) Or am I missing something?

if NUMPY_LT_2_4:
args = (self.q, None, None, None, ", ", "", np._NoValue, {"float": str})
else:
args = (self.q, None, None, None, ", ", "", {"float": str})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I guess it is true, though - I think I should raise an issue over at numpy, they should just not make it positional any more... numpy/numpy#30068 (comment)

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

I wonder if even independently of numpy we should just insist formatter is given as a keyword argument...

Your PR doesn't appear to meet controversy, so I may just wait for it to land before I mirror that move here. Thanks for taking it back to numpy !

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

neutrinoceros commented Nov 5, 2025

This now also fixes all newly detected signature mismatches discovered thanks to numpy/numpy#30143, and which showed as 26 new failures in unstable CI.

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

and there seems to be more incoming (numpy/numpy#30147) so I'd suggest merging this one promptly in order to keep unstable CI's logs manageable and useful.
@mhvk I don't want to make any signature stricter than numpy's because our tests are specifically designed to guard against it (while they allow for looser signatures), so I suggest we postpone refactoring out inspect-based dynamic lookups until your PR upstream is merged and lands in a nightly.

Copy link
Copy Markdown
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

Agreed, let's just put this in, so the tests work again. I think if my numpy PR is merged, we will be alerted by a failure anyway!

Thanks!!

@mhvk mhvk merged commit 266d94d into astropy:main Nov 5, 2025
31 of 33 checks passed
meeseeksmachine pushed a commit to meeseeksmachine/astropy that referenced this pull request Nov 5, 2025
…and `utils.masked` with numpy 2.4 (dev)
@neutrinoceros neutrinoceros deleted the compat/numpy-2.4 branch November 5, 2025 14:46
pllim added a commit that referenced this pull request Nov 5, 2025
…821-on-v7.2.x

Backport PR #18821 on branch v7.2.x (BUG: resolve incompatibilities in `units` and `utils.masked` with numpy 2.4 (dev))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants