From 73ace1935b9c614f84061e7db9852e5ea45d7b62 Mon Sep 17 00:00:00 2001 From: "thomas.wilson" Date: Thu, 1 Dec 2022 16:13:43 +0000 Subject: [PATCH 1/3] fixed _prepare_json_for_init and added type checking & tests --- edr_server/core/models/extents.py | 16 +++++++ tests/unit/core/models/test_extents.py | 59 +++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/edr_server/core/models/extents.py b/edr_server/core/models/extents.py index 9d356a6..2b0c3bb 100644 --- a/edr_server/core/models/extents.py +++ b/edr_server/core/models/extents.py @@ -211,9 +211,25 @@ class VerticalExtent(EdrModel["VerticalExtent"]): # * list of vertical levels (e.g. "2",10,"80","100"} # The value `null` is supported and indicates an open vertical interval. + def __post_init__(self): + if not isinstance(self.values, List): + raise TypeError( + f'Expected List of values, received {type(self.values)}') + if not all(isinstance((invalid_value := value), float) for value in self.values): + raise TypeError( + f"Expected all float values, received value '{invalid_value}' of type {type(invalid_value)}") + if not isinstance(self.vrs, CrsObject): + raise TypeError(f'Expected CrsObject, received {type(self.vrs)}') + @classmethod def _prepare_json_for_init(cls, json_dict: JsonDict) -> JsonDict: json_dict["vrs"] = CrsObject.from_wkt(json_dict["vrs"]) + + with suppress(KeyError): # Remove things not required by __init__ + # 'interval' stores the bounds, which is different from the 'intervals' argument to the __init__ method + del json_dict["interval"] + del json_dict["name"] + return json_dict @classmethod diff --git a/tests/unit/core/models/test_extents.py b/tests/unit/core/models/test_extents.py index 2d7e8b3..9381758 100644 --- a/tests/unit/core/models/test_extents.py +++ b/tests/unit/core/models/test_extents.py @@ -1,9 +1,11 @@ import unittest from datetime import datetime, timedelta from shapely.geometry import Polygon +import numpy as np -from edr_server.core.models.extents import TemporalExtent, SpatialExtent +from edr_server.core.models.extents import TemporalExtent, SpatialExtent, VerticalExtent from edr_server.core.models.time import DateTimeInterval, Duration +from edr_server.core.models.crs import CrsObject class TemporalExtentTest(unittest.TestCase): @@ -443,3 +445,58 @@ def test_init_type_checking_crs(self): with self.assertRaisesRegex(TypeError, "Expected CrsObject, received "): SpatialExtent(poly, input) + + +class VerticalExtentTest(unittest.TestCase): + + def test_from_json(self): + """ + GIVEN a typical json_dict + WHEN from_json is called + THEN a VerticalExtent is returned + """ + expected = VerticalExtent([1.65]) + + json_dict = {'interval': ['ScalarBounds(lower=1.65, upper=1.65)'], + 'values': [1.65], + 'vrs': 'VERTCRS["WGS_1984",VDATUM["World Geodetic System 1984"],CS[vertical,1],AXIS["ellipsoidal height (h)",up,LENGTHUNIT["metre",1,ID["EPSG",9001]]]]', + 'name': 'WGS_1984'} + + actual = VerticalExtent.from_json(json_dict) + + self.assertEqual(actual, expected) + + def test_init_type_checking_values(self): + """ + GIVEN a non-list + WHEN passed to VerticalExtent.values + THEN a TypeError is returned + """ + heights = {"value": 4} + + with self.assertRaisesRegex(TypeError, "Expected List of values, received "): + VerticalExtent(values=heights) + + def test_init_type_checking_values_entry(self): + """ + GIVEN a list of floats with one bad entry + WHEN passed to VerticalExtent.values + THEN a TypeError is returned with value and type + """ + vals = list(np.arange(0, 1, 0.2)) + vals.append('1') + + with self.assertRaisesRegex(TypeError, "Expected all float values, received value '1' of type "): + VerticalExtent(values=vals) + + def test_init_type_checking_vrs(self): + """ + GIVEN a non-CrsObject input + WHEN passed to VerticalExtent + THEN a TypeError is returned + """ + vals = list(np.arange(0, 1, 0.2)) + input = "bad input" + + with self.assertRaisesRegex(TypeError, "Expected CrsObject, received "): + VerticalExtent(values=vals, vrs=input) From b08f70ae73af04d59918378bd546b80143339c15 Mon Sep 17 00:00:00 2001 From: "thomas.wilson" Date: Tue, 6 Dec 2022 13:52:04 +0000 Subject: [PATCH 2/3] fixed issue relating to verticalExtent.from_json and float32 values --- edr_server/core/models/extents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/edr_server/core/models/extents.py b/edr_server/core/models/extents.py index 2b0c3bb..3e00f62 100644 --- a/edr_server/core/models/extents.py +++ b/edr_server/core/models/extents.py @@ -215,9 +215,9 @@ def __post_init__(self): if not isinstance(self.values, List): raise TypeError( f'Expected List of values, received {type(self.values)}') - if not all(isinstance((invalid_value := value), float) for value in self.values): + if not all(isinstance((invalid_value := value), (float, str)) for value in self.values): raise TypeError( - f"Expected all float values, received value '{invalid_value}' of type {type(invalid_value)}") + f"Expected all float or string values, received value '{invalid_value}' of type {type(invalid_value)}") if not isinstance(self.vrs, CrsObject): raise TypeError(f'Expected CrsObject, received {type(self.vrs)}') From 30303f716d0511a9aef0c30ce57e7cfa2cd74d1a Mon Sep 17 00:00:00 2001 From: "thomas.wilson" Date: Tue, 6 Dec 2022 14:49:04 +0000 Subject: [PATCH 3/3] fixed new tox requirement and outdated test --- setup.cfg | 1 + tests/unit/core/models/test_extents.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 0a2da31..25c1ce5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,6 +7,7 @@ version = 0.1.0 # We're affected by https://bugs.python.org/issue43923, so can only use 3.7 & 3.8 python_requires = >=3.7,<3.9 install_requires = + numpy shapely pyproj tornado>=6.1 diff --git a/tests/unit/core/models/test_extents.py b/tests/unit/core/models/test_extents.py index 9381758..954fae4 100644 --- a/tests/unit/core/models/test_extents.py +++ b/tests/unit/core/models/test_extents.py @@ -484,9 +484,9 @@ def test_init_type_checking_values_entry(self): THEN a TypeError is returned with value and type """ vals = list(np.arange(0, 1, 0.2)) - vals.append('1') + vals.append([1]) - with self.assertRaisesRegex(TypeError, "Expected all float values, received value '1' of type "): + with self.assertRaisesRegex(TypeError, r"Expected all float or string values, received value '\[1\]' of type "): VerticalExtent(values=vals) def test_init_type_checking_vrs(self):