|
2 | 2 | # Permissions are hereby granted under the terms of the MIT License: |
3 | 3 | # https://opensource.org/licenses/MIT. |
4 | 4 |
|
| 5 | +import datetime |
5 | 6 | import json |
6 | 7 | import unittest |
7 | | -from datetime import datetime |
8 | 8 |
|
9 | 9 | import numpy as np |
| 10 | +import xarray as xr |
10 | 11 | import pytest |
11 | 12 |
|
12 | 13 | from zappend.config.attrs import ConfigAttrsUserFunctions |
@@ -148,52 +149,108 @@ def test_yes(self): |
148 | 149 |
|
149 | 150 |
|
150 | 151 | class EvalExprTest(unittest.TestCase): |
151 | | - def test_all_cases(self): |
| 152 | + def test_scalar_result(self): |
| 153 | + # scalars |
| 154 | + self.assertEqual(None, eval_expr("None", {})) |
152 | 155 | self.assertEqual(True, eval_expr("True", {})) |
153 | 156 | self.assertEqual(13, eval_expr("13", {})) |
| 157 | + self.assertEqual("nan", eval_expr("float('NaN')", {})) |
154 | 158 | self.assertEqual(0.5, eval_expr("0.5", {})) |
155 | 159 | self.assertEqual("ABC", eval_expr("'ABC'", {})) |
156 | | - |
157 | | - switches = np.array([True, False]) |
| 160 | + time = datetime.date.fromisoformat("2024-01-02") |
158 | 161 | self.assertEqual( |
159 | | - True, |
160 | | - eval_expr("switches[0]", {"switches": switches}), |
| 162 | + "2024-01-02", |
| 163 | + eval_expr("time", dict(time=time)), |
161 | 164 | ) |
162 | | - |
163 | | - levels = [3, 4, 5] |
164 | | - self.assertIs( |
165 | | - levels, |
166 | | - eval_expr("levels", {"levels": levels}), |
| 165 | + time = datetime.datetime.fromisoformat("2024-01-02T10:20:30") |
| 166 | + self.assertEqual( |
| 167 | + "2024-01-02T10:20:30", |
| 168 | + eval_expr("time", dict(time=time)), |
167 | 169 | ) |
| 170 | + with pytest.raises( |
| 171 | + ValueError, match="cannot serialize value of type <class 'object'>" |
| 172 | + ): |
| 173 | + eval_expr("obj", dict(obj=object())) |
168 | 174 |
|
169 | | - levels = np.array([3, 4, 5]) |
| 175 | + def test_dict_result(self): |
| 176 | + self.assertEqual({}, eval_expr("d", dict(d={}))) |
170 | 177 | self.assertEqual( |
171 | | - 3, |
172 | | - eval_expr("levels[0]", {"levels": levels}), |
| 178 | + { |
| 179 | + "b": True, |
| 180 | + "i": 13, |
| 181 | + "t": [1, "B", {}], |
| 182 | + "f": 13.2, |
| 183 | + "d": "2020-05-04", |
| 184 | + "np_a": [0.1, 0.2], |
| 185 | + "xr_a": [0.3, 0.4], |
| 186 | + }, |
| 187 | + eval_expr( |
| 188 | + "d", |
| 189 | + dict( |
| 190 | + d={ |
| 191 | + "b": True, |
| 192 | + "i": 13, |
| 193 | + "t": (1, "B", {}), |
| 194 | + "f": 13.2, |
| 195 | + "d": datetime.date.fromisoformat("2020-05-04"), |
| 196 | + "np_a": np.array([0.1, 0.2]), |
| 197 | + "xr_a": xr.DataArray(np.array([0.3, 0.4])), |
| 198 | + } |
| 199 | + ), |
| 200 | + ), |
173 | 201 | ) |
174 | 202 |
|
175 | | - lon = np.array([11.05, 11.15, 11.25]) |
176 | | - self.assertIs( |
177 | | - lon, |
178 | | - eval_expr("lon", {"lon": lon}), |
179 | | - ) |
| 203 | + def test_array_1d_result(self): |
| 204 | + # arrays |
| 205 | + self.assert_array_ok([True, False]) |
| 206 | + self.assert_array_ok([3, 4, 5]) |
| 207 | + self.assert_array_ok([11.05, 11.15, 11.25]) |
| 208 | + self.assert_array_ok([11.05, "nan", 11.25], dtype="float64") |
| 209 | + self.assert_array_ok(["A", "B"]) |
| 210 | + self.assert_array_ok(["2024-01-02T10:20:30"], dtype="datetime64[s]") |
| 211 | + with pytest.raises( |
| 212 | + ValueError, |
| 213 | + match=( |
| 214 | + "cannot serialize 0-d array" |
| 215 | + " of type <class 'numpy.ndarray'>, dtype=dtype\\('O'\\)" |
| 216 | + ), |
| 217 | + ): |
| 218 | + eval_expr("a", dict(a=xr.DataArray([object(), object()]))) |
180 | 219 |
|
181 | | - lon = np.array([11.05, 11.15, 11.25]) |
| 220 | + def test_array_2d_result(self): |
| 221 | + self.assert_array_ok([[3, 4], [5, 6]]) |
| 222 | + |
| 223 | + def assert_array_ok(self, a: list, dtype=None): |
| 224 | + # Test list |
| 225 | + self.assertEqual( |
| 226 | + a, |
| 227 | + eval_expr("a", dict(a=a)), |
| 228 | + ) |
182 | 229 | self.assertEqual( |
183 | | - 11.05, |
184 | | - eval_expr("lon[0]", {"lon": lon}), |
| 230 | + a[0], |
| 231 | + eval_expr("a[0]", dict(a=a)), |
185 | 232 | ) |
186 | 233 |
|
187 | | - names = np.array(["A", "B"]) |
| 234 | + # Test numpy.ndarray |
| 235 | + np_a = np.array(a, dtype=dtype) if dtype is not None else np.array(a) |
| 236 | + self.assertEqual( |
| 237 | + a, |
| 238 | + eval_expr("a", dict(a=np_a)), |
| 239 | + ) |
188 | 240 | self.assertEqual( |
189 | | - "A", |
190 | | - eval_expr("names[0]", {"names": names}), |
| 241 | + a[0], |
| 242 | + eval_expr("a[0]", dict(a=np_a)), |
191 | 243 | ) |
192 | 244 |
|
193 | | - time = datetime.fromisoformat("2024-01-02T10:20:30") |
| 245 | + # Test xarray-DataArray |
| 246 | + xr_a = xr.DataArray(np_a) |
194 | 247 | self.assertEqual( |
195 | | - "2024-01-02T10:20:30", |
196 | | - eval_expr("time", {"time": time}), |
| 248 | + a, |
| 249 | + eval_expr("a", dict(a=xr_a)), |
| 250 | + ) |
| 251 | + self.assertEqual( |
| 252 | + a[0], |
| 253 | + eval_expr("a[0]", dict(a=xr_a)), |
197 | 254 | ) |
198 | 255 |
|
199 | 256 |
|
|
0 commit comments