Skip to content

Commit

Permalink
Merge pull request #104 from ImperialCollegeLondon/63-add-docstrings-…
Browse files Browse the repository at this point in the history
…to-unit-tests-where-these-are-missing

Add docstrings to tests
  • Loading branch information
davidorme authored Sep 15, 2023
2 parents f4686f3 + 391f05f commit 389a911
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 66 deletions.
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ per-file-ignores =
# Flattening namespace of submodules

max-line-length = 88
exclude = tests/*
# exclude = tests/*
max-complexity = 10
docstring-convention = google

Expand Down Expand Up @@ -51,4 +51,4 @@ ignore_errors = True
[mypy-tests.*]
disallow_untyped_calls = False
disallow_untyped_defs = False
disallow_incomplete_defs = False
disallow_incomplete_defs = False
6 changes: 6 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""The tests module.
This file is required to make tests a module. For some reason, `mypy` will only respect
per-module options, such as suppressing typing checks in tests, for _modules_. Adding a
`[mypy-tests.*]` section in setup.cfg does nothing if tests is not a module.
"""
15 changes: 14 additions & 1 deletion tests/hygro/test_hygro.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Test the functionality of the pyrealm.hygro module."""

import json
from pathlib import Path

Expand All @@ -7,6 +9,7 @@

@pytest.fixture
def bigleaf():
"""A fixture to provide benchmark predictions from the bigleaf package."""
path = Path(__file__).parent
with open(path / "bigleaf_test_values.json") as tvals:
return json.load(tvals)
Expand All @@ -22,7 +25,9 @@ def bigleaf():
@pytest.mark.parametrize(
argnames="formula", argvalues=["Allen1998", "Alduchov1996", "Sonntag1990"]
)
def test_calc_vp_sat(bigleaf, formula):
def test_calc_vp_sat(bigleaf, formula) -> None:
"""Test the calc_vp_sat function."""

from pyrealm.constants import HygroConst
from pyrealm.hygro import calc_vp_sat

Expand All @@ -37,6 +42,8 @@ def test_calc_vp_sat(bigleaf, formula):
argnames="formula", argvalues=["Allen1998", "Alduchov1996", "Sonntag1990"]
)
def test_convert_vp_to_vpd(bigleaf, formula):
"""Test the convert_vp_to_vpd function."""

from pyrealm.constants import HygroConst
from pyrealm.hygro import convert_vp_to_vpd

Expand All @@ -51,6 +58,8 @@ def test_convert_vp_to_vpd(bigleaf, formula):
argnames="formula", argvalues=["Allen1998", "Alduchov1996", "Sonntag1990"]
)
def test_convert_rh_to_vpd(bigleaf, formula):
"""Test the convert_rh_to_vpd function."""

from pyrealm.constants import HygroConst
from pyrealm.hygro import convert_rh_to_vpd

Expand All @@ -62,6 +71,8 @@ def test_convert_rh_to_vpd(bigleaf, formula):


def test_convert_sh_to_vp(bigleaf):
"""Test the convert_sh_to_vp function."""

from pyrealm.hygro import convert_sh_to_vp

results = convert_sh_to_vp(SH, PATM)
Expand All @@ -74,6 +85,8 @@ def test_convert_sh_to_vp(bigleaf):
argnames="formula", argvalues=["Allen1998", "Alduchov1996", "Sonntag1990"]
)
def test_convert_sh_to_vpd(bigleaf, formula):
"""Test the convert_sh_to_vpd function."""

from pyrealm.constants import HygroConst
from pyrealm.hygro import convert_sh_to_vpd

Expand Down
19 changes: 14 additions & 5 deletions tests/pmodel/test_c3c4competition.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,13 @@
],
)
def test_c3c4competition(pmodel_c3_args, pmodel_c4_args, expected):
"""Test the C3/C4 competition model"""
env = PModelEnvironment(
tc=np.array([20, 35]), patm=101325, co2=400, vpd=1000, theta=0.5
tc=np.array([20, 35]),
patm=np.array([101325]),
co2=np.array([400]),
vpd=np.array([1000]),
theta=np.array([0.5]),
)

pmodel_c3 = PModel(env, **pmodel_c3_args)
Expand All @@ -88,17 +93,21 @@ def test_c3c4competition(pmodel_c3_args, pmodel_c4_args, expected):
pmodel_c4.estimate_productivity(fapar=fapar, ppfd=ppfd)

comp = C3C4Competition(
pmodel_c3.gpp, pmodel_c4.gpp, treecover=0, below_t_min=False, cropland=False
pmodel_c3.gpp,
pmodel_c4.gpp,
treecover=np.array([0, 0]),
below_t_min=np.array([False, False]),
cropland=np.array([False, False]),
)

d13CO2 = -8.4
D14CO2 = 19.2
d13CO2 = np.array([-8.4])
D14CO2 = np.array([19.2])

pmodel_c3_iso = CalcCarbonIsotopes(pmodel_c3, d13CO2=d13CO2, D14CO2=D14CO2)
pmodel_c4_iso = CalcCarbonIsotopes(pmodel_c4, d13CO2=d13CO2, D14CO2=D14CO2)

comp.estimate_isotopic_discrimination(
d13CO2=-8.4,
d13CO2=np.array([-8.4]),
Delta13C_C3_alone=pmodel_c3_iso.Delta13C,
Delta13C_C4_alone=pmodel_c4_iso.Delta13C,
)
Expand Down
5 changes: 3 additions & 2 deletions tests/pmodel/test_calc_carbon_isotopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@
),
],
)
def test_temporal_interpolator_init_errors(pmodelenv_args, pmodel_args, expected):
def test_CalcCarbonIsotopes(pmodelenv_args, pmodel_args, expected):
"""Tests the CalcCarbonIsotopes class."""
env = PModelEnvironment(**pmodelenv_args)
pmodel = PModel(env, **pmodel_args)
cci = CalcCarbonIsotopes(pmodel, d13CO2=-8.4, D14CO2=19.2)
cci = CalcCarbonIsotopes(pmodel, d13CO2=np.array([-8.4]), D14CO2=np.array([19.2]))

for attr in expected:
assert np.allclose(getattr(cci, attr), expected[attr], atol=0.001)
24 changes: 16 additions & 8 deletions tests/pmodel/test_fast_slow_pmodel.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Tests the implementation of the FastSlowModel against the reference benchmark."""
from importlib import resources

import numpy as np
Expand All @@ -6,7 +7,7 @@

@pytest.fixture(scope="module")
def be_vie_data():
"""Import the test data"""
"""Import the benchmark test data."""

# This feels like a hack but it isn't obvious how to reference the data files
# included in the source distribution from the package path.
Expand All @@ -26,7 +27,7 @@ def be_vie_data():

@pytest.fixture(scope="module")
def be_vie_data_components(be_vie_data):
"""Convert the test data into a PModelEnv and arrays"""
"""Convert the test data into a PModelEnv and arrays."""

from pyrealm.pmodel import PModelEnvironment

Expand All @@ -48,8 +49,11 @@ def be_vie_data_components(be_vie_data):


def test_FSPModel_JAMES(be_vie_data_components):
"""This tests the legacy calculations from the Mengoli et al JAMES paper, using that
version of the weighted average calculations without acclimating xi."""
"""Test FastSlowPModel_JAMES.
This tests the legacy calculations from the Mengoli et al JAMES paper, using that
version of the weighted average calculations without acclimating xi.
"""

from pyrealm.pmodel import FastSlowScaler
from pyrealm.pmodel.subdaily import FastSlowPModel_JAMES
Expand Down Expand Up @@ -95,8 +99,12 @@ def test_FSPModel_JAMES(be_vie_data_components):


def test_FSPModel_corr(be_vie_data_components):
"""This tests the pyrealm implementation correlates well with the legacy
calculations from the Mengoli et al JAMES paper without acclimating xi."""
"""Test FastSlowPModel.
This tests that the pyrealm implementation including acclimating xi at least
correlates well with the legacy calculations from the Mengoli et al JAMES paper
without acclimating xi.
"""

from pyrealm.pmodel import FastSlowPModel, FastSlowScaler

Expand Down Expand Up @@ -127,12 +135,12 @@ def test_FSPModel_corr(be_vie_data_components):
gpp_in_micromols = fs_pmodel.gpp[valid] / env.const.k_c_molmass
assert np.allclose(gpp_in_micromols, expected_gpp[valid], rtol=0.2)
r_vals = np.corrcoef(gpp_in_micromols, expected_gpp[valid])
assert np.alltrue(r_vals > 0.995)
assert np.all(r_vals > 0.995)


@pytest.mark.parametrize("ndims", [2, 3, 4])
def test_FSPModel_dimensionality(be_vie_data, ndims):
"""This tests that the FastSlowPModel handles dimensions correctly.
"""Tests that the FastSlowPModel handles dimensions correctly.
This broadcasts the BE-Vie onto more dimensions and checks that the code iterates
over those dimensions correctly. fAPAR and PPFD are then fixed across the other
Expand Down
26 changes: 20 additions & 6 deletions tests/pmodel/test_fast_slow_scaler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""This module tests the interpolator routines for the subdaily model.
"""This module tests the FastSlowScaler class.
This class handles estimating daily reference values and then interpolating lagged
responses back to subdaily time scales.
""" # noqa: D205, D415

from contextlib import nullcontext as does_not_raise
Expand All @@ -9,6 +12,7 @@

@pytest.fixture
def fixture_FSS():
"""A fixture providing a FastSlowScaler object."""
from pyrealm.pmodel import FastSlowScaler

return FastSlowScaler(
Expand Down Expand Up @@ -111,10 +115,11 @@ def fixture_FSS():
],
)
def test_FSS_init(ctext_mngr, msg, datetimes):
"""Test the FastSlowScaler init handling of date ranges."""
from pyrealm.pmodel import FastSlowScaler

with ctext_mngr as cman:
drep = FastSlowScaler(datetimes=datetimes)
_ = FastSlowScaler(datetimes=datetimes)

if msg is not None:
assert str(cman.value) == msg
Expand Down Expand Up @@ -158,6 +163,8 @@ def test_FSS_init(ctext_mngr, msg, datetimes):
],
)
def test_FSS_set_window(fixture_FSS, ctext_mngr, msg, kwargs, samp_mean, samp_max):
"""Test the FastSlowScaler set_window method."""

with ctext_mngr as cman:
fixture_FSS.set_window(**kwargs)

Expand Down Expand Up @@ -221,6 +228,7 @@ def test_FSS_set_window(fixture_FSS, ctext_mngr, msg, kwargs, samp_mean, samp_ma
],
)
def test_FSS_set_include(fixture_FSS, ctext_mngr, msg, include, samp_mean, samp_max):
"""Test the FastSlowScaler set_include method."""
with ctext_mngr as cman:
fixture_FSS.set_include(include)

Expand Down Expand Up @@ -283,6 +291,7 @@ def test_FSS_set_include(fixture_FSS, ctext_mngr, msg, include, samp_mean, samp_
],
)
def test_FSS_set_nearest(fixture_FSS, ctext_mngr, msg, time, samp_mean, samp_max):
"""Test the FastSlowScaler set_nearest method."""
with ctext_mngr as cman:
fixture_FSS.set_nearest(time)

Expand All @@ -309,13 +318,14 @@ def test_FSS_set_nearest(fixture_FSS, ctext_mngr, msg, time, samp_mean, samp_max
],
)
def test_FSS_get_wv_errors(fixture_FSS, ctext_mngr, msg, values):
"""Test errors arising in the FastSlowScaler get_window_value method."""
fixture_FSS.set_window(
window_center=np.timedelta64(12, "h"),
half_width=np.timedelta64(2, "h"),
)

with ctext_mngr as cman:
res = fixture_FSS.get_window_values(values)
_ = fixture_FSS.get_window_values(values)

assert str(cman.value) == msg

Expand Down Expand Up @@ -360,7 +370,7 @@ class Test_FSS_get_vals:
"""

def test_FSS_get_vals_window(self, fixture_FSS, values, expected_means):
"""Test a window"""
"""Test a window."""
fixture_FSS.set_window(
window_center=np.timedelta64(12, "h"),
half_width=np.timedelta64(2, "h"),
Expand All @@ -370,7 +380,7 @@ def test_FSS_get_vals_window(self, fixture_FSS, values, expected_means):
assert np.allclose(calculated_means, expected_means)

def test_FSS_get_vals_include(self, fixture_FSS, values, expected_means):
"""Test include"""
"""Test include."""

# This duplicates the selection of the window test but using direct include
inc = np.zeros(48, dtype=np.bool_)
Expand All @@ -381,7 +391,7 @@ def test_FSS_get_vals_include(self, fixture_FSS, values, expected_means):
assert np.allclose(calculated_means, expected_means)

def test_FSS_get_vals_nearest(self, fixture_FSS, values, expected_means):
"""Test nearest"""
"""Test nearest."""

# This assumes the data are symmetrical about the middle hour, which is bit of a
# reach
Expand Down Expand Up @@ -524,6 +534,8 @@ def test_FSS_resample_subdaily(
exp_values,
fill_from,
):
"""Test the calculation of subdaily samples using FastSlowScaler."""

# Set the included observations - the different parameterisations here and for
# the update point should all select the same update point.
func = getattr(fixture_FSS, method_name)
Expand Down Expand Up @@ -602,6 +614,8 @@ def test_FSS_resample_subdaily_linear(
input_values,
exp_values,
):
"""Test FastSlowScaler resampling to subdaily timescale by linear interpolation."""

# Set the included observations
fixture_FSS.set_window(
window_center=np.timedelta64(13, "h"), half_width=np.timedelta64(1, "h")
Expand Down
5 changes: 3 additions & 2 deletions tests/pmodel/test_memory_effect.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Tests the application of the memory effect in the subdaily model."""

from contextlib import nullcontext as does_not_raise

import numpy as np
Expand Down Expand Up @@ -80,8 +82,7 @@ def test_memory_effect(inputs, alpha):
)
@pytest.mark.parametrize(argnames="ndim", argvalues=(1, 2, 3))
def test_memory_effect_inputs(inputs, handle_nan, context_manager, expected, ndim):
"""Simple testing of nan handling and expected predictions across multiple
dimensions."""
"""Simple testing of nan handling and predictions across multiple dimensions."""
from pyrealm.pmodel.subdaily import memory_effect

if ndim == 2:
Expand Down
Loading

0 comments on commit 389a911

Please sign in to comment.