2
2
3
3
import datetime as dt
4
4
import logging
5
+ import os
5
6
import re
7
+ import shutil
6
8
import tempfile
7
9
from abc import ABC , abstractmethod
8
10
from functools import reduce
@@ -147,6 +149,7 @@ def get_coverage(
147
149
run : str | None = None ,
148
150
interval : str | None = None ,
149
151
coverage_id : str = "" ,
152
+ temp_dir : str | None = None ,
150
153
) -> pd .DataFrame :
151
154
"""Return the coverage data (i.e., the weather forecast data).
152
155
@@ -163,6 +166,7 @@ def get_coverage(
163
166
raises an error if specified. Defaults to "P1D" for time-aggregated indicators such
164
167
as TOTAL_PRECIPITATION.
165
168
coverage_id: An id of a coverage, use get_capabilities() to get them.
169
+ temp_dir (str | None): Directory to store the temporary file. Defaults to None.
166
170
167
171
Returns:
168
172
pd.DataFrame: The complete run for the specified execution.
@@ -192,6 +196,7 @@ def get_coverage(
192
196
forecast_horizon = forecast_horizon ,
193
197
lat = lat ,
194
198
long = long ,
199
+ temp_dir = temp_dir ,
195
200
)
196
201
for forecast_horizon in forecast_horizons
197
202
for pressure in pressures
@@ -403,7 +408,11 @@ def _get_coverage_description(self, coverage_id: str) -> dict[Any, Any]:
403
408
response = self ._client .get (url , params = params )
404
409
return xmltodict .parse (response .text )
405
410
406
- def _grib_bytes_to_df (self , grib_str : bytes ) -> pd .DataFrame :
411
+ def _grib_bytes_to_df (
412
+ self ,
413
+ grib_str : bytes ,
414
+ temp_dir : str | None = None ,
415
+ ) -> pd .DataFrame :
407
416
"""(Protected)
408
417
Converts GRIB data (in binary format) into a pandas DataFrame.
409
418
@@ -413,6 +422,7 @@ def _grib_bytes_to_df(self, grib_str: bytes) -> pd.DataFrame:
413
422
414
423
Args:
415
424
grib_str (bytes): Binary GRIB data as a byte string.
425
+ temp_dir (str | None): Directory to store the temporary file. Defaults to None.
416
426
417
427
Returns:
418
428
pd.DataFrame: A pandas DataFrame containing the extracted GRIB data,
@@ -427,8 +437,18 @@ def _grib_bytes_to_df(self, grib_str: bytes) -> pd.DataFrame:
427
437
- The temporary file used for parsing is automatically deleted after use.
428
438
- Ensure the input GRIB data is valid and encoded in a binary format.
429
439
"""
440
+ created_temp_dir = False
441
+
442
+ if temp_dir :
443
+ if not os .path .exists (temp_dir ):
444
+ os .makedirs (temp_dir )
445
+ created_temp_dir = True
446
+ temp_subdir = os .path .join (temp_dir , "temp_grib" )
447
+ os .makedirs (temp_subdir , exist_ok = True )
448
+ else :
449
+ temp_subdir = tempfile .mkdtemp ()
430
450
431
- with tempfile .NamedTemporaryFile () as temp_file :
451
+ with tempfile .NamedTemporaryFile (dir = temp_subdir , delete = False ) as temp_file :
432
452
# Write the GRIB binary data to the temporary file
433
453
temp_file .write (grib_str )
434
454
temp_file .flush () # Ensure the data is written to disk
@@ -439,6 +459,11 @@ def _grib_bytes_to_df(self, grib_str: bytes) -> pd.DataFrame:
439
459
# Convert the Dataset to a pandas DataFrame
440
460
df = ds .to_dataframe ().reset_index ()
441
461
462
+ if created_temp_dir and temp_dir is not None :
463
+ shutil .rmtree (temp_dir )
464
+ else :
465
+ shutil .rmtree (temp_subdir )
466
+
442
467
return df
443
468
444
469
def _get_data_single_forecast (
@@ -449,6 +474,7 @@ def _get_data_single_forecast(
449
474
height : int | None ,
450
475
lat : tuple ,
451
476
long : tuple ,
477
+ temp_dir : str | None = None ,
452
478
) -> pd .DataFrame :
453
479
"""(Protected)
454
480
Return the forecast's data for a given time and indicator.
@@ -460,6 +486,7 @@ def _get_data_single_forecast(
460
486
forecast_horizon (int): the forecast horizon in hours (how many hours ahead)
461
487
lat (tuple): minimum and maximum latitude
462
488
long (tuple): minimum and maximum longitude
489
+ temp_dir (str | None): Directory to store the temporary file. Defaults to None.
463
490
464
491
Returns:
465
492
pd.DataFrame: The forecast for the specified time.
@@ -474,7 +501,7 @@ def _get_data_single_forecast(
474
501
long = long ,
475
502
)
476
503
477
- df : pd .DataFrame = self ._grib_bytes_to_df (grib_binary )
504
+ df : pd .DataFrame = self ._grib_bytes_to_df (grib_binary , temp_dir = temp_dir )
478
505
479
506
# Drop and rename columns
480
507
df .drop (columns = ["surface" , "valid_time" ], errors = "ignore" , inplace = True )
@@ -521,10 +548,7 @@ def _get_coverage_file(
521
548
long : tuple = (- 12 , 16 ),
522
549
) -> bytes :
523
550
"""(Protected)
524
- Retrieves raster data for a specified model prediction and saves it to a file.
525
-
526
- If no `filepath` is provided, the file is saved to a default cache directory under
527
- the current working directory.
551
+ Retrieves data for a specified model prediction.
528
552
529
553
Args:
530
554
coverage_id (str): The coverage ID to retrieve. Use `get_coverage` to list available coverage IDs.
@@ -537,10 +561,6 @@ def _get_coverage_file(
537
561
Defaults to (37.5, 55.4), covering the latitudes of France.
538
562
long (tuple[float, float], optional): Tuple specifying the minimum and maximum longitudes.
539
563
Defaults to (-12, 16), covering the longitudes of France.
540
- file_format (str, optional): The format of the raster file. Supported formats are "grib" and "tiff".
541
- Defaults to "grib".
542
- filepath (Path, optional): The file path where the raster file will be saved. If not specified,
543
- the file is saved to a cache directory.
544
564
545
565
Returns:
546
566
Path: The file path to the saved raster data.
@@ -605,6 +625,7 @@ def get_combined_coverage(
605
625
lat : tuple = FRANCE_METRO_LATITUDES ,
606
626
long : tuple = FRANCE_METRO_LONGITUDES ,
607
627
forecast_horizons : list [int ] | None = None ,
628
+ temp_dir : str | None = None ,
608
629
) -> pd .DataFrame :
609
630
"""
610
631
Get a combined DataFrame of coverage data for multiple indicators and different runs.
@@ -624,6 +645,7 @@ def get_combined_coverage(
624
645
lat (tuple): The latitude range as (min_latitude, max_latitude). Defaults to FRANCE_METRO_LATITUDES.
625
646
long (tuple): The longitude range as (min_longitude, max_longitude). Defaults to FRANCE_METRO_LONGITUDES.
626
647
forecast_horizons (list[int] | None): A list of forecast horizon values in hours. Defaults to None.
648
+ temp_dir (str | None): Directory to store the temporary file. Defaults to None.
627
649
628
650
Returns:
629
651
pd.DataFrame: A combined DataFrame containing coverage data for all specified runs and indicators.
@@ -643,6 +665,7 @@ def get_combined_coverage(
643
665
pressures = pressures ,
644
666
intervals = intervals ,
645
667
forecast_horizons = forecast_horizons ,
668
+ temp_dir = temp_dir ,
646
669
)
647
670
for run in runs
648
671
]
@@ -658,6 +681,7 @@ def _get_combined_coverage_for_single_run(
658
681
lat : tuple = FRANCE_METRO_LATITUDES ,
659
682
long : tuple = FRANCE_METRO_LONGITUDES ,
660
683
forecast_horizons : list [int ] | None = None ,
684
+ temp_dir : str | None = None ,
661
685
) -> pd .DataFrame :
662
686
"""(Protected)
663
687
Get a combined DataFrame of coverage data for a given run considering a list of indicators.
@@ -677,6 +701,7 @@ def _get_combined_coverage_for_single_run(
677
701
lat (tuple): The latitude range as (min_latitude, max_latitude). Defaults to FRANCE_METRO_LATITUDES.
678
702
long (tuple): The longitude range as (min_longitude, max_longitude). Defaults to FRANCE_METRO_LONGITUDES.
679
703
forecast_horizons (list[int] | None): A list of forecast horizon values in hours. Defaults to None.
704
+ temp_dir (str | None): Directory to store the temporary file. Defaults to None.
680
705
681
706
Returns:
682
707
pd.DataFrame: A combined DataFrame containing coverage data for all specified runs and indicators.
@@ -737,6 +762,7 @@ def _check_params_length(params: list[Any] | None, arg_name: str) -> list[Any]:
737
762
heights = [height ] if height is not None else [],
738
763
pressures = [pressure ] if pressure is not None else [],
739
764
forecast_horizons = forecast_horizons ,
765
+ temp_dir = temp_dir ,
740
766
)
741
767
for coverage_id , height , pressure in zip (coverage_ids , heights , pressures )
742
768
]
0 commit comments