Skip to content

Commit da737ae

Browse files
committed
Merge branch 'feature/conftest-for-common-fixtures' into feature/interpolated-trajectories
2 parents 6528721 + 12713e4 commit da737ae

5 files changed

Lines changed: 269 additions & 173 deletions

File tree

climada/test/conftest.py

Lines changed: 66 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969

7070
# Exposure coordinates
7171
EXP_LONS = np.array([4, 4.25, 4.5, 4, 4.25, 4.5])
72-
EXP_LATS = np.array([45, 45, 45, 45.25, 45.25, 45.25])
72+
EXP_LATS = np.array([33, 33, 33, 33.25, 33.25, 33.25])
7373

7474
# ---------------------------------------------------------------------------
7575
# Hazard definition
@@ -104,87 +104,62 @@
104104
IMPF_ID = 1
105105
IMPF_NAME = "IMPF_1"
106106

107-
# Sanity checks
108-
for const in [VALUES, CATEGORIES, EXP_LONS, EXP_LATS]:
109-
assert len(const) == len(
110-
VALUES
111-
), "VALUES, REGIONS, CATEGORIES, EXP_LONS, EXP_LATS should all have the same lengths."
112107

113-
for const in [EVENT_IDS, EVENT_NAMES, DATES, FREQUENCY]:
114-
assert len(const) == len(
115-
EVENT_IDS
116-
), "EVENT_IDS, EVENT_NAMES, DATES, FREQUENCY should all have the same lengths."
117-
118-
119-
@pytest.fixture(scope="session")
120-
def exposure_values():
121-
return VALUES.copy()
122-
123-
124-
@pytest.fixture(scope="session")
125-
def categories():
126-
return CATEGORIES.copy()
127-
128-
129-
@pytest.fixture(scope="session")
130-
def exposure_geometry():
131-
return [Point(lon, lat) for lon, lat in zip(EXP_LONS, EXP_LATS)]
132-
133-
134-
@pytest.fixture(scope="session")
135-
def exposures_factory(
136-
exposure_values,
137-
exposure_geometry,
138-
):
108+
@pytest.fixture
109+
def exposures_factory():
139110
def _make_exposures(
111+
values=VALUES,
112+
exp_lons=EXP_LONS,
113+
exp_lats=EXP_LATS,
140114
value_factor=1.0,
141115
ref_year=EXPOSURE_REF_YEAR,
142116
hazard_type=HAZARD_TYPE,
143117
group_id=None,
118+
crs=CRS_WGS84,
119+
impf_id=IMPF_ID,
120+
description=EXP_DESC,
121+
value_unit=EXPOSURE_VALUE_UNIT,
122+
categories=None,
144123
):
145124
gdf = gpd.GeoDataFrame(
146125
{
147-
"value": exposure_values * value_factor,
148-
f"impf_{hazard_type}": IMPF_ID,
149-
"geometry": exposure_geometry,
126+
"value": values * value_factor,
127+
f"impf_{hazard_type}": impf_id,
128+
"category": categories,
129+
"geometry": gpd.points_from_xy(exp_lons, exp_lats, crs=crs),
150130
},
151-
crs=CRS_WGS84,
131+
crs=crs,
152132
)
153133
if group_id is not None:
154134
gdf["group_id"] = group_id
155135

156136
return Exposures(
157137
data=gdf,
158-
description=EXP_DESC,
138+
description=description,
159139
ref_year=ref_year,
160-
value_unit=EXPOSURE_VALUE_UNIT,
140+
value_unit=value_unit,
161141
)
162142

163143
return _make_exposures
164144

165145

166-
@pytest.fixture(scope="session")
146+
@pytest.fixture
167147
def exposures(exposures_factory):
168148
return exposures_factory()
169149

170150

171-
@pytest.fixture(scope="session")
172-
def hazard_frequency_factory():
173-
base = FREQUENCY
174-
151+
def hazard_frequency_factory(base=FREQUENCY):
175152
def _make_frequency(scale=1.0):
176153
return base * scale
177154

178155
return _make_frequency
179156

180157

