import io
from typing import IO, Any, Dict, Optional, Union, Callable
import numpy as np
from speasy.core.codecs.bundled_codecs.hapi.hapi_file import HapiFile
from speasy.core.codecs.codec_interface import Buffer
from speasy.core.codecs.bundled_codecs.hapi.isotime import format_isotime
from speasy.core.time import make_utc_datetime64
from speasy.core.typing import AnyDateTimeType
def _dataset_range(time_axis: np.ndarray, start_date: Optional[AnyDateTimeType],
stop_date: Optional[AnyDateTimeType]) -> np.ndarray:
# HAPI's startDate/stopDate are required and span the whole dataset, not only the records written,
# so they default to the records' own span and must be given when there are no records.
if (start_date is None) != (stop_date is None):
raise ValueError("start_date and stop_date go together, pass both or neither")
if start_date is None:
if len(time_axis) == 0:
raise ValueError("A HAPI header needs startDate and stopDate, which an empty variable can't provide: "
"pass start_date and stop_date (the dataset's time range), or with_headers=False")
return np.array([time_axis.min(), time_axis.max()])
dataset_range = np.array([make_utc_datetime64(start_date), make_utc_datetime64(stop_date)], dtype="datetime64[ns]")
if dataset_range[0] > dataset_range[1]:
raise ValueError(f"start_date {start_date} is after stop_date {stop_date}")
if len(time_axis) and (time_axis.min() < dataset_range[0] or time_axis.max() > dataset_range[1]):
raise ValueError(f"Records span {time_axis.min()} to {time_axis.max()}, "
f"outside the dataset range {start_date} to {stop_date}")
return dataset_range
[docs]
def save_hapi(
hapi_file: HapiFile,
file: Optional[Union[str, io.IOBase]],
to_func: Optional[Callable[[HapiFile, IO[bytes], Optional[Dict[str, Any]]], bool]],
headers: Optional[Dict[str, Any]] = None,
mode: str = "wb",
) -> Union[bool, Buffer]:
if to_func is None:
raise ValueError("to_func must be provided and cannot be None")
if isinstance(file, str):
with open(file, mode) as f:
return to_func(hapi_file, f, headers)
elif hasattr(file, "write"):
return to_func(hapi_file, file, headers)
elif file is None:
buff = io.BytesIO()
to_func(hapi_file, buff, headers)
return buff.getvalue()
raise ValueError("Invalid file type")