|
1 | 1 | from dataclasses import dataclass |
2 | 2 | from datetime import datetime, timedelta, timezone |
3 | | -from typing import TypeAlias |
| 3 | +from typing import TYPE_CHECKING, Any, TypeAlias |
4 | 4 |
|
5 | | -import numpy as np |
6 | | -import xarray as xr |
7 | 5 | from google.protobuf.duration_pb2 import Duration |
8 | 6 | from google.protobuf.timestamp_pb2 import Timestamp |
9 | | -from pandas.core.tools.datetimes import DatetimeScalar, to_datetime |
10 | 7 |
|
11 | 8 | from tilebox.datasets.tilebox.v1 import query_pb2 |
12 | 9 |
|
| 10 | +if TYPE_CHECKING: |
| 11 | + from pandas.core.tools.datetimes import DatetimeScalar |
| 12 | + from xarray import DataArray, Dataset |
| 13 | + |
13 | 14 | _SMALLEST_POSSIBLE_TIMEDELTA = timedelta(microseconds=1) |
14 | 15 | _EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc) |
15 | 16 |
|
16 | 17 | # A type alias for the different types that can be used to specify a time interval |
17 | 18 | TimeIntervalLike: TypeAlias = ( |
18 | | - "DatetimeScalar | tuple[DatetimeScalar, DatetimeScalar] | xr.DataArray | xr.Dataset | TimeInterval" |
| 19 | + "DatetimeScalar | tuple[DatetimeScalar, DatetimeScalar] | list[DatetimeScalar] | DataArray | Dataset | TimeInterval" |
19 | 20 | ) |
20 | 21 | # once we require python >= 3.12 we can replace this with a type statement, which doesn't require a string at all |
21 | 22 | # type TimeIntervalLike = DatetimeScalar | tuple[DatetimeScalar ... | TimeInterval |
@@ -133,30 +134,34 @@ def parse(cls, arg: TimeIntervalLike) -> "TimeInterval": |
133 | 134 | TimeInterval: The parsed time interval |
134 | 135 | """ |
135 | 136 |
|
136 | | - match arg: |
137 | | - case TimeInterval(_, _, _, _): |
138 | | - return arg |
139 | | - case (start, end): |
140 | | - return TimeInterval(start=_convert_to_datetime(start), end=_convert_to_datetime(end)) |
141 | | - case point_in_time if isinstance(point_in_time, DatetimeScalar | int): |
142 | | - dt = _convert_to_datetime(point_in_time) |
143 | | - return TimeInterval(start=dt, end=dt, start_exclusive=False, end_inclusive=True) |
144 | | - case arr if ( |
145 | | - isinstance(arr, xr.DataArray) |
146 | | - and arr.ndim == 1 |
147 | | - and arr.size > 0 |
148 | | - and arr.dtype == np.dtype("datetime64[ns]") |
149 | | - ): |
150 | | - start = arr.data[0] |
151 | | - end = arr.data[-1] |
152 | | - return TimeInterval( |
153 | | - start=_convert_to_datetime(start), |
154 | | - end=_convert_to_datetime(end), |
155 | | - start_exclusive=False, |
156 | | - end_inclusive=True, |
157 | | - ) |
158 | | - case ds if isinstance(ds, xr.Dataset) and "time" in ds.coords: |
159 | | - return cls.parse(ds.time) |
| 137 | + if isinstance(arg, TimeInterval): |
| 138 | + return arg |
| 139 | + |
| 140 | + if isinstance(arg, list | tuple) and len(arg) == 2: |
| 141 | + start, end = arg |
| 142 | + return TimeInterval(start=_convert_to_datetime(start), end=_convert_to_datetime(end)) |
| 143 | + |
| 144 | + from pandas.core.tools.datetimes import DatetimeScalar # noqa: PLC0415 |
| 145 | + |
| 146 | + if isinstance(arg, DatetimeScalar | int): |
| 147 | + dt = _convert_to_datetime(arg) |
| 148 | + return TimeInterval(start=dt, end=dt, start_exclusive=False, end_inclusive=True) |
| 149 | + |
| 150 | + import numpy as np # noqa: PLC0415 |
| 151 | + import xarray as xr # noqa: PLC0415 |
| 152 | + |
| 153 | + if isinstance(arg, xr.DataArray) and arg.ndim == 1 and arg.size > 0 and arg.dtype == np.dtype("datetime64[ns]"): |
| 154 | + start = arg.data[0] |
| 155 | + end = arg.data[-1] |
| 156 | + return TimeInterval( |
| 157 | + start=_convert_to_datetime(start), |
| 158 | + end=_convert_to_datetime(end), |
| 159 | + start_exclusive=False, |
| 160 | + end_inclusive=True, |
| 161 | + ) |
| 162 | + |
| 163 | + if isinstance(arg, xr.Dataset) and "time" in arg.coords: |
| 164 | + return cls.parse(arg.time) |
160 | 165 |
|
161 | 166 | raise ValueError(f"Failed to convert {arg} ({type(arg)}) to TimeInterval)") |
162 | 167 |
|
@@ -192,8 +197,10 @@ def to_message(self) -> query_pb2.TimeInterval: |
192 | 197 | _EMPTY_TIME_INTERVAL = TimeInterval(_EPOCH, _EPOCH, start_exclusive=True, end_inclusive=False) |
193 | 198 |
|
194 | 199 |
|
195 | | -def _convert_to_datetime(arg: DatetimeScalar) -> datetime: |
| 200 | +def _convert_to_datetime(arg: Any) -> datetime: |
196 | 201 | """Convert the given datetime scalar to a datetime object in the UTC timezone""" |
| 202 | + from pandas.core.tools.datetimes import to_datetime # noqa: PLC0415 |
| 203 | + |
197 | 204 | dt: datetime = to_datetime(arg, utc=True).to_pydatetime() |
198 | 205 | if dt.tzinfo is None: |
199 | 206 | dt = dt.replace(tzinfo=timezone.utc) |
|
0 commit comments