181-
@pytest.fixture(scope="session")
182158
def hazard_frequency():
183159
return hazard_frequency_factory()
184160

185161

186-
@pytest.fixture(scope="session")
187-
def hazard_intensity_factory():
162+
def hazard_intensity(max_intensity=HAZARD_MAX_INTENSITY, scale=1.0):
188163
"""
189164
Intensity matrix designed for analytical expectations:
190165
- Event 1: zero
@@ -195,76 +170,83 @@ def hazard_intensity_factory():
195170
base = csr_matrix(
196171
[
197172
[0, 0, 0, 0, 0, 0],
198-
[HAZARD_MAX_INTENSITY, 0, 0, 0, 0, 0],
199-
[0, HAZARD_MAX_INTENSITY / 2, 0, 0, 0, 0],
173+
[max_intensity, 0, 0, 0, 0, 0],
174+
[0, max_intensity / 2, 0, 0, 0, 0],
200175
[
201-
HAZARD_MAX_INTENSITY / 4,
202-
HAZARD_MAX_INTENSITY / 4,
203-
HAZARD_MAX_INTENSITY / 4,
204-
HAZARD_MAX_INTENSITY / 4,
205-
HAZARD_MAX_INTENSITY / 4,
206-
HAZARD_MAX_INTENSITY / 4,
176+
max_intensity / 4,
177+
max_intensity / 4,
178+
max_intensity / 4,
179+
max_intensity / 4,
180+
max_intensity / 4,
181+
max_intensity / 4,
207182
],
208183
[
209-
HAZARD_MAX_INTENSITY,
210-
HAZARD_MAX_INTENSITY,
211-
HAZARD_MAX_INTENSITY,
212-
HAZARD_MAX_INTENSITY,
213-
HAZARD_MAX_INTENSITY,
214-
HAZARD_MAX_INTENSITY,
184+
max_intensity,
185+
max_intensity,
186+
max_intensity,
187+
max_intensity,
188+
max_intensity,
189+
max_intensity,
215190
],
216191
]
217192
)
218193

219-
def _make_intensity(scale=1.0):
220-
return base * scale
221-
222-
return _make_intensity
223-
194+
return base * scale
224195

225-
@pytest.fixture(scope="session")
226-
def hazard_intensity_matrix(hazard_intensity_factory):
227-
return hazard_intensity_factory()
228196

229-
230-
@pytest.fixture(scope="session")
197+
@pytest.fixture
231198
def centroids():
232199
return Centroids(lat=HAZ_LATS, lon=HAZ_LONS, crs=CRS_WGS84)
233200

234201

235-
@pytest.fixture(scope="session")
202+
@pytest.fixture
236203
def hazard_factory(
237-
hazard_intensity_factory,
238-
hazard_frequency_factory,
239204
centroids,
240205
):
241206
def _make_hazard(
207+
intensity_matrix=None,
208+
frequency_array=FREQUENCY,
209+
max_intensity=HAZARD_MAX_INTENSITY,
210+
centroids=None,
242211
intensity_scale=1.0,
243212
frequency_scale=1.0,
244213
hazard_type=HAZARD_TYPE,
245214
hazard_unit=HAZARD_UNIT,
215+
lat=HAZ_LATS,
216+
lon=HAZ_LONS,
217+
crs=CRS_WGS84,
218+
event_id=EVENT_IDS,
219+
event_name=EVENT_NAMES,
220+
date=DATES,
221+
frequency_unit=FREQUENCY_UNIT,
246222
):
223+
if intensity_matrix is None:
224+
intensity_matrix = hazard_intensity(max_intensity, intensity_scale)
225+
226+
if centroids is None:
227+
centroids = Centroids(lat=lat, lon=lon, crs=crs)
228+
247229
return Hazard(
248230
haz_type=hazard_type,
249231
units=hazard_unit,
250232
centroids=centroids,
251-
event_id=EVENT_IDS,
252-
event_name=EVENT_NAMES,
253-
date=DATES,
254-
frequency=hazard_frequency_factory(scale=frequency_scale),
255-
frequency_unit=FREQUENCY_UNIT,
256-
intensity=hazard_intensity_factory(scale=intensity_scale),
233+
event_id=event_id,
234+
event_name=event_name,
235+
date=date,
236+
frequency=frequency_array * frequency_scale,
237+
frequency_unit=frequency_unit,
238+
intensity=intensity_matrix,
257239
)
258240

259241
return _make_hazard
260242

261243

262-
@pytest.fixture(scope="session")
244+
@pytest.fixture
263245
def hazard(hazard_factory):
264246
return hazard_factory()
265247

266248

267-
@pytest.fixture(scope="session")
249+
@pytest.fixture
268250
def impf_factory():
269251
def _make_impf(
270252
paa_scale=1.0,
@@ -292,12 +274,12 @@ def _make_impf(
292274
return _make_impf
293275

294276

295-
@pytest.fixture(scope="session")
277+
@pytest.fixture
296278
def linear_impact_function(impf_factory):
297279
return impf_factory()
298280

299281

300-
@pytest.fixture(scope="session")
282+
@pytest.fixture
301283
def impfset_factory(impf_factory):
302284
def _make_impfset(
303285
paa_scale=1.0,
@@ -323,6 +305,6 @@ def _make_impfset(
323305
return _make_impfset
324306

325307

326-
@pytest.fixture(scope="session")
308+
@pytest.fixture
327309
def impfset(impfset_factory):
328310
return impfset_factory()

climada/test/fixture_use_example.py

Lines changed: 0 additions & 83 deletions
This file was deleted.

doc/development/Guide_Testing.ipynb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
"Writing tests is work. As a matter of facts, it can be a _lot_ of work, depending on the program often more than writing the original code.\\\n",
2121
"Luckily, it essentially follows always the same basic procedure and a there are a lot of tools and frameworks available to facilitate this work.\n",
2222
"\n",
23-
"In CLIMADA we use the Python in-built _test runner_ [pytest](https://docs.pytest.org/en/7.1.x/index.html) for execution of the tests."
23+
"In CLIMADA we use the Python in-built _test runner_ [pytest](https://docs.pytest.org/en/7.1.x/index.html) for execution of the tests.\n",
24+
"\n",
25+
"We now leverage `pytest` fixtures for defining the data and context used by tests. Please read [how to use fixtures for testing in CLIMADA](fixture-tutorial)."
2426
]
2527
},
2628
{
@@ -53,7 +55,6 @@
5355
},
5456
{
5557
"cell_type": "markdown",
56-
"id": "5819e8c6",
5758
"metadata": {},
5859
"source": [
5960
"### Basic Test Procedure\n",
@@ -277,7 +278,9 @@
277278
"source": [
278279
"### Test Configuration\n",
279280
"\n",
280-
"Use the configuration file `climada.config` in the installation directory to define file paths and external resources used during tests (see the [Constants and Configuration Guide](./Guide_Configuration.ipynb))."
281+
"Integration tests should make use of the fixtures defined in `climada/test/conftest.py`. Learn how to do that in [how to use fixtures for testing in CLIMADA](fixture-tutorial).\n",
282+
"\n",
283+
"Test data can also use paths defined in the configuration file `climada.config` (in the installation directory) which define file paths and external resources to be used during tests (see the [Constants and Configuration Guide](./Guide_Configuration.ipynb))."
281284
]
282285
},
283286
{
@@ -334,9 +337,9 @@
334337
],
335338
"metadata": {
336339
"kernelspec": {
337-
"display_name": "Python 3 (ipykernel)",
340+
"display_name": "Python [conda env:climada_env_dev]",
338341
"language": "python",
339-
"name": "python3"
342+
"name": "conda-env-climada_env_dev-py"
340343
},
341344
"language_info": {
342345
"codemirror_mode": {
@@ -348,7 +351,7 @@
348351
"name": "python",
349352
"nbconvert_exporter": "python",
350353
"pygments_lexer": "ipython3",
351-
"version": "3.12.6"
354+
"version": "3.11.15"
352355
},
353356
"vscode": {
354357
"interpreter": {

0 commit comments

Comments
 (0)