Skip to content
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

TST/BUG: fix array API test skip decorators #19018

Merged
merged 7 commits into from Sep 4, 2023

Conversation

lucascolley
Copy link
Member

@lucascolley lucascolley commented Aug 4, 2023

Reference PR

Fixes decorators which were introduced in #18668.

What does this implement/fix?

  • functools.wraps is introduced to skip_if_array_api_backend so that it can be used as a decorator together with pytest.mark.parametrize.
  • skip_if_array_api_gpu is rewritten in a similar style to skip_if_array_api_backend so that it functions properly. Previously, when used with python dev.py test -b all, decorated tests would be skipped on every backend, not just those which use GPU.

Additional information

The discussion leading up to this PR occurred in the comments of #19005.

If there is a CI fail due to # type: ignore[misc], perhaps this can be removed now? done.

Co-authored-by: Tyler Reddy <tyler.je.reddy@gmail.com>
@lucascolley lucascolley marked this pull request as ready for review August 4, 2023 19:02
@lucascolley
Copy link
Member Author

lucascolley commented Aug 4, 2023

@tylerjereddy CI is green, how does this look?

@tylerjereddy tylerjereddy added this to the 1.12.0 milestone Aug 4, 2023
if xp.__name__ == backend:
pytest.skip(reason=reason)
return func(*args, xp, **kwargs)
return func(*args, **kwargs)
Copy link
Contributor

Choose a reason for hiding this comment

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

If I do this to test on this branch:

--- a/scipy/cluster/tests/test_vq.py
+++ b/scipy/cluster/tests/test_vq.py
@@ -282,7 +282,8 @@ class TestKMean:
 
     @array_api_compatible
     @skip_if_array_api_backend('numpy.array_api')
-    def test_kmeans2_rank1_2(self, xp):
+    @pytest.mark.parametrize("junk", [1, 2])
+    def test_kmeans2_rank1_2(self, xp, junk):
         data = xp.asarray(TESTDATA_2D)
         data1 = data[:, 0]
         kmeans2(data1, xp.asarray(2), iter=1)

python dev.py test -j 32 -b all -- -k "test_kmeans2_rank1_2"

I get: no tests ran in 18.76s, which doesn't seem quite right--shouldn't we still run for torch here? This is particularly complex, because it looks like class TestKMean also has a class-level GPU skip. It also seems to me like we should report the skip(s) with reasons(s) rather than "no tests ran."

If I delete the class-level skip for TestKMean in this branch and main, the behavior in this branch is indeed superior than a cherry-pick of the same diff onto main, where the original problem of breaking parametrize returns:

TypeError: TestKMean.test_kmeans2_rank1_2() missing 1 required positional argument: 'junk'

