tobac 1.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tobac/__init__.py +112 -0
- tobac/analysis/__init__.py +31 -0
- tobac/analysis/cell_analysis.py +628 -0
- tobac/analysis/feature_analysis.py +212 -0
- tobac/analysis/spatial.py +619 -0
- tobac/centerofgravity.py +226 -0
- tobac/feature_detection.py +1758 -0
- tobac/merge_split.py +324 -0
- tobac/plotting.py +2321 -0
- tobac/segmentation/__init__.py +10 -0
- tobac/segmentation/watershed_segmentation.py +1316 -0
- tobac/testing.py +1179 -0
- tobac/tests/segmentation_tests/test_iris_xarray_segmentation.py +0 -0
- tobac/tests/segmentation_tests/test_segmentation.py +1183 -0
- tobac/tests/segmentation_tests/test_segmentation_time_pad.py +104 -0
- tobac/tests/test_analysis_spatial.py +1109 -0
- tobac/tests/test_convert.py +265 -0
- tobac/tests/test_datetime.py +216 -0
- tobac/tests/test_decorators.py +148 -0
- tobac/tests/test_feature_detection.py +1321 -0
- tobac/tests/test_generators.py +273 -0
- tobac/tests/test_import.py +24 -0
- tobac/tests/test_iris_xarray_match_utils.py +244 -0
- tobac/tests/test_merge_split.py +351 -0
- tobac/tests/test_pbc_utils.py +497 -0
- tobac/tests/test_sample_data.py +197 -0
- tobac/tests/test_testing.py +747 -0
- tobac/tests/test_tracking.py +714 -0
- tobac/tests/test_utils.py +650 -0
- tobac/tests/test_utils_bulk_statistics.py +789 -0
- tobac/tests/test_utils_coordinates.py +328 -0
- tobac/tests/test_utils_internal.py +97 -0
- tobac/tests/test_xarray_utils.py +232 -0
- tobac/tracking.py +613 -0
- tobac/utils/__init__.py +27 -0
- tobac/utils/bulk_statistics.py +360 -0
- tobac/utils/datetime.py +184 -0
- tobac/utils/decorators.py +540 -0
- tobac/utils/general.py +753 -0
- tobac/utils/generators.py +87 -0
- tobac/utils/internal/__init__.py +2 -0
- tobac/utils/internal/coordinates.py +430 -0
- tobac/utils/internal/iris_utils.py +462 -0
- tobac/utils/internal/label_props.py +82 -0
- tobac/utils/internal/xarray_utils.py +439 -0
- tobac/utils/mask.py +364 -0
- tobac/utils/periodic_boundaries.py +419 -0
- tobac/wrapper.py +244 -0
- tobac-1.6.2.dist-info/METADATA +154 -0
- tobac-1.6.2.dist-info/RECORD +53 -0
- tobac-1.6.2.dist-info/WHEEL +5 -0
- tobac-1.6.2.dist-info/licenses/LICENSE +29 -0
- tobac-1.6.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"""Tests for the iris/xarray conversion decorators"""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import tobac
|
|
5
|
+
import tobac.testing
|
|
6
|
+
import xarray
|
|
7
|
+
from iris.cube import Cube
|
|
8
|
+
import pandas as pd
|
|
9
|
+
from pandas.testing import assert_frame_equal
|
|
10
|
+
from copy import deepcopy
|
|
11
|
+
from tobac.utils.decorators import (
|
|
12
|
+
xarray_to_iris,
|
|
13
|
+
iris_to_xarray,
|
|
14
|
+
xarray_to_irispandas,
|
|
15
|
+
irispandas_to_xarray,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.mark.parametrize(
|
|
20
|
+
"decorator, input_types, expected_internal_types, expected_output_type",
|
|
21
|
+
[
|
|
22
|
+
(
|
|
23
|
+
xarray_to_iris,
|
|
24
|
+
[xarray.DataArray, xarray.DataArray],
|
|
25
|
+
[Cube, Cube],
|
|
26
|
+
xarray.DataArray,
|
|
27
|
+
),
|
|
28
|
+
(xarray_to_iris, [Cube, Cube], [Cube, Cube], Cube),
|
|
29
|
+
(xarray_to_iris, [Cube, xarray.DataArray], [Cube, Cube], xarray.DataArray),
|
|
30
|
+
(xarray_to_iris, [xarray.DataArray, Cube], [Cube, Cube], xarray.DataArray),
|
|
31
|
+
(iris_to_xarray, [Cube, Cube], [xarray.DataArray, xarray.DataArray], Cube),
|
|
32
|
+
(
|
|
33
|
+
iris_to_xarray,
|
|
34
|
+
[xarray.DataArray, xarray.DataArray],
|
|
35
|
+
[xarray.DataArray, xarray.DataArray],
|
|
36
|
+
xarray.DataArray,
|
|
37
|
+
),
|
|
38
|
+
(
|
|
39
|
+
iris_to_xarray,
|
|
40
|
+
[xarray.DataArray, Cube],
|
|
41
|
+
[xarray.DataArray, xarray.DataArray],
|
|
42
|
+
Cube,
|
|
43
|
+
),
|
|
44
|
+
(
|
|
45
|
+
iris_to_xarray,
|
|
46
|
+
[Cube, xarray.DataArray],
|
|
47
|
+
[xarray.DataArray, xarray.DataArray],
|
|
48
|
+
Cube,
|
|
49
|
+
),
|
|
50
|
+
(
|
|
51
|
+
xarray_to_irispandas,
|
|
52
|
+
[xarray.DataArray, xarray.DataArray],
|
|
53
|
+
[Cube, Cube],
|
|
54
|
+
xarray.DataArray,
|
|
55
|
+
),
|
|
56
|
+
(xarray_to_irispandas, [Cube, Cube], [Cube, Cube], Cube),
|
|
57
|
+
(
|
|
58
|
+
xarray_to_irispandas,
|
|
59
|
+
[Cube, xarray.DataArray],
|
|
60
|
+
[Cube, Cube],
|
|
61
|
+
xarray.DataArray,
|
|
62
|
+
),
|
|
63
|
+
(
|
|
64
|
+
xarray_to_irispandas,
|
|
65
|
+
[xarray.DataArray, Cube],
|
|
66
|
+
[Cube, Cube],
|
|
67
|
+
xarray.DataArray,
|
|
68
|
+
),
|
|
69
|
+
(
|
|
70
|
+
xarray_to_irispandas,
|
|
71
|
+
[xarray.Dataset, xarray.Dataset],
|
|
72
|
+
[pd.DataFrame, pd.DataFrame],
|
|
73
|
+
xarray.Dataset,
|
|
74
|
+
),
|
|
75
|
+
(
|
|
76
|
+
xarray_to_irispandas,
|
|
77
|
+
[pd.DataFrame, pd.DataFrame],
|
|
78
|
+
[pd.DataFrame, pd.DataFrame],
|
|
79
|
+
pd.DataFrame,
|
|
80
|
+
),
|
|
81
|
+
(
|
|
82
|
+
xarray_to_irispandas,
|
|
83
|
+
[xarray.Dataset, pd.DataFrame],
|
|
84
|
+
[pd.DataFrame, pd.DataFrame],
|
|
85
|
+
xarray.Dataset,
|
|
86
|
+
),
|
|
87
|
+
(
|
|
88
|
+
xarray_to_irispandas,
|
|
89
|
+
[pd.DataFrame, xarray.Dataset],
|
|
90
|
+
[pd.DataFrame, pd.DataFrame],
|
|
91
|
+
xarray.Dataset,
|
|
92
|
+
),
|
|
93
|
+
(
|
|
94
|
+
xarray_to_irispandas,
|
|
95
|
+
[xarray.Dataset, xarray.DataArray],
|
|
96
|
+
[pd.DataFrame, Cube],
|
|
97
|
+
xarray.Dataset,
|
|
98
|
+
),
|
|
99
|
+
(
|
|
100
|
+
irispandas_to_xarray,
|
|
101
|
+
[Cube, Cube],
|
|
102
|
+
[xarray.DataArray, xarray.DataArray],
|
|
103
|
+
Cube,
|
|
104
|
+
),
|
|
105
|
+
(
|
|
106
|
+
irispandas_to_xarray,
|
|
107
|
+
[xarray.DataArray, xarray.DataArray],
|
|
108
|
+
[xarray.DataArray, xarray.DataArray],
|
|
109
|
+
xarray.DataArray,
|
|
110
|
+
),
|
|
111
|
+
(
|
|
112
|
+
irispandas_to_xarray,
|
|
113
|
+
[xarray.DataArray, Cube],
|
|
114
|
+
[xarray.DataArray, xarray.DataArray],
|
|
115
|
+
Cube,
|
|
116
|
+
),
|
|
117
|
+
(
|
|
118
|
+
irispandas_to_xarray,
|
|
119
|
+
[Cube, xarray.DataArray],
|
|
120
|
+
[xarray.DataArray, xarray.DataArray],
|
|
121
|
+
Cube,
|
|
122
|
+
),
|
|
123
|
+
(
|
|
124
|
+
irispandas_to_xarray,
|
|
125
|
+
[pd.DataFrame, pd.DataFrame],
|
|
126
|
+
[xarray.Dataset, xarray.Dataset],
|
|
127
|
+
pd.DataFrame,
|
|
128
|
+
),
|
|
129
|
+
(
|
|
130
|
+
irispandas_to_xarray,
|
|
131
|
+
[xarray.Dataset, xarray.Dataset],
|
|
132
|
+
[xarray.Dataset, xarray.Dataset],
|
|
133
|
+
xarray.Dataset,
|
|
134
|
+
),
|
|
135
|
+
(
|
|
136
|
+
irispandas_to_xarray,
|
|
137
|
+
[pd.DataFrame, xarray.Dataset],
|
|
138
|
+
[xarray.Dataset, xarray.Dataset],
|
|
139
|
+
pd.DataFrame,
|
|
140
|
+
),
|
|
141
|
+
(
|
|
142
|
+
irispandas_to_xarray,
|
|
143
|
+
[xarray.Dataset, pd.DataFrame],
|
|
144
|
+
[xarray.Dataset, xarray.Dataset],
|
|
145
|
+
pd.DataFrame,
|
|
146
|
+
),
|
|
147
|
+
(
|
|
148
|
+
irispandas_to_xarray,
|
|
149
|
+
[pd.DataFrame, Cube],
|
|
150
|
+
[xarray.Dataset, xarray.DataArray],
|
|
151
|
+
pd.DataFrame,
|
|
152
|
+
),
|
|
153
|
+
],
|
|
154
|
+
)
|
|
155
|
+
def test_converting(
|
|
156
|
+
decorator, input_types, expected_internal_types, expected_output_type
|
|
157
|
+
):
|
|
158
|
+
"""Testing the conversions of the decorators internally and for the output"""
|
|
159
|
+
|
|
160
|
+
def test_function_kwarg(test_input, kwarg=None):
|
|
161
|
+
assert (
|
|
162
|
+
type(test_input) == expected_internal_types[0]
|
|
163
|
+
), "Expected internal type {}, got {} for {}".format(
|
|
164
|
+
expected_internal_types[0], type(test_input), decorator.__name__
|
|
165
|
+
)
|
|
166
|
+
assert (
|
|
167
|
+
type(kwarg) == expected_internal_types[1]
|
|
168
|
+
), "Expected internal type {}, got {} for {} as keyword argument".format(
|
|
169
|
+
expected_internal_types[1], type(kwarg), decorator.__name__
|
|
170
|
+
)
|
|
171
|
+
return test_input
|
|
172
|
+
|
|
173
|
+
def test_function_tuple_output(test_input, kwarg=None):
|
|
174
|
+
return (test_input, test_input)
|
|
175
|
+
|
|
176
|
+
decorator_i = decorator()
|
|
177
|
+
decorated_function_kwarg = decorator_i(test_function_kwarg)
|
|
178
|
+
decorated_function_tuple = decorator_i(test_function_tuple_output)
|
|
179
|
+
|
|
180
|
+
if input_types[0] == xarray.DataArray:
|
|
181
|
+
data = xarray.DataArray.from_iris(tobac.testing.make_simple_sample_data_2D())
|
|
182
|
+
elif input_types[0] == Cube:
|
|
183
|
+
data = tobac.testing.make_simple_sample_data_2D()
|
|
184
|
+
elif input_types[0] == xarray.Dataset:
|
|
185
|
+
data = tobac.testing.generate_single_feature(
|
|
186
|
+
1, 1, max_h1=100, max_h2=100
|
|
187
|
+
).to_xarray()
|
|
188
|
+
elif input_types[0] == pd.DataFrame:
|
|
189
|
+
data = tobac.testing.generate_single_feature(1, 1, max_h1=100, max_h2=100)
|
|
190
|
+
|
|
191
|
+
if input_types[1] == xarray.DataArray:
|
|
192
|
+
kwarg = xarray.DataArray.from_iris(tobac.testing.make_simple_sample_data_2D())
|
|
193
|
+
elif input_types[1] == Cube:
|
|
194
|
+
kwarg = tobac.testing.make_simple_sample_data_2D()
|
|
195
|
+
elif input_types[1] == xarray.Dataset:
|
|
196
|
+
kwarg = tobac.testing.generate_single_feature(
|
|
197
|
+
1, 1, max_h1=100, max_h2=100
|
|
198
|
+
).to_xarray()
|
|
199
|
+
elif input_types[1] == pd.DataFrame:
|
|
200
|
+
kwarg = tobac.testing.generate_single_feature(1, 1, max_h1=100, max_h2=100)
|
|
201
|
+
|
|
202
|
+
output = decorated_function_kwarg(data, kwarg=kwarg)
|
|
203
|
+
tuple_output = decorated_function_tuple(data, kwarg=kwarg)
|
|
204
|
+
|
|
205
|
+
assert (
|
|
206
|
+
type(output) == expected_output_type
|
|
207
|
+
), "Expected output type {}, got {} for {}".format(
|
|
208
|
+
expected_output_type, type(output), decorator.__name__
|
|
209
|
+
)
|
|
210
|
+
assert (
|
|
211
|
+
type(tuple_output[0]) == expected_output_type
|
|
212
|
+
), "Expected output type {}, but got {} for {} (1st tuple output(".format(
|
|
213
|
+
expected_output_type, type(tuple_output[0]), decorator.__name__
|
|
214
|
+
)
|
|
215
|
+
assert (
|
|
216
|
+
type(tuple_output[1]) == expected_output_type
|
|
217
|
+
), "Expected output type {}, but got {} for {} (2nd tuple output(".format(
|
|
218
|
+
expected_output_type, type(tuple_output[1]), decorator.__name__
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def test_xarray_workflow():
|
|
223
|
+
"""Test comparing the outputs of the standard functions of tobac for a test dataset
|
|
224
|
+
with the output of the same functions decorated with tobac.utils.xarray_to_iris"""
|
|
225
|
+
|
|
226
|
+
data = tobac.testing.make_sample_data_2D_3blobs()
|
|
227
|
+
data_xarray = xarray.DataArray.from_iris(deepcopy(data))
|
|
228
|
+
|
|
229
|
+
# Testing the get_spacings utility
|
|
230
|
+
xarray_to_iris_i = xarray_to_iris()
|
|
231
|
+
get_spacings_xarray = xarray_to_iris_i(tobac.utils.get_spacings)
|
|
232
|
+
dxy, dt = tobac.utils.get_spacings(data)
|
|
233
|
+
dxy_xarray, dt_xarray = get_spacings_xarray(data_xarray)
|
|
234
|
+
|
|
235
|
+
assert dxy == dxy_xarray
|
|
236
|
+
assert dt == dt_xarray
|
|
237
|
+
|
|
238
|
+
# Testing feature detection
|
|
239
|
+
feature_detection_xarray = xarray_to_iris_i(
|
|
240
|
+
tobac.feature_detection.feature_detection_multithreshold
|
|
241
|
+
)
|
|
242
|
+
features = tobac.feature_detection.feature_detection_multithreshold(
|
|
243
|
+
data, dxy, threshold=1.0
|
|
244
|
+
)
|
|
245
|
+
features_xarray = feature_detection_xarray(data_xarray, dxy_xarray, threshold=1.0)
|
|
246
|
+
|
|
247
|
+
assert_frame_equal(features, features_xarray)
|
|
248
|
+
|
|
249
|
+
# Testing the segmentation
|
|
250
|
+
segmentation_xarray = xarray_to_iris_i(tobac.segmentation.segmentation)
|
|
251
|
+
mask, features = tobac.segmentation.segmentation(features, data, dxy, threshold=1.0)
|
|
252
|
+
mask_xarray, features_xarray = segmentation_xarray(
|
|
253
|
+
features_xarray, data_xarray, dxy_xarray, threshold=1.0
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
assert (mask.data == mask_xarray.to_iris().data).all()
|
|
257
|
+
|
|
258
|
+
# testing tracking
|
|
259
|
+
tracking_xarray = xarray_to_iris_i(tobac.tracking.linking_trackpy)
|
|
260
|
+
track = tobac.tracking.linking_trackpy(features, data, dt, dxy, v_max=100.0)
|
|
261
|
+
track_xarray = tracking_xarray(
|
|
262
|
+
features_xarray, data_xarray, dt_xarray, dxy_xarray, v_max=100.0
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
assert_frame_equal(track, track_xarray)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import cftime
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
import tobac.utils.datetime as datetime_utils
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_to_cftime():
|
|
12
|
+
"""Test conversion of datetime types to cftime calendars"""
|
|
13
|
+
test_dates = [
|
|
14
|
+
"2000-01-01",
|
|
15
|
+
"2000-01-01 00:00:00",
|
|
16
|
+
datetime(2000, 1, 1),
|
|
17
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
18
|
+
np.datetime64("2000-01-01 00:00:00"),
|
|
19
|
+
pd.to_datetime("2000-01-01"),
|
|
20
|
+
cftime.datetime(2000, 1, 1),
|
|
21
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
22
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
23
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
for date in test_dates:
|
|
27
|
+
assert datetime_utils.to_cftime(date, "standard") == cftime.datetime(2000, 1, 1)
|
|
28
|
+
assert datetime_utils.to_cftime(date, "gregorian") == cftime.DatetimeGregorian(
|
|
29
|
+
2000, 1, 1
|
|
30
|
+
)
|
|
31
|
+
assert datetime_utils.to_cftime(date, "360_day") == cftime.Datetime360Day(
|
|
32
|
+
2000, 1, 1
|
|
33
|
+
)
|
|
34
|
+
assert datetime_utils.to_cftime(date, "365_day") == cftime.DatetimeNoLeap(
|
|
35
|
+
2000, 1, 1
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Test array-like input
|
|
39
|
+
for date in test_dates:
|
|
40
|
+
assert datetime_utils.to_cftime([date], "standard")[0] == cftime.datetime(
|
|
41
|
+
2000, 1, 1
|
|
42
|
+
)
|
|
43
|
+
assert datetime_utils.to_cftime([date], "gregorian")[
|
|
44
|
+
0
|
|
45
|
+
] == cftime.DatetimeGregorian(2000, 1, 1)
|
|
46
|
+
assert datetime_utils.to_cftime([date], "360_day")[0] == cftime.Datetime360Day(
|
|
47
|
+
2000, 1, 1
|
|
48
|
+
)
|
|
49
|
+
assert datetime_utils.to_cftime([date], "365_day")[0] == cftime.DatetimeNoLeap(
|
|
50
|
+
2000, 1, 1
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_to_timestamp():
|
|
55
|
+
"""Test conversion of various datetime types to pandas timestamps"""
|
|
56
|
+
test_dates = [
|
|
57
|
+
"2000-01-01",
|
|
58
|
+
"2000-01-01 00:00:00",
|
|
59
|
+
datetime(2000, 1, 1),
|
|
60
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
61
|
+
np.datetime64("2000-01-01 00:00:00"),
|
|
62
|
+
pd.to_datetime("2000-01-01"),
|
|
63
|
+
cftime.datetime(2000, 1, 1),
|
|
64
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
65
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
66
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
for date in test_dates:
|
|
70
|
+
assert datetime_utils.to_timestamp(date) == pd.to_datetime("2000-01-01")
|
|
71
|
+
|
|
72
|
+
# Test array input
|
|
73
|
+
for date in test_dates:
|
|
74
|
+
assert datetime_utils.to_timestamp([date])[0] == pd.to_datetime("2000-01-01")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_to_datetime():
|
|
78
|
+
"""Test conversion of various datetime types to python datetime"""
|
|
79
|
+
test_dates = [
|
|
80
|
+
"2000-01-01",
|
|
81
|
+
"2000-01-01 00:00:00",
|
|
82
|
+
datetime(2000, 1, 1),
|
|
83
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
84
|
+
np.datetime64("2000-01-01 00:00:00"),
|
|
85
|
+
pd.to_datetime("2000-01-01"),
|
|
86
|
+
cftime.datetime(2000, 1, 1),
|
|
87
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
88
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
89
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
for date in test_dates:
|
|
93
|
+
assert datetime_utils.to_datetime(date) == datetime(2000, 1, 1)
|
|
94
|
+
|
|
95
|
+
# Test array input
|
|
96
|
+
for date in test_dates:
|
|
97
|
+
assert datetime_utils.to_datetime([date])[0] == datetime(2000, 1, 1)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_to_datetime64():
|
|
101
|
+
"""Test conversion of various datetime types to numpy datetime64"""
|
|
102
|
+
test_dates = [
|
|
103
|
+
"2000-01-01",
|
|
104
|
+
"2000-01-01 00:00:00",
|
|
105
|
+
datetime(2000, 1, 1),
|
|
106
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
107
|
+
np.datetime64("2000-01-01 00:00:00"),
|
|
108
|
+
pd.to_datetime("2000-01-01"),
|
|
109
|
+
cftime.datetime(2000, 1, 1),
|
|
110
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
111
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
112
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
for date in test_dates:
|
|
116
|
+
assert datetime_utils.to_datetime64(date) == np.datetime64(
|
|
117
|
+
"2000-01-01 00:00:00.000000000"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Test array input
|
|
121
|
+
for date in test_dates:
|
|
122
|
+
assert datetime_utils.to_datetime64([date])[0] == np.datetime64(
|
|
123
|
+
"2000-01-01 00:00:00.000000000"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_to_datestr():
|
|
128
|
+
"""Test conversion of various datetime types to ISO format datestring"""
|
|
129
|
+
test_dates = [
|
|
130
|
+
"2000-01-01",
|
|
131
|
+
"2000-01-01 00:00:00",
|
|
132
|
+
datetime(2000, 1, 1),
|
|
133
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
134
|
+
np.datetime64("2000-01-01 00:00:00"),
|
|
135
|
+
pd.to_datetime("2000-01-01"),
|
|
136
|
+
cftime.datetime(2000, 1, 1),
|
|
137
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
138
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
139
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
for date in test_dates:
|
|
143
|
+
assert (
|
|
144
|
+
datetime_utils.to_datestr(date) == "2000-01-01T00:00:00.000000000"
|
|
145
|
+
or datetime_utils.to_datestr(date) == "2000-01-01T00:00:00"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_to_datestr_array():
|
|
150
|
+
"""Test conversion of arrays of various datetime types to ISO format
|
|
151
|
+
datestring
|
|
152
|
+
"""
|
|
153
|
+
test_dates = [
|
|
154
|
+
"2000-01-01",
|
|
155
|
+
"2000-01-01 00:00:00",
|
|
156
|
+
datetime(2000, 1, 1),
|
|
157
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
158
|
+
np.datetime64("2000-01-01 00:00:00"),
|
|
159
|
+
pd.to_datetime("2000-01-01"),
|
|
160
|
+
cftime.datetime(2000, 1, 1),
|
|
161
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
162
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
163
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
164
|
+
]
|
|
165
|
+
for date in test_dates:
|
|
166
|
+
assert datetime_utils.to_datestr([date]) == [
|
|
167
|
+
"2000-01-01T00:00:00.000000000"
|
|
168
|
+
] or datetime_utils.to_datestr([date]) == ["2000-01-01T00:00:00"]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_match_datetime_format():
|
|
172
|
+
"""Test match_datetime_format for various datetime-like combinations"""
|
|
173
|
+
test_dates = [
|
|
174
|
+
"2000-01-01T00:00:00.000000000",
|
|
175
|
+
datetime(2000, 1, 1),
|
|
176
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
177
|
+
pd.to_datetime("2000-01-01"),
|
|
178
|
+
cftime.datetime(2000, 1, 1),
|
|
179
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
180
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
181
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
for target in test_dates:
|
|
185
|
+
for date in test_dates:
|
|
186
|
+
assert datetime_utils.match_datetime_format(date, target) == target
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_match_datetime_format_array():
|
|
190
|
+
"""Test match_datetime_format for various datetime-like combinations with
|
|
191
|
+
array input
|
|
192
|
+
"""
|
|
193
|
+
test_dates = [
|
|
194
|
+
"2000-01-01T00:00:00.000000000",
|
|
195
|
+
datetime(2000, 1, 1),
|
|
196
|
+
np.datetime64("2000-01-01 00:00:00.000000000"),
|
|
197
|
+
pd.to_datetime("2000-01-01"),
|
|
198
|
+
cftime.datetime(2000, 1, 1),
|
|
199
|
+
cftime.DatetimeGregorian(2000, 1, 1),
|
|
200
|
+
cftime.Datetime360Day(2000, 1, 1),
|
|
201
|
+
cftime.DatetimeNoLeap(2000, 1, 1),
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
for target in test_dates:
|
|
205
|
+
for date in test_dates:
|
|
206
|
+
assert datetime_utils.match_datetime_format([date], [target]) == np.array(
|
|
207
|
+
[target]
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def test_match_datetime_format_error():
|
|
212
|
+
"""Test that if a non datetime-like object is provided as target to
|
|
213
|
+
match_datetime_format that a ValueError is raised:
|
|
214
|
+
"""
|
|
215
|
+
with pytest.raises(ValueError, match="Target is not a valid datetime*"):
|
|
216
|
+
datetime_utils.match_datetime_format(datetime(2000, 1, 1), 1.5)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for tobac.utils.decorators
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import xarray as xr
|
|
8
|
+
import iris
|
|
9
|
+
|
|
10
|
+
from tobac.utils import decorators
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_convert_cube_to_dataarray():
|
|
14
|
+
test_da_float = xr.DataArray(np.arange(15, dtype=float).reshape(3, 5) + 0.5)
|
|
15
|
+
test_da_int = xr.DataArray(np.arange(15, dtype=int).reshape(3, 5))
|
|
16
|
+
|
|
17
|
+
assert np.all(
|
|
18
|
+
decorators.convert_cube_to_dataarray(test_da_float.to_iris())
|
|
19
|
+
== test_da_float.values
|
|
20
|
+
)
|
|
21
|
+
assert np.all(
|
|
22
|
+
decorators.convert_cube_to_dataarray(test_da_int.to_iris())
|
|
23
|
+
== test_da_int.values
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_conv_kwargs_iris_to_xarray():
|
|
28
|
+
assert decorators._conv_kwargs_iris_to_xarray({}) == {}
|
|
29
|
+
assert decorators._conv_kwargs_iris_to_xarray(dict(test_int=1)) == dict(test_int=1)
|
|
30
|
+
|
|
31
|
+
test_da = xr.DataArray(np.arange(5))
|
|
32
|
+
|
|
33
|
+
test_xr_kwarg = decorators._conv_kwargs_iris_to_xarray(dict(test_xr=test_da))
|
|
34
|
+
assert isinstance(test_xr_kwarg["test_xr"], xr.DataArray)
|
|
35
|
+
|
|
36
|
+
test_iris_kwarg = decorators._conv_kwargs_iris_to_xarray(
|
|
37
|
+
dict(test_iris=test_da.to_iris())
|
|
38
|
+
)
|
|
39
|
+
assert isinstance(test_iris_kwarg["test_iris"], xr.DataArray)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_conv_kwargs_irispandas_to_xarray():
|
|
43
|
+
assert decorators._conv_kwargs_irispandas_to_xarray({}) == {}
|
|
44
|
+
assert decorators._conv_kwargs_irispandas_to_xarray(dict(test_int=1)) == dict(
|
|
45
|
+
test_int=1
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
test_da = xr.DataArray(np.arange(5))
|
|
49
|
+
|
|
50
|
+
test_xr_kwarg = decorators._conv_kwargs_irispandas_to_xarray(dict(test_xr=test_da))
|
|
51
|
+
assert isinstance(test_xr_kwarg["test_xr"], xr.DataArray)
|
|
52
|
+
|
|
53
|
+
test_iris_kwarg = decorators._conv_kwargs_irispandas_to_xarray(
|
|
54
|
+
dict(test_iris=test_da.to_iris())
|
|
55
|
+
)
|
|
56
|
+
assert isinstance(test_iris_kwarg["test_iris"], xr.DataArray)
|
|
57
|
+
|
|
58
|
+
test_ds = xr.Dataset({"test": test_da})
|
|
59
|
+
test_ds_kwarg = decorators._conv_kwargs_irispandas_to_xarray(dict(test_xr=test_ds))
|
|
60
|
+
assert isinstance(test_ds_kwarg["test_xr"], xr.Dataset)
|
|
61
|
+
|
|
62
|
+
test_pd_kwarg = decorators._conv_kwargs_irispandas_to_xarray(
|
|
63
|
+
dict(test_pd=test_ds.to_pandas())
|
|
64
|
+
)
|
|
65
|
+
assert isinstance(test_pd_kwarg["test_pd"], xr.Dataset)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_conv_kwargs_xarray_to_iris():
|
|
69
|
+
assert decorators._conv_kwargs_xarray_to_iris({}) == {}
|
|
70
|
+
assert decorators._conv_kwargs_xarray_to_iris(dict(test_int=1)) == dict(test_int=1)
|
|
71
|
+
|
|
72
|
+
test_da = xr.DataArray(np.arange(5))
|
|
73
|
+
|
|
74
|
+
test_xr_kwarg = decorators._conv_kwargs_xarray_to_iris(dict(test_xr=test_da))
|
|
75
|
+
assert isinstance(test_xr_kwarg["test_xr"], iris.cube.Cube)
|
|
76
|
+
|
|
77
|
+
test_iris_kwarg = decorators._conv_kwargs_xarray_to_iris(
|
|
78
|
+
dict(test_iris=test_da.to_iris())
|
|
79
|
+
)
|
|
80
|
+
assert isinstance(test_iris_kwarg["test_iris"], iris.cube.Cube)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_conv_kwargs_xarray_to_irispandas():
|
|
84
|
+
assert decorators._conv_kwargs_xarray_to_irispandas({}) == {}
|
|
85
|
+
assert decorators._conv_kwargs_xarray_to_irispandas(dict(test_int=1)) == dict(
|
|
86
|
+
test_int=1
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
test_da = xr.DataArray(np.arange(5))
|
|
90
|
+
|
|
91
|
+
test_xr_kwarg = decorators._conv_kwargs_xarray_to_irispandas(dict(test_xr=test_da))
|
|
92
|
+
assert isinstance(test_xr_kwarg["test_xr"], iris.cube.Cube)
|
|
93
|
+
|
|
94
|
+
test_iris_kwarg = decorators._conv_kwargs_xarray_to_irispandas(
|
|
95
|
+
dict(test_iris=test_da.to_iris())
|
|
96
|
+
)
|
|
97
|
+
assert isinstance(test_iris_kwarg["test_iris"], iris.cube.Cube)
|
|
98
|
+
|
|
99
|
+
test_ds = xr.Dataset({"test": test_da})
|
|
100
|
+
test_ds_kwarg = decorators._conv_kwargs_xarray_to_irispandas(dict(test_xr=test_ds))
|
|
101
|
+
assert isinstance(test_ds_kwarg["test_xr"], pd.DataFrame)
|
|
102
|
+
|
|
103
|
+
test_pd_kwarg = decorators._conv_kwargs_xarray_to_irispandas(
|
|
104
|
+
dict(test_pd=test_ds.to_pandas())
|
|
105
|
+
)
|
|
106
|
+
assert isinstance(test_pd_kwarg["test_pd"], pd.DataFrame)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@decorators.iris_to_xarray(save_iris_info=True)
|
|
110
|
+
def _test_iris_to_xarray(*args, **kwargs):
|
|
111
|
+
return kwargs["converted_from_iris"]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_iris_to_xarray():
|
|
115
|
+
test_da = xr.DataArray(np.arange(5))
|
|
116
|
+
|
|
117
|
+
assert _test_iris_to_xarray(test_da) == False
|
|
118
|
+
assert _test_iris_to_xarray(kwarg_xr=test_da) == False
|
|
119
|
+
|
|
120
|
+
assert _test_iris_to_xarray(test_da.to_iris()) == True
|
|
121
|
+
assert _test_iris_to_xarray(kwarg_ir=test_da.to_iris()) == True
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@decorators.irispandas_to_xarray(save_iris_info=True)
|
|
125
|
+
def _test_irispandas_to_xarray(*args, **kwargs):
|
|
126
|
+
return kwargs["converted_from_iris"]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_irispandas_to_xarray():
|
|
130
|
+
test_da = xr.DataArray(np.arange(5))
|
|
131
|
+
|
|
132
|
+
assert _test_irispandas_to_xarray(test_da) == False
|
|
133
|
+
assert _test_irispandas_to_xarray(kwarg_xr=test_da) == False
|
|
134
|
+
|
|
135
|
+
assert _test_irispandas_to_xarray(test_da.to_iris()) == True
|
|
136
|
+
assert _test_irispandas_to_xarray(kwarg_ir=test_da.to_iris()) == True
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@decorators.xarray_to_irispandas()
|
|
140
|
+
def _test_xarray_to_irispandas(*args, **kwargs):
|
|
141
|
+
return args, kwargs
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_xarray_to_irispandas():
|
|
145
|
+
test_da = xr.DataArray(np.arange(5, dtype=float))
|
|
146
|
+
|
|
147
|
+
assert isinstance(_test_xarray_to_irispandas(test_da)[0][0], iris.cube.Cube)
|
|
148
|
+
assert _test_xarray_to_irispandas(test_da)[1] == {}
|