Skip to content

Commit 5234fa6

Browse files
Feature/fix nightlight test (#718)
* fix test_load_nightlight_noaa The test was failing the integration check on jenkins. Create fake .tif.gz file, execute test, delate.tif.gz file. * formatting * nightlight: fix uninitialized variable * formatting change sat_name from 'F18' to 'E99' * dependencies: use PIL instead of tifffile for image creation * cosmetics --------- Co-authored-by: Nicolas Colombi <[email protected]>
1 parent 7a646c8 commit 5234fa6

File tree

2 files changed

+80
-52
lines changed

2 files changed

+80
-52
lines changed

climada/entity/exposures/litpop/nightlight.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ def download_nl_files(req_files=np.ones(len(BM_FILENAMES),),
311311
continue # file already available or not required
312312
path_check = False
313313
# loop through different possible URLs defined in CONFIG:
314+
value_err = None
314315
for url in CONFIG.exposures.litpop.nightlights.nasa_sites.list():
315316
try: # control for ValueError due to wrong URL
316317
curr_file = url.str() + BM_FILENAMES[num_files] %(year)
@@ -321,10 +322,13 @@ def download_nl_files(req_files=np.ones(len(BM_FILENAMES),),
321322
value_err = err
322323
if path_check: # download succesful
323324
continue
324-
raise ValueError("Download failed, check URLs in " +
325-
"CONFIG.exposures.litpop.nightlights.nasa_sites! \n Last " +
326-
"error message: \n" + value_err.args[0])
327-
325+
if value_err:
326+
raise ValueError("Download failed,"
327+
" check URLs inCONFIG.exposures.litpop.nightlights.nasa_sites!\n"
328+
f" Last error message:\n {value_err.args[0]}")
329+
else:
330+
raise ValueError("Download failed, file not found and no nasa sites configured,"
331+
" check URLs in CONFIG.exposures.litpop.nightlights.nasa_sites!")
328332
except Exception as exc:
329333
raise RuntimeError('Download failed. Please check the network '
330334
'connection and whether filenames are still valid.') from exc

climada/test/test_nightlight.py

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@
1919
Tests on Black marble.
2020
"""
2121

22-
import unittest
23-
import os
22+
import gzip
23+
import io
24+
from pathlib import Path
2425
import tarfile
26+
from tempfile import TemporaryDirectory
27+
import unittest
28+
2529
import affine
2630
import numpy as np
2731
import scipy.sparse as sparse
28-
32+
from PIL import Image
2933
from shapely.geometry import Polygon
30-
from pathlib import Path
31-
from tempfile import TemporaryDirectory
3234
from osgeo import gdal
35+
3336
from climada.entity.exposures.litpop import nightlight
3437
from climada.util.constants import (SYSTEM_DIR, CONFIG)
3538
from climada.util import (files_handler, ureg)
@@ -38,6 +41,7 @@
3841
NOAA_RESOLUTION_DEG = (30 * ureg.arc_second).to(ureg.deg).magnitude
3942

4043
def init_test_shape():
44+
"""provide a rectangular shape"""
4145
bounds = (14.18, 35.78, 14.58, 36.09)
4246
# (min_lon, max_lon, min_lat, max_lat)
4347

@@ -52,7 +56,7 @@ class TestNightlight(unittest.TestCase):
5256
"""Test litpop.nightlight"""
5357

5458
def test_load_nasa_nl_shape_single_tile(self):
55-
""" Test that the function returns a np.ndarray containing
59+
""" Test that the function returns a np.ndarray containing
5660
the cropped .tif image values. Test that
5761
just one layer is returned. """
5862

@@ -63,28 +67,28 @@ def test_load_nasa_nl_shape_single_tile(self):
6367
# Test cropped output
6468
out_image, meta = nightlight.load_nasa_nl_shape_single_tile(geometry = shape, path = path)
6569
self.assertIsInstance(out_image, np.ndarray)
66-
self.assertEqual(len(out_image.shape), 2)
70+
self.assertEqual(len(out_image.shape), 2)
6771

6872
# Test meta ouput
6973
self.assertEqual(meta['height'],out_image.shape[0])
7074
self.assertEqual(meta['width'],out_image.shape[1])
7175
self.assertEqual(meta['driver'], 'GTiff')
72-
self.assertEqual(meta['transform'], affine.Affine(0.004166666666666667, 0.0, 14.179166666666667,
73-
0.0, -0.004166666666666667, 36.09166666666667))
76+
self.assertEqual(meta['transform'], affine.Affine(0.004166666666666667, 0.0,
77+
14.179166666666667, 0.0, -0.004166666666666667, 36.09166666666667))
7478
# Test raises
7579
with self.assertRaises(IndexError) as cm:
7680
nightlight.load_nasa_nl_shape_single_tile(geometry = shape, path = path, layer = 4)
77-
self.assertEqual("BlackMarble_2016_C1_geo_gray.tif has only 3 layers, layer 4 can't be accessed.",
78-
str(cm.exception))
81+
self.assertEqual("BlackMarble_2016_C1_geo_gray.tif has only 3 layers,"
82+
" layer 4 can't be accessed.", str(cm.exception))
7983
# Test logger
8084
with self.assertLogs('climada.entity.exposures.litpop.nightlight', level='DEBUG') as cm:
8185
nightlight.load_nasa_nl_shape_single_tile(geometry = shape, path = path)
8286
self.assertIn('Read cropped BlackMarble_2016_C1_geo_gray.tif as np.ndarray.', cm.output[0])
83-
87+
8488
def test_read_bm_files(self):
8589
"""" Test that read_bm_files function read NASA BlackMarble GeoTiff and output
8690
an array and a gdal DataSet."""
87-
91+
8892
# Download 'BlackMarble_2016_A1_geo_gray.tif' in the temporary directory and create a path
8993
temp_dir = TemporaryDirectory()
9094
urls = CONFIG.exposures.litpop.nightlights.nasa_sites.list()
@@ -114,7 +118,7 @@ def test_read_bm_files(self):
114118

115119
def test_download_nl_files(self):
116120
""" Test that BlackMarble GeoTiff files are downloaded. """
117-
121+
118122
# Test Raises
119123
temp_dir = TemporaryDirectory()
120124
with self.assertRaises(ValueError) as cm:
@@ -148,86 +152,106 @@ def test_download_nl_files(self):
148152
temp_dir.cleanup()
149153

150154
def test_unzip_tif_to_py(self):
151-
""" Test that .gz files are unzipped and read as a sparse matrix,
155+
""" Test that .gz files are unzipped and read as a sparse matrix,
152156
file_name is correct and logger message recorded. """
153157

154-
path_file_tif_gz = str(Path(SYSTEM_DIR, 'F182013.v4c_web.stable_lights.avg_vis.tif.gz'))
158+
path_file_tif_gz = str(SYSTEM_DIR.joinpath('F182013.v4c_web.stable_lights.avg_vis.tif.gz'))
155159
with self.assertLogs('climada.entity.exposures.litpop.nightlight', level='INFO') as cm:
156160
file_name, night = nightlight.unzip_tif_to_py(path_file_tif_gz)
157161
self.assertIn(f'Unzipping file {path_file_tif_gz}', cm.output[0])
158162
self.assertEqual(str(file_name), 'F182013.v4c_web.stable_lights.avg_vis.tif')
159163
self.assertIsInstance(night, sparse._csr.csr_matrix)
160-
os.remove(Path(SYSTEM_DIR, 'F182013.v4c_web.stable_lights.avg_vis.p'))
164+
SYSTEM_DIR.joinpath('F182013.v4c_web.stable_lights.avg_vis.p').unlink()
161165

162166
def test_load_nightlight_noaa(self):
163-
""" Test that data is downloaded if not present in SYSTEM_DIR,
164-
or not downloaded if present. Test the three outputs of the
165-
function."""
166-
167-
# Using an already existing file and without providing arguments
167+
""" Test that data is not downloaded if a .tif.gz file is present
168+
in SYSTEM_DIR. """
169+
170+
# initialization
171+
sat_name = 'E99'
172+
year = 2013
173+
pattern = f"{sat_name}{year}.v4c_web.stable_lights.avg_vis"
174+
gzfile = f"{pattern}.tif.gz"
175+
pfile = f"{pattern}.p"
176+
tiffile = f"{pattern}.tif"
177+
178+
# create an empty image
179+
image = np.zeros((100, 100), dtype=np.uint8)
180+
pilim = Image.fromarray(image)
181+
182+
# save the image as .tif.gz
183+
with io.BytesIO() as mem:
184+
pilim.save(mem, "tiff")
185+
# compressed image to a gzip file
186+
with gzip.GzipFile(SYSTEM_DIR.joinpath(gzfile), 'wb') as f:
187+
f.write(mem.getvalue())
188+
SYSTEM_DIR.joinpath(pfile).unlink(missing_ok=True)
189+
190+
# using already existing file and without providing arguments
168191
night, coord_nl, fn_light = nightlight.load_nightlight_noaa()
169192
self.assertIsInstance(night, sparse._csr.csr_matrix)
170-
self.assertIn('F182013.v4c_web.stable_lights.avg_vis.tif',str(fn_light))
193+
self.assertIn(tiffile, str(fn_light))
171194
self.assertTrue(np.array_equal(np.array([[-65, NOAA_RESOLUTION_DEG],
172195
[-180, NOAA_RESOLUTION_DEG]]),coord_nl))
173-
os.remove(SYSTEM_DIR.joinpath('F182013.v4c_web.stable_lights.avg_vis.p'))
174-
# With arguments
175-
night, coord_nl, fn_light = nightlight.load_nightlight_noaa(ref_year = 2010, sat_name = 'F18')
196+
SYSTEM_DIR.joinpath(pfile).unlink()
197+
198+
# with arguments
199+
night, coord_nl, fn_light = nightlight.load_nightlight_noaa(ref_year=year, sat_name=sat_name)
176200
self.assertIsInstance(night, sparse._csr.csr_matrix)
177-
self.assertIn('F182010.v4d_web.stable_lights.avg_vis', str(fn_light))
178-
file = str(SYSTEM_DIR.joinpath('F182010.v4d_web.stable_lights.avg_vis.p'))
179-
os.remove(file)
201+
self.assertIn(tiffile, str(fn_light))
202+
SYSTEM_DIR.joinpath(pfile).unlink()
203+
SYSTEM_DIR.joinpath(gzfile).unlink()
180204

181-
# Test raises from wrong input agruments
205+
# test raises from wrong input agruments
182206
with self.assertRaises(ValueError) as cm:
183207
night, coord_nl, fn_light = nightlight.load_nightlight_noaa(
184-
ref_year = 2050, sat_name = 'F150')
185-
self.assertEqual('Nightlight intensities for year 2050 and satellite F150 do not exist.',
208+
ref_year=2050, sat_name='F150')
209+
self.assertEqual('Nightlight intensities for year 2050 and satellite F150 do not exist.',
186210
str(cm.exception))
187211

188212
def test_untar_noaa_stable_nighlight(self):
189-
""" Testing that input .tar file is moved into SYSTEM_DIR,
190-
tif.gz file is extracted from .tar file and moved into SYSTEM_DIR,
213+
""" Testing that input .tar file is moved into SYSTEM_DIR,
214+
tif.gz file is extracted from .tar file and moved into SYSTEM_DIR,
191215
exception are raised when no .tif.gz file is present in the tar file,
192-
and the logger message is recorded if more then one .tif.gz is present in
216+
and the logger message is recorded if more then one .tif.gz is present in
193217
.tar file. """
194218

195219
# Create path to .tif.gz and .csv files already existing in SYSTEM_DIR
196-
path_tif_gz_1 = Path(SYSTEM_DIR, 'F182013.v4c_web.stable_lights.avg_vis.tif.gz')
197-
path_csv = Path(SYSTEM_DIR, 'GDP_TWN_IMF_WEO_data.csv')
198-
path_tar = Path(SYSTEM_DIR, 'sample.tar')
220+
path_tif_gz_1 = Path(SYSTEM_DIR, 'F182013.v4c_web.stable_lights.avg_vis.tif.gz')
221+
path_csv = Path(SYSTEM_DIR, 'GDP_TWN_IMF_WEO_data.csv')
222+
path_tar = Path(SYSTEM_DIR, 'sample.tar')
199223

200-
# Create .tar file and add .tif.gz and .csv
224+
# Create .tar file and add .tif.gz and .csv
201225
file_tar = tarfile.open(path_tar, "w") #create the tar file
202-
file_tar.add(name = path_tif_gz_1, recursive = False, arcname = 'F182013.v4c_web.stable_lights.avg_vis.tif.gz')
226+
file_tar.add(name = path_tif_gz_1, recursive = False, arcname = 'F182013.v4c_web.stable_lights.avg_vis.tif.gz')
203227
file_tar.close()
204228

205229
# Test that the files has been moved
206230
path_to_test = nightlight.untar_noaa_stable_nightlight(path_tar)
207231
self.assertTrue(path_to_test.exists())
208232
self.assertTrue(path_tar .exists())
209-
os.remove(path_tar)
233+
path_tar.unlink()
210234

211235
# Put no .tif.gz file in .tar file and check raises
212-
path_tar = Path(SYSTEM_DIR, 'sample.tar')
236+
path_tar = Path(SYSTEM_DIR, 'sample.tar')
213237
file_tar = tarfile.open(path_tar, "w") #create the tar file
214-
file_tar.add(name = path_csv, recursive = False, arcname ='GDP_TWN_IMF_WEO_data.csv' )
238+
file_tar.add(name = path_csv, recursive = False, arcname ='GDP_TWN_IMF_WEO_data.csv' )
215239
file_tar.close()
216240
with self.assertRaises(ValueError) as cm:
217241
nightlight.untar_noaa_stable_nightlight(path_tar)
218242
self.assertEqual('No stable light intensities for selected year and satellite '
219243
f'in file {path_tar}',str(cm.exception))
220-
os.remove(path_tar)
244+
path_tar.unlink()
221245

222-
# Test logger with having two .tif.gz file in .tar file
246+
# Test logger with having two .tif.gz file in .tar file
223247
file_tar = tarfile.open(path_tar, "w") #create the tar file
224-
file_tar.add(name = path_tif_gz_1, recursive = False, arcname = 'F182013.v4c_web.stable_lights.avg_vis.tif.gz' )
225-
file_tar.add(name = path_tif_gz_1, recursive = False, arcname = 'F182013.v4c_web.stable_lights.avg_vis.tif.gz' )
248+
file_tar.add(name = path_tif_gz_1, recursive = False, arcname = 'F182013.v4c_web.stable_lights.avg_vis.tif.gz' )
249+
file_tar.add(name = path_tif_gz_1, recursive = False, arcname = 'F182013.v4c_web.stable_lights.avg_vis.tif.gz' )
226250
file_tar.close()
227251
with self.assertLogs('climada.entity.exposures.litpop.nightlight', level = 'WARNING') as cm:
228252
nightlight.untar_noaa_stable_nightlight(path_tar)
229253
self.assertIn('found more than one potential intensity file in', cm.output[0])
230-
os.remove(path_tar)
254+
path_tar.unlink()
231255

232256
# Execute Tests
233257
if __name__ == "__main__":

0 commit comments

Comments
 (0)