So, this is a bit long-winded, but I think it may be important to consider three things here:

  1. This is probably a solid improvement (I'm slightly biased, obviously)
  2. It isn't the full story yet, and we should probably open an issue for the behavior of class level + function level custom decorators we add, though I'd also be inclined to avoid the class-level ones as much as possible...
  3. This is getting pretty complex to review and test locally already--I hate to say it, but I wonder if we're going to need tests for our new test infrastructure for sanity reasons (this could maybe be discussed in the issue). Would still be messy because devices not available on CI. Obviously, would be nice if this infra could be maintained externally/community level, but that's perhaps farther out...

Copy link
Member Author

Choose a reason for hiding this comment

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

I get: no tests ran in 18.76s, which doesn't seem quite right--shouldn't we still run for torch here?

I suspect that this is down to my use of if torch.cuda.is_available():. I hoped that this would not skip pytorch-cpu but it seems it is. I don't know enough about torch to say how to skip only on GPU then...

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm maybe not, I still get no tests ran with -b numpy rather than -b all. I'm still not confident in if torch.cuda.is_available(): though.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can probably agree this is getting confusing though.

Copy link
Member Author

Choose a reason for hiding this comment

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

The decorator of this branch in combination with the class-level skip is completely broken: python dev.py test -b all -t scipy/cluster/tests/test_vq.py::TestKMean gives

========================================================================================== no tests ran in 0.04s ===========================================================================================
ERROR: not found: /home/lucas/dev/myscipy/build-install/lib/python3.10/site-packages/scipy/cluster/tests/test_vq.py::TestKMean
(no name '/home/lucas/dev/myscipy/build-install/lib/python3.10/site-packages/scipy/cluster/tests/test_vq.py::TestKMean' in any of [<Module test_vq.py>])

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I was a getting a bit worried that we'll end up going in circles because we'll fix N behaviors and cause just 1 other thing to break instead, so that's why the "testing the tests" idea is suggested, but ugh.

Copy link
Member Author

Choose a reason for hiding this comment

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

for what it's worth, class-level skips with skip_if_array_api_backend are currently completely broken on main too, giving the same error as above. It seems that the decorators (other than the faulty GPU skip on main) are written to only wrap functions, not classes. Can we modify these decorators to wrap classes too, or would a separate decorator be needed?

if torch.cuda.is_available():
pytest.skip(reason=reason)
return func(*args, **kwargs)
return wrapped
Copy link
Contributor

Choose a reason for hiding this comment

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

python dev.py test -j 32 -b all -s cluster does seem a bit more sensible here vs. main with 50 tests skipped on this branch vs. 389 on main.

Copy link
Member Author

Choose a reason for hiding this comment

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

Strangely, while I get 389 skips on main, I only get 32 skips here (with 110 passes). Could another dev run this so we can see which number is the odd one out?

Edit: the difference may be that I am not running PyTorch GPU.

@tylerjereddy
Copy link
Contributor

I'll leave this open for a bit if that's "ok," just want perhaps one other core dev to read my comment about the complexities above to make sure I'm not misunderstanding, etc, and so folks are on the same page.

@lucascolley
Copy link
Member Author

I think it would be sensible for now to remove the class-level skips from cluster and open an issue as you have suggested.

More testing is needed of PyTorch CPU/GPU to check whether this is doing what we want it to, but if we can get that working and remove class-level skips then I think that this will be looking like a decent improvement.

@lucascolley
Copy link
Member Author

Just pushed a commit where the torch device check should be correct, i.e. tests are not skipped on PyTorch CPU when CUDA is available but not used.

scipy/conftest.py Outdated Show resolved Hide resolved
@rgommers rgommers added array types Items related to array API support and input array validation (see gh-18286) maintenance Items related to regular maintenance tasks labels Aug 16, 2023
@@ -180,23 +228,3 @@ def check_fpu_mode(request):
SCIPY_HYPOTHESIS_PROFILE = os.environ.get("SCIPY_HYPOTHESIS_PROFILE",
"deterministic")
hypothesis.settings.load_profile(SCIPY_HYPOTHESIS_PROFILE)


def skip_if_array_api_backend(backend):
Copy link
Member Author

Choose a reason for hiding this comment

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

this function is moved above the hypothesis stuff from #18927 so that the array API stuff is not split on either side.

@lucascolley
Copy link
Member Author

Noting that this PR is related to #18668 (comment) from @rgommers, which is concerned with the fact that @skip_if_array_api skips for numpy. It seems desirable to reach a point where all tests pass for numpy when the flag is set.

Perhaps we want to have a decorator which skips every backend apart from numpy.

Some notes from @tupui about @skip_if_array_api:

I had 2 cases in mind which for now are mixed together:

  1. Skip because we know it does not work
  2. Skip because we are ok not running a test and save some CI time

I would be fine separating the 2 use cases or adding some comments to make it more clear that we want to do one or the other

It may be an improvement for @skip_if_array_api_backend to accept multiple backends, or be merged with @skip_if_array_api into one decorator which has all of the needed functionality, perhaps including the option to only run for numpy too.

These changes could be considered in this PR, but it might be better to leave them for a follow-up.

@rgommers
Copy link
Member

rgommers commented Sep 4, 2023

Skip because we are ok not running a test and save some CI time

I've already found this to be a hindrance, it makes it harder to make changes and then run all tests with a single test command. Imho this isn't worth doing for the small-ish gains in test runtime, there are better ways of speeding up the test suite. In addition it's extra boilerplate; so I'd still prefer to simply remove this decorator.

These changes could be considered in this PR, but it might be better to leave them for a follow-up.

Agreed to do this in a separate PR.

@rgommers
Copy link
Member

rgommers commented Sep 4, 2023

@tylerjereddy want to hit the green button if you are happy with this?

@tylerjereddy tylerjereddy merged commit bc15b51 into scipy:main Sep 4, 2023
24 checks passed
@tylerjereddy
Copy link
Contributor

Yeah, I think it is a step in the right direction.

@lucascolley lucascolley deleted the array_api_decorators branch September 4, 2023 17:38
Copy link
Member

@tupui tupui left a comment

Choose a reason for hiding this comment

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

Looks like a good improvement to me 👍 thanks @lucascolley (will let Tyler merge)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
array types Items related to array API support and input array validation (see gh-18286) maintenance Items related to regular maintenance tasks scipy.cluster
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants