1+ import contextlib
12import datetime
23import logging
34import os
1516SWOT_LAKE_SHORT_NAME = "SWOT_L2_HR_LakeSP_D"
1617
1718
19+ @contextlib .contextmanager
20+ def _suppress_granule_size_warning ():
21+ """Suppress known earthaccess DataGranule.size deprecation warning."""
22+ with warnings .catch_warnings ():
23+ warnings .filterwarnings (
24+ "ignore" ,
25+ message = r"As of version 1\.0, `DataGranule\.size` will be accessed as an attribute" ,
26+ category = FutureWarning ,
27+ module = r"earthaccess\.(results|store)" ,
28+ )
29+ yield
30+
31+
32+ def _login (credentials = None ):
33+ """Authenticate with earthaccess, handling credentials if provided.
34+
35+ Parameters
36+ ----------
37+ credentials : tuple(str, str) | None
38+ (username, password) tuple, or None for anonymous login.
39+ """
40+ if credentials :
41+ username , password = credentials
42+ if username and password :
43+ try :
44+ earthaccess .login (strategy = "environment" , persist = True )
45+ except Exception :
46+ earthaccess .login ()
47+ else :
48+ logger .warning (
49+ "No Earthdata credentials provided, attempting anonymous login"
50+ )
51+ earthaccess .login ()
52+ else :
53+ earthaccess .login ()
54+
55+
56+ def _search (** params ):
57+ """Search earthaccess for granules matching query parameters.
58+
59+ Parameters
60+ ----------
61+ **params
62+ Query parameters (short_name, temporal, bounding_box, granule_name, etc.).
63+
64+ Returns
65+ -------
66+ list
67+ Matching granule results, or empty list on error.
68+ """
69+ try :
70+ with _suppress_granule_size_warning ():
71+ results = earthaccess .search_data (** params )
72+ return results
73+ except Exception as e :
74+ logger .error ("Error searching for data: %s" , e )
75+ return []
76+
77+
78+ def _filter_new (results , processed_granules ):
79+ """Filter results to keep only granules not yet processed.
80+
81+ Parameters
82+ ----------
83+ results : list
84+ Granule result objects from earthaccess.search_data().
85+ processed_granules : set[str]
86+ GranuleUR values already processed, to exclude.
87+
88+ Returns
89+ -------
90+ list
91+ Granule result objects not in processed_granules.
92+ """
93+ granule_ids = [result ["umm" ]["GranuleUR" ] for result in results ]
94+ new_granule_ids = [gid for gid in granule_ids if gid not in processed_granules ]
95+ return [r for r in results if r ["umm" ]["GranuleUR" ] in new_granule_ids ]
96+
97+
98+ def _download_files (results , directory ):
99+ """Download granule files to a local directory.
100+
101+ Parameters
102+ ----------
103+ results : list
104+ Granule result objects to download.
105+ directory : str
106+ Local directory to write files to.
107+
108+ Returns
109+ -------
110+ list
111+ Paths to successfully downloaded files, or empty list on error.
112+ """
113+ if not results :
114+ return []
115+
116+ try :
117+ with _suppress_granule_size_warning ():
118+ files = earthaccess .download (results , directory , show_progress = True )
119+ return files or []
120+ except Exception as e :
121+ logger .error ("Error downloading files: %s" , e )
122+ return []
123+
124+
18125def query (
19126 aoi : list ,
20127 startdate : datetime .date ,
21128 enddate : datetime .date ,
22129 product : str = SWOT_LAKE_SHORT_NAME ,
23- earthaccess_client = earthaccess ,
24130) -> object :
25131 # format coordinates and extract bounds
26132 aoi = geometry .format_coord_list (aoi )
27133
28- # login and authenticate earthacess
29- earthaccess_client . login ()
134+ # login and authenticate earthaccess
135+ _login ()
30136
31137 # define query parameters
32138 params = {
@@ -35,21 +141,11 @@ def query(
35141 "bounding_box" : shapely .Polygon (aoi ).bounds ,
36142 }
37143
38- # Silence a known earthaccess deprecation warning until upstream migrates
39- # DataGranule.size() to DataGranule.size attribute access.
40- with warnings .catch_warnings ():
41- warnings .filterwarnings (
42- "ignore" ,
43- message = r"As of version 1\.0, `DataGranule\.size` will be accessed as an attribute" ,
44- category = FutureWarning ,
45- module = r"earthaccess\.results" ,
46- )
47- results = earthaccess_client .search_data (** params )
48-
144+ results = _search (** params )
49145 return results
50146
51147
52- def download (results , download_directory : str , earthaccess_client = earthaccess ):
148+ def download (results , download_directory : str ):
53149 # Check if we have a progress log file in this directory, if not make it
54150 log_path = os .path .join (download_directory , "downloaded.log" )
55151 if not os .path .exists (log_path ):
@@ -71,16 +167,7 @@ def download(results, download_directory: str, earthaccess_client=earthaccess):
71167 logger .info ("%s files shown as downloaded in log" , len (results ) - len (to_download ))
72168 logger .info ("%s files will be downloaded" , len (to_download ))
73169 if to_download :
74- with warnings .catch_warnings ():
75- warnings .filterwarnings (
76- "ignore" ,
77- message = r"As of version 1\.0, `DataGranule\.size` will be accessed as an attribute" ,
78- category = FutureWarning ,
79- module = r"earthaccess\.(results|store)" ,
80- )
81- files = earthaccess_client .download (
82- to_download , download_directory , show_progress = True
83- )
170+ files = _download_files (to_download , download_directory )
84171
85172 with open (log_path , "a" ) as log :
86173 for file in files :
0 commit comments