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

Support numpy2 #580

Merged
merged 4 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Loading