Skip to content

TST: follow numpy/pytest traceback conventions in simple assert_* test helper functions - #16080

Merged
mhvk merged 1 commit into
astropy:mainfrom
neutrinoceros:tests/rfc/hidetraceback_in_assert_functions
Jul 29, 2024
Merged

mhvk merged 1 commit into
astropy:mainfrom
neutrinoceros:tests/rfc/hidetraceback_in_assert_functions

Conversation

@neutrinoceros

@neutrinoceros neutrinoceros commented Feb 20, 2024 •

Copy link
Copy Markdown
Contributor

Description

Fixes #16071 and replaces #16069

Reviews:

  • 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

github-actions Bot commented Feb 20, 2024 •

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.

@pllim pllim added this to the v6.1.0 milestone Feb 20, 2024
Comment thread astropy/io/fits/tests/test_connect.py Outdated


def assert_objects_equal(obj1, obj2, attrs, compare_class=True):
__tracebackhide__ = True

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.

Not sure to understand the benefit. If a test fail I will want to know why and hence dive into this function to find which attribute and examine the value, so why hiding it ?

@neutrinoceros neutrinoceros Feb 20, 2024 •

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 tried to explain the expected gain in #16071
I could furthermore add that:

  • in a sense, this satisfies the principle of least surprise (as a user of numpy.testing.assert_* functions, I grew to expect the internals of such functions to be hidden in tracebacks)
  • you can still opt-in the current behaviour using --full-trace, while the behaviour this is enabling is not achievable currently

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 personally would be more surprised by not being able to know why I had a failure. The traceback would still go through the failure within the unit test. Often I end up having to bisect issues by examining these helper functions and making temporary modifications to them.

If we do go through with this change I suggest we carefully consider the error messages being raised so that they are more indicative of what has caused the failure.

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.

Yes but being useful for numpy.testing.assert_ doesn't mean it's always better. Here the code is specific to what is being tested and used by a few tests only, and there is a good chance that I will want to see the full traceback is there a problem.
Also the problem is that I don't know what to expect with __tracebackhide__ activated, what will pytest print ?

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.

As you'll have seen from my comment above, I agree with @saimn here - I can see representations as being a single object where one wants to hide the traceback, since their content is uniform, but not a more complicated object where one also compares attributes.

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.

If we do go through with this change I suggest we carefully consider the error messages being raised so that they are more indicative of what has caused the failure.

Also the problem is that I don't know what to expect with tracebackhide activated, what will pytest print ?

In short: pytest prints the exact same message as it would without __tracebackhide__, the difference is in the line that is associated with that message.

To illustrate let's take my t.py test module from #16071 (copied here in a dropdown for convenience)

t.py
# t.py
import numpy as np

def assert_equal_len_v1(x, y):
    assert len(x) == len(y)

def assert_equal_len_v2(x, y):
    __tracebackhide__ = True
    assert len(x) == len(y)

def test_v1():
    a = np.arange(2)
    b = np.arange(3)
    assert_equal_len_v1(a, b)

def test_v2():
    a = np.arange(2)
    b = np.arange(3)
    assert_equal_len_v2(a, b)

Here's the output

$ pytest t.py
====================== test session starts ======================
platform darwin -- Python 3.12.0, pytest-8.0.0, pluggy-1.4.0
...
t.py FF                                                   [100%]

=========================== FAILURES ============================
____________________________ test_v1 ____________________________

    def test_v1():
        a = np.arange(2)
        b = np.arange(3)
>       assert_equal_len_v1(a, b)

t.py:14:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

x = array([0, 1]), y = array([0, 1, 2])

    def assert_equal_len_v1(x, y):
>       assert len(x) == len(y)
E       assert 2 == 3
E        +  where 2 = len(array([0, 1]))
E        +  and   3 = len(array([0, 1, 2]))

t.py:5: AssertionError
____________________________ test_v2 ____________________________

    def test_v2():
        a = np.arange(2)
        b = np.arange(3)
>       assert_equal_len_v2(a, b)
E       assert 2 == 3
E        +  where 2 = len(array([0, 1]))
E        +  and   3 = len(array([0, 1, 2]))

t.py:19: AssertionError
==================== short test summary info ====================
FAILED t.py::test_v1 - assert 2 == 3
FAILED t.py::test_v2 - assert 2 == 3
======================= 2 failed in 0.06s =======================

@mhvk mhvk left a comment

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.

While I like the general idea, I think this goes too far. Note that the numpy assert_array_equal, etc., actually tell you about the mismatched elements; they don't just fail. I think in such a case there is indeed no reason to keep the full trace. However, absent that, one should have the trace for any function which does not have such a message - so I think we should not change any of the more complicated functions, where a lot of different things can go wrong.

Anyway, bottom line, I'd only do the simple ones that use assert_array_equal etc under the hood.

@@ -26,12 +26,15 @@ def teardown_function(function):

# Compatibility functions to convert from nose to pytest

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.

Hmm, really these should just be replaced! But can be for follow-up...

@neutrinoceros neutrinoceros Feb 21, 2024 •

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.

Right. I can do that as a follow up ! Meanwhile, I'll avoid touching them here

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.

There's an open issue for this already: #15782

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.

These are being removed already in #15839, but in most instances the corresponding numpy.testing functions would be used; so if I understood you correctly, the numpy versions would already take care of setting __tracebackhide__? A couple uses of assert_equal would be changed to simple asserts though.

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.

