From 1d533417927d735f05882f82ef379898288c5ee4 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Mon, 25 Sep 2023 11:45:10 -0400 Subject: [PATCH 1/8] update QUEST and GenQuery classes for argo integration (#441) * Adding argo search and download script * Create get_argo.py Download the 'classic' argo data with physical variables only * begin implementing argo dataset * 1st draft implementing argo dataset * implement search_data for physical argo * doctests and general cleanup for physical argo query * beginning of BGC Argo download * parse BGC profiles into DF * plan to query BGC profiles * validate BGC param input function * order BGC params in order in which they should be queried * fix bug in parse_into_df() - init blank df to take in union of params from all profiles * identify profiles from initial API request containing all required params * creates df with only profiles that contain all user specified params Need to dload additional params * modified to populate prof df by querying individual profiles * finished up BGC argo download! * assert bounding box type in Argo init, begin framework for unit tests * Adding argo search and download script * Create get_argo.py Download the 'classic' argo data with physical variables only * begin implementing argo dataset * 1st draft implementing argo dataset * implement search_data for physical argo * doctests and general cleanup for physical argo query * beginning of BGC Argo download * parse BGC profiles into DF * plan to query BGC profiles * validate BGC param input function * order BGC params in order in which they should be queried * fix bug in parse_into_df() - init blank df to take in union of params from all profiles * identify profiles from initial API request containing all required params * creates df with only profiles that contain all user specified params Need to dload additional params * modified to populate prof df by querying individual profiles * finished up BGC argo download! * assert bounding box type in Argo init, begin framework for unit tests * need to confirm spatial extent is bbox * begin test case for available profiles * add tests for argo.py * add typing, add example json, and use it to test parsing * update argo to submit successful api request (update keys and values submitted) * first pass at porting argo over to metadata+per profile download (WIP) * basic working argo script * simplify parameter validation (ordered list no longer needed) * add option to delete existing data before new download * continue cleaning up argo.py * fix download_by_profile to properly store all downloaded data * remove old get_argo.py script * remove _filter_profiles function in favor of submitting data kwarg in request * start filling in docstrings * clean up nearly duplicate functions * add more docstrings * get a few minimal argo tests working * add bgc argo params. begin adding merge for second download runs * some changes * WIP test commit to see if can push to GH * WIP handling argo merge issue * update profile to df to return df and move merging to get_dataframe * merge profiles with existing df * clean up docstrings and code * add test_argo.py * add prelim test case for adding to Argo df * remove sandbox files * remove bgc argo test file * update variables notebook from development * simplify import statements * quickfix for granules error * draft subpage on available QUEST datasets * small reference fix in text * add reference to top of .rst file * test argo df merge * add functionality to Quest class to pass search criteria to all datasets * add functionality to Quest class to pass search criteria to all datasets * update dataset docstrings; reorder argo.py to match * implement quest search+download for IS2 * move spatial and temporal properties from query to genquery * add query docstring test for cycles,tracks to test file * add quest test module * standardize print outputs for quest search and download; is2 download needs auth updates * remove extra files from this branch * comment out argo portions of quest for PR * remove argo-branch-only init file * remove argo script from branch * remove argo test file from branch * comment out another line of argo stuff * Update quest.py Added Docstrings to functions within quest.py and edited the primary docstring for the QUEST class here. Note I did not add Docstrings to the implicit __self__ function. * Update test_quest.py Added comments (not Docstrings) to test functions * Update dataset.py Minor edits to the doc strings * Update quest.py Edited docstrings * catch error with downloading datasets in Quest; template test case for multi dataset query --------- Co-authored-by: Kelsey Bisson <48059682+kelseybisson@users.noreply.github.com> Co-authored-by: Romina Co-authored-by: zachghiaccio Co-authored-by: Zach Fair <48361714+zachghiaccio@users.noreply.github.com> --- .../contributing/quest-available-datasets.rst | 25 ++ icepyx/core/query.py | 345 +++++++++--------- icepyx/quest/__init__.py | 0 icepyx/quest/dataset_scripts/dataset.py | 90 +++-- icepyx/quest/quest.py | 104 +++++- icepyx/tests/test_query.py | 12 + icepyx/tests/test_quest.py | 80 ++++ 7 files changed, 424 insertions(+), 232 deletions(-) create mode 100644 doc/source/contributing/quest-available-datasets.rst delete mode 100644 icepyx/quest/__init__.py create mode 100644 icepyx/tests/test_quest.py diff --git a/doc/source/contributing/quest-available-datasets.rst b/doc/source/contributing/quest-available-datasets.rst new file mode 100644 index 000000000..91a6283a0 --- /dev/null +++ b/doc/source/contributing/quest-available-datasets.rst @@ -0,0 +1,25 @@ +.. _quest_supported_label: + +QUEST Supported Datasets +======================== + +On this page, we outline the datasets that are supported by the QUEST module. Click on the links for each dataset to view information about the API and sensor/data platform used. + + +List of Datasets +---------------- + +* `Argo `_ + * The Argo mission involves a series of floats that are designed to capture vertical ocean profiles of temperature, salinity, and pressure down to ~2000 m. Some floats are in support of BGC-Argo, which also includes data relevant for biogeochemical applications: oxygen, nitrate, chlorophyll, backscatter, and solar irradiance. + * (Link Kelsey's paper here) + * (Link to example workbook here) + + +Adding a Dataset to QUEST +------------------------- + +Want to add a new dataset to QUEST? No problem! QUEST includes a template script (``dataset.py``) that may be used to create your own querying module for a dataset of interest. + +Guidelines on how to construct your dataset module may be found here: (link to be added) + +Once you have developed a script with the template, you may request for the module to be added to QUEST via Github. Please see the How to Contribute page :ref:`dev_guide_label` for instructions on how to contribute to icepyx. \ No newline at end of file diff --git a/icepyx/core/query.py b/icepyx/core/query.py index e8f1d8e7c..3459fd132 100644 --- a/icepyx/core/query.py +++ b/icepyx/core/query.py @@ -12,11 +12,9 @@ import icepyx.core.APIformatting as apifmt from icepyx.core.auth import EarthdataAuthMixin import icepyx.core.granules as granules -from icepyx.core.granules import Granules as Granules +# QUESTION: why doesn't from granules import Granules work, since granules=icepyx.core.granules? +from icepyx.core.granules import Granules import icepyx.core.is2ref as is2ref - -# QUESTION: why doesn't from granules import Granules as Granules work, since granules=icepyx.core.granules? -# from icepyx.core.granules import Granules import icepyx.core.spatial as spat import icepyx.core.temporal as tp import icepyx.core.validate_inputs as val @@ -148,6 +146,177 @@ def __str__(self): ) return str + # ---------------------------------------------------------------------- + # Properties + + @property + def temporal(self): + """ + Return the Temporal object containing date/time range information for the query object. + + See Also + -------- + temporal.Temporal.start + temporal.Temporal.end + temporal.Temporal + + Examples + -------- + >>> reg_a = GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28']) + >>> print(reg_a.temporal) + Start date and time: 2019-02-20 00:00:00 + End date and time: 2019-02-28 23:59:59 + + >>> reg_a = GenQuery([-55, 68, -48, 71],cycles=['03','04','05','06','07'], tracks=['0849','0902']) + >>> print(reg_a.temporal) + ['No temporal parameters set'] + """ + + if hasattr(self, "_temporal"): + return self._temporal + else: + return ["No temporal parameters set"] + + @property + def spatial(self): + """ + Return the spatial object, which provides the underlying functionality for validating + and formatting geospatial objects. The spatial object has several properties to enable + user access to the stored spatial extent in multiple formats. + + See Also + -------- + spatial.Spatial.spatial_extent + spatial.Spatial.extent_type + spatial.Spatial.extent_file + spatial.Spatial + + Examples + -------- + >>> reg_a = ipx.GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28']) + >>> reg_a.spatial # doctest: +SKIP + + + >>> print(reg_a.spatial) + Extent type: bounding_box + Coordinates: [-55.0, 68.0, -48.0, 71.0] + + """ + return self._spatial + + @property + def spatial_extent(self): + """ + Return an array showing the spatial extent of the query object. + Spatial extent is returned as an input type (which depends on how + you initially entered your spatial data) followed by the geometry data. + Bounding box data is [lower-left-longitude, lower-left-latitute, upper-right-longitude, upper-right-latitude]. + Polygon data is [longitude1, latitude1, longitude2, latitude2, + ... longitude_n,latitude_n, longitude1,latitude1]. + + Returns + ------- + tuple of length 2 + First tuple element is the spatial type ("bounding box" or "polygon"). + Second tuple element is the spatial extent as a list of coordinates. + + Examples + -------- + + # Note: coordinates returned as float, not int + >>> reg_a = GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28']) + >>> reg_a.spatial_extent + ('bounding_box', [-55.0, 68.0, -48.0, 71.0]) + + >>> reg_a = GenQuery([(-55, 68), (-55, 71), (-48, 71), (-48, 68), (-55, 68)],['2019-02-20','2019-02-28']) + >>> reg_a.spatial_extent + ('polygon', [-55.0, 68.0, -55.0, 71.0, -48.0, 71.0, -48.0, 68.0, -55.0, 68.0]) + + # NOTE Is this where we wanted to put the file-based test/example? + # The test file path is: examples/supporting_files/simple_test_poly.gpkg + + See Also + -------- + Spatial.extent + Spatial.extent_type + Spatial.extent_as_gdf + + """ + + return (self._spatial._ext_type, self._spatial._spatial_ext) + + @property + def dates(self): + """ + Return an array showing the date range of the query object. + Dates are returned as an array containing the start and end datetime objects, inclusive, in that order. + + Examples + -------- + >>> reg_a = ipx.GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28']) + >>> reg_a.dates + ['2019-02-20', '2019-02-28'] + + >>> reg_a = GenQuery([-55, 68, -48, 71]) + >>> reg_a.dates + ['No temporal parameters set'] + """ + if not hasattr(self, "_temporal"): + return ["No temporal parameters set"] + else: + return [ + self._temporal._start.strftime("%Y-%m-%d"), + self._temporal._end.strftime("%Y-%m-%d"), + ] # could also use self._start.date() + + @property + def start_time(self): + """ + Return the start time specified for the start date. + + Examples + -------- + >>> reg_a = ipx.GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28']) + >>> reg_a.start_time + '00:00:00' + + >>> reg_a = ipx.GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28'], start_time='12:30:30') + >>> reg_a.start_time + '12:30:30' + + >>> reg_a = GenQuery([-55, 68, -48, 71]) + >>> reg_a.start_time + ['No temporal parameters set'] + """ + if not hasattr(self, "_temporal"): + return ["No temporal parameters set"] + else: + return self._temporal._start.strftime("%H:%M:%S") + + @property + def end_time(self): + """ + Return the end time specified for the end date. + + Examples + -------- + >>> reg_a = ipx.GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28']) + >>> reg_a.end_time + '23:59:59' + + >>> reg_a = ipx.GenQuery([-55, 68, -48, 71],['2019-02-20','2019-02-28'], end_time='10:20:20') + >>> reg_a.end_time + '10:20:20' + + >>> reg_a = GenQuery([-55, 68, -48, 71]) + >>> reg_a.end_time + ['No temporal parameters set'] + """ + if not hasattr(self, "_temporal"): + return ["No temporal parameters set"] + else: + return self._temporal._end.strftime("%H:%M:%S") + # DevGoal: update docs throughout to allow for polygon spatial extent # Note: add files to docstring once implemented @@ -333,174 +502,6 @@ def product_version(self): """ return self._version - @property - def temporal(self): - """ - Return the Temporal object containing date/time range information for the query object. - - See Also - -------- - temporal.Temporal.start - temporal.Temporal.end - temporal.Temporal - - Examples - -------- - >>> reg_a = Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28']) - >>> print(reg_a.temporal) - Start date and time: 2019-02-20 00:00:00 - End date and time: 2019-02-28 23:59:59 - - >>> reg_a = Query('ATL06',[-55, 68, -48, 71],cycles=['03','04','05','06','07'], tracks=['0849','0902']) - >>> print(reg_a.temporal) - ['No temporal parameters set'] - """ - - if hasattr(self, "_temporal"): - return self._temporal - else: - return ["No temporal parameters set"] - - @property - def spatial(self): - """ - Return the spatial object, which provides the underlying functionality for validating - and formatting geospatial objects. The spatial object has several properties to enable - user access to the stored spatial extent in multiple formats. - - See Also - -------- - spatial.Spatial.spatial_extent - spatial.Spatial.extent_type - spatial.Spatial.extent_file - spatial.Spatial - - Examples - -------- - >>> reg_a = ipx.Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28']) - >>> reg_a.spatial # doctest: +SKIP - - - >>> print(reg_a.spatial) - Extent type: bounding_box - Coordinates: [-55.0, 68.0, -48.0, 71.0] - - """ - return self._spatial - - @property - def spatial_extent(self): - """ - Return an array showing the spatial extent of the query object. - Spatial extent is returned as an input type (which depends on how - you initially entered your spatial data) followed by the geometry data. - Bounding box data is [lower-left-longitude, lower-left-latitute, upper-right-longitude, upper-right-latitude]. - Polygon data is [longitude1, latitude1, longitude2, latitude2, - ... longitude_n,latitude_n, longitude1,latitude1]. - - Returns - ------- - tuple of length 2 - First tuple element is the spatial type ("bounding box" or "polygon"). - Second tuple element is the spatial extent as a list of coordinates. - - Examples - -------- - - # Note: coordinates returned as float, not int - >>> reg_a = Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28']) - >>> reg_a.spatial_extent - ('bounding_box', [-55.0, 68.0, -48.0, 71.0]) - - >>> reg_a = Query('ATL06',[(-55, 68), (-55, 71), (-48, 71), (-48, 68), (-55, 68)],['2019-02-20','2019-02-28']) - >>> reg_a.spatial_extent - ('polygon', [-55.0, 68.0, -55.0, 71.0, -48.0, 71.0, -48.0, 68.0, -55.0, 68.0]) - - # NOTE Is this where we wanted to put the file-based test/example? - # The test file path is: examples/supporting_files/simple_test_poly.gpkg - - See Also - -------- - Spatial.extent - Spatial.extent_type - Spatial.extent_as_gdf - - """ - - return (self._spatial._ext_type, self._spatial._spatial_ext) - - @property - def dates(self): - """ - Return an array showing the date range of the query object. - Dates are returned as an array containing the start and end datetime objects, inclusive, in that order. - - Examples - -------- - >>> reg_a = ipx.Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28']) - >>> reg_a.dates - ['2019-02-20', '2019-02-28'] - - >>> reg_a = Query('ATL06',[-55, 68, -48, 71],cycles=['03','04','05','06','07'], tracks=['0849','0902']) - >>> reg_a.dates - ['No temporal parameters set'] - """ - if not hasattr(self, "_temporal"): - return ["No temporal parameters set"] - else: - return [ - self._temporal._start.strftime("%Y-%m-%d"), - self._temporal._end.strftime("%Y-%m-%d"), - ] # could also use self._start.date() - - @property - def start_time(self): - """ - Return the start time specified for the start date. - - Examples - -------- - >>> reg_a = ipx.Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28']) - >>> reg_a.start_time - '00:00:00' - - >>> reg_a = ipx.Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28'], start_time='12:30:30') - >>> reg_a.start_time - '12:30:30' - - >>> reg_a = Query('ATL06',[-55, 68, -48, 71],cycles=['03','04','05','06','07'], tracks=['0849','0902']) - >>> reg_a.start_time - ['No temporal parameters set'] - """ - if not hasattr(self, "_temporal"): - return ["No temporal parameters set"] - else: - return self._temporal._start.strftime("%H:%M:%S") - - @property - def end_time(self): - """ - Return the end time specified for the end date. - - Examples - -------- - >>> reg_a = ipx.Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28']) - >>> reg_a.end_time - '23:59:59' - - >>> reg_a = ipx.Query('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28'], end_time='10:20:20') - >>> reg_a.end_time - '10:20:20' - - >>> reg_a = Query('ATL06',[-55, 68, -48, 71],cycles=['03','04','05','06','07'], tracks=['0849','0902']) - >>> reg_a.end_time - ['No temporal parameters set'] - """ - if not hasattr(self, "_temporal"): - return ["No temporal parameters set"] - else: - return self._temporal._end.strftime("%H:%M:%S") - @property def cycles(self): """ diff --git a/icepyx/quest/__init__.py b/icepyx/quest/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/icepyx/quest/dataset_scripts/dataset.py b/icepyx/quest/dataset_scripts/dataset.py index 13e926229..e76081e08 100644 --- a/icepyx/quest/dataset_scripts/dataset.py +++ b/icepyx/quest/dataset_scripts/dataset.py @@ -1,4 +1,5 @@ import warnings +from icepyx.core.query import GenQuery warnings.filterwarnings("ignore") @@ -6,78 +7,75 @@ class DataSet: """ - Parent Class for all supported datasets (i.e. ATL03, ATL07, MODIS, etc.) - all sub classes must support the following methods for use in - colocated data class + Template parent class for all QUEST supported datasets (i.e. ICESat-2, Argo BGC, Argo, MODIS, etc.). + All sub-classes must support the following methods for use via the QUEST class. """ - def __init__(self, boundingbox, timeframe): + def __init__( + self, spatial_extent=None, date_range=None, start_time=None, end_time=None + ): """ - * use existing Icepyx functionality to initialise this - :param timeframe: datetime + Complete any dataset specific initializations (i.e. beyond space and time) required here. + For instance, ICESat-2 requires a product, and Argo requires parameters. + One can also check that the "default" space and time supplied by QUEST are the right format + (e.g. if the spatial extent must be a bounding box). """ - self.bounding_box = boundingbox - self.time_frame = timeframe - - def _fmt_coordinates(self): - # use icepyx geospatial module (icepyx core) raise NotImplementedError - def _fmt_timerange(self): + # ---------------------------------------------------------------------- + # Formatting API Inputs + + def _fmt_coordinates(self): """ - will return list of datetime objects [start_time, end_time] + Convert spatial extent into format needed by DataSet API, + if different than the formats available directly from SuperQuery. """ raise NotImplementedError - # todo: merge with Icepyx SuperQuery - def _validate_input(self): + def _fmt_timerange(self): """ - This may already be done in icepyx. - Not sure if we need this here + Convert temporal information into format needed by DataSet API, + if different than the formats available directly from SuperQuery. """ raise NotImplementedError - def search_data(self, delta_t): + # ---------------------------------------------------------------------- + # Validation + + def _validate_inputs(self): """ - query dataset given the spatio temporal criteria - and other params specic to the dataset + Create any additional validation functions for verifying inputs. + This function is not explicitly called by QUEST, + but is frequently needed for preparing API requests. + + See Also + -------- + quest.dataset_scripts.argo.Argo._validate_parameters """ raise NotImplementedError - def download(self, out_path): + # ---------------------------------------------------------------------- + # Querying and Getting Data + + def search_data(self): """ - once data is querried, the user may choose to dowload the - data locally + Query the dataset (i.e. search for available data) + given the spatiotemporal criteria and other parameters specific to the dataset. """ raise NotImplementedError - def visualize(self): + def download(self): """ - (once data is downloaded)?, makes a quick plot showing where - data are located - e.g. Plots location of Argo profile or highlights ATL03 photon track + Download the data to your local machine. """ raise NotImplementedError - def _add2colocated_plot(self): + # ---------------------------------------------------------------------- + # Working with Data + + def visualize(self): """ - Takes visualise() functionality and adds the plot to central - plot with other coincident data. This will be called by - show_area_overlap() in Colocateddata class + Tells QUEST how to plot data (for instance, which parameters to plot) on a basemap. + For ICESat-2, it might show a photon track, and for Argo it might show a profile location. """ raise NotImplementedError - - """ - The following are low priority functions - Not sure these are even worth keeping. Doesn't make sense for - all datasets. - """ - - # def get_meltpond_fraction(self): - # raise NotImplementedError - # - # def get_sea_ice_fraction(self): - # raise NotImplementedError - # - # def get_roughness(self): - # raise NotImplementedError diff --git a/icepyx/quest/quest.py b/icepyx/quest/quest.py index 2855a879c..c54e49b73 100644 --- a/icepyx/quest/quest.py +++ b/icepyx/quest/quest.py @@ -1,25 +1,26 @@ import matplotlib.pyplot as plt -from icepyx.core.query import GenQuery +from icepyx.core.query import GenQuery, Query + +# from icepyx.quest.dataset_scripts.argo import Argo # todo: implement the subclass inheritance class Quest(GenQuery): """ QUEST - Query Unify Explore SpatioTemporal - object to query, obtain, and perform basic - operations on datasets for combined analysis with ICESat-2 data products. - A new dataset can be added using the `dataset.py` template. - A list of already supported datasets is available at: - Expands the icepyx GenQuery superclass. + operations on datasets (i.e. Argo, BGC Argo, MODIS, etc) for combined analysis with ICESat-2 + data products. A new dataset can be added using the `dataset.py` template. + QUEST expands the icepyx GenQuery superclass. See the doc page for GenQuery for details on temporal and spatial input parameters. Parameters ---------- - projection : proj4 string - Not yet implemented - Ex text: a string name of projection to be used for plotting (e.g. 'Mercator', 'NorthPolarStereographic') + proj : proj4 string + Geospatial projection. + Not yet implemented Returns ------- @@ -38,7 +39,6 @@ class Quest(GenQuery): Date range: (2019-02-20 00:00:00, 2019-02-28 23:59:59) Data sets: None - # todo: make this work with real datasets Add datasets to the quest object. >>> reg_a.datasets = {'ATL07':None, 'Argo':None} @@ -61,13 +61,11 @@ def __init__( end_time=None, proj="Default", ): + """ + Tells QUEST to initialize data given the user input spatiotemporal data. + """ super().__init__(spatial_extent, date_range, start_time, end_time) self.datasets = {} - self.projection = self._determine_proj(proj) - - # todo: maybe move this to icepyx superquery class - def _determine_proj(self, proj): - return None def __str__(self): str = super(Quest, self).__str__() @@ -83,4 +81,82 @@ def __str__(self): return str + # ---------------------------------------------------------------------- + # Datasets + + def add_icesat2( + self, + product=None, + start_time=None, + end_time=None, + version=None, + cycles=None, + tracks=None, + files=None, + **kwargs, + ): + """ + Adds ICESat-2 datasets to QUEST structure. + """ + + query = Query( + product, + self._spatial.extent, + [self._temporal.start, self._temporal.end], + start_time, + end_time, + version, + cycles, + tracks, + files, + **kwargs, + ) + + self.datasets["icesat2"] = query + + # def add_argo(self, params=["temperature"], presRange=None): + + # argo = Argo(self._spatial, self._temporal, params, presRange) + # self.datasets["argo"] = argo + + # ---------------------------------------------------------------------- + # Methods (on all datasets) + + # error handling? what happens when one of i fails... + def search_all(self): + """ + Searches for requred dataset within platform (i.e. ICESat-2, Argo) of interest. + """ + print("\nSearching all datasets...") + + for i in self.datasets.values(): + print() + try: + # querying ICESat-2 data + if isinstance(i, Query): + print("---ICESat-2---") + msg = i.avail_granules() + print(msg) + else: # querying all other data sets + print(i) + i.search_data() + except: + dataset_name = type(i).__name__ + print("Error querying data from {0}".format(dataset_name)) + + # error handling? what happens when one of i fails... + def download_all(self, path=""): + ' ' 'Downloads requested dataset(s).' ' ' + print("\nDownloading all datasets...") + + for i in self.datasets.values(): + print() + if isinstance(i, Query): + print("---ICESat-2---") + msg = i.download_granules(path) + print(msg) + else: + i.download() + print(i) + # DEVNOTE: see colocated data branch and phyto team files for code that expands quest functionality diff --git a/icepyx/tests/test_query.py b/icepyx/tests/test_query.py index 55b25ef4a..7738c424a 100644 --- a/icepyx/tests/test_query.py +++ b/icepyx/tests/test_query.py @@ -41,6 +41,18 @@ def test_icepyx_boundingbox_query(): assert obs_tuple == exp_tuple +def test_temporal_properties_cycles_tracks(): + reg_a = ipx.Query( + "ATL06", + [-55, 68, -48, 71], + cycles=["03", "04", "05", "06", "07"], + tracks=["0849", "0902"], + ) + exp = ["No temporal parameters set"] + + assert [obs == exp for obs in (reg_a.dates, reg_a.start_time, reg_a.end_time)] + + # Tests need to add (given can't do them within docstrings/they're behind NSIDC login) # reqparams post-order # product_all_info diff --git a/icepyx/tests/test_quest.py b/icepyx/tests/test_quest.py new file mode 100644 index 000000000..043ee159e --- /dev/null +++ b/icepyx/tests/test_quest.py @@ -0,0 +1,80 @@ +import pytest +import re + +import icepyx as ipx +from icepyx.quest.quest import Quest + + +@pytest.fixture +def quest_instance(scope="module", autouse=True): + bounding_box = [-150, 30, -120, 60] + date_range = ["2022-06-07", "2022-06-14"] + my_quest = Quest(spatial_extent=bounding_box, date_range=date_range) + return my_quest + + +########## PER-DATASET ADDITION TESTS ########## + +# Paramaterize these add_dataset tests once more datasets are added +def test_add_is2(quest_instance): + # Add ATL06 as a test to QUEST + + prod = "ATL06" + quest_instance.add_icesat2(product=prod) + exp_key = "icesat2" + exp_type = ipx.Query + + obs = quest_instance.datasets + + assert type(obs) == dict + assert exp_key in obs.keys() + assert type(obs[exp_key]) == exp_type + assert quest_instance.datasets[exp_key].product == prod + + +# def test_add_argo(quest_instance): +# params = ["down_irradiance412", "temperature"] +# quest_instance.add_argo(params=params) +# exp_key = "argo" +# exp_type = ipx.quest.dataset_scripts.argo.Argo + +# obs = quest_instance.datasets + +# assert type(obs) == dict +# assert exp_key in obs.keys() +# assert type(obs[exp_key]) == exp_type +# assert quest_instance.datasets[exp_key].params == params + +# def test_add_multiple_datasets(): +# bounding_box = [-150, 30, -120, 60] +# date_range = ["2022-06-07", "2022-06-14"] +# my_quest = Quest(spatial_extent=bounding_box, date_range=date_range) +# +# # print(my_quest.spatial) +# # print(my_quest.temporal) +# +# # my_quest.add_argo(params=["down_irradiance412", "temperature"]) +# # print(my_quest.datasets["argo"].params) +# +# my_quest.add_icesat2(product="ATL06") +# # print(my_quest.datasets["icesat2"].product) +# +# print(my_quest) +# +# # my_quest.search_all() +# # +# # # this one still needs work for IS2 because of auth... +# # my_quest.download_all() + +########## ALL DATASET METHODS TESTS ########## + +# is successful execution enough here? +# each of the query functions should be tested in their respective modules +def test_search_all(quest_instance): + # Search and test all datasets + quest_instance.search_all() + + +def test_download_all(): + # this will require auth in some cases... + pass From b130b927f0683c1b1a7857b377f623cbaa93f323 Mon Sep 17 00:00:00 2001 From: zachghiaccio Date: Wed, 9 Apr 2025 18:48:01 +0000 Subject: [PATCH 2/8] Adding h5coro to reader module. Making init recognize changes. --- icepyx/__init__.py | 9 ++++++--- icepyx/core/read.py | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/icepyx/__init__.py b/icepyx/__init__.py index 3d92e2e60..5d8410747 100644 --- a/icepyx/__init__.py +++ b/icepyx/__init__.py @@ -1,5 +1,8 @@ -from icepyx.core.query import Query, GenQuery -from icepyx.core.read import Read -from icepyx.quest.quest import Quest +import sys +sys.path.append("/home/jovyan/") + +from icepyx_personal.icepyx.core.query import Query, GenQuery +from icepyx_personal.icepyx.core.read import Read +from icepyx_personal.icepyx.quest.quest import Quest from _icepyx_version import version as __version__ diff --git a/icepyx/core/read.py b/icepyx/core/read.py index a7ee15db7..ac5a94e36 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -711,11 +711,11 @@ def _read_single_grp(self, file, grp_path): Xarray dataset with the specified group. """ - + print('using h5coro to read into xarray...') return xr.open_dataset( file, group=grp_path, - engine="h5netcdf", + engine="h5coro", backend_kwargs={"phony_dims": "access"}, ) @@ -785,7 +785,7 @@ def _build_single_file_dataset(self, file, groups_list): ) while wanted_groups_list: - # print(wanted_groups_list) + print(wanted_groups_list) grp_path = wanted_groups_list[0] wanted_groups_list = wanted_groups_list[1:] ds = self._read_single_grp(file, grp_path) From ec5f418a1539c8a93b6f543726b3649bc6bcfc06 Mon Sep 17 00:00:00 2001 From: zachghiaccio Date: Wed, 9 Apr 2025 18:58:27 +0000 Subject: [PATCH 3/8] resolved conflict in init --- icepyx/__init__.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/icepyx/__init__.py b/icepyx/__init__.py index 7480985d6..8aba372f6 100644 --- a/icepyx/__init__.py +++ b/icepyx/__init__.py @@ -1,11 +1,3 @@ -<<<<<<< HEAD -import sys -sys.path.append("/home/jovyan/") - -from icepyx_personal.icepyx.core.query import Query, GenQuery -from icepyx_personal.icepyx.core.read import Read -from icepyx_personal.icepyx.quest.quest import Quest -======= from warnings import warn deprecation_msg = """icepyx v1.x is being deprecated; the back-end systems on which it relies @@ -19,8 +11,6 @@ # work. warn(deprecation_msg, FutureWarning, stacklevel=2) ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 - from _icepyx_version import version as __version__ from icepyx.core.query import GenQuery, Query From 245fcace5ece06332cd8b88e8db8626e6b612c0a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:57:50 +0000 Subject: [PATCH 4/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- icepyx/core/read.py | 2 +- icepyx/tests/test_quest.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index b33e602bb..9a2be2d67 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -653,7 +653,7 @@ def _read_single_grp(self, file, grp_path): Xarray dataset with the specified group. """ - print('using h5coro to read into xarray...') + print("using h5coro to read into xarray...") return xr.open_dataset( file, group=grp_path, diff --git a/icepyx/tests/test_quest.py b/icepyx/tests/test_quest.py index 043ee159e..b38a19788 100644 --- a/icepyx/tests/test_quest.py +++ b/icepyx/tests/test_quest.py @@ -1,5 +1,4 @@ import pytest -import re import icepyx as ipx from icepyx.quest.quest import Quest @@ -15,6 +14,7 @@ def quest_instance(scope="module", autouse=True): ########## PER-DATASET ADDITION TESTS ########## + # Paramaterize these add_dataset tests once more datasets are added def test_add_is2(quest_instance): # Add ATL06 as a test to QUEST @@ -68,6 +68,7 @@ def test_add_is2(quest_instance): ########## ALL DATASET METHODS TESTS ########## + # is successful execution enough here? # each of the query functions should be tested in their respective modules def test_search_all(quest_instance): From 83ae9a43953b3904f83165d32802a5419559bc66 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 7 May 2025 17:53:12 +0000 Subject: [PATCH 5/8] restore quest file to development state --- icepyx/core/query.py | 29 +-------- icepyx/quest/__init__.py | 0 icepyx/quest/dataset_scripts/dataset.py | 12 +--- icepyx/quest/quest.py | 71 +--------------------- icepyx/tests/test_quest.py | 81 ------------------------- 5 files changed, 3 insertions(+), 190 deletions(-) create mode 100644 icepyx/quest/__init__.py delete mode 100644 icepyx/tests/test_quest.py diff --git a/icepyx/core/query.py b/icepyx/core/query.py index d697f9efc..9b55ea8c0 100644 --- a/icepyx/core/query.py +++ b/icepyx/core/query.py @@ -8,10 +8,6 @@ import icepyx.core.APIformatting as apifmt from icepyx.core.auth import EarthdataAuthMixin import icepyx.core.granules as granules -<<<<<<< HEAD -# QUESTION: why doesn't from granules import Granules work, since granules=icepyx.core.granules? -======= ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 from icepyx.core.granules import Granules import icepyx.core.is2ref as is2ref import icepyx.core.spatial as spat @@ -162,11 +158,7 @@ def __str__(self): # Properties @property -<<<<<<< HEAD - def temporal(self): -======= def temporal(self) -> Union[tp.Temporal, list[str]]: ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 """ Return the Temporal object containing date/time range information for the query object. @@ -226,12 +218,8 @@ def spatial_extent(self): Return an array showing the spatial extent of the query object. Spatial extent is returned as an input type (which depends on how you initially entered your spatial data) followed by the geometry data. -<<<<<<< HEAD - Bounding box data is [lower-left-longitude, lower-left-latitute, upper-right-longitude, upper-right-latitude]. -======= Bounding box data is [lower-left-longitude, lower-left-latitute, ... upper-right-longitude, upper-right-latitude]. ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 Polygon data is [longitude1, latitude1, longitude2, latitude2, ... longitude_n,latitude_n, longitude1,latitude1]. @@ -267,18 +255,11 @@ def spatial_extent(self): return (self._spatial._ext_type, self._spatial._spatial_ext) @property -<<<<<<< HEAD - def dates(self): - """ - Return an array showing the date range of the query object. - Dates are returned as an array containing the start and end datetime objects, inclusive, in that order. -======= def dates(self) -> list[str]: """ Return an array showing the date range of the query object. Dates are returned as an array containing the start and end datetime objects, inclusive, in that order. ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 Examples -------- @@ -299,11 +280,7 @@ def dates(self) -> list[str]: ] # could also use self._start.date() @property -<<<<<<< HEAD - def start_time(self): -======= def start_time(self) -> Union[list[str], str]: ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 """ Return the start time specified for the start date. @@ -327,11 +304,7 @@ def start_time(self) -> Union[list[str], str]: return self._temporal._start.strftime("%H:%M:%S") @property -<<<<<<< HEAD - def end_time(self): -======= def end_time(self) -> Union[list[str], str]: ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 """ Return the end time specified for the end date. @@ -1188,4 +1161,4 @@ def visualize_elevation(self): viz = Visualize(self) cycle_map, rgt_map = viz.viz_elevation() - return cycle_map, rgt_map + return cycle_map, rgt_map \ No newline at end of file diff --git a/icepyx/quest/__init__.py b/icepyx/quest/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/icepyx/quest/dataset_scripts/dataset.py b/icepyx/quest/dataset_scripts/dataset.py index e3f3cf9a8..a2ecd341c 100644 --- a/icepyx/quest/dataset_scripts/dataset.py +++ b/icepyx/quest/dataset_scripts/dataset.py @@ -1,5 +1,4 @@ import warnings -from icepyx.core.query import GenQuery warnings.filterwarnings("ignore") @@ -10,13 +9,7 @@ class DataSet: All sub-classes must support the following methods for use via the QUEST class. """ -<<<<<<< HEAD - def __init__( - self, spatial_extent=None, date_range=None, start_time=None, end_time=None - ): -======= def __init__(self, spatial_extent, date_range, start_time=None, end_time=None): ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 """ Complete any dataset specific initializations (i.e. beyond space and time) required here. For instance, ICESat-2 requires a product, and Argo requires parameters. @@ -73,15 +66,12 @@ def download(self): """ raise NotImplementedError -<<<<<<< HEAD -======= def save(self, filepath): """ Save the downloaded data to a directory on your local machine. """ raise NotImplementedError ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 # ---------------------------------------------------------------------- # Working with Data @@ -90,4 +80,4 @@ def visualize(self): Tells QUEST how to plot data (for instance, which parameters to plot) on a basemap. For ICESat-2, it might show a photon track, and for Argo it might show a profile location. """ - raise NotImplementedError + raise NotImplementedError \ No newline at end of file diff --git a/icepyx/quest/quest.py b/icepyx/quest/quest.py index 042efba6f..1fe77b10b 100644 --- a/icepyx/quest/quest.py +++ b/icepyx/quest/quest.py @@ -1,13 +1,5 @@ -<<<<<<< HEAD -import matplotlib.pyplot as plt - -from icepyx.core.query import GenQuery, Query - -# from icepyx.quest.dataset_scripts.argo import Argo -======= from icepyx.core.query import GenQuery, Query from icepyx.quest.dataset_scripts.argo import Argo ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 class Quest(GenQuery): @@ -67,10 +59,7 @@ def __init__( """ Tells QUEST to initialize data given the user input spatiotemporal data. """ -<<<<<<< HEAD -======= ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 super().__init__(spatial_extent, date_range, start_time, end_time) self.datasets = {} @@ -93,11 +82,7 @@ def __str__(self): def add_icesat2( self, -<<<<<<< HEAD - product=None, -======= product, ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 start_time=None, end_time=None, version=None, @@ -105,11 +90,6 @@ def add_icesat2( tracks=None, files=None, **kwargs, -<<<<<<< HEAD - ): - """ - Adds ICESat-2 datasets to QUEST structure. -======= ) -> None: """ Adds ICESat-2 datasets to QUEST structure. @@ -126,7 +106,6 @@ def add_icesat2( -------- icepyx.core.GenQuery icepyx.core.Query ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 """ query = Query( @@ -144,12 +123,6 @@ def add_icesat2( self.datasets["icesat2"] = query -<<<<<<< HEAD - # def add_argo(self, params=["temperature"], presRange=None): - - # argo = Argo(self._spatial, self._temporal, params, presRange) - # self.datasets["argo"] = argo -======= def add_argo(self, params=["temperature"], presRange=None) -> None: """ Adds Argo (including Argo-BGC) to QUEST structure. @@ -176,51 +149,10 @@ def add_argo(self, params=["temperature"], presRange=None) -> None: argo = Argo(self._spatial, self._temporal, params, presRange) self.datasets["argo"] = argo ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 # ---------------------------------------------------------------------- # Methods (on all datasets) -<<<<<<< HEAD - # error handling? what happens when one of i fails... - def search_all(self): - """ - Searches for requred dataset within platform (i.e. ICESat-2, Argo) of interest. - """ - print("\nSearching all datasets...") - - for i in self.datasets.values(): - print() - try: - # querying ICESat-2 data - if isinstance(i, Query): - print("---ICESat-2---") - msg = i.avail_granules() - print(msg) - else: # querying all other data sets - print(i) - i.search_data() - except: - dataset_name = type(i).__name__ - print("Error querying data from {0}".format(dataset_name)) - - # error handling? what happens when one of i fails... - def download_all(self, path=""): - ' ' 'Downloads requested dataset(s).' ' ' - print("\nDownloading all datasets...") - - for i in self.datasets.values(): - print() - if isinstance(i, Query): - print("---ICESat-2---") - msg = i.download_granules(path) - print(msg) - else: - i.download() - print(i) - - # DEVNOTE: see colocated data branch and phyto team files for code that expands quest functionality -======= # error handling? what happens when the user tries to re-query? def search_all(self, **kwargs): """ @@ -313,5 +245,4 @@ def save_all(self, path): print("ICESat-2 granules are saved during download") else: print("Saving " + k) - v.save(path) ->>>>>>> 386d73f69512d13ebb92ef32bb9e83006ada29f1 + v.save(path) \ No newline at end of file diff --git a/icepyx/tests/test_quest.py b/icepyx/tests/test_quest.py deleted file mode 100644 index b38a19788..000000000 --- a/icepyx/tests/test_quest.py +++ /dev/null @@ -1,81 +0,0 @@ -import pytest - -import icepyx as ipx -from icepyx.quest.quest import Quest - - -@pytest.fixture -def quest_instance(scope="module", autouse=True): - bounding_box = [-150, 30, -120, 60] - date_range = ["2022-06-07", "2022-06-14"] - my_quest = Quest(spatial_extent=bounding_box, date_range=date_range) - return my_quest - - -########## PER-DATASET ADDITION TESTS ########## - - -# Paramaterize these add_dataset tests once more datasets are added -def test_add_is2(quest_instance): - # Add ATL06 as a test to QUEST - - prod = "ATL06" - quest_instance.add_icesat2(product=prod) - exp_key = "icesat2" - exp_type = ipx.Query - - obs = quest_instance.datasets - - assert type(obs) == dict - assert exp_key in obs.keys() - assert type(obs[exp_key]) == exp_type - assert quest_instance.datasets[exp_key].product == prod - - -# def test_add_argo(quest_instance): -# params = ["down_irradiance412", "temperature"] -# quest_instance.add_argo(params=params) -# exp_key = "argo" -# exp_type = ipx.quest.dataset_scripts.argo.Argo - -# obs = quest_instance.datasets - -# assert type(obs) == dict -# assert exp_key in obs.keys() -# assert type(obs[exp_key]) == exp_type -# assert quest_instance.datasets[exp_key].params == params - -# def test_add_multiple_datasets(): -# bounding_box = [-150, 30, -120, 60] -# date_range = ["2022-06-07", "2022-06-14"] -# my_quest = Quest(spatial_extent=bounding_box, date_range=date_range) -# -# # print(my_quest.spatial) -# # print(my_quest.temporal) -# -# # my_quest.add_argo(params=["down_irradiance412", "temperature"]) -# # print(my_quest.datasets["argo"].params) -# -# my_quest.add_icesat2(product="ATL06") -# # print(my_quest.datasets["icesat2"].product) -# -# print(my_quest) -# -# # my_quest.search_all() -# # -# # # this one still needs work for IS2 because of auth... -# # my_quest.download_all() - -########## ALL DATASET METHODS TESTS ########## - - -# is successful execution enough here? -# each of the query functions should be tested in their respective modules -def test_search_all(quest_instance): - # Search and test all datasets - quest_instance.search_all() - - -def test_download_all(): - # this will require auth in some cases... - pass From 237871a72f3d4a38acd4c595b047757e4fbc0533 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 17:54:25 +0000 Subject: [PATCH 6/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- icepyx/core/query.py | 2 +- icepyx/quest/dataset_scripts/dataset.py | 2 +- icepyx/quest/quest.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/icepyx/core/query.py b/icepyx/core/query.py index 9b55ea8c0..74012c037 100644 --- a/icepyx/core/query.py +++ b/icepyx/core/query.py @@ -1161,4 +1161,4 @@ def visualize_elevation(self): viz = Visualize(self) cycle_map, rgt_map = viz.viz_elevation() - return cycle_map, rgt_map \ No newline at end of file + return cycle_map, rgt_map diff --git a/icepyx/quest/dataset_scripts/dataset.py b/icepyx/quest/dataset_scripts/dataset.py index a2ecd341c..7637b5d4f 100644 --- a/icepyx/quest/dataset_scripts/dataset.py +++ b/icepyx/quest/dataset_scripts/dataset.py @@ -80,4 +80,4 @@ def visualize(self): Tells QUEST how to plot data (for instance, which parameters to plot) on a basemap. For ICESat-2, it might show a photon track, and for Argo it might show a profile location. """ - raise NotImplementedError \ No newline at end of file + raise NotImplementedError diff --git a/icepyx/quest/quest.py b/icepyx/quest/quest.py index 1fe77b10b..c24029070 100644 --- a/icepyx/quest/quest.py +++ b/icepyx/quest/quest.py @@ -245,4 +245,4 @@ def save_all(self, path): print("ICESat-2 granules are saved during download") else: print("Saving " + k) - v.save(path) \ No newline at end of file + v.save(path) From 6ba50c656cfca634cd98f5ee4929a2963fddb524 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 7 May 2025 19:34:43 +0000 Subject: [PATCH 7/8] add credentials and update filestring --- icepyx/core/read.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 9a2be2d67..70c83d110 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -2,6 +2,7 @@ import os import sys import warnings +import time # TODO Remove this at end import earthaccess import numpy as np @@ -590,8 +591,9 @@ def load(self): if file.startswith("s3"): # If path is an s3 path create an s3fs filesystem to reference the file # TODO would it be better to be able to generate an s3fs session from the Mixin? - s3 = earthaccess.get_s3fs_session(daac="NSIDC") - file = s3.open(file, "rb") + # s3 = earthaccess.get_s3fs_session(daac="NSIDC") + # file = s3.open(file, "rb") + file = file[5:] # Remove s3:// from filepath (h5coro's needed input) all_dss.append( self._build_single_file_dataset(file, groups_list) @@ -658,7 +660,8 @@ def _read_single_grp(self, file, grp_path): file, group=grp_path, engine="h5coro", - backend_kwargs={"phony_dims": "access"}, + credentials=self.s3login_credentials, + # backend_kwargs={"phony_dims": "access"}, ) def _build_single_file_dataset(self, file, groups_list): @@ -770,7 +773,9 @@ def _build_single_file_dataset(self, file, groups_list): while wanted_groups_list: grp_path = wanted_groups_list[0] wanted_groups_list = wanted_groups_list[1:] + print('Starting group', grp_path, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) ds = self._read_single_grp(file, grp_path) + print('Finished group', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) is2ds, ds = Read._add_vars_to_ds( is2ds, ds, grp_path, wanted_groups_tiered, wanted_dict ) From 664d5173fe6923c0522a20e6dbbc41b71ca01dd7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 19:35:14 +0000 Subject: [PATCH 8/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- icepyx/core/read.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 70c83d110..aa2a5f37d 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -1,10 +1,9 @@ import glob import os import sys -import warnings import time # TODO Remove this at end +import warnings -import earthaccess import numpy as np import xarray as xr @@ -773,9 +772,16 @@ def _build_single_file_dataset(self, file, groups_list): while wanted_groups_list: grp_path = wanted_groups_list[0] wanted_groups_list = wanted_groups_list[1:] - print('Starting group', grp_path, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) + print( + "Starting group", + grp_path, + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), + ) ds = self._read_single_grp(file, grp_path) - print('Finished group', time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))) + print( + "Finished group", + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), + ) is2ds, ds = Read._add_vars_to_ds( is2ds, ds, grp_path, wanted_groups_tiered, wanted_dict )