diff --git a/CHANGELOG.md b/CHANGELOG.md index a745f55..a094e99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Consolidate package metadata and configuration in *pyproject.toml* ([#165](https://github.com/mpytools/mplotutils/pull/165)). - Replace deprecated `matplotlib.rcsetup.all_backends` with `matplotlib.backends.backend_registry.list_builtin()` ([#160](https://github.com/mpytools/mplotutils/pull/160)). +- Converted the hatch tests to a class based approach ([#146](https://github.com/mpytools/mplotutils/issues/146)). - Also upload coverage report in upstream dev CI ([#162](https://github.com/mpytools/mplotutils/pull/162)). ## v0.6.0 (04.12.2024) diff --git a/mplotutils/tests/test_hatch.py b/mplotutils/tests/test_hatch.py index a210dd5..2490994 100644 --- a/mplotutils/tests/test_hatch.py +++ b/mplotutils/tests/test_hatch.py @@ -14,13 +14,6 @@ requires_mpl_ge_310 = pytest.mark.skipif(not MPL_GE_310, reason="requires mpl >= 3.10") -HATCH_FUNCTIONS = ( - pytest.param(mpu.hatch, id="hatch"), - pytest.param(mpu.hatch_map, id="hatch_map"), - pytest.param(mpu.hatch_map_global, id="hatch_map_global"), -) - - def get_hatchcolor(h): if MPL_GE_311: return mpl.colors.to_rgba(h.get_hatchcolor()) @@ -28,211 +21,206 @@ def get_hatchcolor(h): return h._hatch_color -@pytest.mark.parametrize("obj", (None, xr.Dataset(), np.array([]))) -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_not_a_dataarray(obj, function): +class HatchBase: - with pytest.raises(TypeError, match="Expected a xr.DataArray"): - function(obj, "*") + @pytest.mark.parametrize("obj", (None, xr.Dataset(), np.array([]))) + def test_hatch_not_a_dataarray(self, obj): + with pytest.raises(TypeError, match="Expected a xr.DataArray"): + self.function(obj, "*") -@pytest.mark.parametrize("dtype", (float, int)) -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_not_bool(dtype, function): + @pytest.mark.parametrize("dtype", (float, int)) + def test_hatch_not_bool(self, dtype): - da = xr.DataArray(np.ones((3, 3), dtype=dtype)) + da = xr.DataArray(np.ones((3, 3), dtype=dtype)) - with pytest.raises(TypeError, match="Expected a boolean array"): - function(da, "*") + with pytest.raises(TypeError, match="Expected a boolean array"): + self.function(da, "*") + @pytest.mark.parametrize("ndim", (1, 3)) + def test_hatch_not_2D(self, ndim): -@pytest.mark.parametrize("ndim", (1, 3)) -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_not_2D(ndim, function): + da = xr.DataArray(np.ones([3] * ndim, dtype=bool)) - da = xr.DataArray(np.ones([3] * ndim, dtype=bool)) + with pytest.raises(ValueError, match="Expected a 2D array"): + self.function(da, "*") - with pytest.raises(ValueError, match="Expected a 2D array"): - function(da, "*") + def test_hatch_pattern(self): + da = xr.DataArray( + np.ones([3, 3], dtype=bool), + dims=("lat", "lon"), + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, + ) -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_pattern(function): + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): - da = xr.DataArray( - np.ones([3, 3], dtype=bool), - dims=("lat", "lon"), - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, - ) + h = self.function(da, "*", ax=ax) + assert h.hatches == ["", "*"] + h = self.function(da, "//", ax=ax) + assert h.hatches == ["", "//"] - subplot_kw = {"projection": ccrs.PlateCarree()} + def test_hatch_label(self): - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + da = xr.DataArray( + np.ones([3, 3], dtype=bool), + dims=("lat", "lon"), + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, + ) - h = function(da, "*", ax=ax) - assert h.hatches == ["", "*"] - h = function(da, "//", ax=ax) - assert h.hatches == ["", "//"] + # test label with default color + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): + self.function(da, "*", ax=ax, label="label") -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_label(function): + legend = ax.legend() + h = legend.legend_handles - da = xr.DataArray( - np.ones([3, 3], dtype=bool), - dims=("lat", "lon"), - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, - ) + assert len(h) == 1 - subplot_kw = {"projection": ccrs.PlateCarree()} + (rect,) = h - # test label with default color - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + assert rect.get_label() == "label" + assert mpl.colors.to_rgba("0.1") == get_hatchcolor(rect) - function(da, "*", ax=ax, label="label") + # test 2 labels with non-default color + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): - legend = ax.legend() - h = legend.legend_handles + self.function(da, "*", ax=ax, label="label0", color="#2ca25f") + self.function(da, "*", ax=ax, label="label1", color="#2ca25f") - assert len(h) == 1 + legend = ax.legend() + h = legend.legend_handles - (rect,) = h + assert len(h) == 2 - assert rect.get_label() == "label" - assert mpl.colors.to_rgba("0.1") == get_hatchcolor(rect) + for i, rect in enumerate(h): + assert rect.get_label() == f"label{i}" + assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(rect) - # test 2 labels with non-default color - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + @pytest.mark.skipif(MPL_GE_310, reason="only for mpl < 3.10") + def test_hatch_linewidth_mpl_lt_310(self): - function(da, "*", ax=ax, label="label0", color="#2ca25f") - function(da, "*", ax=ax, label="label1", color="#2ca25f") + da = xr.DataArray( + np.ones([3, 3], dtype=bool), + dims=("lat", "lon"), + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, + ) - legend = ax.legend() - h = legend.legend_handles + # test linewidth default width + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): + self.function(da, "*", ax=ax) - assert len(h) == 2 + assert mpl.rcParams["hatch.linewidth"] == 0.25 - for i, rect in enumerate(h): - assert rect.get_label() == f"label{i}" - assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(rect) + # changing away from the default linewidth does not raise a warning + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): + self.function(da, "*", ax=ax) + assert mpl.rcParams["hatch.linewidth"] == 0.25 -@pytest.mark.skipif(MPL_GE_310, reason="only for mpl < 3.10") -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_linewidth_mpl_lt_310(function): + with assert_no_warnings(): + self.function(da, "*", ax=ax, linewidth=1) - da = xr.DataArray( - np.ones([3, 3], dtype=bool), - dims=("lat", "lon"), - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, - ) + assert mpl.rcParams["hatch.linewidth"] == 1 - subplot_kw = {"projection": ccrs.PlateCarree()} + # changing away from the linewidth does raise a warning + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): - # test linewidth default width - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): - function(da, "*", ax=ax) + self.function(da, "*", ax=ax, linewidth=2) + assert mpl.rcParams["hatch.linewidth"] == 2 - assert mpl.rcParams["hatch.linewidth"] == 0.25 + with pytest.warns(match="Setting more than one hatch `linewidth`"): + self.function(da, "*", ax=ax, linewidth=1) - # changing away from the default linewidth does not raise a warning - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + assert mpl.rcParams["hatch.linewidth"] == 1 - function(da, "*", ax=ax) - assert mpl.rcParams["hatch.linewidth"] == 0.25 + @requires_mpl_ge_310 + @pytest.mark.filterwarnings("ignore:Passing 'N' to ListedColormap is deprecated") + def test_hatch_linewidth_mpl_ge_310(self): - with assert_no_warnings(): - function(da, "*", ax=ax, linewidth=1) + da = xr.DataArray( + np.ones([3, 3], dtype=bool), + dims=("lat", "lon"), + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, + ) - assert mpl.rcParams["hatch.linewidth"] == 1 + # test linewidth default width + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): + q = self.function(da, "*", ax=ax) + assert q.get_hatch_linewidth() == 0.25 + assert mpl.rcParams["hatch.linewidth"] == 0.25 - # changing away from the linewidth does raise a warning - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + # changing away from the default linewidth does not raise a warning + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): - function(da, "*", ax=ax, linewidth=2) - assert mpl.rcParams["hatch.linewidth"] == 2 + q = self.function(da, "*", ax=ax) + assert q.get_hatch_linewidth() == 0.25 + assert mpl.rcParams["hatch.linewidth"] == 0.25 - with pytest.warns(match="Setting more than one hatch `linewidth`"): - function(da, "*", ax=ax, linewidth=1) + with assert_no_warnings(): + q = self.function(da, "*", ax=ax, linewidth=1) - assert mpl.rcParams["hatch.linewidth"] == 1 + assert q.get_hatch_linewidth() == 1 + assert mpl.rcParams["hatch.linewidth"] == 1 + q = self.function(da, "*", ax=ax) + assert q.get_hatch_linewidth() == 0.25 + assert mpl.rcParams["hatch.linewidth"] == 0.25 -@requires_mpl_ge_310 -@pytest.mark.filterwarnings("ignore:Passing 'N' to ListedColormap is deprecated") -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_linewidth_mpl_ge_310(function): + # changing away from the linewidth does NOT raise a warning + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): - da = xr.DataArray( - np.ones([3, 3], dtype=bool), - dims=("lat", "lon"), - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, - ) + q = self.function(da, "*", ax=ax, linewidth=2) + assert q.get_hatch_linewidth() == 2 + assert mpl.rcParams["hatch.linewidth"] == 2 - subplot_kw = {"projection": ccrs.PlateCarree()} + with assert_no_warnings(): + q = self.function(da, "*", ax=ax, linewidth=1) - # test linewidth default width - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): - q = function(da, "*", ax=ax) - assert q.get_hatch_linewidth() == 0.25 - assert mpl.rcParams["hatch.linewidth"] == 0.25 + assert q.get_hatch_linewidth() == 1 + assert mpl.rcParams["hatch.linewidth"] == 1 - # changing away from the default linewidth does not raise a warning - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + def test_hatch_color(self): - q = function(da, "*", ax=ax) - assert q.get_hatch_linewidth() == 0.25 - assert mpl.rcParams["hatch.linewidth"] == 0.25 + da = xr.DataArray( + np.ones([3, 3], dtype=bool), + dims=("lat", "lon"), + coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, + ) - with assert_no_warnings(): - q = function(da, "*", ax=ax, linewidth=1) + # test default color + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): + h = self.function(da, "*", ax=ax) - assert q.get_hatch_linewidth() == 1 - assert mpl.rcParams["hatch.linewidth"] == 1 + assert mpl.colors.to_rgba("0.1") == get_hatchcolor(h) - q = function(da, "*", ax=ax) - assert q.get_hatch_linewidth() == 0.25 - assert mpl.rcParams["hatch.linewidth"] == 0.25 + # different colors can be set + with subplots_context(1, 1, subplot_kw=self.subplot_kw) as (__, ax): - # changing away from the linewidth does NOT raise a warning - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): + h = self.function(da, "*", ax=ax, color="#2ca25f") + assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(h) - q = function(da, "*", ax=ax, linewidth=2) - assert q.get_hatch_linewidth() == 2 - assert mpl.rcParams["hatch.linewidth"] == 2 + h = self.function(da, "*", ax=ax, color="#e5f5f9") + assert mpl.colors.to_rgba("#e5f5f9") == get_hatchcolor(h) - with assert_no_warnings(): - q = function(da, "*", ax=ax, linewidth=1) - assert q.get_hatch_linewidth() == 1 - assert mpl.rcParams["hatch.linewidth"] == 1 +class TestHatch(HatchBase): + function = staticmethod(mpu.hatch) + subplot_kw = {} -@pytest.mark.parametrize("function", HATCH_FUNCTIONS) -def test_hatch_color(function): - da = xr.DataArray( - np.ones([3, 3], dtype=bool), - dims=("lat", "lon"), - coords={"lat": [0, 1, 2], "lon": [1, 2, 3]}, - ) +class TestHatchMap(HatchBase): + function = staticmethod(mpu.hatch_map_global) subplot_kw = {"projection": ccrs.PlateCarree()} - # test default color - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): - h = function(da, "*", ax=ax) - - assert mpl.colors.to_rgba("0.1") == get_hatchcolor(h) - # different colors can be set - with subplots_context(1, 1, subplot_kw=subplot_kw) as (__, ax): +class TestHatchMapGlobal(HatchBase): - h = function(da, "*", ax=ax, color="#2ca25f") - assert mpl.colors.to_rgba("#2ca25f") == get_hatchcolor(h) - - h = function(da, "*", ax=ax, color="#e5f5f9") - assert mpl.colors.to_rgba("#e5f5f9") == get_hatchcolor(h) + function = staticmethod(mpu.hatch_map_global) + subplot_kw = {"projection": ccrs.PlateCarree()} def test_hatch_bbox():