thanks @eerovaher , I wasn't aware of this issue. Since it's mark with "good first issue" I should leave it to new contributors, right ?

if I understood you correctly, the numpy versions would already take care of setting __tracebackhide__?

Correct ! For instance, see the first line in numpy.testing.assert_equal's definition https://github.com/numpy/numpy/blob/e920ca42d98c4911c2294784f8809b38735923a4/numpy/testing/_private/utils.py#L313

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.

Simple and non-critical tasks such as removing these functions are indeed best left for new contributors.

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.

thanks @eerovaher , I wasn't aware of this issue. Since it's mark with "good first issue" I should leave it to new contributors, right ?

It is all but done in #15839 already, but your comments would be very welcome there. Pretty much all that remains to be done is settling on where to best use numpy.testing.assert_equal() vs. assert a == b. And if this PR is being merged first, might be worth looking if the new asserts in #15839 should get their __tracebackhide__ as well.

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.

Thank you, I'll make sure to review this one tomorrow !

Comment thread astropy/io/ascii/tests/test_ecsv.py Resolved
Comment thread astropy/io/ascii/tests/test_rst.py Resolved
Comment thread astropy/io/fits/tests/test_connect.py Outdated


def assert_objects_equal(obj1, obj2, attrs, compare_class=True):
__tracebackhide__ = True

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.

As you'll have seen from my comment above, I agree with @saimn here - I can see representations as being a single object where one wants to hide the traceback, since their content is uniform, but not a more complicated object where one also compares attributes.

Comment thread astropy/io/misc/tests/test_hdf5.py Resolved
Comment thread astropy/tests/helper.py Resolved
@neutrinoceros
neutrinoceros force-pushed the tests/rfc/hidetraceback_in_assert_functions branch from f578c44 to 356eccb Compare February 21, 2024 07:11
@neutrinoceros

Copy link
Copy Markdown
Contributor Author

I'm not sure all labels are still appropriate, they were added by the bot based on my initial commit, which had a larger scope.
In particular samp, visualization.wcsaxes and wcs.wcsapi seem outdated.
But that's still a lot of different packages touched in one PR, so I'm happy to split everything that was already approved parts into an isolated PR if desired.

@pllim

pllim commented Apr 3, 2024

Copy link
Copy Markdown
Member

Updated the labels. FYI.

Yes, the bot does not re-label every commit (and I think doing that would be a little excessive).

@astrofrog astrofrog modified the milestones: v6.1.0, v7.0.0 Apr 4, 2024
@pllim

pllim commented Apr 29, 2024

Copy link
Copy Markdown
Member

@saimn , how do you feel about io.fits?

@eerovaher eerovaher left a comment

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.

Setting __tracebackhide__ = True is a good idea if the test helper function is written to produce good output in case of failure (like the numpy.testing functions are) or if it is a thin wrapper around such a function. It looks like in coordinates the only function that should have __tracebackhide__ = True is assert_representation_allclose() in test_representation_arithmetic.py.

@neutrinoceros
neutrinoceros force-pushed the tests/rfc/hidetraceback_in_assert_functions branch from c05a670 to 5d8430b Compare April 30, 2024 07:49
@neutrinoceros

Copy link
Copy Markdown
Contributor Author

@eerovaher thank you, I've reverted everything else in coordinates

@eerovaher eerovaher left a comment

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 can approve for coordinates, assuming 5d8430b gets squashed away.

@neutrinoceros
neutrinoceros force-pushed the tests/rfc/hidetraceback_in_assert_functions branch from 5d8430b to d1d3496 Compare May 1, 2024 07:03
@neutrinoceros

Copy link
Copy Markdown
Contributor Author

(squashed)

@neutrinoceros
neutrinoceros force-pushed the tests/rfc/hidetraceback_in_assert_functions branch from d1d3496 to 4e6e1f7 Compare July 9, 2024 07:13
@neutrinoceros

Copy link
Copy Markdown
Contributor Author

rebased to fix a trivial conflict. I also added a checklist to keep track of reviews, if we absolutely require every package maintainer to approve.

@pllim pllim left a comment

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.

Does not hurt for io.votable.

Comment thread astropy/io/misc/tests/test_parquet.py Resolved
@neutrinoceros
neutrinoceros force-pushed the tests/rfc/hidetraceback_in_assert_functions branch from 4e6e1f7 to aa168f9 Compare July 9, 2024 21:11
@neutrinoceros
neutrinoceros force-pushed the tests/rfc/hidetraceback_in_assert_functions branch from aa168f9 to b6e8317 Compare July 9, 2024 21:12
@pllim pllim removed the io.misc label Jul 10, 2024

@mhvk mhvk left a comment

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.

utils.masked and uncertainties are OK; thanks for pushing this forward!

@mhvk

mhvk commented Jul 29, 2024

Copy link
Copy Markdown
Contributor

I think this is really all fine - and a nice addition - so let's get it in. Thanks, @neutrinoceros!

@mhvk
mhvk merged commit 377b6ca into astropy:main Jul 29, 2024
@neutrinoceros
neutrinoceros deleted the tests/rfc/hidetraceback_in_assert_functions branch July 29, 2024 15:24
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.

TST: should we adopt __tracebackhide__=True in assert_* test helper functions ?