Skip to content

BUG: fix forward compatibility for np.arange(<Quantity>, ...) against numpy 2.4 (dev)#18849

Merged
mhvk merged 11 commits intoastropy:mainfrom
neutrinoceros:bug/compat-numpy-2.4-b2
Nov 11, 2025
Merged

BUG: fix forward compatibility for np.arange(<Quantity>, ...) against numpy 2.4 (dev)#18849
mhvk merged 11 commits intoastropy:mainfrom
neutrinoceros:bug/compat-numpy-2.4-b2

Conversation

@neutrinoceros
Copy link
Copy Markdown
Contributor

Description

xref: numpy/numpy#30147

This one was unusually hard to pull of, because np.arange, mimicking the builtin range, has a very peculiar signature, where the meaning of the first positional argument depends on the rest of the arguments. A full refactor of the wrapper function ended up being necessary to make this forward compatible. Hopefully inline comments should help understanding why.

Because it's taken so long to wrap things up (I've been playing whac-a-mole on-and-off on this for 2 days), I haven't yet collapsed my commits. I'd like to take the current state for a spin on CI first.

  • 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 7, 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 7, 2025

Welcome to Astropy 👋 and congratulations on your first pull request! 🎉

A project member will respond to you as soon as possible; in the meantime, please have a look over the Checklist for Contributed Code and make sure you've addressed as many of the questions there as possible.

If you feel that this pull request has not been responded to in a timely manner, please send a message directly to the development mailing list. If the issue is urgent or sensitive in nature (e.g., a security vulnerability) please send an e-mail directly to the private e-mail feedback@astropy.org.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 7, 2025

👋 Thank you for your draft pull request! Do you know that you can use [ci skip] or [skip ci] in your commit messages to skip running continuous integration tests until you are ready?

