From 747253a531b6f0e2e62138ee12edadc0235456be Mon Sep 17 00:00:00 2001 From: Harrison Cook Date: Mon, 7 Jul 2025 16:17:32 +0000 Subject: [PATCH 1/3] fix: Update MemoryReader to read more than one field --- eccodes/highlevel/reader.py | 8 +++-- tests/test_highlevel.py | 59 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/eccodes/highlevel/reader.py b/eccodes/highlevel/reader.py index e0ca516..5dd747e 100644 --- a/eccodes/highlevel/reader.py +++ b/eccodes/highlevel/reader.py @@ -74,12 +74,16 @@ class MemoryReader(ReaderBase): def __init__(self, buf, kind=eccodes.CODES_PRODUCT_GRIB): super().__init__(kind=kind) self.buf = buf + self._index = 0 def _next_handle(self): if self.buf is None: return None - handle = eccodes.codes_new_from_message(self.buf) - self.buf = None + handle = eccodes.codes_new_from_message(self.buf[self._index :]) + self._index += eccodes.codes_get(handle, "totalLength") + + if self._index >= len(self.buf): + self.buf = None return handle diff --git a/tests/test_highlevel.py b/tests/test_highlevel.py index 4647d3e..480f215 100644 --- a/tests/test_highlevel.py +++ b/tests/test_highlevel.py @@ -1,4 +1,5 @@ import collections +import io import itertools import pathlib @@ -179,3 +180,61 @@ def test_grib_message_from_samples(): def test_bufr_message_from_samples(): message = eccodes.BUFRMessage.from_samples("BUFR4") assert message["edition"] == 4 + +def test_read_memory(): + buffer = io.BytesIO() + with eccodes.FileReader(TEST_GRIB_DATA2) as reader1: + written = [] + for message in itertools.islice(reader1, 15): + message.write_to(buffer) + written.append(message) + + with eccodes.MemoryReader(buffer.getvalue()) as reader2: + for message1, message2 in itertools.zip_longest(written, reader2): + assert message1 is not None + assert message2 is not None + for key in [ + "edition", + "centre", + "typeOfLevel", + "level", + "dataDate", + "stepRange", + "dataType", + "shortName", + "packingType", + "gridType", + "number", + ]: + assert message1[key] == message2[key] + assert np.all(message1.data == message2.data) + +def test_read_stream(): + buffer = io.BytesIO() + with eccodes.FileReader(TEST_GRIB_DATA2) as reader1: + written = [] + for message in itertools.islice(reader1, 15): + message.write_to(buffer) + written.append(message) + + buffer.seek(0, 0) + + with eccodes.StreamReader(buffer) as reader2: + for message1, message2 in itertools.zip_longest(written, reader2): + assert message1 is not None + assert message2 is not None + for key in [ + "edition", + "centre", + "typeOfLevel", + "level", + "dataDate", + "stepRange", + "dataType", + "shortName", + "packingType", + "gridType", + "number", + ]: + assert message1[key] == message2[key] + assert np.all(message1.data == message2.data) \ No newline at end of file From 9fc5f7e11f6238860955a26fb204f56e180e74a4 Mon Sep 17 00:00:00 2001 From: Harrison Cook Date: Mon, 7 Jul 2025 16:21:00 +0000 Subject: [PATCH 2/3] Ran black --- tests/test_highlevel.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_highlevel.py b/tests/test_highlevel.py index 480f215..680a1fc 100644 --- a/tests/test_highlevel.py +++ b/tests/test_highlevel.py @@ -181,6 +181,7 @@ def test_bufr_message_from_samples(): message = eccodes.BUFRMessage.from_samples("BUFR4") assert message["edition"] == 4 + def test_read_memory(): buffer = io.BytesIO() with eccodes.FileReader(TEST_GRIB_DATA2) as reader1: @@ -209,6 +210,7 @@ def test_read_memory(): assert message1[key] == message2[key] assert np.all(message1.data == message2.data) + def test_read_stream(): buffer = io.BytesIO() with eccodes.FileReader(TEST_GRIB_DATA2) as reader1: @@ -237,4 +239,4 @@ def test_read_stream(): "number", ]: assert message1[key] == message2[key] - assert np.all(message1.data == message2.data) \ No newline at end of file + assert np.all(message1.data == message2.data) From 712147ff23d82ca3268ee4cdececcbff8480083a Mon Sep 17 00:00:00 2001 From: Harrison Cook Date: Mon, 7 Jul 2025 17:56:04 +0000 Subject: [PATCH 3/3] Return None on failure of `totalLength` --- eccodes/highlevel/reader.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eccodes/highlevel/reader.py b/eccodes/highlevel/reader.py index 5dd747e..751c455 100644 --- a/eccodes/highlevel/reader.py +++ b/eccodes/highlevel/reader.py @@ -80,8 +80,13 @@ def _next_handle(self): if self.buf is None: return None handle = eccodes.codes_new_from_message(self.buf[self._index :]) - self._index += eccodes.codes_get(handle, "totalLength") + try: + handle_length = eccodes.codes_get(handle, "totalLength") + except eccodes.GribInternalError: + return None + + self._index += handle_length if self._index >= len(self.buf): self.buf = None return handle