Skip to content

Use Exception.add_note() for enriched error context in nddata and coordinates#18877

Open
FazeelUsmani wants to merge 23 commits intoastropy:mainfrom
FazeelUsmani:fix-exceptions-add-note
Open

Use Exception.add_note() for enriched error context in nddata and coordinates#18877
FazeelUsmani wants to merge 23 commits intoastropy:mainfrom
FazeelUsmani:fix-exceptions-add-note

Conversation

@FazeelUsmani
Copy link
Copy Markdown
Contributor

This PR adopts Python 3.11's Exception.add_note() method to enrich exception messages with contextual information, replacing the older exc.args += pattern.

Changes

  • astropy/nddata/utils.py: Updated extract_array() to use add_note() when fill_value type is incompatible
  • astropy/coordinates/earth.py: Updated gravitational_redshift() to use add_note() for mass/gravitational parameter unit errors
  • Added comprehensive tests to verify exception notes are properly attached

Testing

Added two new test functions:

  • test_extract_array_fill_value_exception_note(): Verifies notes in nddata.utils
  • test_gravitational_redshift_exception_note(): Verifies notes in coordinates.earth

References

Fixes #16879

Related

This is part of the larger effort to adopt exception notes throughout the Astropy codebase. These changes demonstrate the pattern for other contributors to follow.


Changelog Entry

astropy.nddata
^^^^^^^^^^^^^^

- Enhanced error messages in ``extract_array()`` using Python 3.11's 
  ``Exception.add_note()`` for better debugging context. [#16879]

astropy.coordinates
^^^^^^^^^^^^^^^^^^^

- Enhanced error messages in ``EarthLocation.gravitational_redshift()`` 
  using Python 3.11's ``Exception.add_note()`` for better debugging context. [#16879]

@github-actions
Copy link
Copy Markdown
Contributor

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.

@FazeelUsmani FazeelUsmani marked this pull request as draft November 11, 2025 08:13
@FazeelUsmani FazeelUsmani marked this pull request as ready for review November 11, 2025 09:34
@pllim pllim added this to the v8.0.0 milestone Nov 11, 2025
Copy link
Copy Markdown
Contributor

@neutrinoceros neutrinoceros left a comment

Choose a reason for hiding this comment

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

pytest 8.0 (which we require) supports matching exception notes with the match keyword argument in pytest.raises, please use that instead of capturing the exception manually.

See pytest-dev/pytest#11227

@neutrinoceros
Copy link
Copy Markdown
Contributor

@FazeelUsmani could you avoid merging from main 4 times a day ? I get notified every single time and it's a waste of CI resources

@FazeelUsmani
Copy link
Copy Markdown
Contributor Author

Okay, sure.

@FazeelUsmani
Copy link
Copy Markdown
Contributor Author

Please review this PR

Copy link
Copy Markdown
Member

@nstarman nstarman left a comment

Choose a reason for hiding this comment

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

Thanks @FazeelUsmani ! This looks like a nice addition.

Co-authored-by: Nathaniel Starkman <nstarman@users.noreply.github.com>
Copy link
Copy Markdown
Member

@nstarman nstarman left a comment

Choose a reason for hiding this comment

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

Thanks @FazeelUsmani !
Ping @eerovaher @mhvk @mwcraig for final reviews.

Copy link
Copy Markdown
Member

@mwcraig mwcraig left a comment

Choose a reason for hiding this comment

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

Thanks for this @FazeelUsmani!

Comment on lines +406 to +420
def test_gravitational_redshift_exception_note():
"""Test that exception notes are added for UnitsError in gravitational_redshift."""
someloc = EarthLocation(lon=-87.7 * u.deg, lat=37 * u.deg)
sometime = Time("2017-8-21 18:26:40")

# Test with wrong units to trigger UnitsError
masses = {
"sun": constants.G * constants.M_sun,
"jupiter": 1 * u.km, # wrong units - should be mass or G*mass
}

with pytest.raises(u.UnitsError, match="masses.*gravitational parameters"):
someloc.gravitational_redshift(sometime, masses=masses)


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
def test_gravitational_redshift_exception_note():
"""Test that exception notes are added for UnitsError in gravitational_redshift."""
someloc = EarthLocation(lon=-87.7 * u.deg, lat=37 * u.deg)
sometime = Time("2017-8-21 18:26:40")
# Test with wrong units to trigger UnitsError
masses = {
"sun": constants.G * constants.M_sun,
"jupiter": 1 * u.km, # wrong units - should be mass or G*mass
}
with pytest.raises(u.UnitsError, match="masses.*gravitational parameters"):
someloc.gravitational_redshift(sometime, masses=masses)

There is no need for a new test. The UnitsError is already being tested, so the existing test should be updated instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This does not need a change log entry.

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.

OK

FazeelUsmani and others added 2 commits December 2, 2025 15:00
Comment on lines +776 to +782
def test_extract_array_fill_value_exception_note():
"""Test that exception notes are added when fill_value type is incompatible."""
data = np.arange(12, dtype=int).reshape(3, 4)

# Try to extract with partial mode and incompatible fill_value (NaN for integer array)
with pytest.raises(ValueError, match="fill_value.*data type"):
extract_array(data, (5, 5), (1, 1), mode="partial", fill_value=np.nan)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It shouldn't be my job to review nddata, but why is this new test needed if we already have

def test_extract_array_nan_fillvalue():
if Version(np.__version__) >= Version("1.20"):
msg = "fill_value cannot be set to np.nan if the input array has"
with pytest.raises(ValueError, match=msg):
extract_array(
np.ones((10, 10), dtype=int), (5, 5), (1, 1), fill_value=np.nan
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If anything I would prefer that the new test replace the old test given that the new test explains what it is checking. I am also fine with both staying in there since they are not quite identical....hence the approval.

If @FazeelUsmani would like to replace the old test you cited with this new test I'm happy to approve that also.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see what's the point of having two separate tests for checking a single static error message.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this PR is AI generated.

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.

Yes, I used Claude code

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, I used Claude code

That in and of itself is not an issue -- I also use Claud Code. One needs to happen here is cleaning up the tests. As @eerovaher points out, the tests generated by Claude are already present elsewhere in the code (though I actually like Claude's version of the test in NDData more than the current test).

There are a couple paths forward here:

  • You can manually delete the two new tests from the pull request
  • You can ask Claude to delete them

I often find that I need to "coach" Claude to end up with a useful result on par with what a skilled programmer would produce.

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.

Obligatory link to https://xkcd.com/1319/ (and https://arxiv.org/abs/2507.09089 - "Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity"; certainly a case to be made if one includes reviewer productivity)

@@ -0,0 +1 @@
Enhanced error messages in ``extract_array`` using Python 3.11's ``Exception.add_note()`` to provide additional context when ``fill_value`` type is incompatible with the array dtype.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This PR changes some details regarding how exactly the error messages are constructed, but the messages in this PR don't contain any information or provide any additional context compared to the messages in main.

@nstarman nstarman requested a review from eerovaher February 6, 2026 17:12
Copy link
Copy Markdown
Contributor

@neutrinoceros neutrinoceros left a comment

Choose a reason for hiding this comment

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

I agree with Eero that the changelog fragment is superfluous or misleading. Other than that, I don't think this PR should close the issue it's linked to.
Taking a step back, I also feel like much more work went into reviewing AI output here than would it would normally take to produce the patch manually. This is extractive work at best: extracting value both from human coders from the past whose work was fed into the model, and reviewer time. In my opinion it is not worth its cost, and I would recommend taking collection action against this.

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.

Use Exceptions with Notes

7 participants