@neutrinoceros neutrinoceros force-pushed the bug/compat-numpy-2.4-b2 branch from b143697 to 8bc9f1f Compare November 7, 2025 14:50
@neutrinoceros neutrinoceros changed the title BUG: fix forward compatibility for \np.arange(<Quantity>, ...)\ against numpy 2.4 (dev) BUG: fix forward compatibility for np.arange(<Quantity>, ...) against numpy 2.4 (dev) Nov 7, 2025
@neutrinoceros neutrinoceros force-pushed the bug/compat-numpy-2.4-b2 branch from 6eb9f2e to 53e0d4a Compare November 7, 2025 15:39
Comment on lines +617 to +620
# reverse positional arguments so `stop`` always comes first
# this is done to ensure that the arrays are first converted to the
# expected unit, which we guarantee should be stop's
args_rev, out_unit_loc = _quantities2arrays(*reversed(qty_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.

overall, I'm not sure using _quantities2arrays is a good idea here, but it's the easiest way to ensure backward compat with the previous implementation, so I'll give it a rest for now.

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

This might take a little while to get properly reviewed, for understandable reasons, but since it works out of the box even now (while the breaking change in numpy hasn't landed in a nightly yet), let's open it for review to maximize visibility !

@neutrinoceros neutrinoceros marked this pull request as ready for review November 7, 2025 16:34
@neutrinoceros neutrinoceros requested a review from mhvk November 7, 2025 16:34
@neutrinoceros neutrinoceros force-pushed the bug/compat-numpy-2.4-b2 branch from 87a3d95 to 906e7a3 Compare November 7, 2025 17:57
@neutrinoceros
Copy link
Copy Markdown
Contributor Author

Hum actually, I'm think the upstream PR I'm mirroring here should be taken with a grain of salt: for instance, the start argument was and still is accepted as keyword, eventhough that's explicitly not allowed by the newly defined signature. I'm going to move this to draft and take the conversation back upstream.

@neutrinoceros neutrinoceros added the Upstream Action Required Was: Upstream Fix Required label Nov 8, 2025
@neutrinoceros neutrinoceros marked this pull request as draft November 8, 2025 11:21
@neutrinoceros
Copy link
Copy Markdown
Contributor Author

oh actually, this is explicitly refered to in the changelog entry associated to that PR, I just missed it
https://github.com/numpy/numpy/blob/main/doc/release/upcoming_changes/30147.compatibility.rst

so, it is actually intended that type checkers now reject start being passed as keyword, but the runtime behavior is backwards compatible. Meanwhile, our tests are written within the assumption that the typecheck time and runtime signature are one and the same, so I'll need to think a bit more about how to adapt here, but I don't think we need to take it upstream just yet after all.

@jorenham
Copy link
Copy Markdown
Contributor

jorenham commented Nov 11, 2025

If you have a better (yet concise) way to say this, I'm all ears 😄

First things that come to mind are usage signature, call/call-time signature, access/acces-time signature, true/actual signature, hidden/latent signature, supported signature, or "dark matter energy bosons signature" if you want to stay in theme ... and I guess I'll stop there for now :P

  • cost: breaks backward compat for users relying, e.g., passing start as keyword, or dtype as positional

I suppose it would be fair to blame numpy or me for this, if it turns out to be needed

  • cost: the additional complexity would likely become irrelevant in the future if/when numpy's runtime behavior changes, and we might not know about it, since our tests explicitly allow wrapper signatures to be more flexible than what they wrap

Yea that's not unlikely. It might even happen accidentally, since tools like stubtest wouldn't even notice it, and I'm not sure if we have unit-tests for it.
So maybe option 2 is delaying the inevitable?


There's also secret option no. 3: change the runtime (inspect) signature to match that of NumPy, while keeping the <insert one of the listed signature options from above> backwards-compatible, i.e.

arange.__signature__ = inspect.signature(np.arange)  # or construct it from scratch

or slightly more hacky:

arange.__text_signature__ = np.arange.__text_signature__  # or just copy-paste it

The first one is the least hacky, but still kinda hacky. It's nowhere near as hacky as what numpy does though 😅

@neutrinoceros neutrinoceros force-pushed the bug/compat-numpy-2.4-b2 branch from 6cb61a2 to 564d9e7 Compare November 11, 2025 14:01
@neutrinoceros
Copy link
Copy Markdown
Contributor Author

I suppose it would be fair to blame numpy or me for this, if it turns out to be needed

I'll keep this in mind 😈 (seriously though, I'll take a bet that no-one is actively relying on this)

So maybe option 2 is delaying the inevitable?

great, so I think everyone is on board with option 1 then !

There's also secret option no. 3 (...) It's nowhere near as hacky as what numpy does though

I don't want to know unless I have to 🙈

@neutrinoceros neutrinoceros marked this pull request as ready for review November 11, 2025 14:07
@neutrinoceros
Copy link
Copy Markdown
Contributor Author

Hopefully this is ready for a final review now. I should have finally answered all comments, but of course do feel free to remind me if I accidentally missed some !

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.

It still feels like overly long and thus distracting amount of code, but given that it is a corner case, I don't want to belabor this too much further. However, two in-line comments still about replacing reversed with [::-1], which really is fine if one knows one has a tuple (as we do here).

# reverse positional arguments so `stop` always comes first
# this is done to ensure that the arrays are first converted to the
# expected unit, which we guarantee should be stop's
args_rev, out_unit = _quantities2arrays(*reversed(qty_args))
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 hadn't seen this before, but you have just constructed qty_args, so you know it is a tuple -- no reason not to do qty_args[::-1].

Or even construct them reversed; indeed, the whole match and this part can be combined by doing,

if start is None:
    q_stop = _as_quantity(stop)
    args_rev, out_unit = (q_stop.value,), q_stop.unit
else:
    args_rev, out_unit = _quantities2arrays(stop, start)

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.

I don't think combining operations that can be separate makes the code any simpler.

Copy link
Copy Markdown
Contributor

@mhvk mhvk Nov 11, 2025

Choose a reason for hiding this comment

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

Fine to now do the full think, but please do just use _quantities2arrays(*qty_args[::-1]) (probably removes need to even import reversed.

Just to state the logic for my other suggestion: It makes it shorter, which helps for the clarity of the module as a whole. For a function like this, I'd rather have a single implementation that is dense and well-commented, to make going through the file easier for all the other functions. Anyway, I know that this is very much a matter of taste, so no worries!

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.

coming right up.
For full disclosure, and because I fear I might be sounding a bit blunt; I'm at the end of a tiresome day where I've been juggling with at least 3 concurrent issues in devdeps CI, including this one. My priority is to get it back to green so it becomes easy again to understand logs. Anyway, apologies for my tone in previous responses, I'm trying my best but it's not always enough.

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.

@neutrinoceros - no worries, my dutch self had not even noticed any bad tone or anything... (and I'm a bit in the same boat in the sense of currently having a bit too much on my plate). Anyway, FWIW, I find our discussions usually end up with things in a good place!

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.

Me too ! Good luck with your plate 😅

assert out_unit == stop.unit

# reverse args again to restore initial order
args = tuple(reversed(args_rev))
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'm still confused: args_rev is guaranteed to be a tuple (since quantities2arrays returns a tuple). So the idiomatic way would seem to be args = args[::-1].

@neutrinoceros
Copy link
Copy Markdown
Contributor Author

@mhvk if you're satisfied with the current state of things, please use a squash-merge for this one. Thank you !

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.

OK, let's get it in. Will be nice to have devdeps green again!

@mhvk mhvk enabled auto-merge (squash) November 11, 2025 21:40
@mhvk mhvk merged commit d3cfb63 into astropy:main Nov 11, 2025
33 checks passed
@pllim pllim added the backport-v7.2.x on-merge: backport to v7.2.x label Nov 11, 2025
@pllim
Copy link
Copy Markdown
Member

pllim commented Nov 11, 2025

@meeseeksdev backport to v7.2.x

meeseeksmachine pushed a commit to meeseeksmachine/astropy that referenced this pull request Nov 11, 2025
…nge(<Quantity>, ...)` against numpy 2.4 (dev)
@neutrinoceros neutrinoceros deleted the bug/compat-numpy-2.4-b2 branch November 12, 2025 05:10
neutrinoceros added a commit to meeseeksmachine/astropy that referenced this pull request Nov 12, 2025
…nge(<Quantity>, ...)` against 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