Skip to content

Commit

Permalink
Support numpy2 (#580)
Browse files Browse the repository at this point in the history
* Convert hindcast tests to pytest.

* Use signed int64 in hindcast conversion: works with numpy 2.

* Use pytest mocker to patch.
  • Loading branch information
pp-mo authored Dec 16, 2024
1 parent 11169cf commit 640ebf4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 43 deletions.
8 changes: 6 additions & 2 deletions src/iris_grib/_load_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,14 @@ def _masker(item):
_MDI = None


class HindcastOverflowWarning(Warning):
pass


# Non-standardised usage for negative forecast times.
def _hindcast_fix(forecast_time):
"""Return a forecast time interpreted as a possibly negative value."""
uft = np.array(forecast_time).astype(np.uint32)
uft = np.array(forecast_time).astype(np.int64)
HIGHBIT = 2**30

# Workaround grib api's assumption that forecast time is positive.
Expand All @@ -221,7 +225,7 @@ def _hindcast_fix(forecast_time):
msg = "Re-interpreting large grib forecastTime " "from {} to {}.".format(
original_forecast_time, forecast_time
)
warnings.warn(msg)
warnings.warn(msg, HindcastOverflowWarning)

return forecast_time

Expand Down
79 changes: 38 additions & 41 deletions src/iris_grib/tests/unit/load_convert/test__hindcast_fix.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,50 @@
"""

# import iris_grib.tests first so that some things can be initialised
# before importing anything else.
import iris_grib.tests as tests

from collections import namedtuple
import warnings

from iris_grib._load_convert import _hindcast_fix as hindcast_fix

import pytest

class TestHindcastFix(tests.IrisGribTest):
# setup tests : provided value, fix-applies, expected-fixed
FixTest = namedtuple("FixTest", ("given", "fixable", "fixed"))
test_values = [
FixTest(0, False, None),
FixTest(100, False, None),
FixTest(2 * 2**30 - 1, False, None),
FixTest(2 * 2**30, False, None),
FixTest(2 * 2**30 + 1, True, -1),
FixTest(2 * 2**30 + 2, True, -2),
FixTest(3 * 2**30 - 1, True, -(2**30 - 1)),
FixTest(3 * 2**30, False, None),
]

def setUp(self):
self.patch_warn = self.patch("warnings.warn")

def test_fix(self):
from iris_grib._load_convert import _hindcast_fix as hindcast_fix
from iris_grib._load_convert import HindcastOverflowWarning


FixTest = namedtuple("FixTest", ("given", "fixable", "fixed"))
HINDCAST_TESTCASES = {
"zero_x": FixTest(0, False, None),
"n100_x": FixTest(100, False, None),
"n2^31m1_x": FixTest(2 * 2**30 - 1, False, None),
"n2^31_x": FixTest(2 * 2**30, False, None),
"n2^31p1_m1": FixTest(2 * 2**30 + 1, True, -1),
"n2^31p2_m2": FixTest(2 * 2**30 + 2, True, -2),
"n3x2^30m1_m2^30m1": FixTest(3 * 2**30 - 1, True, -(2**30 - 1)),
"n3x2^30^30_x": FixTest(3 * 2**30, False, None),
}


class TestHindcastFix:
@pytest.mark.parametrize(
"testval",
list(HINDCAST_TESTCASES.values()),
ids=list(HINDCAST_TESTCASES.keys()),
)
def test_fix(self, testval):
# Check hindcast fixing.
for given, fixable, fixed in self.test_values:
result = hindcast_fix(given)
expected = fixed if fixable else given
self.assertEqual(result, expected)
given, fixable, fixed = testval
result = hindcast_fix(given)
expected = fixed if fixable else given
assert result == expected

def test_fix_warning(self):
def test_fix_warning(self, mocker):
# Check warning appears when enabled.
self.patch("iris_grib._load_convert.options.warn_on_unsupported", True)
hindcast_fix(2 * 2**30 + 5)
self.assertEqual(self.patch_warn.call_count, 1)
self.assertIn(
"Re-interpreting large grib forecastTime", self.patch_warn.call_args[0][0]
)
mocker.patch("iris_grib._load_convert.options.warn_on_unsupported", True)
msg = "Re-interpreting large grib forecastTime"
with pytest.warns(HindcastOverflowWarning, match=msg):
hindcast_fix(2 * 2**30 + 5)

def test_fix_warning_disabled(self):
# Default is no warning.
hindcast_fix(2 * 2**30 + 5)
self.assertEqual(self.patch_warn.call_count, 0)


if __name__ == "__main__":
tests.main()
with warnings.catch_warnings():
warnings.simplefilter(category=HindcastOverflowWarning, action="error")
hindcast_fix(2 * 2**30 + 5)

0 comments on commit 640ebf4

Please sign in to comment.