1+ #!/usr/bin/env python
2+ #
3+ # Package Name: metoppy
4+ # Author: Simon Kok Lupemba, Francesco Murdaca
5+ # License: MIT License
6+ # Copyright (c) 2025 EUMETSAT
7+
8+ # This package is licensed under the MIT License.
9+ # See the LICENSE file for more details.
10+
11+ """Test file."""
12+
13+ import pytest
14+ from pathlib import Path
15+ from metoppy .metopreader import MetopReader
16+
17+
18+ @pytest .fixture (scope = "module" )
19+ def metop_reader ():
20+ """
21+ Initialize the MetopReader once for the entire module
22+ """
23+ reader = MetopReader ()
24+ return reader # Make it available to tests
25+
26+
27+ @pytest .fixture
28+ def test_file (request , metop_reader ):
29+ """
30+ Fixture to get test file
31+ """
32+ product_type = request .param # get parameter from the test
33+
34+ reduced_data_folder = Path (metop_reader .get_test_data_artifact ())
35+ reduced_data_files = [f for f in reduced_data_folder .iterdir () if f .is_file ()]
36+ test_file_name = next ((f for f in reduced_data_files if f .name .startswith (product_type )), None )
37+ test_file_path = reduced_data_folder / test_file_name
38+
39+ return test_file_path
40+
41+
42+ @pytest .mark .parametrize ("test_file" , ["ASCA_SZO" ], indirect = True )
43+ def test_get_keys (metop_reader , test_file ):
44+ """
45+ Simple test for metop_reader.get_key
46+ """
47+ # arrange
48+ ds = metop_reader .open_dataset (file_path = str (test_file ))
49+
50+ # act
51+ keys = metop_reader .get_keys (ds )
52+
53+ # assert
54+ assert "latitude" in keys
55+ assert "record_start_time" in keys
56+ assert "sigma0_trip" in keys
57+ assert "utc_line_nodes" in keys
58+ assert "latitude_full" not in keys
59+
60+ # clean
61+ metop_reader .close_dataset (ds )
62+
63+
64+ @pytest .mark .parametrize ("test_file" , ["ASCA_SZO" ], indirect = True )
65+ def test_close_dataset (metop_reader , test_file ):
66+ """
67+ Test for metop_reader.test_close_dataset. It should not be
68+ possible to read from a closed dataset
69+ """
70+ # arrange
71+ import juliacall
72+ ds = metop_reader .open_dataset (file_path = str (test_file ))
73+
74+ # act
75+ metop_reader .close_dataset (ds )
76+
77+ # assert
78+ with pytest .raises (juliacall .JuliaError ):
79+ ds ['longitude' ][0 ,0 ]
80+
81+
82+ @pytest .mark .parametrize ("test_file" , ["ASCA_SZO" ], indirect = True )
83+ def test_shape (metop_reader , test_file ):
84+ """
85+ Simple test for metop_reader.shape.
86+ """
87+ # arrange
88+ ds = metop_reader .open_dataset (file_path = str (test_file ))
89+
90+ # act
91+ latitude = ds ['latitude' ]
92+ longitude_slice = ds ['longitude' ][10 :14 ,0 :2 ]
93+
94+ shape_latitude = metop_reader .shape (latitude )
95+ shape_longitude_slice = metop_reader .shape (longitude_slice )
96+
97+ # assert
98+ assert shape_latitude == (42 ,10 )
99+ assert shape_longitude_slice == (4 ,2 )
100+
101+ # clean
102+ metop_reader .close_dataset (ds )
103+
104+
105+ @pytest .mark .parametrize ("test_file" , ["IASI_xxx" ], indirect = True )
106+ def test_read_single_value (metop_reader , test_file ):
107+ """
108+ Test reading scalar value and assert that the value is correct.
109+ The test also checks that Julia datetimes are converted to Python datetime.datetime
110+ """
111+ # arrange
112+ import datetime
113+ ds = metop_reader .open_dataset (file_path = str (test_file ))
114+
115+ # act
116+ CO2_radiance = ds ["gs1cspect" ][91 , 0 , 0 , 0 ]
117+ start_time = ds ["record_start_time" ][0 ]
118+
119+ # assert
120+ assert CO2_radiance == pytest .approx (0.0006165 , abs = 2e-5 )
121+ assert isinstance (CO2_radiance , float )
122+
123+ assert start_time .year == 2024
124+ assert start_time .month == 9
125+ assert start_time .day == 25
126+ assert isinstance (start_time , datetime .datetime )
127+
128+ # clean
129+ metop_reader .close_dataset (ds )
130+
131+ @pytest .mark .parametrize ("test_file" , ["ASCA_SZR" ], indirect = True )
132+ def test_read_array (metop_reader , test_file ):
133+ """
134+ Test reading varible as an array and conveting it to numpy.
135+ This test uses default parameter which results in less performant
136+ dynamic types.
137+ """
138+ # arrange
139+ import numpy as np
140+ ds = metop_reader .open_dataset (file_path = str (test_file ))
141+
142+ # act
143+ latitude_julia = metop_reader .as_array (ds ['latitude' ])
144+ longitude_julia = metop_reader .as_array (ds ['longitude' ])
145+ longitude_slice_julia = ds ['longitude' ][10 :14 ,0 :2 ]
146+ latitude = np .array (latitude_julia , copy = None )
147+ longitude = np .array (longitude_julia , copy = None )
148+ longitude_slice = np .array (longitude_slice_julia , copy = None )
149+
150+ # assert
151+ assert np .all ((0 < longitude )& (longitude < 360 ))
152+ assert np .all ((- 90 < latitude )& (latitude < 90 ))
153+ assert np .all ((0 < longitude_slice )& (longitude_slice < 360 ))
154+ assert longitude_slice .shape == (4 ,2 )
155+
156+ # clean
157+ metop_reader .close_dataset (ds )
158+
159+ @pytest .mark .parametrize ("test_file" , ["ASCA_SZR" ], indirect = True )
160+ def test_type_stable_array (metop_reader , test_file ):
161+ """
162+ Test reading varible as an array and conveting it to numpy the performant way.
163+ This also check that the numpy data type is set correctly.
164+ "maskingvalue = float("nan")" is used to generate arrays with concrete data type.
165+ """
166+ # arrange
167+ import numpy as np
168+ ds = metop_reader .open_dataset (file_path = str (test_file ), maskingvalue = float ("nan" ))
169+
170+ # act
171+ latitude = np .array (metop_reader .as_array (ds ['latitude' ]), copy = None )
172+ longitude = np .array (metop_reader .as_array (ds ['longitude' ]), copy = None )
173+
174+ # assert
175+ assert latitude .dtype == np .dtype ('float64' )
176+ assert longitude .dtype == np .dtype ('float64' )
177+ assert np .all ((0 < longitude )& (longitude < 360 ))
178+ assert np .all ((- 90 < latitude )& (latitude < 90 ))
179+
180+ # clean
181+ metop_reader .close_dataset (ds )
182+
183+ @pytest .mark .parametrize ("test_file" , ["ASCA_SZF" , "ASCA_SZO" ,"ASCA_SZR" , "MHSx_xxx" , "HIRS_xxx" , "AMSA_xxx" , "IASI_SND" , "IASI_xxx" ], indirect = True )
184+ def test_different_file_types (metop_reader , test_file ):
185+ """
186+ Test that different types of test files can be opened.
187+ """
188+ # act
189+ ds = metop_reader .open_dataset (file_path = str (test_file ))
190+
191+ # assert
192+ assert ds is not None
193+ assert "record_start_time" in metop_reader .get_keys (ds )
194+
195+ # clean
196+ metop_reader .close_dataset (ds )
0 commit comments