From 502a4bf2740dc1382005e95c262c08dca72c8e7e Mon Sep 17 00:00:00 2001 From: JessicaS11 Date: Thu, 2 Jul 2020 20:04:24 +0000 Subject: [PATCH 1/9] add black pre-commit hook and reformat files using black --- .pre-commit-config.yaml | 5 + doc/source/conf.py | 56 +- icepyx/__init__.py | 2 +- icepyx/core/APIformatting.py | 299 +++++--- icepyx/core/Earthdata.py | 55 +- icepyx/core/geospatial.py | 82 +- icepyx/core/granules.py | 355 +++++---- icepyx/core/icesat2data.py | 347 +++++---- icepyx/core/is2ref.py | 222 ++++-- icepyx/core/validate_inputs.py | 151 ++-- icepyx/core/variables.py | 323 ++++---- icepyx/tests/is2class_query.py | 80 +- icepyx/tests/test_APIformatting.py | 1059 ++++++++++++++++++++++++-- icepyx/tests/test_geospatial.py | 12 +- icepyx/tests/test_granules.py | 944 ++++++++++++++--------- icepyx/tests/test_is2ref.py | 50 +- icepyx/tests/test_validate_inputs.py | 121 ++- requirements.txt | 1 + 18 files changed, 2908 insertions(+), 1256 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..ace746317 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: +- repo: https://github.com/ambv/black + rev: stable + hooks: + - id: black \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py index 861271b8b..fb572207f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -12,7 +12,8 @@ # import os import sys -sys.path.insert(0, os.path.abspath('../..')) + +sys.path.insert(0, os.path.abspath("../..")) import datetime import icepyx @@ -21,9 +22,9 @@ # -- Project information ----------------------------------------------------- -project = 'icepyx' +project = "icepyx" year = datetime.date.today().year -copyright = '2019-{}, The icepyx Developers'.format(year) +copyright = "2019-{}, The icepyx Developers".format(year) # -- General configuration --------------------------------------------------- @@ -35,24 +36,23 @@ "sphinx.ext.autosectionlabel", "numpydoc", "nbsphinx", - "recommonmark" - + "recommonmark", ] source_suffix = { - '.rst': 'restructuredtext', - '.txt': 'markdown', - '.md': 'markdown', + ".rst": "restructuredtext", + ".txt": "markdown", + ".md": "markdown", } # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['**.ipynb_checkpoints'] +exclude_patterns = ["**.ipynb_checkpoints"] # location of master document (by default sphinx looks for contents.rst) -master_doc = 'index' +master_doc = "index" # -- Configuration options --------------------------------------------------- @@ -68,24 +68,30 @@ # html_theme = 'alabaster' html_theme = "sphinx_rtd_theme" html_theme_options = { - 'logo_only': True, - 'display_version': False, - 'prev_next_buttons_location': None, - 'navigation_depth': 4, - 'collapse_navigation': True + "logo_only": True, + "display_version": False, + "prev_next_buttons_location": None, + "navigation_depth": 4, + "collapse_navigation": True, } -html_logo = '_static/icepyx_v2_oval_orig_nobackgr.png' -html_favicon = '_static/icepyx_v2_oval_tiny-uml_nobackgr.png' -html_static_path = ['_static'] +html_logo = "_static/icepyx_v2_oval_orig_nobackgr.png" +html_favicon = "_static/icepyx_v2_oval_tiny-uml_nobackgr.png" +html_static_path = ["_static"] html_context = { - 'menu_links_name': '', - 'menu_links': [ - (' icepyx Github', 'https://github.com/icesat2py/icepyx'), - (' Pangeo Discourse', 'https://discourse.pangeo.io/t/icepyx-python-tools-for-icesat-2-data/404/2') - - ] + "menu_links_name": "", + "menu_links": [ + ( + ' icepyx Github', + "https://github.com/icesat2py/icepyx", + ), + ( + ' Pangeo Discourse', + "https://discourse.pangeo.io/t/icepyx-python-tools-for-icesat-2-data/404/2", + ), + ], } + def setup(app): app.add_stylesheet("style.css") diff --git a/icepyx/__init__.py b/icepyx/__init__.py index efae9241b..33422cc96 100644 --- a/icepyx/__init__.py +++ b/icepyx/__init__.py @@ -1 +1 @@ -from .core import icesat2data \ No newline at end of file +from .core import icesat2data diff --git a/icepyx/core/APIformatting.py b/icepyx/core/APIformatting.py index 0e89b011c..aadaafb7a 100644 --- a/icepyx/core/APIformatting.py +++ b/icepyx/core/APIformatting.py @@ -1,4 +1,4 @@ -#Generate and format information for submitting to API (CMR and NSIDC) +# Generate and format information for submitting to API (CMR and NSIDC) import datetime as dt import geopandas as gpd @@ -6,13 +6,15 @@ from shapely.geometry import Polygon from shapely.geometry.polygon import orient import fiona -fiona.drvsupport.supported_drivers['LIBKML'] = 'rw' + +fiona.drvsupport.supported_drivers["LIBKML"] = "rw" # ---------------------------------------------------------------------- # parameter-specific formatting for display # or input to a set of API parameters (CMR or NSIDC) -def _fmt_temporal(start,end,key): + +def _fmt_temporal(start, end, key): """ Format the start and end dates and times into a temporal CMR search or subsetting key value. @@ -34,14 +36,25 @@ def _fmt_temporal(start,end,key): assert isinstance(start, dt.datetime) assert isinstance(end, dt.datetime) - assert key in ['time', 'temporal'], 'An invalid time key was submitted for formatting.' - - if key == 'temporal': - fmt_timerange = start.strftime('%Y-%m-%dT%H:%M:%SZ') +',' + end.strftime('%Y-%m-%dT%H:%M:%SZ') - elif key == 'time': - fmt_timerange = start.strftime('%Y-%m-%dT%H:%M:%S') +',' + end.strftime('%Y-%m-%dT%H:%M:%S') - - return {key:fmt_timerange} + assert key in [ + "time", + "temporal", + ], "An invalid time key was submitted for formatting." + + if key == "temporal": + fmt_timerange = ( + start.strftime("%Y-%m-%dT%H:%M:%SZ") + + "," + + end.strftime("%Y-%m-%dT%H:%M:%SZ") + ) + elif key == "time": + fmt_timerange = ( + start.strftime("%Y-%m-%dT%H:%M:%S") + + "," + + end.strftime("%Y-%m-%dT%H:%M:%S") + ) + + return {key: fmt_timerange} def _fmt_spatial(ext_type, extent): @@ -66,30 +79,33 @@ def _fmt_spatial(ext_type, extent): """ - #CMR keywords: ['bounding_box', 'polygon'] - #subsetting keywords: ['bbox','Boundingshape'] - assert ext_type in ['bounding_box', 'polygon'] or ext_type in ['bbox','Boundingshape'],\ - "Invalid spatial extent type." + # CMR keywords: ['bounding_box', 'polygon'] + # subsetting keywords: ['bbox','Boundingshape'] + assert ext_type in ["bounding_box", "polygon"] or ext_type in [ + "bbox", + "Boundingshape", + ], "Invalid spatial extent type." - if ext_type in ['bounding_box', 'bbox']: - fmt_extent = ','.join(map(str, extent)) + if ext_type in ["bounding_box", "bbox"]: + fmt_extent = ",".join(map(str, extent)) - - elif ext_type == 'polygon': - #Simplify polygon. The larger the tolerance value, the more simplified the polygon. See Bruce Wallin's function to do this + elif ext_type == "polygon": + # Simplify polygon. The larger the tolerance value, the more simplified the polygon. See Bruce Wallin's function to do this poly = extent.simplify(0.05, preserve_topology=False) poly = orient(poly, sign=1.0) - #Format dictionary to polygon coordinate pairs for API submission - polygon = (','.join([str(c) for xy in zip(*poly.exterior.coords.xy) for c in xy])).split(",") + # Format dictionary to polygon coordinate pairs for API submission + polygon = ( + ",".join([str(c) for xy in zip(*poly.exterior.coords.xy) for c in xy]) + ).split(",") extent = [float(i) for i in polygon] - fmt_extent = ','.join(map(str, extent)) + fmt_extent = ",".join(map(str, extent)) - #DevNote: this elif currently does not have a test (seems like it would just be testing geopandas?) - elif ext_type == 'Boundingshape': + # DevNote: this elif currently does not have a test (seems like it would just be testing geopandas?) + elif ext_type == "Boundingshape": poly = orient(extent, sign=1.0) fmt_extent = gpd.GeoSeries(poly).to_json() - fmt_extent = fmt_extent.replace(' ', '') #remove spaces for API call + fmt_extent = fmt_extent.replace(" ", "") # remove spaces for API call return {ext_type: fmt_extent} @@ -104,13 +120,14 @@ def _fmt_var_subset_list(vdict): Dictionary containing variable names as keys with values containing a list of paths to those variables (so each variable key may have multiple paths, e.g. for multiple beams) - """ - - subcover = '' + """ + + subcover = "" for vn in vdict.keys(): vpaths = vdict[vn] - for vpath in vpaths: subcover += '/'+vpath+',' - + for vpath in vpaths: + subcover += "/" + vpath + "," + return subcover[:-1] @@ -139,18 +156,18 @@ def combine_params(*param_dicts): 'page_size': 10, 'page_num': 1} """ - params={} + params = {} for dictionary in param_dicts: params.update(dictionary) return params # ---------------------------------------------------------------------- -#DevNote: Currently, this class is not tested!! -#DevGoal: this could be expanded, similar to the variables class, to provide users with valid options if need be -#DevGoal: currently this does not do much by way of checking/formatting of other subsetting options (reprojection or formats) -#it would be great to incorporate that so that people can't just feed any keywords in... -class Parameters(): +# DevNote: Currently, this class is not tested!! +# DevGoal: this could be expanded, similar to the variables class, to provide users with valid options if need be +# DevGoal: currently this does not do much by way of checking/formatting of other subsetting options (reprojection or formats) +# it would be great to incorporate that so that people can't just feed any keywords in... +class Parameters: """ Build and update the parameter lists needed to submit a data order @@ -169,16 +186,22 @@ class Parameters(): """ def __init__(self, partype, values=None, reqtype=None): - - assert partype in ['CMR','required','subset'], "You need to submit a valid parametery type." + + assert partype in [ + "CMR", + "required", + "subset", + ], "You need to submit a valid parametery type." self.partype = partype - - if partype == 'required': - assert reqtype in ['search','download'], "A valid require parameter type is needed" + + if partype == "required": + assert reqtype in [ + "search", + "download", + ], "A valid require parameter type is needed" self._reqtype = reqtype - - self._fmted_keys = values if values is not None else {} + self._fmted_keys = values if values is not None else {} @property def poss_keys(self): @@ -187,9 +210,9 @@ def poss_keys(self): Possible input keys depend on the parameter type (partype). """ - if not hasattr(self,'_poss_keys'): + if not hasattr(self, "_poss_keys"): self._get_possible_keys() - + return self._poss_keys # @property @@ -198,77 +221,109 @@ def poss_keys(self): # self._wanted = [] # return self._wanted - + @property def fmted_keys(self): """ Returns the dictionary of formated keys associated with the parameter object. - """ + """ return self._fmted_keys - def _get_possible_keys(self): """ Use the parameter type to get a list of possible parameter keys. """ - - if self.partype == 'CMR': - self._poss_keys = {'default': ['short_name','version','temporal'], 'spatial': ['bounding_box','polygon'], 'optional': []} - elif self.partype == 'required': - self._poss_keys = {'search': ['page_size','page_num'], 'download': ['page_size','page_num','request_mode','token','email','include_meta']} - elif self.partype == 'subset': - self._poss_keys = {'default': ['time'],'spatial': ['bbox','Boundingshape'],'optional': ['format','projection','projection_parameters','Coverage']} + if self.partype == "CMR": + self._poss_keys = { + "default": ["short_name", "version", "temporal"], + "spatial": ["bounding_box", "polygon"], + "optional": [], + } + elif self.partype == "required": + self._poss_keys = { + "search": ["page_size", "page_num"], + "download": [ + "page_size", + "page_num", + "request_mode", + "token", + "email", + "include_meta", + ], + } + elif self.partype == "subset": + self._poss_keys = { + "default": ["time"], + "spatial": ["bbox", "Boundingshape"], + "optional": [ + "format", + "projection", + "projection_parameters", + "Coverage", + ], + } def _check_valid_keys(self): """ Checks that any keys passed in with values are valid keys. """ - + # if self._wanted == None: # raise ValueError("No desired parameter list was passed") - + val_list = list(set(val for lis in self.poss_keys.values() for val in lis)) - + for key in self.fmted_keys.keys(): - assert key in val_list, "An invalid key (" + key + ") was passed. Please remove it using `del`" + assert key in val_list, ( + "An invalid key (" + key + ") was passed. Please remove it using `del`" + ) - def check_req_values(self): """ Check that all of the required keys have values, if the key was passed in with the values parameter. """ - - assert self.partype == 'required', "You cannot call this function for your parameter type" + + assert ( + self.partype == "required" + ), "You cannot call this function for your parameter type" reqkeys = self.poss_keys[self._reqtype] - + if all(keys in self.fmted_keys.keys() for keys in reqkeys): - assert all(self.fmted_keys.get(key, -9999) != -9999 for key in reqkeys),"One of your formated parameters is missing a value" + assert all( + self.fmted_keys.get(key, -9999) != -9999 for key in reqkeys + ), "One of your formated parameters is missing a value" return True else: return False - def check_values(self): """ Check that the non-required keys have values, if the key was passed in with the values parameter. """ - assert self.partype != 'required', "You cannot call this function for your parameter type" - - default_keys = self.poss_keys['default'] - spatial_keys = self.poss_keys['spatial'] + assert ( + self.partype != "required" + ), "You cannot call this function for your parameter type" + + default_keys = self.poss_keys["default"] + spatial_keys = self.poss_keys["spatial"] if all(keys in self._fmted_keys.keys() for keys in default_keys): - assert all(self.fmted_keys.get(key, -9999) != -9999 for key in default_keys),"One of your formated parameters is missing a value" - - #not the most robust check, but better than nothing... + assert all( + self.fmted_keys.get(key, -9999) != -9999 for key in default_keys + ), "One of your formated parameters is missing a value" + + # not the most robust check, but better than nothing... if any(keys in self._fmted_keys.keys() for keys in spatial_keys): - assert any(self.fmted_keys.get(key, -9999) != -9999 for key in default_keys),"One of your formated parameters is missing a value" + assert any( + self.fmted_keys.get(key, -9999) != -9999 for key in default_keys + ), "One of your formated parameters is missing a value" return True - else: return False + else: + return False else: return False @@ -291,70 +346,80 @@ def build_params(self, **kwargs): """ - if not kwargs: kwargs={} + if not kwargs: + kwargs = {} else: self._check_valid_keys() - - if self.partype == 'required': - if self.check_req_values==True and kwargs=={}: pass + + if self.partype == "required": + if self.check_req_values == True and kwargs == {}: + pass else: reqkeys = self.poss_keys[self._reqtype] - defaults={'page_size':10,'page_num':1,'request_mode':'async','include_meta':'Y'} + defaults = { + "page_size": 10, + "page_num": 1, + "request_mode": "async", + "include_meta": "Y", + } for key in reqkeys: if key in kwargs: - self._fmted_keys.update({key:kwargs[key]}) - # elif key in defaults: - # if key is 'page_num': - # pnum = math.ceil(len(is2obj.granules)/reqparams['page_size']) - # if pnum > 0: - # reqparams.update({key:pnum}) - # else: - # reqparams.update({key:defaults[key]}) + self._fmted_keys.update({key: kwargs[key]}) + # elif key in defaults: + # if key is 'page_num': + # pnum = math.ceil(len(is2obj.granules)/reqparams['page_size']) + # if pnum > 0: + # reqparams.update({key:pnum}) + # else: + # reqparams.update({key:defaults[key]}) elif key in defaults: - self._fmted_keys.update({key:defaults[key]}) + self._fmted_keys.update({key: defaults[key]}) else: pass - self._fmted_keys['page_num'] = 1 + self._fmted_keys["page_num"] = 1 else: - if self.check_values==True and kwargs==None: pass + if self.check_values == True and kwargs == None: + pass else: - default_keys = self.poss_keys['default'] - spatial_keys = self.poss_keys['spatial'] - opt_keys = self.poss_keys['optional'] + default_keys = self.poss_keys["default"] + spatial_keys = self.poss_keys["spatial"] + opt_keys = self.poss_keys["optional"] for key in default_keys: if key in self._fmted_keys.values(): assert self._fmted_keys[key] else: - if key == 'short_name': - self._fmted_keys.update({key:kwargs['dataset']}) - elif key == 'version': - self._fmted_keys.update({key:kwargs['version']}) - elif key == 'temporal' or key == 'time': - self._fmted_keys.update(_fmt_temporal(kwargs['start'],kwargs['end'],key)) - - + if key == "short_name": + self._fmted_keys.update({key: kwargs["dataset"]}) + elif key == "version": + self._fmted_keys.update({key: kwargs["version"]}) + elif key == "temporal" or key == "time": + self._fmted_keys.update( + _fmt_temporal(kwargs["start"], kwargs["end"], key) + ) + for key in opt_keys: - if key == 'Coverage' and key in kwargs.keys(): - #DevGoal: make there be an option along the lines of Coverage=default, which will get the default variables for that dataset without the user having to input is2obj.build_wanted_wanted_var_list as their input value for using the Coverage kwarg - self._fmted_keys.update({key:_fmt_var_subset_list(kwargs[key])}) + if key == "Coverage" and key in kwargs.keys(): + # DevGoal: make there be an option along the lines of Coverage=default, which will get the default variables for that dataset without the user having to input is2obj.build_wanted_wanted_var_list as their input value for using the Coverage kwarg + self._fmted_keys.update( + {key: _fmt_var_subset_list(kwargs[key])} + ) elif key in kwargs: - self._fmted_keys.update({key:kwargs[key]}) + self._fmted_keys.update({key: kwargs[key]}) else: pass - - + if any(keys in self._fmted_keys for keys in spatial_keys): pass else: - if self.partype =='CMR': - k = kwargs['extent_type'] - elif self.partype == 'subset': - if kwargs['extent_type'] == 'bounding_box': - k = 'bbox' - elif kwargs['extent_type'] == 'polygon': - k = 'Boundingshape' - - self._fmted_keys.update(_fmt_spatial(k,kwargs['spatial_extent'])) + if self.partype == "CMR": + k = kwargs["extent_type"] + elif self.partype == "subset": + if kwargs["extent_type"] == "bounding_box": + k = "bbox" + elif kwargs["extent_type"] == "polygon": + k = "Boundingshape" + + self._fmted_keys.update(_fmt_spatial(k, kwargs["spatial_extent"])) diff --git a/icepyx/core/Earthdata.py b/icepyx/core/Earthdata.py index f34be4063..d628fc2b5 100644 --- a/icepyx/core/Earthdata.py +++ b/icepyx/core/Earthdata.py @@ -5,8 +5,8 @@ import re import json -#DevNote: currently this class is not tested -class Earthdata(): +# DevNote: currently this class is not tested +class Earthdata: """ Initiate an Earthdata session for interacting with the NSIDC DAAC. @@ -28,15 +28,13 @@ class Earthdata(): """ def __init__( - self, - uid, - email, - capability_url, - pswd=None, + self, uid, email, capability_url, pswd=None, ): assert isinstance(uid, str), "Enter your login user id as a string" - assert re.match(r'[^@]+@[^@]+\.[^@]+',email), "Enter a properly formatted email address" + assert re.match( + r"[^@]+@[^@]+\.[^@]+", email + ), "Enter a properly formatted email address" self.netrc = None self.uid = uid @@ -45,32 +43,41 @@ def __init__( self.pswd = pswd def _start_session(self): - #Request CMR token using Earthdata credentials - token_api_url = 'https://cmr.earthdata.nasa.gov/legacy-services/rest/tokens' + # Request CMR token using Earthdata credentials + token_api_url = "https://cmr.earthdata.nasa.gov/legacy-services/rest/tokens" hostname = socket.gethostname() ip = socket.gethostbyname(hostname) - data = {'token': {'username': self.uid, 'password': self.pswd,\ - 'client_id': 'NSIDC_client_id','user_ip_address': ip} + data = { + "token": { + "username": self.uid, + "password": self.pswd, + "client_id": "NSIDC_client_id", + "user_ip_address": ip, + } } response = None - response = requests.post(token_api_url, json=data, headers={'Accept': 'application/json'}) + response = requests.post( + token_api_url, json=data, headers={"Accept": "application/json"} + ) - #check for a valid login + # check for a valid login try: - json.loads(response.content)['token'] + json.loads(response.content)["token"] except KeyError: try: - print(json.loads(response.content)['errors']) + print(json.loads(response.content)["errors"]) except KeyError: - print("There are no error messages, but an Earthdata login token was not successfully generated") + print( + "There are no error messages, but an Earthdata login token was not successfully generated" + ) - token = json.loads(response.content)['token']['id'] + token = json.loads(response.content)["token"]["id"] session = requests.session() s = session.get(self.capability_url) - response = session.get(s.url,auth=(self.uid,self.pswd)) + response = session.get(s.url, auth=(self.uid, self.pswd)) self.session = session @@ -102,19 +109,19 @@ def login(self): """ try: - url = 'urs.earthdata.nasa.gov' - self.uid,_,self.pswd = netrc.netrc(self.netrc).authenticators(url) + url = "urs.earthdata.nasa.gov" + self.uid, _, self.pswd = netrc.netrc(self.netrc).authenticators(url) session = self._start_session() except: - self.pswd = getpass.getpass('Earthdata Login password: ') + self.pswd = getpass.getpass("Earthdata Login password: ") for i in range(5): try: session = self._start_session() break except KeyError: self.uid = input("Please re-enter your Earthdata user ID: ") - self.pswd = getpass.getpass('Earthdata Login password: ') + self.pswd = getpass.getpass("Earthdata Login password: ") i += 1 else: raise RuntimeError("You could not successfully log in to Earthdata") @@ -122,7 +129,7 @@ def login(self): return self.session -#DevGoal: try turning this into a class that uses super... an initial attempt at portions of this is below +# DevGoal: try turning this into a class that uses super... an initial attempt at portions of this is below """ class Earthdata(requests.Session): diff --git a/icepyx/core/geospatial.py b/icepyx/core/geospatial.py index 7282cd39f..5e39e5030 100644 --- a/icepyx/core/geospatial.py +++ b/icepyx/core/geospatial.py @@ -1,9 +1,9 @@ import geopandas as gpd from shapely.geometry import Polygon - -#DevGoal: need to update the spatial_extent docstring to describe coordinate order for input + +# DevGoal: need to update the spatial_extent docstring to describe coordinate order for input def geodataframe(extent_type, spatial_extent, file=False): - """ + """ Return a geodataframe of the spatial extent Parameters @@ -35,37 +35,53 @@ def geodataframe(extent_type, spatial_extent, file=False): Name: geometry, dtype: geometry """ - if extent_type == 'bounding_box': - boxx = [spatial_extent[0], spatial_extent[0], spatial_extent[2],\ - spatial_extent[2], spatial_extent[0]] - boxy = [spatial_extent[1], spatial_extent[3], spatial_extent[3],\ - spatial_extent[1], spatial_extent[1]] - #DevGoal: check to see that the box is actually correctly constructed; have not checked actual location of test coordinates - gdf = gpd.GeoDataFrame(geometry=[Polygon(list(zip(boxx,boxy)))]) + if extent_type == "bounding_box": + boxx = [ + spatial_extent[0], + spatial_extent[0], + spatial_extent[2], + spatial_extent[2], + spatial_extent[0], + ] + boxy = [ + spatial_extent[1], + spatial_extent[3], + spatial_extent[3], + spatial_extent[1], + spatial_extent[1], + ] + # DevGoal: check to see that the box is actually correctly constructed; have not checked actual location of test coordinates + gdf = gpd.GeoDataFrame(geometry=[Polygon(list(zip(boxx, boxy)))]) - #DevGoal: Currently this if/else within this elif are not tested... - #DevGoal: the crs setting and management needs to be improved - elif extent_type == 'polygon' and file==False: - #DevGoal: look into when/if this if is even called. I think all the incoming spatial_extents without a file will be floats... - #DEL: I don't think this if is ever used, so long as the spatial extent always comes in as a list of floats - # if isinstance(spatial_extent,str): - # print('this string instance is needed') - # spat_extent = spatial_extent.split(',') - # spatial_extent_geom = Polygon(zip(spat_extent[0::2], spat_extent[1::2])) - if isinstance(spatial_extent, Polygon): - spatial_extent_geom = spatial_extent - else: - spatial_extent_geom = Polygon(zip(spatial_extent[0::2], spatial_extent[1::2])) #spatial_extent - - gdf = gpd.GeoDataFrame(index=[0],crs='epsg:4326', geometry=[spatial_extent_geom]) + # DevGoal: Currently this if/else within this elif are not tested... + # DevGoal: the crs setting and management needs to be improved + elif extent_type == "polygon" and file == False: + # DevGoal: look into when/if this if is even called. I think all the incoming spatial_extents without a file will be floats... + # DEL: I don't think this if is ever used, so long as the spatial extent always comes in as a list of floats + # if isinstance(spatial_extent,str): + # print('this string instance is needed') + # spat_extent = spatial_extent.split(',') + # spatial_extent_geom = Polygon(zip(spat_extent[0::2], spat_extent[1::2])) + if isinstance(spatial_extent, Polygon): + spatial_extent_geom = spatial_extent + else: + spatial_extent_geom = Polygon( + zip(spatial_extent[0::2], spatial_extent[1::2]) + ) # spatial_extent - #DevGoal: Currently this elif isn't tested... - elif extent_type == 'polygon' and file==True: - gdf = gpd.read_file(spatial_extent) + gdf = gpd.GeoDataFrame( + index=[0], crs="epsg:4326", geometry=[spatial_extent_geom] + ) - else: - raise TypeError("Your spatial extent type is not an accepted input and a geodataframe cannot be constructed") - #DevNote: can't get test for this else to pass if print the extent_type in the string... - # raise TypeError("Your spatial extent type (" + extent_type + ") is not an accepted input and a geodataframe cannot be constructed") + # DevGoal: Currently this elif isn't tested... + elif extent_type == "polygon" and file == True: + gdf = gpd.read_file(spatial_extent) + + else: + raise TypeError( + "Your spatial extent type is not an accepted input and a geodataframe cannot be constructed" + ) + # DevNote: can't get test for this else to pass if print the extent_type in the string... + # raise TypeError("Your spatial extent type (" + extent_type + ") is not an accepted input and a geodataframe cannot be constructed") - return gdf \ No newline at end of file + return gdf diff --git a/icepyx/core/granules.py b/icepyx/core/granules.py index ee9b80402..a35d53acc 100644 --- a/icepyx/core/granules.py +++ b/icepyx/core/granules.py @@ -10,6 +10,7 @@ import icepyx.core.APIformatting as apifmt + def info(grans): """ Return some basic summary information about a set of granules for an @@ -17,35 +18,36 @@ def info(grans): from NSIDC (for ordering/download) or a list of granules present on the file system. """ - assert len(grans)>0, "Your data object has no granules associated with it" + assert len(grans) > 0, "Your data object has no granules associated with it" gran_info = {} - gran_info.update({'Number of available granules': len(grans)}) + gran_info.update({"Number of available granules": len(grans)}) - gran_sizes = [float(gran['granule_size']) for gran in grans] - gran_info.update({'Average size of granules (MB)': np.mean(gran_sizes)}) - gran_info.update({'Total size of all granules (MB)': sum(gran_sizes)}) + gran_sizes = [float(gran["granule_size"]) for gran in grans] + gran_info.update({"Average size of granules (MB)": np.mean(gran_sizes)}) + gran_info.update({"Total size of all granules (MB)": sum(gran_sizes)}) return gran_info -#DevNote: currently this fn is not tested + +# DevNote: currently this fn is not tested def gran_IDs(grans): """ Returns a list of the granule IDs for the granule dictionary. Granule info may be from a list of those available from NSIDC (for ordering/download) or a list of granules present on the file system. """ - assert len(grans)>0, "Your data object has no granules associated with it" + assert len(grans) > 0, "Your data object has no granules associated with it" gran_ids = [] for gran in grans: - gran_ids.append(gran['producer_granule_id']) - + gran_ids.append(gran["producer_granule_id"]) + return gran_ids -#DevGoal: this will be a great way/place to manage data from the local file system -#where the user already has downloaded data! -#DevNote: currently this class is not tested -class Granules(): +# DevGoal: this will be a great way/place to manage data from the local file system +# where the user already has downloaded data! +# DevNote: currently this class is not tested +class Granules: """ Interact with ICESat-2 data granules. This includes finding, ordering, and downloading them as well as (not yet implemented) getting already @@ -55,7 +57,7 @@ class Granules(): ------- Granules object """ - + def __init__( self, # avail=[], @@ -68,7 +70,7 @@ def __init__( # self.orderIDs = orderIDs # self.files = files # session = session - + # ---------------------------------------------------------------------- # Methods @@ -96,44 +98,59 @@ def get_avail(self, CMRparams, reqparams): icesat2data.Icesat2Data.avail_granules """ - assert CMRparams is not None and reqparams is not None, "Missing required input parameter dictionaries" + assert ( + CMRparams is not None and reqparams is not None + ), "Missing required input parameter dictionaries" - # if not hasattr(self, 'avail'): - self.avail=[] + # if not hasattr(self, 'avail'): + self.avail = [] - granule_search_url = 'https://cmr.earthdata.nasa.gov/search/granules' + granule_search_url = "https://cmr.earthdata.nasa.gov/search/granules" - headers={'Accept': 'application/json'} - #DevGoal: check the below request/response for errors and show them if they're there; then gather the results - #note we should also do this whenever we ping NSIDC-API - make a function to check for errors + headers = {"Accept": "application/json"} + # DevGoal: check the below request/response for errors and show them if they're there; then gather the results + # note we should also do this whenever we ping NSIDC-API - make a function to check for errors while True: - response = requests.get(granule_search_url, headers=headers,\ - params=apifmt.combine_params(CMRparams,\ - {k: reqparams[k] for k in ('page_size','page_num')})) + response = requests.get( + granule_search_url, + headers=headers, + params=apifmt.combine_params( + CMRparams, {k: reqparams[k] for k in ("page_size", "page_num")} + ), + ) results = json.loads(response.content) # print(results) - - if len(results['feed']['entry']) == 0: + + if len(results["feed"]["entry"]) == 0: # Out of results, so break out of loop break # Collect results and increment page_num - self.avail.extend(results['feed']['entry']) - reqparams['page_num'] += 1 + self.avail.extend(results["feed"]["entry"]) + reqparams["page_num"] += 1 - #DevNote: The above calculated page_num is wrong when mod(granule number, page_size)=0. + # DevNote: The above calculated page_num is wrong when mod(granule number, page_size)=0. # print(reqparams['page_num']) - reqparams['page_num'] = int(np.ceil(len(self.avail)/reqparams['page_size'])) - - assert len(self.avail)>0, "Your search returned no results; try different search parameters" - - - #DevNote: currently, default subsetting DOES NOT include variable subsetting, only spatial and temporal - #DevGoal: add kwargs to allow subsetting and more control over request options. - def place_order(self, CMRparams, reqparams, subsetparams, verbose, - subset=True, session=None, geom_filepath=None): #, **kwargs): + reqparams["page_num"] = int(np.ceil(len(self.avail) / reqparams["page_size"])) + + assert ( + len(self.avail) > 0 + ), "Your search returned no results; try different search parameters" + + # DevNote: currently, default subsetting DOES NOT include variable subsetting, only spatial and temporal + # DevGoal: add kwargs to allow subsetting and more control over request options. + def place_order( + self, + CMRparams, + reqparams, + subsetparams, + verbose, + subset=True, + session=None, + geom_filepath=None, + ): # , **kwargs): """ Place an order for the available granules for the icesat2data object. Adds the list of zipped files (orders) to the granules data object (which is @@ -177,135 +194,157 @@ def place_order(self, CMRparams, reqparams, subsetparams, verbose, """ if session is None: - raise ValueError("Don't forget to log in to Earthdata using is2_data.earthdata_login(uid, email)") + raise ValueError( + "Don't forget to log in to Earthdata using is2_data.earthdata_login(uid, email)" + ) - base_url = 'https://n5eil02u.ecs.nsidc.org/egi/request' - #DevGoal: get the base_url from the granules? + base_url = "https://n5eil02u.ecs.nsidc.org/egi/request" + # DevGoal: get the base_url from the granules? - - self.get_avail(CMRparams, reqparams) #this way the reqparams['page_num'] is updated + self.get_avail( + CMRparams, reqparams + ) # this way the reqparams['page_num'] is updated if subset is False: - request_params = apifmt.combine_params(CMRparams, reqparams, {'agent':'NO'}) + request_params = apifmt.combine_params( + CMRparams, reqparams, {"agent": "NO"} + ) else: - request_params = apifmt.combine_params(CMRparams, reqparams, subsetparams) - - order_fn = '.order_restart' - - print('Total number of data order requests is ',request_params['page_num'], ' for ',len(self.avail), ' granules.') - #DevNote/05/27/20/: Their page_num values are the same, but use the combined version anyway. - #I'm switching back to reqparams, because that value is not changed by the for loop. I shouldn't cause an issue either way, but I've had issues with mutable types in for loops elsewhere. - for i in range(reqparams['page_num']): -# for i in range(request_params['page_num']): + request_params = apifmt.combine_params(CMRparams, reqparams, subsetparams) + + order_fn = ".order_restart" + + print( + "Total number of data order requests is ", + request_params["page_num"], + " for ", + len(self.avail), + " granules.", + ) + # DevNote/05/27/20/: Their page_num values are the same, but use the combined version anyway. + # I'm switching back to reqparams, because that value is not changed by the for loop. I shouldn't cause an issue either way, but I've had issues with mutable types in for loops elsewhere. + for i in range(reqparams["page_num"]): + # for i in range(request_params['page_num']): page_val = i + 1 - - print('Data request ', page_val, ' of ', reqparams['page_num'],' is submitting to NSIDC') - request_params.update( {'page_num': page_val} ) - #DevNote: earlier versions of the code used a file upload+post rather than putting the geometries - #into the parameter dictionaries. However, this wasn't working with shapefiles, but this more general - #solution does, so the geospatial parameters are included in the parameter dictionaries. + print( + "Data request ", + page_val, + " of ", + reqparams["page_num"], + " is submitting to NSIDC", + ) + request_params.update({"page_num": page_val}) + + # DevNote: earlier versions of the code used a file upload+post rather than putting the geometries + # into the parameter dictionaries. However, this wasn't working with shapefiles, but this more general + # solution does, so the geospatial parameters are included in the parameter dictionaries. request = session.get(base_url, params=request_params) - - #DevGoal: use the request response/number to do some error handling/give the user better messaging for failures + + # DevGoal: use the request response/number to do some error handling/give the user better messaging for failures # print(request.content) - root=ET.fromstring(request.content) - #print([subset_agent.attrib for subset_agent in root.iter('SubsetAgent')]) + root = ET.fromstring(request.content) + # print([subset_agent.attrib for subset_agent in root.iter('SubsetAgent')]) if verbose is True: - print('Request HTTP response: ', request.status_code) + print("Request HTTP response: ", request.status_code) # print('Order request URL: ', request.url) - # Raise bad request: Loop will stop for bad response code. + # Raise bad request: Loop will stop for bad response code. request.raise_for_status() esir_root = ET.fromstring(request.content) if verbose is True: - print('Order request URL: ', request.url) - print('Order request response XML content: ', request.content) + print("Order request URL: ", request.url) + print("Order request response XML content: ", request.content) - #Look up order ID + # Look up order ID orderlist = [] for order in esir_root.findall("./order/"): # if verbose is True: # print(order) orderlist.append(order.text) orderID = orderlist[0] - print('order ID: ', orderID) + print("order ID: ", orderID) - #Create status URL - statusURL = base_url + '/' + orderID + # Create status URL + statusURL = base_url + "/" + orderID if verbose is True: - print('status URL: ', statusURL) + print("status URL: ", statusURL) - #Find order status + # Find order status request_response = session.get(statusURL) if verbose is True: - print('HTTP response from order response URL: ', request_response.status_code) + print( + "HTTP response from order response URL: ", + request_response.status_code, + ) - # Raise bad request: Loop will stop for bad response code. + # Raise bad request: Loop will stop for bad response code. request_response.raise_for_status() request_root = ET.fromstring(request_response.content) statuslist = [] for status in request_root.findall("./requestStatus/"): statuslist.append(status.text) status = statuslist[0] - print('Initial status of your order request at NSIDC is: ', status) - - #Continue loop while request is still processing - while status == 'pending' or status == 'processing': - print('Your order status is still ', status, ' at NSIDC. Please continue waiting... this may take a few moments.') + print("Initial status of your order request at NSIDC is: ", status) + + # Continue loop while request is still processing + while status == "pending" or status == "processing": + print( + "Your order status is still ", + status, + " at NSIDC. Please continue waiting... this may take a few moments.", + ) # print('Status is not complete. Trying again') time.sleep(10) loop_response = session.get(statusURL) - # Raise bad request: Loop will stop for bad response code. + # Raise bad request: Loop will stop for bad response code. loop_response.raise_for_status() loop_root = ET.fromstring(loop_response.content) - #find status + # find status statuslist = [] for status in loop_root.findall("./requestStatus/"): statuslist.append(status.text) status = statuslist[0] # print('Retry request status is: ', status) - if status == 'pending' or status == 'processing': + if status == "pending" or status == "processing": continue - #Order can either complete, complete_with_errors, or fail: - # Provide complete_with_errors error message: - if status == 'complete_with_errors' or status == 'failed': + # Order can either complete, complete_with_errors, or fail: + # Provide complete_with_errors error message: + if status == "complete_with_errors" or status == "failed": messagelist = [] for message in loop_root.findall("./processInfo/"): messagelist.append(message.text) - print('Your order is: ', status) - print('NSIDC provided these error messages:') + print("Your order is: ", status) + print("NSIDC provided these error messages:") pprint.pprint(messagelist) - if status == 'complete' or status == 'complete_with_errors': - print('Your order is:', status) - if not hasattr(self,'orderIDs'): - self.orderIDs=[] + if status == "complete" or status == "complete_with_errors": + print("Your order is:", status) + if not hasattr(self, "orderIDs"): + self.orderIDs = [] self.orderIDs.append(orderID) - else: print('Request failed.') - - #DevGoal: save orderIDs more frequently than just at the end for large orders (e.g. for len(reqparams['page_num']) > 5 or 10 or something) - #Save orderIDs to file to avoid resubmitting order in case kernel breaks down. - # save orderIDs for every 5 orders when more than 10 orders are submitted. - # DevNote: These numbers are hard coded for now. Consider to allow user to set them in future? - if reqparams['page_num']>=10 and i%5==0: - with open(order_fn,'w') as fid: - json.dump({'orderIDs':self.orderIDs},fid) - - # --- Output the final orderIDs - with open(order_fn,'w') as fid: - json.dump({'orderIDs':self.orderIDs},fid) + else: + print("Request failed.") + # DevGoal: save orderIDs more frequently than just at the end for large orders (e.g. for len(reqparams['page_num']) > 5 or 10 or something) + # Save orderIDs to file to avoid resubmitting order in case kernel breaks down. + # save orderIDs for every 5 orders when more than 10 orders are submitted. + # DevNote: These numbers are hard coded for now. Consider to allow user to set them in future? + if reqparams["page_num"] >= 10 and i % 5 == 0: + with open(order_fn, "w") as fid: + json.dump({"orderIDs": self.orderIDs}, fid) + # --- Output the final orderIDs + with open(order_fn, "w") as fid: + json.dump({"orderIDs": self.orderIDs}, fid) return self.orderIDs - def download(self, verbose, path, session=None, restart=False): """ Downloads the data for the object's orderIDs, which are generated by ordering data @@ -341,64 +380,74 @@ def download(self, verbose, path, session=None, restart=False): Unzip the downloaded granules. """ - #Note: need to test these checks still + # Note: need to test these checks still if session is None: - raise ValueError("Don't forget to log in to Earthdata using is2_data.earthdata_login(uid, email)") - #DevGoal: make this a more robust check for an active session - - #DevNote: this will replace any existing orderIDs with the saved list (could create confusion depending on whether download was interrupted or kernel restarted) - order_fn = '.order_restart' - if os.path.exists( order_fn ): - with open(order_fn,'r') as fid: + raise ValueError( + "Don't forget to log in to Earthdata using is2_data.earthdata_login(uid, email)" + ) + # DevGoal: make this a more robust check for an active session + + # DevNote: this will replace any existing orderIDs with the saved list (could create confusion depending on whether download was interrupted or kernel restarted) + order_fn = ".order_restart" + if os.path.exists(order_fn): + with open(order_fn, "r") as fid: order_dat = json.load(fid) - self.orderIDs = order_dat['orderIDs'] - - if not hasattr(self,'orderIDs') or len(self.orderIDs)==0: - raise ValueError('Please confirm that you have submitted a valid order and it has successfully completed.') - - #DevNote: Temporary. Hard code the orderID info files here. order_fn should be consistent with place_order. - - downid_fn = '.download_ID' - + self.orderIDs = order_dat["orderIDs"] + + if not hasattr(self, "orderIDs") or len(self.orderIDs) == 0: + raise ValueError( + "Please confirm that you have submitted a valid order and it has successfully completed." + ) + + # DevNote: Temporary. Hard code the orderID info files here. order_fn should be consistent with place_order. + + downid_fn = ".download_ID" + i_order = 0 - - if restart: - print('Restarting download ... ') - - # --- update the starting point of download list - if os.path.exists( downid_fn ): - order_start = str(int( np.loadtxt(downid_fn) ) ) - i_order = self.orderIDs.index(order_start) + 1 - + + if restart: + print("Restarting download ... ") + + # --- update the starting point of download list + if os.path.exists(downid_fn): + order_start = str(int(np.loadtxt(downid_fn))) + i_order = self.orderIDs.index(order_start) + 1 + for order in self.orderIDs[i_order:]: - downloadURL = 'https://n5eil02u.ecs.nsidc.org/esir/' + order + '.zip' - #DevGoal: get the download_url from the granules + downloadURL = "https://n5eil02u.ecs.nsidc.org/esir/" + order + ".zip" + # DevGoal: get the download_url from the granules - if verbose is True: - print('Zip download URL: ', downloadURL) - print('Beginning download of zipped output...') + print("Zip download URL: ", downloadURL) + print("Beginning download of zipped output...") zip_response = session.get(downloadURL) # Raise bad request: Loop will stop for bad response code. zip_response.raise_for_status() - print('Data request', order, 'of ', len(self.orderIDs[i_order:]), ' order(s) is downloaded.') - - #DevGoal: move this option back out to the is2class level and implement it in an alternate way? - # #Note: extract the dataset to save it locally - # if extract is True: + print( + "Data request", + order, + "of ", + len(self.orderIDs[i_order:]), + " order(s) is downloaded.", + ) + + # DevGoal: move this option back out to the is2class level and implement it in an alternate way? + # #Note: extract the dataset to save it locally + # if extract is True: with zipfile.ZipFile(io.BytesIO(zip_response.content)) as z: for zfile in z.filelist: # Remove the subfolder name from the filepath zfile.filename = os.path.basename(zfile.filename) z.extract(member=zfile, path=path) - + # update the current finished order id and save to file - with open(downid_fn,'w') as fid: - fid.write( order ) - - # remove orderID and download id files at the end - if os.path.exists( order_fn ): os.remove(order_fn) - if os.path.exists( downid_fn ): os.remove(downid_fn) - - print('Download complete') - \ No newline at end of file + with open(downid_fn, "w") as fid: + fid.write(order) + + # remove orderID and download id files at the end + if os.path.exists(order_fn): + os.remove(order_fn) + if os.path.exists(downid_fn): + os.remove(downid_fn) + + print("Download complete") diff --git a/icepyx/core/icesat2data.py b/icepyx/core/icesat2data.py index f8a7e36e1..217f41239 100644 --- a/icepyx/core/icesat2data.py +++ b/icepyx/core/icesat2data.py @@ -13,16 +13,17 @@ import icepyx.core.is2ref as is2ref import icepyx.core.granules as granules from icepyx.core.granules import Granules as Granules -#QUESTION: why doesn't from granules import Granules as Granules work, since granules=icepyx.core.granules? + +# QUESTION: why doesn't from granules import Granules as Granules work, since granules=icepyx.core.granules? # from icepyx.core.granules import Granules from icepyx.core.variables import Variables as Variables import icepyx.core.geospatial as geospatial import icepyx.core.validate_inputs as val -#DevGoal: update docs throughout to allow for polygon spatial extent -#Note: add files to docstring once implemented -#DevNote: currently this class is not tested -class Icesat2Data(): +# DevGoal: update docs throughout to allow for polygon spatial extent +# Note: add files to docstring once implemented +# DevNote: currently this class is not tested +class Icesat2Data: """ ICESat-2 Data object to query, obtain, and perform basic operations on available ICESat-2 datasets using temporal and spatial input parameters. @@ -96,43 +97,47 @@ class Icesat2Data(): """ - # ---------------------------------------------------------------------- # Constructors def __init__( self, - dataset = None, - spatial_extent = None, - date_range = None, - start_time = None, - end_time = None, - version = None, - files = None, + dataset=None, + spatial_extent=None, + date_range=None, + start_time=None, + end_time=None, + version=None, + files=None, ): # warnings.filterwarnings("always") # warnings.warn("Please note: as of 2020-05-05, a major reorganization of the core icepyx.icesat2data code may result in errors produced by now depricated functions. Please see our documentation pages or example notebooks for updates.") - - if (dataset is None or spatial_extent is None or date_range is None) and files is None: - raise ValueError("Please provide the required inputs. Use help([function]) to view the function's documentation") + + if ( + dataset is None or spatial_extent is None or date_range is None + ) and files is None: + raise ValueError( + "Please provide the required inputs. Use help([function]) to view the function's documentation" + ) if files is not None: - self._source = 'files' + self._source = "files" # self.file_vars = Variables(self._source) else: - self._source = 'order' + self._source = "order" # self.order_vars = Variables(self._source) # self.variables = Variables(self._source) self._dset = is2ref._validate_dataset(dataset) - self.extent_type, self._spat_extent, self._geom_filepath = val.spatial(spatial_extent) + self.extent_type, self._spat_extent, self._geom_filepath = val.spatial( + spatial_extent + ) self._start, self._end = val.temporal(date_range, start_time, end_time) - + self._version = val.dset_version(self.latest_version(), version) - # ---------------------------------------------------------------------- # Properties @@ -187,15 +192,14 @@ def spatial_extent(self): ['polygon', [-55.0, 68.0, -55.0, 71.0, -48.0, 71.0, -48.0, 68.0, -55.0, 68.0]] """ - - if self.extent_type == 'bounding_box': - return ['bounding box', self._spat_extent] - elif self.extent_type == 'polygon': + if self.extent_type == "bounding_box": + return ["bounding box", self._spat_extent] + elif self.extent_type == "polygon": # return ['polygon', self._spat_extent] # Note: self._spat_extent is a shapely geometry object - return ['polygon', self._spat_extent.exterior.coords.xy] + return ["polygon", self._spat_extent.exterior.coords.xy] else: - return ['unknown spatial type', None] + return ["unknown spatial type", None] @property def dates(self): @@ -209,7 +213,10 @@ def dates(self): >>> reg_a.dates ['2019-02-20', '2019-02-28'] """ - return [self._start.strftime('%Y-%m-%d'), self._end.strftime('%Y-%m-%d')] #could also use self._start.date() + return [ + self._start.strftime("%Y-%m-%d"), + self._end.strftime("%Y-%m-%d"), + ] # could also use self._start.date() @property def start_time(self): @@ -226,7 +233,7 @@ def start_time(self): >>> reg_a.start_time '12:30:30' """ - return self._start.strftime('%H:%M:%S') + return self._start.strftime("%H:%M:%S") @property def end_time(self): @@ -243,7 +250,7 @@ def end_time(self): >>> reg_a.end_time '10:20:20' """ - return self._end.strftime('%H:%M:%S') + return self._end.strftime("%H:%M:%S") @property def CMRparams(self): @@ -260,14 +267,20 @@ def CMRparams(self): 'bounding_box': '-55,68,-48,71'} """ - if not hasattr(self, '_CMRparams'): - self._CMRparams = apifmt.Parameters('CMR') + if not hasattr(self, "_CMRparams"): + self._CMRparams = apifmt.Parameters("CMR") # print(self._CMRparams) # print(self._CMRparams.fmted_keys) if self._CMRparams.fmted_keys == {}: - self._CMRparams.build_params(dataset=self.dataset, version=self._version,\ - start=self._start, end=self._end, extent_type=self.extent_type, spatial_extent=self._spat_extent) + self._CMRparams.build_params( + dataset=self.dataset, + version=self._version, + start=self._start, + end=self._end, + extent_type=self.extent_type, + spatial_extent=self._spat_extent, + ) return self._CMRparams.fmted_keys @@ -290,14 +303,14 @@ def reqparams(self): {'page_size': 10, 'page_num': 1, 'request_mode': 'async', 'include_meta': 'Y'} """ - if not hasattr(self, '_reqparams'): - self._reqparams = apifmt.Parameters('required', reqtype='search') + if not hasattr(self, "_reqparams"): + self._reqparams = apifmt.Parameters("required", reqtype="search") self._reqparams.build_params() - + return self._reqparams.fmted_keys # @property - #DevQuestion: if I make this a property, I get a "dict" object is not callable when I try to give input kwargs... what approach should I be taking? + # DevQuestion: if I make this a property, I get a "dict" object is not callable when I try to give input kwargs... what approach should I be taking? def subsetparams(self, **kwargs): """ Display the subsetting key:value pairs that will be submitted. It generates the dictionary if it does not already exist @@ -321,24 +334,36 @@ def subsetparams(self, **kwargs): >>> reg_a.subsetparams() {'time': '2019-02-20T00:00:00,2019-02-28T23:59:59', 'bbox': '-55,68,-48,71'} """ - if not hasattr(self, '_subsetparams'): self._subsetparams = apifmt.Parameters('subset') - - if self._subsetparams==None and not kwargs: + if not hasattr(self, "_subsetparams"): + self._subsetparams = apifmt.Parameters("subset") + + if self._subsetparams == None and not kwargs: return {} else: - if self._subsetparams==None: self._subsetparams = apifmt.Parameters('subset') + if self._subsetparams == None: + self._subsetparams = apifmt.Parameters("subset") if self._geom_filepath is not None: - self._subsetparams.build_params(geom_filepath = self._geom_filepath, \ - start=self._start, end=self._end, extent_type=self.extent_type, \ - spatial_extent=self._spat_extent, **kwargs) + self._subsetparams.build_params( + geom_filepath=self._geom_filepath, + start=self._start, + end=self._end, + extent_type=self.extent_type, + spatial_extent=self._spat_extent, + **kwargs, + ) else: - self._subsetparams.build_params(start=self._start, end=self._end,\ - extent_type=self.extent_type, spatial_extent=self._spat_extent, **kwargs) + self._subsetparams.build_params( + start=self._start, + end=self._end, + extent_type=self.extent_type, + spatial_extent=self._spat_extent, + **kwargs, + ) return self._subsetparams.fmted_keys - - #DevGoal: add to tests - #DevGoal: add statements to the following vars properties to let the user know if they've got a mismatched source and vars type + + # DevGoal: add to tests + # DevGoal: add statements to the following vars properties to let the user know if they've got a mismatched source and vars type @property def order_vars(self): """ @@ -357,24 +382,33 @@ def order_vars(self): >>> reg_a.order_vars """ - - if not hasattr(self, '_order_vars'): - if self._source == 'order': - #DevGoal: check for active session here - if hasattr(self, '_cust_options'): - self._order_vars = Variables(self._source, session=self._session, dataset=self.dataset, avail=self._cust_options['variables']) - else: - self._order_vars = Variables(self._source, session=self._session, dataset=self.dataset, version=self._version) - # I think this is where property setters come in, and one should be used here? Right now order_vars.avail is only filled in - #if _cust_options exists when the class is initialized, but not if _cust_options is filled in prior to another call to order_vars + if not hasattr(self, "_order_vars"): + if self._source == "order": + # DevGoal: check for active session here + if hasattr(self, "_cust_options"): + self._order_vars = Variables( + self._source, + session=self._session, + dataset=self.dataset, + avail=self._cust_options["variables"], + ) + else: + self._order_vars = Variables( + self._source, + session=self._session, + dataset=self.dataset, + version=self._version, + ) + + # I think this is where property setters come in, and one should be used here? Right now order_vars.avail is only filled in + # if _cust_options exists when the class is initialized, but not if _cust_options is filled in prior to another call to order_vars # if self._order_vars.avail == None and hasattr(self, '_cust_options'): # print('got into the loop') # self._order_vars.avail = self._cust_options['variables'] return self._order_vars - @property def file_vars(self): """ @@ -393,9 +427,9 @@ def file_vars(self): >>> reg_a.file_vars """ - - if not hasattr(self, '_file_vars'): - if self._source == 'file': + + if not hasattr(self, "_file_vars"): + if self._source == "file": self._file_vars = Variables(self._source, dataset=self.dataset) return self._file_vars @@ -421,13 +455,12 @@ def granules(self): """ - if not hasattr(self, '_granules'): + if not hasattr(self, "_granules"): self._granules = Granules() - elif self._granules==None: + elif self._granules == None: self._granules = Granules() - - return self._granules + return self._granules # ---------------------------------------------------------------------- # Methods - Get and display neatly information at the dataset level @@ -449,10 +482,19 @@ def dataset_summary_info(self): summary : This data set (ATL06) provides geolocated, land-ice surface heights (above the WGS 84 ellipsoid, ITRF2014 reference frame), plus ancillary parameters that can be used to interpret and assess the quality of the height estimates. The data were acquired by the Advanced Topographic Laser Altimeter System (ATLAS) instrument on board the Ice, Cloud and land Elevation Satellite-2 (ICESat-2) observatory. orbit_parameters : {'swath_width': '36.0', 'period': '94.29', 'inclination_angle': '92.0', 'number_of_orbits': '0.071428571', 'start_circular_latitude': '0.0'} """ - if not hasattr(self, '_about_dataset'): self._about_dataset=is2data(self._dset) - summ_keys = ['dataset_id', 'short_name', 'version_id', 'time_start', 'coordinate_system', 'summary', 'orbit_parameters'] + if not hasattr(self, "_about_dataset"): + self._about_dataset = is2data(self._dset) + summ_keys = [ + "dataset_id", + "short_name", + "version_id", + "time_start", + "coordinate_system", + "summary", + "orbit_parameters", + ] for key in summ_keys: - print(key,': ',self._about_dataset['feed']['entry'][-1][key]) + print(key, ": ", self._about_dataset["feed"]["entry"][-1][key]) def dataset_all_info(self): """ @@ -465,7 +507,8 @@ def dataset_all_info(self): {very long prettily-formatted dictionary output} """ - if not hasattr(self, '_about_dataset'): self._about_dataset=is2data(self._dset) + if not hasattr(self, "_about_dataset"): + self._about_dataset = is2data(self._dset) pprint.pprint(self._about_dataset) def latest_version(self): @@ -478,8 +521,11 @@ def latest_version(self): >>> reg_a.latest_version() '003' """ - if not hasattr(self, '_about_dataset'): self._about_dataset=is2ref.about_dataset(self._dset) - return max([entry['version_id'] for entry in self._about_dataset['feed']['entry']]) + if not hasattr(self, "_about_dataset"): + self._about_dataset = is2ref.about_dataset(self._dset) + return max( + [entry["version_id"] for entry in self._about_dataset["feed"]["entry"]] + ) def show_custom_options(self, dictview=False): """ @@ -523,31 +569,42 @@ def show_custom_options(self, dictview=False): . 'quality_assessment/gt3r/signal_selection_source_fraction_3'] """ - headers=['Subsetting options', 'Data File Formats (Reformatting Options)', 'Reprojection Options', - 'Data File (Reformatting) Options Supporting Reprojection', - 'Data File (Reformatting) Options NOT Supporting Reprojection', - 'Data Variables (also Subsettable)'] - keys=['options', 'fileformats', 'reprojectionONLY', 'formatreproj', 'noproj', 'variables'] + headers = [ + "Subsetting options", + "Data File Formats (Reformatting Options)", + "Reprojection Options", + "Data File (Reformatting) Options Supporting Reprojection", + "Data File (Reformatting) Options NOT Supporting Reprojection", + "Data Variables (also Subsettable)", + ] + keys = [ + "options", + "fileformats", + "reprojectionONLY", + "formatreproj", + "noproj", + "variables", + ] try: all(key in self._cust_options.keys() for key in keys) except AttributeError or KeyError: - self._cust_options=is2ref._get_custom_options(self._session, self.dataset, self._version) + self._cust_options = is2ref._get_custom_options( + self._session, self.dataset, self._version + ) - for h,k in zip(headers,keys): + for h, k in zip(headers, keys): print(h) - if k=='variables' and dictview: - vgrp,paths = Variables.parse_var_list(self._cust_options[k]) + if k == "variables" and dictview: + vgrp, paths = Variables.parse_var_list(self._cust_options[k]) pprint.pprint(vgrp) else: pprint.pprint(self._cust_options[k]) - - # ---------------------------------------------------------------------- # Methods - Login and Granules (NSIDC-API) - def earthdata_login(self,uid,email): + def earthdata_login(self, uid, email): """ Log in to NSIDC EarthData to access data. Generates the needed session and token for most data searches and data ordering/download. @@ -569,12 +626,12 @@ def earthdata_login(self,uid,email): >>> reg_a.earthdata_login(user_id,user_email) Earthdata Login password: ········ """ - - capability_url = f'https://n5eil02u.ecs.nsidc.org/egi/capabilities/{self.dataset}.{self._version}.xml' - self._session = Earthdata(uid,email,capability_url).login() + + capability_url = f"https://n5eil02u.ecs.nsidc.org/egi/capabilities/{self.dataset}.{self._version}.xml" + self._session = Earthdata(uid, email, capability_url).login() self._email = email - #DevGoal: check to make sure the see also bits of the docstrings work properly in RTD + # DevGoal: check to make sure the see also bits of the docstrings work properly in RTD def avail_granules(self, ids=False): """ Obtain information about the available granules for the icesat2data @@ -600,23 +657,22 @@ def avail_granules(self, ids=False): >>> reg_a.avail_granules(ids=True) """ - -# REFACTOR: add test to make sure there's a session - if not hasattr(self, '_granules'): self.granules - try: self.granules.avail + + # REFACTOR: add test to make sure there's a session + if not hasattr(self, "_granules"): + self.granules + try: + self.granules.avail except AttributeError: - self.granules.get_avail(self.CMRparams,self.reqparams) + self.granules.get_avail(self.CMRparams, self.reqparams) - if ids==True: + if ids == True: return granules.gran_IDs(self.granules.avail) else: return granules.info(self.granules.avail) - - - - #DevGoal: display output to indicate number of granules successfully ordered (and number of errors) - #DevGoal: deal with subset=True for variables now, and make sure that if a variable subset Coverage kwarg is input it's successfully passed through all other functions even if this is the only one run. + # DevGoal: display output to indicate number of granules successfully ordered (and number of errors) + # DevGoal: deal with subset=True for variables now, and make sure that if a variable subset Coverage kwarg is input it's successfully passed through all other functions even if this is the only one run. def order_granules(self, verbose=False, subset=True, email=True, **kwargs): """ Place an order for the available granules for the icesat2data object. @@ -660,31 +716,46 @@ def order_granules(self, verbose=False, subset=True, email=True, **kwargs): . Retry request status is: complete """ - - if not hasattr(self, 'reqparams'): self.reqparams - - if self._reqparams._reqtype == 'search': - self._reqparams._reqtype = 'download' - - if 'email' in self._reqparams.fmted_keys.keys() or email==False: + if not hasattr(self, "reqparams"): + self.reqparams + + if self._reqparams._reqtype == "search": + self._reqparams._reqtype = "download" + + if "email" in self._reqparams.fmted_keys.keys() or email == False: self._reqparams.build_params(**self._reqparams.fmted_keys) else: - self._reqparams.build_params(**self._reqparams.fmted_keys, email=self._email) - + self._reqparams.build_params( + **self._reqparams.fmted_keys, email=self._email + ) if subset is False: - self._subsetparams=None - elif subset==True and hasattr(self, '_subsetparams') and self._subsetparams==None: + self._subsetparams = None + elif ( + subset == True + and hasattr(self, "_subsetparams") + and self._subsetparams == None + ): del self._subsetparams - - #REFACTOR: add checks here to see if the granules object has been created, and also if it already has a list of avail granules (if not, need to create one and add session) - if not hasattr(self, '_granules'): self.granules - self._granules.place_order(self.CMRparams, self.reqparams, self.subsetparams(**kwargs), verbose, subset, session=self._session, geom_filepath=self._geom_filepath) - - #DevGoal: put back in the kwargs here so that people can just call download granules with subset=False! - def download_granules(self, path, verbose=False, subset=True, restart=False, **kwargs): #, extract=False): + # REFACTOR: add checks here to see if the granules object has been created, and also if it already has a list of avail granules (if not, need to create one and add session) + if not hasattr(self, "_granules"): + self.granules + self._granules.place_order( + self.CMRparams, + self.reqparams, + self.subsetparams(**kwargs), + verbose, + subset, + session=self._session, + geom_filepath=self._geom_filepath, + ) + + # DevGoal: put back in the kwargs here so that people can just call download granules with subset=False! + def download_granules( + self, path, verbose=False, subset=True, restart=False, **kwargs + ): # , extract=False): """ Downloads the data ordered using order_granules. @@ -727,26 +798,32 @@ def download_granules(self, path, verbose=False, subset=True, restart=False, **k Beginning download of zipped output... Data request [##########] of x order(s) is complete. """ - + # if not os.path.exists(path): # os.mkdir(path) # os.chdir(path) - if not hasattr(self, '_granules'): self.granules - + if not hasattr(self, "_granules"): + self.granules + if restart == True: pass else: - if not hasattr(self._granules, 'orderIDs') or len(self._granules.orderIDs)==0: self.order_granules(verbose=verbose, subset=subset, **kwargs) - + if ( + not hasattr(self._granules, "orderIDs") + or len(self._granules.orderIDs) == 0 + ): + self.order_granules(verbose=verbose, subset=subset, **kwargs) + self._granules.download(verbose, path, session=self._session, restart=restart) - - - #DevGoal: add testing? What do we test, and how, given this is a visualization. - #DevGoal(long term): modify this to accept additional inputs, etc. - #DevGoal: move this to it's own module for visualizing, etc. - #DevGoal: see Amy's data access notebook for a zoomed in map - implement here? - def visualize_spatial_extent(self): #additional args, basemap, zoom level, cmap, export + + # DevGoal: add testing? What do we test, and how, given this is a visualization. + # DevGoal(long term): modify this to accept additional inputs, etc. + # DevGoal: move this to it's own module for visualizing, etc. + # DevGoal: see Amy's data access notebook for a zoomed in map - implement here? + def visualize_spatial_extent( + self, + ): # additional args, basemap, zoom level, cmap, export """ Creates a map displaying the input spatial extent @@ -757,8 +834,10 @@ def visualize_spatial_extent(self): #additional args, basemap, zoom level, cmap, [visual map output] """ - world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) + world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")) f, ax = plt.subplots(1, figsize=(12, 6)) - world.plot(ax=ax, facecolor='lightgray', edgecolor='gray') - geospatial.geodataframe(self.extent_type,self._spat_extent).plot(ax=ax, color='#FF8C00',alpha = 0.7) + world.plot(ax=ax, facecolor="lightgray", edgecolor="gray") + geospatial.geodataframe(self.extent_type, self._spat_extent).plot( + ax=ax, color="#FF8C00", alpha=0.7 + ) plt.show() diff --git a/icepyx/core/is2ref.py b/icepyx/core/is2ref.py index 0bd9cca56..cb407a190 100644 --- a/icepyx/core/is2ref.py +++ b/icepyx/core/is2ref.py @@ -4,8 +4,9 @@ import icepyx -#ICESat-2 specific reference functions -#options to get customization options for ICESat-2 data (though could be used generally) +# ICESat-2 specific reference functions +# options to get customization options for ICESat-2 data (though could be used generally) + def _validate_dataset(dataset): """ @@ -13,15 +14,27 @@ def _validate_dataset(dataset): """ if isinstance(dataset, str): dataset = str.upper(dataset) - assert dataset in ['ATL01','ATL02', 'ATL03', 'ATL04','ATL06', 'ATL07', 'ATL08', 'ATL09', 'ATL10', \ - 'ATL12', 'ATL13'],\ - "Please enter a valid dataset" + assert dataset in [ + "ATL01", + "ATL02", + "ATL03", + "ATL04", + "ATL06", + "ATL07", + "ATL08", + "ATL09", + "ATL10", + "ATL12", + "ATL13", + ], "Please enter a valid dataset" else: raise TypeError("Please enter a dataset string") return dataset -#DevGoal: See if there's a way to dynamically get this list so it's automatically updated - -#DevNote: test for this function is commented out; dates in some of the values were causing the test to fail... + + +# DevGoal: See if there's a way to dynamically get this list so it's automatically updated + +# DevNote: test for this function is commented out; dates in some of the values were causing the test to fail... def about_dataset(dset): """ Ping Earthdata to get metadata about the dataset of interest (the collection). @@ -31,109 +44,174 @@ def about_dataset(dset): icesat2data.Icesat2Data.dataset_all_info """ - cmr_collections_url = 'https://cmr.earthdata.nasa.gov/search/collections.json' - response = requests.get(cmr_collections_url, params={'short_name': dset}) + cmr_collections_url = "https://cmr.earthdata.nasa.gov/search/collections.json" + response = requests.get(cmr_collections_url, params={"short_name": dset}) results = json.loads(response.content) return results -#DevGoal: use a mock of this output to test later functions, such as displaying options and widgets, etc. +# DevGoal: use a mock of this output to test later functions, such as displaying options and widgets, etc. def _get_custom_options(session, dataset, version): """ Get lists of what customization options are available for the dataset from NSIDC. """ - cust_options={} - + cust_options = {} + if session is None: - raise ValueError("Don't forget to log in to Earthdata using is2_data.earthdata_login(uid, email)") + raise ValueError( + "Don't forget to log in to Earthdata using is2_data.earthdata_login(uid, email)" + ) - capability_url = f'https://n5eil02u.ecs.nsidc.org/egi/capabilities/{dataset}.{version}.xml' + capability_url = ( + f"https://n5eil02u.ecs.nsidc.org/egi/capabilities/{dataset}.{version}.xml" + ) response = session.get(capability_url) root = ET.fromstring(response.content) # collect lists with each service option - subagent = [subset_agent.attrib for subset_agent in root.iter('SubsetAgent')] - cust_options.update({'options':subagent}) + subagent = [subset_agent.attrib for subset_agent in root.iter("SubsetAgent")] + cust_options.update({"options": subagent}) # reformatting - formats = [Format.attrib for Format in root.iter('Format')] - format_vals = [formats[i]['value'] for i in range(len(formats))] - format_vals.remove('') - cust_options.update({'fileformats':format_vals}) + formats = [Format.attrib for Format in root.iter("Format")] + format_vals = [formats[i]["value"] for i in range(len(formats))] + format_vals.remove("") + cust_options.update({"fileformats": format_vals}) # reprojection only applicable on ICESat-2 L3B products, yet to be available. # reformatting options that support reprojection - normalproj = [Projections.attrib for Projections in root.iter('Projections')] + normalproj = [Projections.attrib for Projections in root.iter("Projections")] normalproj_vals = [] - normalproj_vals.append(normalproj[0]['normalProj']) - format_proj = normalproj_vals[0].split(',') - format_proj.remove('') - format_proj.append('No reformatting') - cust_options.update({'formatreproj':format_proj}) - - #reprojection options - projections = [Projection.attrib for Projection in root.iter('Projection')] + normalproj_vals.append(normalproj[0]["normalProj"]) + format_proj = normalproj_vals[0].split(",") + format_proj.remove("") + format_proj.append("No reformatting") + cust_options.update({"formatreproj": format_proj}) + + # reprojection options + projections = [Projection.attrib for Projection in root.iter("Projection")] proj_vals = [] for i in range(len(projections)): - if (projections[i]['value']) != 'NO_CHANGE' : - proj_vals.append(projections[i]['value']) - cust_options.update({'reprojectionONLY':proj_vals}) + if (projections[i]["value"]) != "NO_CHANGE": + proj_vals.append(projections[i]["value"]) + cust_options.update({"reprojectionONLY": proj_vals}) # reformatting options that do not support reprojection no_proj = [i for i in format_vals if i not in format_proj] - cust_options.update({'noproj':no_proj}) + cust_options.update({"noproj": no_proj}) # variable subsetting - vars_raw = [] + vars_raw = [] + def get_varlist(elem): childlist = list(elem) - if len(childlist)==0 and elem.tag=='SubsetVariable': - vars_raw.append(elem.attrib['value']) + if len(childlist) == 0 and elem.tag == "SubsetVariable": + vars_raw.append(elem.attrib["value"]) for child in childlist: get_varlist(child) + get_varlist(root) - vars_vals = [v.replace(':', '/') if v.startswith('/') == False else v.replace('/:','') for v in vars_raw] - cust_options.update({'variables':vars_vals}) + vars_vals = [ + v.replace(":", "/") if v.startswith("/") == False else v.replace("/:", "") + for v in vars_raw + ] + cust_options.update({"variables": vars_vals}) return cust_options -#DevGoal: populate this with default variable lists for all of the datasets! -#DevGoal: add a test for this function (to make sure it returns the right list, but also to deal with dataset not being in the list, though it should since it was checked as valid earlier...) + +# DevGoal: populate this with default variable lists for all of the datasets! +# DevGoal: add a test for this function (to make sure it returns the right list, but also to deal with dataset not being in the list, though it should since it was checked as valid earlier...) def _default_varlists(dataset): """ Return a list of default variables to select and send to the NSIDC subsetter. """ - common_list = ['delta_time','latitude','longitude'] - - if dataset == 'ATL06': - return common_list + ['h_li','h_li_sigma','atl06_quality_summary','segment_id','sigma_geo_h', - 'x_atc', 'y_atc','seg_azimuth','sigma_geo_at','sigma_geo_xt', 'dh_fit_dx','dh_fit_dx_sigma', - 'h_mean', 'dh_fit_dy','h_rms_misfit','h_robust_sprd','n_fit_photons','signal_selection_source', - 'snr_significance','w_surface_window_final','bsnow_conf','bsnow_h','cloud_flg_asr', - 'cloud_flg_atm','r_eff','tide_ocean'] - - - elif dataset == 'ATL07': - return common_list + ['seg_dist_x', - 'height_segment_height','height_segment_length_seg','height_segment_ssh_flag', - 'height_segment_type', 'height_segment_quality', 'height_segment_confidence' ] - - - elif dataset == 'ATL09': - return common_list + ['bsnow_h','bsnow_dens','bsnow_con','bsnow_psc','bsnow_od', - 'cloud_flag_asr','cloud_fold_flag','cloud_flag_atm', - 'column_od_asr','column_od_asr_qf', - 'layer_attr','layer_bot','layer_top','layer_flag','layer_dens','layer_ib', - 'msw_flag','prof_dist_x','prof_dist_y','apparent_surf_reflec'] - - - elif dataset == 'ATL10': - return common_list + ['seg_dist_x','lead_height','lead_length', - 'beam_fb_height', 'beam_fb_length', 'beam_fb_confidence', 'beam_fb_quality_flag', - 'height_segment_height','height_segment_length_seg','height_segment_ssh_flag', - 'height_segment_type', 'height_segment_confidence'] + common_list = ["delta_time", "latitude", "longitude"] + + if dataset == "ATL06": + return common_list + [ + "h_li", + "h_li_sigma", + "atl06_quality_summary", + "segment_id", + "sigma_geo_h", + "x_atc", + "y_atc", + "seg_azimuth", + "sigma_geo_at", + "sigma_geo_xt", + "dh_fit_dx", + "dh_fit_dx_sigma", + "h_mean", + "dh_fit_dy", + "h_rms_misfit", + "h_robust_sprd", + "n_fit_photons", + "signal_selection_source", + "snr_significance", + "w_surface_window_final", + "bsnow_conf", + "bsnow_h", + "cloud_flg_asr", + "cloud_flg_atm", + "r_eff", + "tide_ocean", + ] + + elif dataset == "ATL07": + return common_list + [ + "seg_dist_x", + "height_segment_height", + "height_segment_length_seg", + "height_segment_ssh_flag", + "height_segment_type", + "height_segment_quality", + "height_segment_confidence", + ] + + elif dataset == "ATL09": + return common_list + [ + "bsnow_h", + "bsnow_dens", + "bsnow_con", + "bsnow_psc", + "bsnow_od", + "cloud_flag_asr", + "cloud_fold_flag", + "cloud_flag_atm", + "column_od_asr", + "column_od_asr_qf", + "layer_attr", + "layer_bot", + "layer_top", + "layer_flag", + "layer_dens", + "layer_ib", + "msw_flag", + "prof_dist_x", + "prof_dist_y", + "apparent_surf_reflec", + ] + + elif dataset == "ATL10": + return common_list + [ + "seg_dist_x", + "lead_height", + "lead_length", + "beam_fb_height", + "beam_fb_length", + "beam_fb_confidence", + "beam_fb_quality_flag", + "height_segment_height", + "height_segment_length_seg", + "height_segment_ssh_flag", + "height_segment_type", + "height_segment_confidence", + ] else: - print("THE REQUESTED DATASET DOES NOT YET HAVE A DEFAULT LIST SET UP. ONLY DELTA_TIME, LATITUTDE, AND LONGITUDE WILL BE RETURNED") - return common_list \ No newline at end of file + print( + "THE REQUESTED DATASET DOES NOT YET HAVE A DEFAULT LIST SET UP. ONLY DELTA_TIME, LATITUTDE, AND LONGITUDE WILL BE RETURNED" + ) + return common_list diff --git a/icepyx/core/validate_inputs.py b/icepyx/core/validate_inputs.py index eb1420608..149796c17 100644 --- a/icepyx/core/validate_inputs.py +++ b/icepyx/core/validate_inputs.py @@ -6,6 +6,7 @@ import icepyx.core.APIformatting as apifmt import icepyx.core.geospatial as geospatial + def dset_version(latest_vers, version): """ Check if the submitted dataset version is valid, and warn the user if a newer version is available. @@ -14,7 +15,7 @@ def dset_version(latest_vers, version): vers = latest_vers else: if isinstance(version, str): - assert int(version)>0, "Version number must be positive" + assert int(version) > 0, "Version number must be positive" vers_length = 3 vers = version.zfill(vers_length) else: @@ -23,35 +24,51 @@ def dset_version(latest_vers, version): if int(vers) < int(latest_vers): warnings.filterwarnings("always") warnings.warn("You are using an old version of this dataset") - + return vers -#DevGoal: clean up; turn into classes (see validate_inputs_classes.py) +# DevGoal: clean up; turn into classes (see validate_inputs_classes.py) def spatial(spatial_extent): """ Validate the input spatial extent and return the needed parameters to the icesat2data object. """ if isinstance(spatial_extent, list): - #bounding box - if len(spatial_extent)==4 and all(type(i) in [int, float] for i in spatial_extent): + # bounding box + if len(spatial_extent) == 4 and all( + type(i) in [int, float] for i in spatial_extent + ): assert -90 <= spatial_extent[1] <= 90, "Invalid latitude value" assert -90 <= spatial_extent[3] <= 90, "Invalid latitude value" - assert -180 <= spatial_extent[0] <= 360, "Invalid longitude value" #tighten these ranges depending on actual allowed inputs + assert ( + -180 <= spatial_extent[0] <= 360 + ), "Invalid longitude value" # tighten these ranges depending on actual allowed inputs assert -180 <= spatial_extent[2] <= 360, "Invalid longitude value" - assert spatial_extent[0] <= spatial_extent[2], "Invalid bounding box longitudes" - assert spatial_extent[1] <= spatial_extent[3], "Invalid bounding box latitudes" + assert ( + spatial_extent[0] <= spatial_extent[2] + ), "Invalid bounding box longitudes" + assert ( + spatial_extent[1] <= spatial_extent[3] + ), "Invalid bounding box latitudes" _spat_extent = spatial_extent - extent_type = 'bounding_box' - - #user-entered polygon as list of lon, lat coordinate pairs + extent_type = "bounding_box" + + # user-entered polygon as list of lon, lat coordinate pairs elif all(type(i) in [list, tuple] for i in spatial_extent): - assert len(spatial_extent)>=4, "Your spatial extent polygon has too few vertices" - assert spatial_extent[0][0] == spatial_extent[-1][0], "Starting longitude doesn't match ending longitude" - assert spatial_extent[0][1] == spatial_extent[-1][1], "Starting latitude doesn't match ending latitude" - polygon = (','.join([str(c) for xy in spatial_extent for c in xy])).split(",") - - extent_type = 'polygon' + assert ( + len(spatial_extent) >= 4 + ), "Your spatial extent polygon has too few vertices" + assert ( + spatial_extent[0][0] == spatial_extent[-1][0] + ), "Starting longitude doesn't match ending longitude" + assert ( + spatial_extent[0][1] == spatial_extent[-1][1] + ), "Starting latitude doesn't match ending latitude" + polygon = (",".join([str(c) for xy in spatial_extent for c in xy])).split( + "," + ) + + extent_type = "polygon" polygon = [float(i) for i in polygon] gdf = geospatial.geodataframe(extent_type, polygon, file=False) @@ -62,13 +79,21 @@ def spatial(spatial_extent): # #DevGoal: properly format this input type (and any polygon type) so that it is clockwise (and only contains 1 pole)!! # warnings.warn("this type of input is not yet well handled and you may not be able to find data") - #user-entered polygon as a single list of lon and lat coordinates + # user-entered polygon as a single list of lon and lat coordinates elif all(type(i) in [int, float] for i in spatial_extent): - assert len(spatial_extent)>=8, "Your spatial extent polygon has too few vertices" - assert len(spatial_extent)%2 == 0, "Your spatial extent polygon list should have an even number of entries" - assert spatial_extent[0] == spatial_extent[-2], "Starting longitude doesn't match ending longitude" - assert spatial_extent[1] == spatial_extent[-1], "Starting latitude doesn't match ending latitude" - extent_type = 'polygon' + assert ( + len(spatial_extent) >= 8 + ), "Your spatial extent polygon has too few vertices" + assert ( + len(spatial_extent) % 2 == 0 + ), "Your spatial extent polygon list should have an even number of entries" + assert ( + spatial_extent[0] == spatial_extent[-2] + ), "Starting longitude doesn't match ending longitude" + assert ( + spatial_extent[1] == spatial_extent[-1] + ), "Starting latitude doesn't match ending latitude" + extent_type = "polygon" polygon = [float(i) for i in spatial_extent] gdf = geospatial.geodataframe(extent_type, polygon, file=False) @@ -76,70 +101,84 @@ def spatial(spatial_extent): # _spat_extent = polygon - else: - raise ValueError('Your spatial extent does not meet minimum input criteria') - - #DevGoal: write a test for this? - #make sure there is nothing set to _geom_filepath since its existence determines later steps - try: del _geom_filepath - except: UnboundLocalError - - #DevGoal: revisit this section + geospatial.geodataframe. There might be some good ways to combine the functionality in these checks with that + raise ValueError("Your spatial extent does not meet minimum input criteria") + + # DevGoal: write a test for this? + # make sure there is nothing set to _geom_filepath since its existence determines later steps + try: + del _geom_filepath + except: + UnboundLocalError + + # DevGoal: revisit this section + geospatial.geodataframe. There might be some good ways to combine the functionality in these checks with that elif isinstance(spatial_extent, str): - assert os.path.exists(spatial_extent), "Check that the path and filename of your geometry file are correct" - #DevGoal: more robust polygon inputting (see Bruce's code): correct for clockwise/counterclockwise coordinates, deal with simplification, etc. - if spatial_extent.split('.')[-1] in ['kml','shp','gpkg']: - extent_type = 'polygon' + assert os.path.exists( + spatial_extent + ), "Check that the path and filename of your geometry file are correct" + # DevGoal: more robust polygon inputting (see Bruce's code): correct for clockwise/counterclockwise coordinates, deal with simplification, etc. + if spatial_extent.split(".")[-1] in ["kml", "shp", "gpkg"]: + extent_type = "polygon" gdf = geospatial.geodataframe(extent_type, spatial_extent, file=True) # print(gdf.iloc[0].geometry) - #DevGoal: does the below line mandate that only the first polygon will be read? Perhaps we should require files containing only one polygon? - #RAPHAEL - It only selects the first polygon if there are multiple. Unless we can supply the CMR params with muliple polygon inputs we should probably req a single polygon. + # DevGoal: does the below line mandate that only the first polygon will be read? Perhaps we should require files containing only one polygon? + # RAPHAEL - It only selects the first polygon if there are multiple. Unless we can supply the CMR params with muliple polygon inputs we should probably req a single polygon. _spat_extent = gdf.iloc[0].geometry # _spat_extent = apifmt._fmt_polygon(spatial_extent) _geom_filepath = spatial_extent else: - raise TypeError('Input spatial extent file must be a kml, shp, or gpkg') + raise TypeError("Input spatial extent file must be a kml, shp, or gpkg") - #DevGoal: currently no specific test for this if statement... - if '_geom_filepath' not in locals(): _geom_filepath = None + # DevGoal: currently no specific test for this if statement... + if "_geom_filepath" not in locals(): + _geom_filepath = None return extent_type, _spat_extent, _geom_filepath + def temporal(date_range, start_time, end_time): """ Validate the input temporal parameters and return the needed parameters to the icesat2data object. """ if isinstance(date_range, list): - if len(date_range)==2: - _start = dt.datetime.strptime(date_range[0], '%Y-%m-%d') - _end = dt.datetime.strptime(date_range[1], '%Y-%m-%d') + if len(date_range) == 2: + _start = dt.datetime.strptime(date_range[0], "%Y-%m-%d") + _end = dt.datetime.strptime(date_range[1], "%Y-%m-%d") assert _start.date() <= _end.date(), "Your date range is invalid" else: - raise ValueError("Your date range list is the wrong length. It should have start and end dates only.") - -#DevGoal: accept more date/time input formats -# elif isinstance(date_range, date-time object): -# print('it is a date-time object') -# elif isinstance(date_range, dict): -# print('it is a dictionary. now check the keys for start and end dates') + raise ValueError( + "Your date range list is the wrong length. It should have start and end dates only." + ) + # DevGoal: accept more date/time input formats + # elif isinstance(date_range, date-time object): + # print('it is a date-time object') + # elif isinstance(date_range, dict): + # print('it is a dictionary. now check the keys for start and end dates') if start_time is None: - _start = _start.combine(_start.date(),dt.datetime.strptime('00:00:00', '%H:%M:%S').time()) + _start = _start.combine( + _start.date(), dt.datetime.strptime("00:00:00", "%H:%M:%S").time() + ) else: if isinstance(start_time, str): - _start = _start.combine(_start.date(),dt.datetime.strptime(start_time, '%H:%M:%S').time()) + _start = _start.combine( + _start.date(), dt.datetime.strptime(start_time, "%H:%M:%S").time() + ) else: raise TypeError("Please enter your start time as a string") if end_time is None: - _end = _start.combine(_end.date(),dt.datetime.strptime('23:59:59', '%H:%M:%S').time()) + _end = _start.combine( + _end.date(), dt.datetime.strptime("23:59:59", "%H:%M:%S").time() + ) else: if isinstance(end_time, str): - _end = _start.combine(_end.date(),dt.datetime.strptime(end_time, '%H:%M:%S').time()) + _end = _start.combine( + _end.date(), dt.datetime.strptime(end_time, "%H:%M:%S").time() + ) else: raise TypeError("Please enter your end time as a string") - + return _start, _end diff --git a/icepyx/core/variables.py b/icepyx/core/variables.py index 31e885a2b..978bc0973 100644 --- a/icepyx/core/variables.py +++ b/icepyx/core/variables.py @@ -1,15 +1,14 @@ - import numpy as np import os import pprint import icepyx.core.is2ref as is2ref -#DEVGOAL: use h5py to simplify some of these tasks, if possible! +# DEVGOAL: use h5py to simplify some of these tasks, if possible! -#REFACTOR: class needs better docstrings -#DevNote: currently this class is not tested -class Variables(): +# REFACTOR: class needs better docstrings +# DevNote: currently this class is not tested +class Variables: """ Get, create, interact, and manipulate lists of variables and variable paths contained in ICESat-2 datasets. @@ -36,31 +35,38 @@ class Variables(): For vartype file, a path to a directory or single input source files (not yet implemented) """ - def __init__(self, vartype, avail=None, wanted=None, session=None, - dataset=None, version=None, source=None): - - assert vartype in ['order','file'], "Please submit a valid variables type flag" - + def __init__( + self, + vartype, + avail=None, + wanted=None, + session=None, + dataset=None, + version=None, + source=None, + ): + + assert vartype in ["order", "file"], "Please submit a valid variables type flag" + self._vartype = vartype self.dataset = dataset self._avail = avail self.wanted = wanted self._session = session - #DevGoal: put some more/robust checks here to assess validity of inputs + # DevGoal: put some more/robust checks here to assess validity of inputs - if self._vartype == 'order': + if self._vartype == "order": if self._avail == None: self._version = version - elif self._vartype == 'file': - #DevGoal: check that the list or string are valid dir/files + elif self._vartype == "file": + # DevGoal: check that the list or string are valid dir/files self.source = source - # @property # def wanted(self): # return self._wanted - + def avail(self, options=False, internal=False): """ Get the list of available variables and variable paths from the input dataset @@ -83,23 +89,25 @@ def avail(self, options=False, internal=False): # if hasattr(self, '_avail'): # return self._avail # else: - if not hasattr(self, '_avail') or self._avail==None: - if self._vartype == 'order': - self._avail = is2ref._get_custom_options(self._session, self.dataset, self._version)['variables'] + if not hasattr(self, "_avail") or self._avail == None: + if self._vartype == "order": + self._avail = is2ref._get_custom_options( + self._session, self.dataset, self._version + )["variables"] - elif self._vartype == 'file': + elif self._vartype == "file": self._avail = None - if options==True: - vgrp, paths = self.parse_var_list(self._avail) + if options == True: + vgrp, paths = self.parse_var_list(self._avail) allpaths = [] [allpaths.extend(np.unique(np.array(paths[p]))) for p in range(len(paths))] allpaths = np.unique(allpaths) - if internal==False: - print('var_list inputs: ' + ', '.join(vgrp.keys())) - print('keyword_list and beam_list inputs: ' + ', '.join(allpaths)) - elif internal==True: - return vgrp,allpaths + if internal == False: + print("var_list inputs: " + ", ".join(vgrp.keys())) + print("keyword_list and beam_list inputs: " + ", ".join(allpaths)) + elif internal == True: + return vgrp, allpaths else: return self._avail @@ -169,32 +177,33 @@ def parse_var_list(varlist): # create a dictionary of variable names and paths vgrp = {} - num = np.max([v.count('/') for v in varlist]) - # print('max needed: ' + str(num)) + num = np.max([v.count("/") for v in varlist]) + # print('max needed: ' + str(num)) paths = [[] for i in range(num)] - - #print(self._cust_options['variables']) + + # print(self._cust_options['variables']) for vn in varlist: - vpath,vkey = os.path.split(vn) - #print('path '+ vpath + ', key '+vkey) + vpath, vkey = os.path.split(vn) + # print('path '+ vpath + ', key '+vkey) if vkey not in vgrp.keys(): vgrp[vkey] = [vn] else: vgrp[vkey].append(vn) if vpath: - j=0 - for d in vpath.split('/'): - paths[j].append(d) - j=j+1 - for i in range(j,num): - paths[i].append('none') - i=i+1 - + j = 0 + for d in vpath.split("/"): + paths[j].append(d) + j = j + 1 + for i in range(j, num): + paths[i].append("none") + i = i + 1 + return vgrp, paths - - def _check_valid_lists(self, vgrp, allpaths, var_list=None, beam_list=None, keyword_list=None): + def _check_valid_lists( + self, vgrp, allpaths, var_list=None, beam_list=None, keyword_list=None + ): """ Check that the user is requesting valid paths and/or variables for their dataset. @@ -218,111 +227,115 @@ def _check_valid_lists(self, vgrp, allpaths, var_list=None, beam_list=None, keyw List of user requested variable path keywords """ - # check if the list of variables, if specified, are available in the dataset + # check if the list of variables, if specified, are available in the dataset if var_list is not None: for var_id in var_list: if var_id not in vgrp.keys(): - err_msg_varid = "Invalid variable name: " + var_id + '. ' - err_msg_varid = err_msg_varid + 'Please select from this list: ' - err_msg_varid = err_msg_varid + ', '.join(vgrp.keys()) + err_msg_varid = "Invalid variable name: " + var_id + ". " + err_msg_varid = err_msg_varid + "Please select from this list: " + err_msg_varid = err_msg_varid + ", ".join(vgrp.keys()) raise ValueError(err_msg_varid) - - #DevGoal: is there a way to not have this hard-coded in? + + # DevGoal: is there a way to not have this hard-coded in? # check if the list of beams, if specified, are available in the dataset - if self.dataset=='ATL09': - beam_avail = ['profile_'+str(i+1) for i in range(3)] + if self.dataset == "ATL09": + beam_avail = ["profile_" + str(i + 1) for i in range(3)] else: - beam_avail = ['gt'+str(i+1)+'l' for i in range(3)] - beam_avail = beam_avail + ['gt'+str(i+1)+'r' for i in range(3)] + beam_avail = ["gt" + str(i + 1) + "l" for i in range(3)] + beam_avail = beam_avail + ["gt" + str(i + 1) + "r" for i in range(3)] if beam_list is not None: for beam_id in beam_list: if beam_id not in beam_avail: - err_msg_beam = "Invalid beam_id: " + beam_id + '. ' - err_msg_beam = err_msg_beam + 'Please select from this list: ' - err_msg_beam = err_msg_beam + ', '.join(beam_avail) + err_msg_beam = "Invalid beam_id: " + beam_id + ". " + err_msg_beam = err_msg_beam + "Please select from this list: " + err_msg_beam = err_msg_beam + ", ".join(beam_avail) raise ValueError(err_msg_beam) - #check if keywords, if specified, are available for the dataset + # check if keywords, if specified, are available for the dataset if keyword_list is not None: for kw in keyword_list: -# assert kw in allpaths, "Invalid keyword. Please select from: " + ', '.join(allpaths) - - #DevGoal: update here to not include profiles/beams in the allpaths list + # assert kw in allpaths, "Invalid keyword. Please select from: " + ', '.join(allpaths) + + # DevGoal: update here to not include profiles/beams in the allpaths list if kw not in allpaths: - err_msg_kw = "Invalid keyword: " + kw + '. ' - err_msg_kw = err_msg_kw + 'Please select from this list: ' - err_msg_kw = err_msg_kw + ', '.join(np.unique(np.array(allpaths))) + err_msg_kw = "Invalid keyword: " + kw + ". " + err_msg_kw = err_msg_kw + "Please select from this list: " + err_msg_kw = err_msg_kw + ", ".join(np.unique(np.array(allpaths))) raise ValueError(err_msg_kw) - + def _get_sum_varlist(self, var_list, all_vars, defaults): - ''' + """ Get the list of variables to add or iterate through, depending on function inputs. - ''' + """ sum_varlist = [] - if defaults==True: + if defaults == True: sum_varlist = sum_varlist + is2ref._default_varlists(self.dataset) if var_list is not None: for vn in var_list: - if vn not in sum_varlist: sum_varlist.append(vn) - if len(sum_varlist)==0: + if vn not in sum_varlist: + sum_varlist.append(vn) + if len(sum_varlist) == 0: sum_varlist = all_vars return sum_varlist - + @staticmethod def _get_combined_list(beam_list, keyword_list): - ''' + """ Get the combined list of beams and/or keywords to add or iterate through. - ''' + """ combined_list = [] - if beam_list==None: - combined_list = keyword_list - elif keyword_list==None: + if beam_list == None: + combined_list = keyword_list + elif keyword_list == None: combined_list = beam_list else: combined_list = keyword_list + beam_list - + return combined_list @staticmethod def _iter_vars(sum_varlist, req_vars, vgrp): - ''' + """ Iterate through the wanted variables supplied in sum_varlist and add them and their paths to the list of requested variables. - ''' + """ for vn in sum_varlist: req_vars[vn] = vgrp[vn] return req_vars def _iter_paths(self, sum_varlist, req_vars, vgrp, beam_list, keyword_list): - ''' + """ Iterate through the list of paths for each variable in sum_varlist. Add the paths that have matches to combined_list the dictionary of requested variables. - ''' + """ combined_list = self._get_combined_list(beam_list, keyword_list) - + for vkey in sum_varlist: for vpath in vgrp[vkey]: - vpath_kws = vpath.split('/') - + vpath_kws = vpath.split("/") + try: for bkw in beam_list: if bkw in vpath_kws: for kw in keyword_list: if kw in vpath_kws: - if vkey not in req_vars: req_vars[vkey] = [] - if vpath not in req_vars[vkey]: req_vars[vkey].append(vpath) + if vkey not in req_vars: + req_vars[vkey] = [] + if vpath not in req_vars[vkey]: + req_vars[vkey].append(vpath) except TypeError: for kw in combined_list: if kw in vpath_kws: - if vkey not in req_vars: req_vars[vkey] = [] - if vpath not in req_vars[vkey]: req_vars[vkey].append(vpath) + if vkey not in req_vars: + req_vars[vkey] = [] + if vpath not in req_vars[vkey]: + req_vars[vkey].append(vpath) return req_vars - - #DevGoal: we can ultimately add an "interactive" trigger that will open the not-yet-made widget. Otherwise, it will use the var_list passed by the user/defaults + # DevGoal: we can ultimately add an "interactive" trigger that will open the not-yet-made widget. Otherwise, it will use the var_list passed by the user/defaults def append(self, defaults=False, var_list=None, beam_list=None, keyword_list=None): - ''' + """ Add to the list of desired variables using user specified beams and variable list. A pregenerated default variable list can be used by setting defaults to True. Note: The calibrated backscatter cab_prof is not in the default list for ATL09 @@ -375,43 +388,58 @@ def append(self, defaults=False, var_list=None, beam_list=None, keyword_list=Non To add all variables and paths in ancillary_data >>> reg_a.order_vars.append(keyword_list=['ancillary_data']) - ''' + """ + + assert not ( + defaults == False + and var_list == None + and beam_list == None + and keyword_list == None + ), "You must enter parameters to add to a variable subset list. If you do not want to subset by variable, ensure your is2.subsetparams dictionary does not contain the key 'Coverage'." - assert not (defaults==False and var_list==None and beam_list==None and keyword_list==None), \ - "You must enter parameters to add to a variable subset list. If you do not want to subset by variable, ensure your is2.subsetparams dictionary does not contain the key 'Coverage'." - req_vars = {} # if not hasattr(self, 'avail') or self.avail==None: self.get_avail() - # vgrp, paths = self.parse_var_list(self.avail) + # vgrp, paths = self.parse_var_list(self.avail) # allpaths = [] # [allpaths.extend(np.unique(np.array(paths[p]))) for p in range(len(paths))] - vgrp,allpaths = self.avail(options=True, internal=True) + vgrp, allpaths = self.avail(options=True, internal=True) self._check_valid_lists(vgrp, allpaths, var_list, beam_list, keyword_list) - #add the mandatory variables to the data object - nec_varlist = ['sc_orient','sc_orient_time','atlas_sdp_gps_epoch','data_start_utc','data_end_utc', - 'granule_start_utc','granule_end_utc','start_delta_time','end_delta_time'] - - if not hasattr(self, 'wanted') or self.wanted==None: + # add the mandatory variables to the data object + nec_varlist = [ + "sc_orient", + "sc_orient_time", + "atlas_sdp_gps_epoch", + "data_start_utc", + "data_end_utc", + "granule_start_utc", + "granule_end_utc", + "start_delta_time", + "end_delta_time", + ] + + if not hasattr(self, "wanted") or self.wanted == None: for varid in nec_varlist: req_vars[varid] = vgrp[varid] self.wanted = req_vars - #DEVGOAL: add a secondary var list to include uncertainty/error information for lower level data if specific data variables have been specified... + # DEVGOAL: add a secondary var list to include uncertainty/error information for lower level data if specific data variables have been specified... - #generate a list of variable names to include, depending on user input + # generate a list of variable names to include, depending on user input sum_varlist = self._get_sum_varlist(var_list, vgrp.keys(), defaults) - - #Case only variables (but not keywords or beams) are specified - if beam_list==None and keyword_list==None: + + # Case only variables (but not keywords or beams) are specified + if beam_list == None and keyword_list == None: req_vars.update(self._iter_vars(sum_varlist, req_vars, vgrp)) - - #Case a beam and/or keyword list is specified (with or without variables) + + # Case a beam and/or keyword list is specified (with or without variables) else: - req_vars.update(self._iter_paths(sum_varlist, req_vars, vgrp, beam_list, keyword_list)) - + req_vars.update( + self._iter_paths(sum_varlist, req_vars, vgrp, beam_list, keyword_list) + ) + # update the data object variables for vkey in req_vars.keys(): # add all matching keys and paths for new variables @@ -419,12 +447,12 @@ def append(self, defaults=False, var_list=None, beam_list=None, keyword_list=Non self.wanted[vkey] = req_vars[vkey] else: for vpath in req_vars[vkey]: - if vpath not in self.wanted[vkey]: self.wanted[vkey].append(vpath) - - - #DevGoal: we can ultimately add an "interactive" trigger that will open the not-yet-made widget. Otherwise, it will use the var_list passed by the user/defaults + if vpath not in self.wanted[vkey]: + self.wanted[vkey].append(vpath) + + # DevGoal: we can ultimately add an "interactive" trigger that will open the not-yet-made widget. Otherwise, it will use the var_list passed by the user/defaults def remove(self, all=False, var_list=None, beam_list=None, keyword_list=None): - ''' + """ Remove the variables and paths from the wanted list using user specified beam, keyword, and variable lists. @@ -473,50 +501,58 @@ def remove(self, all=False, var_list=None, beam_list=None, keyword_list=None): To remove all variables and paths in ancillary_data >>> reg_a.order_vars.remove(keyword_list=['ancillary_data']) - ''' + """ - if not hasattr(self, 'wanted') or self.wanted==None: - raise ValueError("You must construct a wanted variable list in order to remove values from it.") + if not hasattr(self, "wanted") or self.wanted == None: + raise ValueError( + "You must construct a wanted variable list in order to remove values from it." + ) - assert not (all==False and var_list==None and beam_list==None and keyword_list==None), \ - "You must specify which variables/paths/beams you would like to remove from your wanted list." + assert not ( + all == False + and var_list == None + and beam_list == None + and keyword_list == None + ), "You must specify which variables/paths/beams you would like to remove from your wanted list." - # if not hasattr(self, 'avail'): self.get_avail() - # vgrp, paths = self.parse_var_list(self.avail) - # # vgrp, paths = self.parse_var_list(self._cust_options['variables']) + # vgrp, paths = self.parse_var_list(self.avail) + # # vgrp, paths = self.parse_var_list(self._cust_options['variables']) # allpaths = [] # [allpaths.extend(np.unique(np.array(paths[p]))) for p in range(len(paths))] # allpaths = np.unique(allpaths) # self._check_valid_lists(vgrp, allpaths, var_list, beam_list, keyword_list) - if all==True: - try: self.wanted=None + if all == True: + try: + self.wanted = None except NameError: pass - + else: - #Case only variables (but not keywords or beams) are specified - if beam_list==None and keyword_list==None: + # Case only variables (but not keywords or beams) are specified + if beam_list == None and keyword_list == None: for vn in var_list: - try: del self.wanted[vn] - except KeyError: pass - - - #DevGoal: Do we want to enable the user to remove mandatory variables (how it's written now)? - #Case a beam and/or keyword list is specified (with or without variables) - else: + try: + del self.wanted[vn] + except KeyError: + pass + + # DevGoal: Do we want to enable the user to remove mandatory variables (how it's written now)? + # Case a beam and/or keyword list is specified (with or without variables) + else: combined_list = self._get_combined_list(beam_list, keyword_list) - if var_list==None: var_list=self.wanted.keys() - + if var_list == None: + var_list = self.wanted.keys() + # nec_varlist = ['sc_orient','atlas_sdp_gps_epoch','data_start_utc','data_end_utc', # 'granule_start_utc','granule_end_utc','start_delta_time','end_delta_time'] - for vkey in tuple(var_list): #self.wanted.keys()): + for vkey in tuple(var_list): # self.wanted.keys()): for vpath in tuple(self.wanted[vkey]): - vpath_kws = vpath.split('/') - + vpath_kws = vpath.split("/") + try: for bkw in beam_list: if bkw in vpath_kws: @@ -529,9 +565,8 @@ def remove(self, all=False, var_list=None, beam_list=None, keyword_list=None): if kw in vpath_kws and vkey in var_list: self.wanted[vkey].remove(vpath) - try: - if self.wanted[vkey] == []: del self.wanted[vkey] + if self.wanted[vkey] == []: + del self.wanted[vkey] except KeyError: - pass - \ No newline at end of file + pass diff --git a/icepyx/tests/is2class_query.py b/icepyx/tests/is2class_query.py index d778f1205..4554e4873 100644 --- a/icepyx/tests/is2class_query.py +++ b/icepyx/tests/is2class_query.py @@ -2,46 +2,74 @@ import pytest import warnings + def test_CMRparams(): - reg_a = ipd.Icesat2Data('ATL06',[-64, 66, -55, 72],['2019-02-22','2019-02-28']) + reg_a = ipd.Icesat2Data("ATL06", [-64, 66, -55, 72], ["2019-02-22", "2019-02-28"]) reg_a.build_CMR_params() obs_keys = reg_a.CMRparams.keys() - exp_keys_all = ['short_name','version','temporal'] - exp_keys_any = ['bounding_box','polygon'] - + exp_keys_all = ["short_name", "version", "temporal"] + exp_keys_any = ["bounding_box", "polygon"] + assert all(keys in obs_keys for keys in exp_keys_all) assert any(key in obs_keys for key in exp_keys_any) - + + def test_reqconfig_params(): - reg_a = ipd.Icesat2Data('ATL06',[-64, 66, -55, 72],['2019-02-22','2019-02-28']) - - #test for search params - reg_a.build_reqconfig_params('search') + reg_a = ipd.Icesat2Data("ATL06", [-64, 66, -55, 72], ["2019-02-22", "2019-02-28"]) + + # test for search params + reg_a.build_reqconfig_params("search") obs_keys = reg_a.reqparams.keys() - exp_keys_all = ['page_size','page_num'] + exp_keys_all = ["page_size", "page_num"] assert all(keys in obs_keys for keys in exp_keys_all) - #test for download params - reg_a.reqparams=None - reg_a.build_reqconfig_params('download') - reg_a.reqparams.update({'token':'','email':''}) + # test for download params + reg_a.reqparams = None + reg_a.build_reqconfig_params("download") + reg_a.reqparams.update({"token": "", "email": ""}) obs_keys = reg_a.reqparams.keys() - exp_keys_all = ['page_size','page_num','request_mode','token','email','include_meta'] + exp_keys_all = [ + "page_size", + "page_num", + "request_mode", + "token", + "email", + "include_meta", + ] assert all(keys in obs_keys for keys in exp_keys_all) - + + def test_properties(): - reg_a = ipd.Icesat2Data('ATL06',[-64, 66, -55, 72],['2019-02-22','2019-02-28'],\ - start_time='03:30:00', end_time='21:30:00', version='2') - obs_list = [reg_a.dataset, reg_a.dates, reg_a.start_time, reg_a.end_time, reg_a.dataset_version, reg_a.spatial_extent] - exp_list = ['ATL06',['2019-02-22', '2019-02-28'], '03:30:00', '21:30:00', '002', ['bounding box', [-64, 66, -55, 72]]] - - for obs, expected in zip(obs_list,exp_list): - assert obs == expected + reg_a = ipd.Icesat2Data( + "ATL06", + [-64, 66, -55, 72], + ["2019-02-22", "2019-02-28"], + start_time="03:30:00", + end_time="21:30:00", + version="2", + ) + obs_list = [ + reg_a.dataset, + reg_a.dates, + reg_a.start_time, + reg_a.end_time, + reg_a.dataset_version, + reg_a.spatial_extent, + ] + exp_list = [ + "ATL06", + ["2019-02-22", "2019-02-28"], + "03:30:00", + "21:30:00", + "002", + ["bounding box", [-64, 66, -55, 72]], + ] -#BestPractices: should do additional properties tests for each potential property type (e.g. spatial extent can have type bounding_box or polygon) + for obs, expected in zip(obs_list, exp_list): + assert obs == expected +# BestPractices: should do additional properties tests for each potential property type (e.g. spatial extent can have type bounding_box or polygon) - -#check that search results are correct (spatially, temporally, match actually available data) \ No newline at end of file +# check that search results are correct (spatially, temporally, match actually available data) diff --git a/icepyx/tests/test_APIformatting.py b/icepyx/tests/test_APIformatting.py index 802cfc872..73ef97144 100644 --- a/icepyx/tests/test_APIformatting.py +++ b/icepyx/tests/test_APIformatting.py @@ -6,62 +6,1023 @@ import icepyx.core.APIformatting as apifmt -#DevNote: is this a situation where you'd ideally build a test class, since you're just repeating the -#test function with different inputs? Especially for the _fmt_spaital, where there's >2 tests? +# DevNote: is this a situation where you'd ideally build a test class, since you're just repeating the +# test function with different inputs? Especially for the _fmt_spaital, where there's >2 tests? -#CMR temporal and spatial formats --> what's the best way to compare formatted text? character by character comparison of strings? +# CMR temporal and spatial formats --> what's the best way to compare formatted text? character by character comparison of strings? ########## _fmt_temporal ########## def test_time_fmt(): - obs = apifmt._fmt_temporal(dt.datetime(2019,1,11,12,30,30), dt.datetime(2020,10,31,1,15), 'time') - exp = {'time': '2019-01-11T12:30:30,2020-10-31T01:15:00'} + obs = apifmt._fmt_temporal( + dt.datetime(2019, 1, 11, 12, 30, 30), dt.datetime(2020, 10, 31, 1, 15), "time" + ) + exp = {"time": "2019-01-11T12:30:30,2020-10-31T01:15:00"} assert obs == exp + def test_temporal_fmt(): - obs = apifmt._fmt_temporal(dt.datetime(2019,1,11,12,30,30), dt.datetime(2020,10,31,1,15), 'temporal') - exp = {'temporal': '2019-01-11T12:30:30Z,2020-10-31T01:15:00Z'} + obs = apifmt._fmt_temporal( + dt.datetime(2019, 1, 11, 12, 30, 30), + dt.datetime(2020, 10, 31, 1, 15), + "temporal", + ) + exp = {"temporal": "2019-01-11T12:30:30Z,2020-10-31T01:15:00Z"} assert obs == exp ########## _fmt_spatial ########## def test_bounding_box_fmt(): - obs = apifmt._fmt_spatial('bounding_box', [-55, 68, -48, 71]) - exp = {'bounding_box': '-55,68,-48,71'} + obs = apifmt._fmt_spatial("bounding_box", [-55, 68, -48, 71]) + exp = {"bounding_box": "-55,68,-48,71"} assert obs == exp + def test_bbox_fmt(): - obs = apifmt._fmt_spatial('bbox', [-55, 68, -48, 71]) - exp = {'bbox': '-55,68,-48,71'} + obs = apifmt._fmt_spatial("bbox", [-55, 68, -48, 71]) + exp = {"bbox": "-55,68,-48,71"} assert obs == exp + def test_polygon_fmt(): - poly = Polygon([[-86.622742, -74.908126, 0.0], [-86.602149, -74.998483, 0.0], [-86.671945, -74.999545, 0.0], [-86.667881, -75.01762, 0.0], [-86.737771, -75.018662, 0.0], [-86.717729, -75.109052, 0.0], [-86.788057, -75.110077, 0.0], [-86.780144, -75.14624, 0.0], [-86.850654, -75.147247, 0.0], [-86.835058, -75.219586, 0.0], [-86.905925, -75.220574, 0.0], [-86.894389, -75.274839, 0.0], [-86.965529, -75.27581, 0.0], [-86.950368, -75.348177, 0.0], [-87.021872, -75.349129, 0.0], [-87.003154, -75.439609, 0.0], [-87.075115, -75.440545, 0.0], [-87.052886, -75.549149, 0.0], [-86.98038, -75.548205, 0.0], [-86.965004, -75.620616, 0.0], [-87.037878, -75.621564, 0.0], [-87.034102, -75.63967, 0.0], [-86.961136, -75.63872, 0.0], [-86.957257, -75.656825, 0.0], [-86.884208, -75.655851, 0.0], [-86.872234, -75.710165, 0.0], [-86.945563, -75.711143, 0.0], [-86.925871, -75.801686, 0.0], [-86.999681, -75.802647, 0.0], [-86.988029, -75.856983, 0.0], [-87.062135, -75.857925, 0.0], [-87.058326, -75.87604, 0.0], [-87.132537, -75.876959, 0.0], [-87.128815, -75.895075, 0.0], [-87.203132, -75.895972, 0.0], [-87.199496, -75.914091, 0.0], [-87.273919, -75.914965, 0.0], [-87.27037, -75.933086, 0.0], [-87.344899, -75.933938, 0.0], [-87.341438, -75.95206, 0.0], [-87.490715, -75.953695, 0.0], [-87.487439, -75.97182, 0.0], [-87.562188, -75.972604, 0.0], [-87.559001, -75.99073, 0.0], [-87.633856, -75.991491, 0.0], [-87.627653, -76.027748, 0.0], [-87.777778, -76.029203, 0.0], [-87.774861, -76.047334, 0.0], [-87.925213, -76.048696, 0.0], [-87.922485, -76.06683, 0.0], [-87.997771, -76.067476, 0.0], [-87.995135, -76.085611, 0.0], [-88.070527, -76.086234, 0.0], [-88.067983, -76.104371, 0.0], [-88.143481, -76.104971, 0.0], [-88.14103, -76.123109, 0.0], [-88.216633, -76.123686, 0.0], [-88.214276, -76.141826, 0.0], [-88.365701, -76.142909, 0.0], [-88.363537, -76.161051, 0.0], [-88.439359, -76.161557, 0.0], [-88.43729, -76.1797, 0.0], [-88.513217, -76.180183, 0.0], [-88.511244, -76.198328, 0.0], [-88.587276, -76.198787, 0.0], [-88.585399, -76.216933, 0.0], [-88.737681, -76.217781, 0.0], [-88.736001, -76.235929, 0.0], [-88.81225, -76.236317, 0.0], [-88.810667, -76.254466, 0.0], [-88.887022, -76.254831, 0.0], [-88.885537, -76.272981, 0.0], [-88.961998, -76.273321, 0.0], [-88.960611, -76.291473, 0.0], [-89.037177, -76.29179, 0.0], [-89.035889, -76.309942, 0.0], [-89.112561, -76.310235, 0.0], [-89.111372, -76.328389, 0.0], [-89.264932, -76.328903, 0.0], [-89.263946, -76.347058, 0.0], [-89.340833, -76.347279, 0.0], [-89.339947, -76.365434, 0.0], [-89.41694, -76.365631, 0.0], [-89.416155, -76.383788, 0.0], [-89.493254, -76.383961, 0.0], [-89.492571, -76.402118, 0.0], [-89.569775, -76.402267, 0.0], [-89.569195, -76.420425, 0.0], [-89.723816, -76.420649, 0.0], [-89.723443, -76.438808, 0.0], [-89.800859, -76.438884, 0.0], [-89.80059, -76.457044, 0.0], [-89.878112, -76.457095, 0.0], [-89.877947, -76.475255, 0.0], [-89.955575, -76.475282, 0.0], [-89.955514, -76.493443, 0.0], [-90.033248, -76.493445, 0.0], [-90.033293, -76.511607, 0.0], [-90.111131, -76.511584, 0.0], [-90.111283, -76.529747, 0.0], [-90.345113, -76.52953, 0.0], [-90.345583, -76.547693, 0.0], [-90.42363, -76.547571, 0.0], [-90.424208, -76.565734, 0.0], [-90.50236, -76.565588, 0.0], [-90.503734, -76.601916, 0.0], [-90.582098, -76.601744, 0.0], [-90.583695, -76.638075, 0.0], [-90.662272, -76.637877, 0.0], [-90.664093, -76.67421, 0.0], [-90.742884, -76.673987, 0.0], [-90.743907, -76.692154, 0.0], [-90.822803, -76.691906, 0.0], [-90.823937, -76.710073, 0.0], [-91.060932, -76.709176, 0.0], [-91.062397, -76.727343, 0.0], [-91.536922, -76.72487, 0.0], [-91.539047, -76.743034, 0.0], [-91.697397, -76.742008, 0.0], [-91.699746, -76.760171, 0.0], [-91.779021, -76.759619, 0.0], [-91.783959, -76.795946, 0.0], [-91.863446, -76.795367, 0.0], [-91.873848, -76.868024, 0.0], [-91.793917, -76.868605, 0.0], [-91.796424, -76.886772, 0.0], [-91.716375, -76.887329, 0.0], [-91.721186, -76.923666, 0.0], [-91.640906, -76.924199, 0.0], [-91.647835, -76.97871, 0.0], [-91.325297, -76.980597, 0.0], [-91.327166, -76.998771, 0.0], [-91.165637, -76.999562, 0.0], [-91.167283, -77.017738, 0.0], [-91.086397, -77.018096, 0.0], [-91.089474, -77.054451, 0.0], [-91.008355, -77.054784, 0.0], [-91.015545, -77.145686, 0.0], [-91.178934, -77.144989, 0.0], [-91.180618, -77.16317, 0.0], [-91.426015, -77.16193, 0.0], [-91.434206, -77.234653, 0.0], [-92.092069, -77.230176, 0.0], [-92.08907, -77.212001, 0.0], [-92.335283, -77.209895, 0.0], [-92.352136, -77.300761, 0.0], [-92.269483, -77.301495, 0.0], [-92.276054, -77.337847, 0.0], [-92.193152, -77.338557, 0.0], [-92.199521, -77.374914, 0.0], [-92.282662, -77.374202, 0.0], [-92.285981, -77.392381, 0.0], [-92.369233, -77.391642, 0.0], [-92.383091, -77.464357, 0.0], [-92.466819, -77.463587, 0.0], [-92.470431, -77.481766, 0.0], [-92.386581, -77.482537, 0.0], [-92.390081, -77.500717, 0.0], [-92.138102, -77.502874, 0.0], [-92.141243, -77.521058, 0.0], [-91.972963, -77.522365, 0.0], [-91.984627, -77.595116, 0.0], [-91.899978, -77.595733, 0.0], [-91.90279, -77.613923, 0.0], [-91.4788, -77.616608, 0.0], [-91.480993, -77.634803, 0.0], [-91.14118, -77.636469, 0.0], [-91.14799, -77.709264, 0.0], [-91.062516, -77.709615, 0.0], [-91.070502, -77.800626, 0.0], [-90.812128, -77.801523, 0.0], [-90.81335, -77.819728, 0.0], [-90.727088, -77.819973, 0.0], [-90.732603, -77.911009, 0.0], [-90.81952, -77.910763, 0.0], [-90.820765, -77.928971, 0.0], [-90.90781, -77.928697, 0.0], [-90.909191, -77.946905, 0.0], [-90.822014, -77.94718, 0.0], [-90.823267, -77.96539, 0.0], [-90.735953, -77.965638, 0.0], [-90.737076, -77.983849, 0.0], [-90.824523, -77.983601, 0.0], [-90.825784, -78.001812, 0.0], [-90.91336, -78.001535, 0.0], [-90.914759, -78.019746, 0.0], [-91.090167, -78.019109, 0.0], [-91.093515, -78.055531, 0.0], [-91.181481, -78.05517, 0.0], [-91.188783, -78.128018, 0.0], [-91.365784, -78.127206, 0.0], [-91.370017, -78.163631, 0.0], [-91.458782, -78.163181, 0.0], [-91.463317, -78.199607, 0.0], [-91.552351, -78.199128, 0.0], [-91.554767, -78.217341, 0.0], [-91.643932, -78.216832, 0.0], [-91.651645, -78.271472, 0.0], [-91.830785, -78.270365, 0.0], [-91.833652, -78.288578, 0.0], [-92.013037, -78.287355, 0.0], [-92.016194, -78.305566, 0.0], [-92.106013, -78.30491, 0.0], [-92.115968, -78.359544, 0.0], [-92.025726, -78.360203, 0.0], [-92.035347, -78.414844, 0.0], [-91.944667, -78.415477, 0.0], [-91.947751, -78.433693, 0.0], [-91.856918, -78.434298, 0.0], [-91.859867, -78.452516, 0.0], [-91.76888, -78.453093, 0.0], [-91.771695, -78.471312, 0.0], [-91.680555, -78.471861, 0.0], [-91.683233, -78.490081, 0.0], [-91.591939, -78.490602, 0.0], [-91.59703, -78.527046, 0.0], [-91.505436, -78.52754, 0.0], [-91.507847, -78.545764, 0.0], [-91.324343, -78.546665, 0.0], [-91.330738, -78.601343, 0.0], [-91.238533, -78.601752, 0.0], [-91.24053, -78.61998, 0.0], [-91.14817, -78.62036, 0.0], [-91.150024, -78.638589, 0.0], [-90.872462, -78.639554, 0.0], [-90.873874, -78.657786, 0.0], [-90.781194, -78.658049, 0.0], [-90.78246, -78.676281, 0.0], [-90.689626, -78.676516, 0.0], [-90.691868, -78.712982, 0.0], [-90.598728, -78.713188, 0.0], [-90.599703, -78.731422, 0.0], [-90.506409, -78.731598, 0.0], [-90.508064, -78.76807, 0.0], [-90.414462, -78.768217, 0.0], [-90.41582, -78.804691, 0.0], [-90.32191, -78.804808, 0.0], [-90.324034, -78.877764, 0.0], [-90.229502, -78.877852, 0.0], [-90.230262, -78.914333, 0.0], [-90.040568, -78.914419, 0.0], [-90.040635, -78.932661, 0.0], [-89.94563, -78.932659, 0.0], [-89.94554, -78.950901, 0.0], [-89.850378, -78.950868, 0.0], [-89.850129, -78.969111, 0.0], [-89.754809, -78.969048, 0.0], [-89.75399, -79.005535, 0.0], [-89.562719, -79.005317, 0.0], [-89.561988, -79.023561, 0.0], [-89.466196, -79.023406, 0.0], [-89.465302, -79.04165, 0.0], [-89.273406, -79.041249, 0.0], [-89.272187, -79.059493, 0.0], [-88.983893, -79.05866, 0.0], [-88.982186, -79.076903, 0.0], [-89.1747, -79.07749, 0.0], [-89.173311, -79.095734, 0.0], [-89.269737, -79.095982, 0.0], [-89.268506, -79.114228, 0.0], [-89.365099, -79.114445, 0.0], [-89.364027, -79.132691, 0.0], [-89.460787, -79.132879, 0.0], [-89.458959, -79.169374, 0.0], [-89.55605, -79.16953, 0.0], [-89.555296, -79.187779, 0.0], [-89.652554, -79.187905, 0.0], [-89.651963, -79.206154, 0.0], [-89.749389, -79.20625, 0.0], [-89.748962, -79.2245, 0.0], [-89.846555, -79.224564, 0.0], [-89.846293, -79.242815, 0.0], [-90.041814, -79.24285, 0.0], [-90.042029, -79.297606, 0.0], [-90.140292, -79.297577, 0.0], [-90.140775, -79.334083, 0.0], [-90.042173, -79.334112, 0.0], [-90.042319, -79.37062, 0.0], [-90.141261, -79.370591, 0.0], [-90.141505, -79.388846, 0.0], [-90.240618, -79.388785, 0.0], [-90.241873, -79.443552, 0.0], [-90.341501, -79.443459, 0.0], [-90.342693, -79.479973, 0.0], [-90.442666, -79.479848, 0.0], [-90.444995, -79.534621, 0.0], [-90.545492, -79.534464, 0.0], [-90.546451, -79.552722, 0.0], [-90.445777, -79.55288, 0.0], [-90.447349, -79.5894, 0.0], [-91.053456, -79.587965, 0.0], [-91.055316, -79.606223, 0.0], [-91.257663, -79.605486, 0.0], [-91.259887, -79.623743, 0.0], [-91.361228, -79.623325, 0.0], [-91.36364, -79.641582, 0.0], [-91.465152, -79.641131, 0.0], [-91.488897, -79.805457, 0.0], [-91.695178, -79.804442, 0.0], [-91.698235, -79.822701, 0.0], [-91.801545, -79.822143, 0.0], [-91.808067, -79.85866, 0.0], [-91.704384, -79.85922, 0.0], [-91.707475, -79.87748, 0.0], [-91.811346, -79.876919, 0.0], [-91.814637, -79.895179, 0.0], [-91.918685, -79.894584, 0.0], [-91.922176, -79.912843, 0.0], [-92.026401, -79.912214, 0.0], [-92.030095, -79.930472, 0.0], [-92.134495, -79.929808, 0.0], [-92.138393, -79.948066, 0.0], [-92.347532, -79.946636, 0.0], [-92.351826, -79.964891, 0.0], [-92.456562, -79.964125, 0.0], [-92.461064, -79.982379, 0.0], [-92.565975, -79.981578, 0.0], [-92.570685, -79.999832, 0.0], [-92.78084, -79.998126, 0.0], [-92.785952, -80.016376, 0.0], [-92.891195, -80.015471, 0.0], [-92.896519, -80.033721, 0.0], [-93.001935, -80.032781, 0.0], [-93.007473, -80.051029, 0.0], [-93.113062, -80.050053, 0.0], [-93.118814, -80.0683, 0.0], [-93.224577, -80.067288, 0.0], [-93.230546, -80.085534, 0.0], [-93.336481, -80.084487, 0.0], [-93.324176, -80.048001, 0.0], [-93.429699, -80.046925, 0.0], [-93.417099, -80.010444, 0.0], [-93.522213, -80.009338, 0.0], [-93.515756, -79.991101, 0.0], [-93.620655, -79.989964, 0.0], [-93.61403, -79.971729, 0.0], [-93.718714, -79.97056, 0.0], [-93.711924, -79.952328, 0.0], [-93.816393, -79.951128, 0.0], [-93.788723, -79.87821, 0.0], [-93.892414, -79.876987, 0.0], [-93.864399, -79.804083, 0.0], [-93.967323, -79.802836, 0.0], [-93.946026, -79.748169, 0.0], [-93.843651, -79.749409, 0.0], [-93.823125, -79.694739, 0.0], [-93.924956, -79.693505, 0.0], [-93.90411, -79.638844, 0.0], [-94.005379, -79.637584, 0.0], [-93.998302, -79.619367, 0.0], [-94.099369, -79.618077, 0.0], [-94.092139, -79.599863, 0.0], [-94.193003, -79.598544, 0.0], [-94.185623, -79.580332, 0.0], [-94.386921, -79.577602, 0.0], [-94.379215, -79.559395, 0.0], [-94.680431, -79.555069, 0.0], [-94.672229, -79.53687, 0.0], [-94.772403, -79.535367, 0.0], [-94.747448, -79.48078, 0.0], [-94.847075, -79.479253, 0.0], [-94.81352, -79.406486, 0.0], [-94.912434, -79.404938, 0.0], [-94.903948, -79.38675, 0.0], [-95.101351, -79.383566, 0.0], [-95.092557, -79.365384, 0.0], [-95.191045, -79.363748, 0.0], [-95.155505, -79.291032, 0.0], [-95.253295, -79.289376, 0.0], [-95.244321, -79.271201, 0.0], [-95.341915, -79.269517, 0.0], [-95.332806, -79.251344, 0.0], [-95.430206, -79.249633, 0.0], [-95.420964, -79.231464, 0.0], [-95.323729, -79.233172, 0.0], [-95.269903, -79.124145, 0.0], [-95.366167, -79.122454, 0.0], [-95.357141, -79.104287, 0.0], [-95.453215, -79.102568, 0.0], [-95.425842, -79.048076, 0.0], [-95.616944, -79.044565, 0.0], [-95.598218, -79.00825, 0.0], [-95.693408, -79.006456, 0.0], [-95.683935, -78.988302, 0.0], [-95.588901, -78.990093, 0.0], [-95.579615, -78.971937, 0.0], [-95.484707, -78.973695, 0.0], [-95.475607, -78.955536, 0.0], [-95.380824, -78.957262, 0.0], [-95.37191, -78.9391, 0.0], [-95.466538, -78.937377, 0.0], [-95.457498, -78.919218, 0.0], [-95.551942, -78.917468, 0.0], [-95.542778, -78.899312, 0.0], [-95.637038, -78.897535, 0.0], [-95.609268, -78.843079, 0.0], [-95.515467, -78.844846, 0.0], [-95.506423, -78.826692, 0.0], [-95.412744, -78.828427, 0.0], [-95.403881, -78.81027, 0.0], [-95.310325, -78.811973, 0.0], [-95.301642, -78.793813, 0.0], [-95.114747, -78.797124, 0.0], [-95.106394, -78.778959, 0.0], [-95.013057, -78.780567, 0.0], [-95.004882, -78.7624, 0.0], [-94.911669, -78.763976, 0.0], [-94.895698, -78.727637, 0.0], [-94.988611, -78.726066, 0.0], [-94.940425, -78.617072, 0.0], [-95.032424, -78.615487, 0.0], [-95.024337, -78.597325, 0.0], [-95.207964, -78.594073, 0.0], [-95.191285, -78.557761, 0.0], [-95.465652, -78.552682, 0.0], [-95.474413, -78.57083, 0.0], [-95.748962, -78.565482, 0.0], [-95.721466, -78.511065, 0.0], [-95.812493, -78.509234, 0.0], [-95.803243, -78.491098, 0.0], [-96.075717, -78.48544, 0.0], [-96.06607, -78.467314, 0.0], [-96.156692, -78.465373, 0.0], [-96.146934, -78.447251, 0.0], [-96.327803, -78.44329, 0.0], [-96.297869, -78.388943, 0.0], [-96.387836, -78.386929, 0.0], [-96.377781, -78.368817, 0.0], [-96.467577, -78.366779, 0.0], [-96.457416, -78.34867, 0.0], [-96.547041, -78.346606, 0.0], [-96.536773, -78.328501, 0.0], [-96.80504, -78.32215, 0.0], [-96.794392, -78.304055, 0.0], [-96.883611, -78.301886, 0.0], [-96.872859, -78.283794, 0.0], [-96.961909, -78.2816, 0.0], [-96.940233, -78.245425, 0.0], [-97.028977, -78.243209, 0.0], [-97.018054, -78.225125, 0.0], [-97.19517, -78.220617, 0.0], [-97.184011, -78.20254, 0.0], [-97.272383, -78.200248, 0.0], [-97.238713, -78.14603, 0.0], [-97.326651, -78.14372, 0.0], [-97.315364, -78.125651, 0.0], [-97.403134, -78.123318, 0.0], [-97.391749, -78.105253, 0.0], [-97.566921, -78.10051, 0.0], [-97.555308, -78.082453, 0.0], [-97.64271, -78.080044, 0.0], [-97.607693, -78.025883, 0.0], [-97.520682, -78.02828, 0.0], [-97.497773, -77.992166, 0.0], [-97.410987, -77.994529, 0.0], [-97.399713, -77.976468, 0.0], [-97.313022, -77.9788, 0.0], [-97.27979, -77.924608, 0.0], [-97.193451, -77.926901, 0.0], [-97.139363, -77.836566, 0.0], [-96.967859, -77.841038, 0.0], [-96.946954, -77.804891, 0.0], [-96.861407, -77.80708, 0.0], [-96.851127, -77.789004, 0.0], [-96.765675, -77.791162, 0.0], [-96.725358, -77.718845, 0.0], [-96.640377, -77.720964, 0.0], [-96.620645, -77.6848, 0.0], [-96.535882, -77.686886, 0.0], [-96.526184, -77.668801, 0.0], [-96.441516, -77.670857, 0.0], [-96.384656, -77.562336, 0.0], [-96.552494, -77.558236, 0.0], [-96.514174, -77.485919, 0.0], [-96.59757, -77.483841, 0.0], [-96.58794, -77.465766, 0.0], [-96.671187, -77.463665, 0.0], [-96.680937, -77.481738, 0.0], [-97.263693, -77.466276, 0.0], [-97.253111, -77.448226, 0.0], [-97.336123, -77.445916, 0.0], [-97.325453, -77.42787, 0.0], [-97.491148, -77.423178, 0.0], [-97.480274, -77.405139, 0.0], [-97.397559, -77.407495, 0.0], [-97.376139, -77.371411, 0.0], [-97.293628, -77.373733, 0.0], [-97.28308, -77.355688, 0.0], [-98.433698, -77.320866, 0.0], [-98.421564, -77.302872, 0.0], [-98.666926, -77.294764, 0.0], [-98.642079, -77.2588, 0.0], [-99.049167, -77.244815, 0.0], [-99.036233, -77.226854, 0.0], [-99.522851, -77.209257, 0.0], [-99.509284, -77.191321, 0.0], [-99.832489, -77.179101, 0.0], [-99.818518, -77.161182, 0.0], [-99.979666, -77.154929, 0.0], [-99.965515, -77.137019, 0.0], [-100.447336, -77.117686, 0.0], [-100.432572, -77.099804, 0.0], [-100.512625, -77.096499, 0.0], [-100.483005, -77.060743, 0.0], [-100.642555, -77.054077, 0.0], [-100.627593, -77.036208, 0.0], [-100.707198, -77.032842, 0.0], [-100.692171, -77.014978, 0.0], [-100.851044, -77.008182, 0.0], [-100.835847, -76.990327, 0.0], [-100.915114, -76.986897, 0.0], [-100.899853, -76.969047, 0.0], [-101.058051, -76.962123, 0.0], [-101.042622, -76.944282, 0.0], [-101.121553, -76.940788, 0.0], [-101.090613, -76.905114, 0.0], [-101.169293, -76.901606, 0.0], [-101.153783, -76.883774, 0.0], [-101.232316, -76.880245, 0.0], [-101.216746, -76.862418, 0.0], [-101.295133, -76.85887, 0.0], [-101.217404, -76.769752, 0.0], [-101.295238, -76.766205, 0.0], [-101.279717, -76.748385, 0.0], [-101.357407, -76.744819, 0.0], [-101.310795, -76.691373, 0.0], [-101.388141, -76.687797, 0.0], [-101.372587, -76.669986, 0.0], [-101.449791, -76.666392, 0.0], [-101.326063, -76.523929, 0.0], [-101.402436, -76.52035, 0.0], [-101.341168, -76.449131, 0.0], [-101.265184, -76.45269, 0.0], [-101.175067, -76.345822, 0.0], [-101.250474, -76.342292, 0.0], [-101.190803, -76.27106, 0.0], [-101.265793, -76.267525, 0.0], [-101.250878, -76.249721, 0.0], [-101.325735, -76.246168, 0.0], [-101.280944, -76.192769, 0.0], [-101.429978, -76.185621, 0.0], [-101.399941, -76.150039, 0.0], [-101.474214, -76.14644, 0.0], [-101.459161, -76.128654, 0.0], [-101.533304, -76.125037, 0.0], [-101.518198, -76.107255, 0.0], [-101.59221, -76.10362, 0.0], [-101.577051, -76.085842, 0.0], [-101.650932, -76.082189, 0.0], [-101.635722, -76.064416, 0.0], [-101.709473, -76.060745, 0.0], [-101.694211, -76.042976, 0.0], [-101.767832, -76.039287, 0.0], [-101.752518, -76.021523, 0.0], [-101.899461, -76.014086, 0.0], [-101.837882, -75.943066, 0.0], [-101.910936, -75.939333, 0.0], [-101.89555, -75.921582, 0.0], [-101.968477, -75.917832, 0.0], [-101.953041, -75.900085, 0.0], [-102.02584, -75.896317, 0.0], [-102.010356, -75.878575, 0.0], [-102.083027, -75.87479, 0.0], [-102.067494, -75.857052, 0.0], [-102.140038, -75.853249, 0.0], [-102.124457, -75.835516, 0.0], [-102.196874, -75.831696, 0.0], [-102.181245, -75.813967, 0.0], [-102.253535, -75.810129, 0.0], [-102.237859, -75.792406, 0.0], [-102.310023, -75.78855, 0.0], [-102.294299, -75.770832, 0.0], [-102.366338, -75.766959, 0.0], [-102.350567, -75.749245, 0.0], [-102.494353, -75.741443, 0.0], [-102.478451, -75.723738, 0.0], [-102.693572, -75.711884, 0.0], [-102.70973, -75.729573, 0.0], [-102.853113, -75.72155, 0.0], [-102.869482, -75.739229, 0.0], [-102.941198, -75.735179, 0.0], [-102.957693, -75.752851, 0.0], [-103.029452, -75.748774, 0.0], [-103.012872, -75.731107, 0.0], [-103.227644, -75.718758, 0.0], [-103.210852, -75.701106, 0.0], [-103.282275, -75.696951, 0.0], [-103.265441, -75.679303, 0.0], [-103.336738, -75.675132, 0.0], [-103.303027, -75.639846, 0.0], [-103.445162, -75.631459, 0.0], [-103.428203, -75.613826, 0.0], [-103.923762, -75.583823, 0.0], [-103.90627, -75.566227, 0.0], [-103.976811, -75.56186, 0.0], [-103.941793, -75.526678, 0.0], [-104.012128, -75.5223, 0.0], [-103.942283, -75.45195, 0.0], [-103.914847, -75.426057, 0.0], [-103.846549, -75.420428, 0.0], [-103.814359, -75.41156, 0.0], [-103.74731, -75.394972, 0.0], [-103.643531, -75.376578, 0.0], [-103.639472, -75.360155, 0.0], [-103.549124, -75.339049, 0.0], [-103.509054, -75.329656, 0.0], [-103.456714, -75.307204, 0.0], [-103.37484, -75.273725, 0.0], [-103.284801, -75.264374, 0.0], [-103.224839, -75.25812, 0.0], [-103.182394, -75.249825, 0.0], [-103.086408, -75.237813, 0.0], [-103.042136, -75.231576, 0.0], [-102.981295, -75.215486, 0.0], [-102.956754, -75.210167, 0.0], [-102.921448, -75.203018, 0.0], [-102.898283, -75.198106, 0.0], [-102.873449, -75.192921, 0.0], [-102.84957, -75.188785, 0.0], [-102.825705, -75.184646, 0.0], [-102.789524, -75.181222, 0.0], [-102.744295, -75.17242, 0.0], [-102.656346, -75.16239, 0.0], [-102.607491, -75.160775, 0.0], [-102.560626, -75.159773, 0.0], [-102.511333, -75.159268, 0.0], [-102.378744, -75.152045, 0.0], [-102.34262, -75.146716, 0.0], [-102.266406, -75.132957, 0.0], [-102.223828, -75.128342, 0.0], [-102.157455, -75.12945, 0.0], [-102.113853, -75.130386, 0.0], [-102.068876, -75.13139, 0.0], [-102.040635, -75.126691, 0.0], [-102.013199, -75.12121, 0.0], [-101.969076, -75.11627, 0.0], [-101.953576, -75.113073, 0.0], [-101.923326, -75.111044, 0.0], [-101.896684, -75.109917, 0.0], [-101.821333, -75.103337, 0.0], [-101.766389, -75.098945, 0.0], [-101.726414, -75.090073, 0.0], [-101.723655, -75.079577, 0.0], [-101.631989, -75.054005, 0.0], [-101.564382, -75.02971, 0.0], [-101.547244, -75.015213, 0.0], [-101.531499, -75.000643, 0.0], [-101.549303, -74.990901, 0.0], [-101.489949, -74.940509, 0.0], [-101.469959, -74.921526, 0.0], [-101.455398, -74.908855, 0.0], [-101.420557, -74.891146, 0.0], [-101.399072, -74.882138, 0.0], [-101.391177, -74.870096, 0.0], [-101.371447, -74.860874, 0.0], [-101.363063, -74.853621, 0.0], [-101.338827, -74.838164, 0.0], [-101.312982, -74.826333, 0.0], [-101.29282, -74.816401, 0.0], [-101.276851, -74.808624, 0.0], [-101.27464, -74.804247, 0.0], [-101.259243, -74.798558, 0.0], [-101.251822, -74.792086, 0.0], [-101.267741, -74.78708, 0.0], [-101.256493, -74.781809, 0.0], [-101.257733, -74.779767, 0.0], [-101.250447, -74.777156, 0.0], [-101.240613, -74.770054, 0.0], [-101.222641, -74.763963, 0.0], [-101.216307, -74.748673, 0.0], [-101.212936, -74.740259, 0.0], [-101.200426, -74.734469, 0.0], [-101.197349, -74.72643, 0.0], [-101.188725, -74.7179, 0.0], [-101.207959, -74.716895, 0.0], [-101.219968, -74.709239, 0.0], [-101.232933, -74.706803, 0.0], [-101.230248, -74.703234, 0.0], [-101.238372, -74.70027, 0.0], [-101.254074, -74.700252, 0.0], [-101.275428, -74.693637, 0.0], [-101.306089, -74.693851, 0.0], [-101.351676, -74.691805, 0.0], [-101.364701, -74.681592, 0.0], [-101.396392, -74.67954, 0.0], [-101.416381, -74.679976, 0.0], [-101.462601, -74.674445, 0.0], [-101.482989, -74.660146, 0.0], [-101.530932, -74.656493, 0.0], [-101.545802, -74.657827, 0.0], [-101.570915, -74.655354, 0.0], [-101.627933, -74.648117, 0.0], [-101.647793, -74.639151, 0.0], [-101.676385, -74.635907, 0.0], [-101.678978, -74.633321, 0.0], [-101.695894, -74.628422, 0.0], [-101.728673, -74.621731, 0.0], [-101.781287, -74.617603, 0.0], [-101.794801, -74.615021, 0.0], [-101.870395, -74.608983, 0.0], [-101.933735, -74.601768, 0.0], [-101.986726, -74.595483, 0.0], [-102.032573, -74.595827, 0.0], [-102.026749, -74.590285, 0.0], [-102.010395, -74.580201, 0.0], [-102.035597, -74.564212, 0.0], [-102.090552, -74.553133, 0.0], [-102.264411, -74.519626, 0.0], [-102.339743, -74.51083, 0.0], [-102.411915, -74.510518, 0.0], [-102.424826, -74.497263, 0.0], [-102.377212, -74.483896, 0.0], [-102.280808, -74.473374, 0.0], [-102.236421, -74.463717, 0.0], [-102.185211, -74.450043, 0.0], [-102.150282, -74.438359, 0.0], [-102.110682, -74.429878, 0.0], [-102.080455, -74.419386, 0.0], [-102.029215, -74.421347, 0.0], [-101.986657, -74.414487, 0.0], [-101.942992, -74.405238, 0.0], [-101.914922, -74.383364, 0.0], [-101.795349, -74.369597, 0.0], [-101.698034, -74.375051, 0.0], [-101.572267, -74.390817, 0.0], [-101.433665, -74.404266, 0.0], [-101.358339, -74.410301, 0.0], [-101.276679, -74.412744, 0.0], [-101.200663, -74.403148, 0.0], [-101.126055, -74.400282, 0.0], [-101.050277, -74.385754, 0.0], [-100.925725, -74.378623, 0.0], [-100.827076, -74.373988, 0.0], [-100.786332, -74.316362, 0.0], [-100.72066, -74.319735, 0.0], [-100.708238, -74.301973, 0.0], [-100.642611, -74.305321, 0.0], [-100.617997, -74.26979, 0.0], [-100.552486, -74.273111, 0.0], [-100.528129, -74.237572, 0.0], [-100.462734, -74.240864, 0.0], [-100.355131, -74.080906, 0.0], [-100.290352, -74.084143, 0.0], [-100.278602, -74.066367, 0.0], [-100.213868, -74.06958, 0.0], [-100.190588, -74.03402, 0.0], [-100.125968, -74.037206, 0.0], [-100.114438, -74.019422, 0.0], [-100.049863, -74.022585, 0.0], [-100.061323, -74.040372, 0.0], [-99.996651, -74.043518, 0.0], [-100.008066, -74.061309, 0.0], [-99.943298, -74.064439, 0.0], [-99.954667, -74.082234, 0.0], [-99.889802, -74.085347, 0.0], [-99.878504, -74.067549, 0.0], [-99.68397, -74.076757, 0.0], [-99.672911, -74.058947, 0.0], [-99.218628, -74.079702, 0.0], [-99.208094, -74.061869, 0.0], [-98.688058, -74.08435, 0.0], [-98.678122, -74.06649, 0.0], [-98.026778, -74.092735, 0.0], [-98.035988, -74.110626, 0.0], [-97.774563, -74.120566, 0.0], [-97.783502, -74.138469, 0.0], [-97.521457, -74.148094, 0.0], [-97.512812, -74.13018, 0.0], [-97.447324, -74.132532, 0.0], [-97.438772, -74.114615, 0.0], [-97.242413, -74.121541, 0.0], [-97.234101, -74.103616, 0.0], [-97.103247, -74.108126, 0.0], [-97.095101, -74.090197, 0.0], [-97.02972, -74.092418, 0.0], [-97.021665, -74.074486, 0.0], [-96.825632, -74.08102, 0.0], [-96.833465, -74.098959, 0.0], [-96.768011, -74.101099, 0.0], [-96.775789, -74.119041, 0.0], [-96.513501, -74.127404, 0.0], [-96.506019, -74.109452, 0.0], [-96.374919, -74.113506, 0.0], [-96.367602, -74.095549, 0.0], [-96.302101, -74.097543, 0.0], [-96.294875, -74.079584, 0.0], [-96.229432, -74.081555, 0.0], [-96.222295, -74.063595, 0.0], [-96.156909, -74.065543, 0.0], [-96.149863, -74.047581, 0.0], [-95.95383, -74.053295, 0.0], [-95.947021, -74.035326, 0.0], [-95.816402, -74.039029, 0.0], [-95.809755, -74.021057, 0.0], [-95.679223, -74.024673, 0.0], [-95.672738, -74.006697, 0.0], [-95.542294, -74.010228, 0.0], [-95.535971, -73.992248, 0.0], [-95.405616, -73.995692, 0.0], [-95.399454, -73.97771, 0.0], [-95.26919, -73.981068, 0.0], [-95.263189, -73.963082, 0.0], [-95.133017, -73.966355, 0.0], [-95.121348, -73.930376, 0.0], [-95.056388, -73.931978, 0.0], [-95.050646, -73.913988, 0.0], [-94.985747, -73.915568, 0.0], [-94.980091, -73.897576, 0.0], [-94.915251, -73.899134, 0.0], [-94.909681, -73.881141, 0.0], [-94.844902, -73.882677, 0.0], [-94.839417, -73.864683, 0.0], [-94.774698, -73.866196, 0.0], [-94.769297, -73.848201, 0.0], [-94.704639, -73.849692, 0.0], [-94.699323, -73.831696, 0.0], [-94.634725, -73.833165, 0.0], [-94.629493, -73.815168, 0.0], [-94.564955, -73.816615, 0.0], [-94.559808, -73.798617, 0.0], [-94.430842, -73.801447, 0.0], [-94.420869, -73.765446, 0.0], [-94.356514, -73.766828, 0.0], [-94.351616, -73.748827, 0.0], [-94.287321, -73.750186, 0.0], [-94.277701, -73.714183, 0.0], [-94.213539, -73.715519, 0.0], [-94.223015, -73.751526, 0.0], [-94.158698, -73.752845, 0.0], [-94.168073, -73.788858, 0.0], [-94.103602, -73.79016, 0.0], [-94.117527, -73.844188, 0.0], [-94.052828, -73.845474, 0.0], [-94.057417, -73.863487, 0.0], [-93.992635, -73.864754, 0.0], [-93.997163, -73.882768, 0.0], [-93.5429, -73.89108, 0.0], [-93.546925, -73.909105, 0.0], [-93.416904, -73.911299, 0.0], [-93.420791, -73.929327, 0.0], [-93.095219, -73.934459, 0.0], [-93.098746, -73.952494, 0.0], [-93.033533, -73.95346, 0.0], [-93.030081, -73.935424, 0.0], [-92.117389, -73.946779, 0.0], [-92.114979, -73.92873, 0.0], [-92.049815, -73.929387, 0.0], [-92.05215, -73.947436, 0.0], [-91.921656, -73.948689, 0.0], [-91.923848, -73.96674, 0.0], [-91.793186, -73.967912, 0.0], [-91.795233, -73.985966, 0.0], [-91.729821, -73.986521, 0.0], [-91.731798, -74.004576, 0.0], [-91.666307, -74.005112, 0.0], [-91.668214, -74.023169, 0.0], [-91.077936, -74.027065, 0.0], [-91.076703, -74.009003, 0.0], [-91.011175, -74.009332, 0.0], [-91.01002, -73.991272, 0.0], [-90.879106, -73.991867, 0.0], [-90.878103, -73.973806, 0.0], [-90.812717, -73.974073, 0.0], [-90.811791, -73.956012, 0.0], [-90.746478, -73.956258, 0.0], [-90.74733, -73.974319, 0.0], [-90.551155, -73.974933, 0.0], [-90.551785, -73.992995, 0.0], [-90.486316, -73.993159, 0.0], [-90.486872, -74.011222, 0.0], [-90.290232, -74.011589, 0.0], [-90.290565, -74.029653, 0.0], [-90.159318, -74.029795, 0.0], [-90.1595, -74.047861, 0.0], [-90.028101, -74.04792, 0.0], [-90.028133, -74.065986, 0.0], [-89.830808, -74.065919, 0.0], [-89.830418, -74.102053, 0.0], [-89.764492, -74.10199, 0.0], [-89.764221, -74.120058, 0.0], [-89.69822, -74.119973, 0.0], [-89.697523, -74.156112, 0.0], [-89.63137, -74.156006, 0.0], [-89.630517, -74.192147, 0.0], [-89.564212, -74.19202, 0.0], [-89.563707, -74.210092, 0.0], [-89.430947, -74.209775, 0.0], [-89.430287, -74.227847, 0.0], [-89.29738, -74.227445, 0.0], [-89.296564, -74.245518, 0.0], [-89.230036, -74.245285, 0.0], [-89.22914, -74.263358, 0.0], [-89.162537, -74.263104, 0.0], [-89.161562, -74.281178, 0.0], [-89.028207, -74.280607, 0.0], [-89.02594, -74.316754, 0.0], [-88.892285, -74.316097, 0.0], [-88.890991, -74.334171, 0.0], [-88.82409, -74.333811, 0.0], [-88.822715, -74.351885, 0.0], [-88.688766, -74.3511, 0.0], [-88.687231, -74.369174, 0.0], [-88.620184, -74.368749, 0.0], [-88.618567, -74.386824, 0.0], [-88.484327, -74.38591, 0.0], [-88.482549, -74.403984, 0.0], [-88.348167, -74.402984, 0.0], [-88.346228, -74.421057, 0.0], [-88.278965, -74.420525, 0.0], [-88.276942, -74.438598, 0.0], [-88.142273, -74.437468, 0.0], [-88.140087, -74.455541, 0.0], [-88.072681, -74.454944, 0.0], [-88.07041, -74.473017, 0.0], [-87.935456, -74.471756, 0.0], [-87.93302, -74.489828, 0.0], [-87.865472, -74.489165, 0.0], [-87.862952, -74.507237, 0.0], [-87.79533, -74.506552, 0.0], [-87.792724, -74.524624, 0.0], [-87.65734, -74.523188, 0.0], [-87.654567, -74.541259, 0.0], [-87.586805, -74.540508, 0.0], [-87.583946, -74.558579, 0.0], [-87.51611, -74.557806, 0.0], [-87.513164, -74.575876, 0.0], [-87.241573, -74.572566, 0.0], [-87.238298, -74.590633, 0.0], [-87.034444, -74.587922, 0.0], [-87.03092, -74.605986, 0.0], [-86.962905, -74.605038, 0.0], [-86.955671, -74.641167, 0.0], [-86.887503, -74.640195, 0.0], [-86.868859, -74.730522, 0.0], [-86.800293, -74.729523, 0.0], [-86.792609, -74.765656, 0.0], [-86.723889, -74.764633, 0.0], [-86.716003, -74.800766, 0.0], [-86.647127, -74.799719, 0.0], [-86.63091, -74.871988, 0.0], [-86.561712, -74.870913, 0.0], [-86.553377, -74.907049, 0.0], [-86.622742, -74.908126, 0.0]]) - obs = apifmt._fmt_spatial('polygon', poly) - exp = {'polygon': '-86.622742,-74.908126,-86.561712,-74.870913,-86.868859,-74.730522,-86.962905,-74.605038,-89.02594,-74.316754,-89.630517,-74.192147,-89.830808,-74.065919,-90.746478,-73.956258,-91.668214,-74.023169,-92.049815,-73.929387,-93.420791,-73.929327,-93.997163,-73.882768,-94.277701,-73.714183,-95.133017,-73.966355,-96.513501,-74.127404,-99.889802,-74.085347,-100.114438,-74.019422,-100.355131,-74.080906,-100.462734,-74.240864,-100.827076,-74.373988,-101.795349,-74.369597,-102.424826,-74.497263,-101.188725,-74.7179,-101.564382,-75.02971,-103.37484,-75.273725,-103.914847,-75.426057,-104.012128,-75.5223,-103.029452,-75.748774,-102.350567,-75.749245,-101.837882,-75.943066,-101.899461,-76.014086,-101.280944,-76.192769,-101.325735,-76.246168,-101.190803,-76.27106,-101.250474,-76.342292,-101.175067,-76.345822,-101.402436,-76.52035,-101.326063,-76.523929,-101.449791,-76.666392,-101.310795,-76.691373,-101.357407,-76.744819,-101.217404,-76.769752,-101.295133,-76.85887,-101.058051,-76.962123,-100.447336,-77.117686,-98.433698,-77.320866,-97.28308,-77.355688,-97.491148,-77.423178,-96.514174,-77.485919,-96.552494,-77.558236,-96.384656,-77.562336,-96.441516,-77.670857,-97.139363,-77.836566,-97.193451,-77.926901,-97.64271,-78.080044,-96.297869,-78.388943,-96.327803,-78.44329,-95.721466,-78.511065,-95.748962,-78.565482,-94.940425,-78.617072,-94.988611,-78.726066,-94.911669,-78.763976,-95.609268,-78.843079,-95.637038,-78.897535,-95.37191,-78.9391,-95.693408,-79.006456,-95.269903,-79.124145,-95.323729,-79.233172,-95.430206,-79.249633,-95.155505,-79.291032,-95.191045,-79.363748,-94.81352,-79.406486,-94.847075,-79.479253,-94.747448,-79.48078,-94.772403,-79.535367,-93.90411,-79.638844,-93.843651,-79.749409,-93.967323,-79.802836,-93.788723,-79.87821,-93.816393,-79.951128,-93.230546,-80.085534,-91.707475,-79.87748,-91.801545,-79.822143,-91.488897,-79.805457,-91.465152,-79.641131,-90.447349,-79.5894,-90.545492,-79.534464,-90.042319,-79.37062,-90.140775,-79.334083,-90.041814,-79.24285,-88.982186,-79.076903,-90.230262,-78.914333,-90.32191,-78.804808,-90.689626,-78.676516,-91.150024,-78.638589,-92.035347,-78.414844,-92.106013,-78.30491,-91.651645,-78.271472,-91.365784,-78.127206,-91.188783,-78.128018,-91.090167,-78.019109,-90.737076,-77.983849,-90.909191,-77.946905,-90.732603,-77.911009,-90.727088,-77.819973,-91.070502,-77.800626,-91.14118,-77.636469,-91.90279,-77.613923,-91.984627,-77.595116,-91.972963,-77.522365,-92.466819,-77.463587,-92.199521,-77.374914,-92.352136,-77.300761,-92.335283,-77.209895,-91.434206,-77.234653,-91.426015,-77.16193,-91.015545,-77.145686,-91.008355,-77.054784,-91.086397,-77.018096,-91.647835,-76.97871,-91.640906,-76.924199,-91.873848,-76.868024,-91.779021,-76.759619,-90.823937,-76.710073,-90.345113,-76.52953,-86.988029,-75.856983,-86.945563,-75.711143,-86.872234,-75.710165,-87.034102,-75.63967,-86.965004,-75.620616,-87.075115,-75.440545,-87.003154,-75.439609,-87.021872,-75.349129,-86.835058,-75.219586,-86.850654,-75.147247,-86.717729,-75.109052,-86.737771,-75.018662,-86.602149,-74.998483,-86.622742,-74.908126'} + poly = Polygon( + [ + [-86.622742, -74.908126, 0.0], + [-86.602149, -74.998483, 0.0], + [-86.671945, -74.999545, 0.0], + [-86.667881, -75.01762, 0.0], + [-86.737771, -75.018662, 0.0], + [-86.717729, -75.109052, 0.0], + [-86.788057, -75.110077, 0.0], + [-86.780144, -75.14624, 0.0], + [-86.850654, -75.147247, 0.0], + [-86.835058, -75.219586, 0.0], + [-86.905925, -75.220574, 0.0], + [-86.894389, -75.274839, 0.0], + [-86.965529, -75.27581, 0.0], + [-86.950368, -75.348177, 0.0], + [-87.021872, -75.349129, 0.0], + [-87.003154, -75.439609, 0.0], + [-87.075115, -75.440545, 0.0], + [-87.052886, -75.549149, 0.0], + [-86.98038, -75.548205, 0.0], + [-86.965004, -75.620616, 0.0], + [-87.037878, -75.621564, 0.0], + [-87.034102, -75.63967, 0.0], + [-86.961136, -75.63872, 0.0], + [-86.957257, -75.656825, 0.0], + [-86.884208, -75.655851, 0.0], + [-86.872234, -75.710165, 0.0], + [-86.945563, -75.711143, 0.0], + [-86.925871, -75.801686, 0.0], + [-86.999681, -75.802647, 0.0], + [-86.988029, -75.856983, 0.0], + [-87.062135, -75.857925, 0.0], + [-87.058326, -75.87604, 0.0], + [-87.132537, -75.876959, 0.0], + [-87.128815, -75.895075, 0.0], + [-87.203132, -75.895972, 0.0], + [-87.199496, -75.914091, 0.0], + [-87.273919, -75.914965, 0.0], + [-87.27037, -75.933086, 0.0], + [-87.344899, -75.933938, 0.0], + [-87.341438, -75.95206, 0.0], + [-87.490715, -75.953695, 0.0], + [-87.487439, -75.97182, 0.0], + [-87.562188, -75.972604, 0.0], + [-87.559001, -75.99073, 0.0], + [-87.633856, -75.991491, 0.0], + [-87.627653, -76.027748, 0.0], + [-87.777778, -76.029203, 0.0], + [-87.774861, -76.047334, 0.0], + [-87.925213, -76.048696, 0.0], + [-87.922485, -76.06683, 0.0], + [-87.997771, -76.067476, 0.0], + [-87.995135, -76.085611, 0.0], + [-88.070527, -76.086234, 0.0], + [-88.067983, -76.104371, 0.0], + [-88.143481, -76.104971, 0.0], + [-88.14103, -76.123109, 0.0], + [-88.216633, -76.123686, 0.0], + [-88.214276, -76.141826, 0.0], + [-88.365701, -76.142909, 0.0], + [-88.363537, -76.161051, 0.0], + [-88.439359, -76.161557, 0.0], + [-88.43729, -76.1797, 0.0], + [-88.513217, -76.180183, 0.0], + [-88.511244, -76.198328, 0.0], + [-88.587276, -76.198787, 0.0], + [-88.585399, -76.216933, 0.0], + [-88.737681, -76.217781, 0.0], + [-88.736001, -76.235929, 0.0], + [-88.81225, -76.236317, 0.0], + [-88.810667, -76.254466, 0.0], + [-88.887022, -76.254831, 0.0], + [-88.885537, -76.272981, 0.0], + [-88.961998, -76.273321, 0.0], + [-88.960611, -76.291473, 0.0], + [-89.037177, -76.29179, 0.0], + [-89.035889, -76.309942, 0.0], + [-89.112561, -76.310235, 0.0], + [-89.111372, -76.328389, 0.0], + [-89.264932, -76.328903, 0.0], + [-89.263946, -76.347058, 0.0], + [-89.340833, -76.347279, 0.0], + [-89.339947, -76.365434, 0.0], + [-89.41694, -76.365631, 0.0], + [-89.416155, -76.383788, 0.0], + [-89.493254, -76.383961, 0.0], + [-89.492571, -76.402118, 0.0], + [-89.569775, -76.402267, 0.0], + [-89.569195, -76.420425, 0.0], + [-89.723816, -76.420649, 0.0], + [-89.723443, -76.438808, 0.0], + [-89.800859, -76.438884, 0.0], + [-89.80059, -76.457044, 0.0], + [-89.878112, -76.457095, 0.0], + [-89.877947, -76.475255, 0.0], + [-89.955575, -76.475282, 0.0], + [-89.955514, -76.493443, 0.0], + [-90.033248, -76.493445, 0.0], + [-90.033293, -76.511607, 0.0], + [-90.111131, -76.511584, 0.0], + [-90.111283, -76.529747, 0.0], + [-90.345113, -76.52953, 0.0], + [-90.345583, -76.547693, 0.0], + [-90.42363, -76.547571, 0.0], + [-90.424208, -76.565734, 0.0], + [-90.50236, -76.565588, 0.0], + [-90.503734, -76.601916, 0.0], + [-90.582098, -76.601744, 0.0], + [-90.583695, -76.638075, 0.0], + [-90.662272, -76.637877, 0.0], + [-90.664093, -76.67421, 0.0], + [-90.742884, -76.673987, 0.0], + [-90.743907, -76.692154, 0.0], + [-90.822803, -76.691906, 0.0], + [-90.823937, -76.710073, 0.0], + [-91.060932, -76.709176, 0.0], + [-91.062397, -76.727343, 0.0], + [-91.536922, -76.72487, 0.0], + [-91.539047, -76.743034, 0.0], + [-91.697397, -76.742008, 0.0], + [-91.699746, -76.760171, 0.0], + [-91.779021, -76.759619, 0.0], + [-91.783959, -76.795946, 0.0], + [-91.863446, -76.795367, 0.0], + [-91.873848, -76.868024, 0.0], + [-91.793917, -76.868605, 0.0], + [-91.796424, -76.886772, 0.0], + [-91.716375, -76.887329, 0.0], + [-91.721186, -76.923666, 0.0], + [-91.640906, -76.924199, 0.0], + [-91.647835, -76.97871, 0.0], + [-91.325297, -76.980597, 0.0], + [-91.327166, -76.998771, 0.0], + [-91.165637, -76.999562, 0.0], + [-91.167283, -77.017738, 0.0], + [-91.086397, -77.018096, 0.0], + [-91.089474, -77.054451, 0.0], + [-91.008355, -77.054784, 0.0], + [-91.015545, -77.145686, 0.0], + [-91.178934, -77.144989, 0.0], + [-91.180618, -77.16317, 0.0], + [-91.426015, -77.16193, 0.0], + [-91.434206, -77.234653, 0.0], + [-92.092069, -77.230176, 0.0], + [-92.08907, -77.212001, 0.0], + [-92.335283, -77.209895, 0.0], + [-92.352136, -77.300761, 0.0], + [-92.269483, -77.301495, 0.0], + [-92.276054, -77.337847, 0.0], + [-92.193152, -77.338557, 0.0], + [-92.199521, -77.374914, 0.0], + [-92.282662, -77.374202, 0.0], + [-92.285981, -77.392381, 0.0], + [-92.369233, -77.391642, 0.0], + [-92.383091, -77.464357, 0.0], + [-92.466819, -77.463587, 0.0], + [-92.470431, -77.481766, 0.0], + [-92.386581, -77.482537, 0.0], + [-92.390081, -77.500717, 0.0], + [-92.138102, -77.502874, 0.0], + [-92.141243, -77.521058, 0.0], + [-91.972963, -77.522365, 0.0], + [-91.984627, -77.595116, 0.0], + [-91.899978, -77.595733, 0.0], + [-91.90279, -77.613923, 0.0], + [-91.4788, -77.616608, 0.0], + [-91.480993, -77.634803, 0.0], + [-91.14118, -77.636469, 0.0], + [-91.14799, -77.709264, 0.0], + [-91.062516, -77.709615, 0.0], + [-91.070502, -77.800626, 0.0], + [-90.812128, -77.801523, 0.0], + [-90.81335, -77.819728, 0.0], + [-90.727088, -77.819973, 0.0], + [-90.732603, -77.911009, 0.0], + [-90.81952, -77.910763, 0.0], + [-90.820765, -77.928971, 0.0], + [-90.90781, -77.928697, 0.0], + [-90.909191, -77.946905, 0.0], + [-90.822014, -77.94718, 0.0], + [-90.823267, -77.96539, 0.0], + [-90.735953, -77.965638, 0.0], + [-90.737076, -77.983849, 0.0], + [-90.824523, -77.983601, 0.0], + [-90.825784, -78.001812, 0.0], + [-90.91336, -78.001535, 0.0], + [-90.914759, -78.019746, 0.0], + [-91.090167, -78.019109, 0.0], + [-91.093515, -78.055531, 0.0], + [-91.181481, -78.05517, 0.0], + [-91.188783, -78.128018, 0.0], + [-91.365784, -78.127206, 0.0], + [-91.370017, -78.163631, 0.0], + [-91.458782, -78.163181, 0.0], + [-91.463317, -78.199607, 0.0], + [-91.552351, -78.199128, 0.0], + [-91.554767, -78.217341, 0.0], + [-91.643932, -78.216832, 0.0], + [-91.651645, -78.271472, 0.0], + [-91.830785, -78.270365, 0.0], + [-91.833652, -78.288578, 0.0], + [-92.013037, -78.287355, 0.0], + [-92.016194, -78.305566, 0.0], + [-92.106013, -78.30491, 0.0], + [-92.115968, -78.359544, 0.0], + [-92.025726, -78.360203, 0.0], + [-92.035347, -78.414844, 0.0], + [-91.944667, -78.415477, 0.0], + [-91.947751, -78.433693, 0.0], + [-91.856918, -78.434298, 0.0], + [-91.859867, -78.452516, 0.0], + [-91.76888, -78.453093, 0.0], + [-91.771695, -78.471312, 0.0], + [-91.680555, -78.471861, 0.0], + [-91.683233, -78.490081, 0.0], + [-91.591939, -78.490602, 0.0], + [-91.59703, -78.527046, 0.0], + [-91.505436, -78.52754, 0.0], + [-91.507847, -78.545764, 0.0], + [-91.324343, -78.546665, 0.0], + [-91.330738, -78.601343, 0.0], + [-91.238533, -78.601752, 0.0], + [-91.24053, -78.61998, 0.0], + [-91.14817, -78.62036, 0.0], + [-91.150024, -78.638589, 0.0], + [-90.872462, -78.639554, 0.0], + [-90.873874, -78.657786, 0.0], + [-90.781194, -78.658049, 0.0], + [-90.78246, -78.676281, 0.0], + [-90.689626, -78.676516, 0.0], + [-90.691868, -78.712982, 0.0], + [-90.598728, -78.713188, 0.0], + [-90.599703, -78.731422, 0.0], + [-90.506409, -78.731598, 0.0], + [-90.508064, -78.76807, 0.0], + [-90.414462, -78.768217, 0.0], + [-90.41582, -78.804691, 0.0], + [-90.32191, -78.804808, 0.0], + [-90.324034, -78.877764, 0.0], + [-90.229502, -78.877852, 0.0], + [-90.230262, -78.914333, 0.0], + [-90.040568, -78.914419, 0.0], + [-90.040635, -78.932661, 0.0], + [-89.94563, -78.932659, 0.0], + [-89.94554, -78.950901, 0.0], + [-89.850378, -78.950868, 0.0], + [-89.850129, -78.969111, 0.0], + [-89.754809, -78.969048, 0.0], + [-89.75399, -79.005535, 0.0], + [-89.562719, -79.005317, 0.0], + [-89.561988, -79.023561, 0.0], + [-89.466196, -79.023406, 0.0], + [-89.465302, -79.04165, 0.0], + [-89.273406, -79.041249, 0.0], + [-89.272187, -79.059493, 0.0], + [-88.983893, -79.05866, 0.0], + [-88.982186, -79.076903, 0.0], + [-89.1747, -79.07749, 0.0], + [-89.173311, -79.095734, 0.0], + [-89.269737, -79.095982, 0.0], + [-89.268506, -79.114228, 0.0], + [-89.365099, -79.114445, 0.0], + [-89.364027, -79.132691, 0.0], + [-89.460787, -79.132879, 0.0], + [-89.458959, -79.169374, 0.0], + [-89.55605, -79.16953, 0.0], + [-89.555296, -79.187779, 0.0], + [-89.652554, -79.187905, 0.0], + [-89.651963, -79.206154, 0.0], + [-89.749389, -79.20625, 0.0], + [-89.748962, -79.2245, 0.0], + [-89.846555, -79.224564, 0.0], + [-89.846293, -79.242815, 0.0], + [-90.041814, -79.24285, 0.0], + [-90.042029, -79.297606, 0.0], + [-90.140292, -79.297577, 0.0], + [-90.140775, -79.334083, 0.0], + [-90.042173, -79.334112, 0.0], + [-90.042319, -79.37062, 0.0], + [-90.141261, -79.370591, 0.0], + [-90.141505, -79.388846, 0.0], + [-90.240618, -79.388785, 0.0], + [-90.241873, -79.443552, 0.0], + [-90.341501, -79.443459, 0.0], + [-90.342693, -79.479973, 0.0], + [-90.442666, -79.479848, 0.0], + [-90.444995, -79.534621, 0.0], + [-90.545492, -79.534464, 0.0], + [-90.546451, -79.552722, 0.0], + [-90.445777, -79.55288, 0.0], + [-90.447349, -79.5894, 0.0], + [-91.053456, -79.587965, 0.0], + [-91.055316, -79.606223, 0.0], + [-91.257663, -79.605486, 0.0], + [-91.259887, -79.623743, 0.0], + [-91.361228, -79.623325, 0.0], + [-91.36364, -79.641582, 0.0], + [-91.465152, -79.641131, 0.0], + [-91.488897, -79.805457, 0.0], + [-91.695178, -79.804442, 0.0], + [-91.698235, -79.822701, 0.0], + [-91.801545, -79.822143, 0.0], + [-91.808067, -79.85866, 0.0], + [-91.704384, -79.85922, 0.0], + [-91.707475, -79.87748, 0.0], + [-91.811346, -79.876919, 0.0], + [-91.814637, -79.895179, 0.0], + [-91.918685, -79.894584, 0.0], + [-91.922176, -79.912843, 0.0], + [-92.026401, -79.912214, 0.0], + [-92.030095, -79.930472, 0.0], + [-92.134495, -79.929808, 0.0], + [-92.138393, -79.948066, 0.0], + [-92.347532, -79.946636, 0.0], + [-92.351826, -79.964891, 0.0], + [-92.456562, -79.964125, 0.0], + [-92.461064, -79.982379, 0.0], + [-92.565975, -79.981578, 0.0], + [-92.570685, -79.999832, 0.0], + [-92.78084, -79.998126, 0.0], + [-92.785952, -80.016376, 0.0], + [-92.891195, -80.015471, 0.0], + [-92.896519, -80.033721, 0.0], + [-93.001935, -80.032781, 0.0], + [-93.007473, -80.051029, 0.0], + [-93.113062, -80.050053, 0.0], + [-93.118814, -80.0683, 0.0], + [-93.224577, -80.067288, 0.0], + [-93.230546, -80.085534, 0.0], + [-93.336481, -80.084487, 0.0], + [-93.324176, -80.048001, 0.0], + [-93.429699, -80.046925, 0.0], + [-93.417099, -80.010444, 0.0], + [-93.522213, -80.009338, 0.0], + [-93.515756, -79.991101, 0.0], + [-93.620655, -79.989964, 0.0], + [-93.61403, -79.971729, 0.0], + [-93.718714, -79.97056, 0.0], + [-93.711924, -79.952328, 0.0], + [-93.816393, -79.951128, 0.0], + [-93.788723, -79.87821, 0.0], + [-93.892414, -79.876987, 0.0], + [-93.864399, -79.804083, 0.0], + [-93.967323, -79.802836, 0.0], + [-93.946026, -79.748169, 0.0], + [-93.843651, -79.749409, 0.0], + [-93.823125, -79.694739, 0.0], + [-93.924956, -79.693505, 0.0], + [-93.90411, -79.638844, 0.0], + [-94.005379, -79.637584, 0.0], + [-93.998302, -79.619367, 0.0], + [-94.099369, -79.618077, 0.0], + [-94.092139, -79.599863, 0.0], + [-94.193003, -79.598544, 0.0], + [-94.185623, -79.580332, 0.0], + [-94.386921, -79.577602, 0.0], + [-94.379215, -79.559395, 0.0], + [-94.680431, -79.555069, 0.0], + [-94.672229, -79.53687, 0.0], + [-94.772403, -79.535367, 0.0], + [-94.747448, -79.48078, 0.0], + [-94.847075, -79.479253, 0.0], + [-94.81352, -79.406486, 0.0], + [-94.912434, -79.404938, 0.0], + [-94.903948, -79.38675, 0.0], + [-95.101351, -79.383566, 0.0], + [-95.092557, -79.365384, 0.0], + [-95.191045, -79.363748, 0.0], + [-95.155505, -79.291032, 0.0], + [-95.253295, -79.289376, 0.0], + [-95.244321, -79.271201, 0.0], + [-95.341915, -79.269517, 0.0], + [-95.332806, -79.251344, 0.0], + [-95.430206, -79.249633, 0.0], + [-95.420964, -79.231464, 0.0], + [-95.323729, -79.233172, 0.0], + [-95.269903, -79.124145, 0.0], + [-95.366167, -79.122454, 0.0], + [-95.357141, -79.104287, 0.0], + [-95.453215, -79.102568, 0.0], + [-95.425842, -79.048076, 0.0], + [-95.616944, -79.044565, 0.0], + [-95.598218, -79.00825, 0.0], + [-95.693408, -79.006456, 0.0], + [-95.683935, -78.988302, 0.0], + [-95.588901, -78.990093, 0.0], + [-95.579615, -78.971937, 0.0], + [-95.484707, -78.973695, 0.0], + [-95.475607, -78.955536, 0.0], + [-95.380824, -78.957262, 0.0], + [-95.37191, -78.9391, 0.0], + [-95.466538, -78.937377, 0.0], + [-95.457498, -78.919218, 0.0], + [-95.551942, -78.917468, 0.0], + [-95.542778, -78.899312, 0.0], + [-95.637038, -78.897535, 0.0], + [-95.609268, -78.843079, 0.0], + [-95.515467, -78.844846, 0.0], + [-95.506423, -78.826692, 0.0], + [-95.412744, -78.828427, 0.0], + [-95.403881, -78.81027, 0.0], + [-95.310325, -78.811973, 0.0], + [-95.301642, -78.793813, 0.0], + [-95.114747, -78.797124, 0.0], + [-95.106394, -78.778959, 0.0], + [-95.013057, -78.780567, 0.0], + [-95.004882, -78.7624, 0.0], + [-94.911669, -78.763976, 0.0], + [-94.895698, -78.727637, 0.0], + [-94.988611, -78.726066, 0.0], + [-94.940425, -78.617072, 0.0], + [-95.032424, -78.615487, 0.0], + [-95.024337, -78.597325, 0.0], + [-95.207964, -78.594073, 0.0], + [-95.191285, -78.557761, 0.0], + [-95.465652, -78.552682, 0.0], + [-95.474413, -78.57083, 0.0], + [-95.748962, -78.565482, 0.0], + [-95.721466, -78.511065, 0.0], + [-95.812493, -78.509234, 0.0], + [-95.803243, -78.491098, 0.0], + [-96.075717, -78.48544, 0.0], + [-96.06607, -78.467314, 0.0], + [-96.156692, -78.465373, 0.0], + [-96.146934, -78.447251, 0.0], + [-96.327803, -78.44329, 0.0], + [-96.297869, -78.388943, 0.0], + [-96.387836, -78.386929, 0.0], + [-96.377781, -78.368817, 0.0], + [-96.467577, -78.366779, 0.0], + [-96.457416, -78.34867, 0.0], + [-96.547041, -78.346606, 0.0], + [-96.536773, -78.328501, 0.0], + [-96.80504, -78.32215, 0.0], + [-96.794392, -78.304055, 0.0], + [-96.883611, -78.301886, 0.0], + [-96.872859, -78.283794, 0.0], + [-96.961909, -78.2816, 0.0], + [-96.940233, -78.245425, 0.0], + [-97.028977, -78.243209, 0.0], + [-97.018054, -78.225125, 0.0], + [-97.19517, -78.220617, 0.0], + [-97.184011, -78.20254, 0.0], + [-97.272383, -78.200248, 0.0], + [-97.238713, -78.14603, 0.0], + [-97.326651, -78.14372, 0.0], + [-97.315364, -78.125651, 0.0], + [-97.403134, -78.123318, 0.0], + [-97.391749, -78.105253, 0.0], + [-97.566921, -78.10051, 0.0], + [-97.555308, -78.082453, 0.0], + [-97.64271, -78.080044, 0.0], + [-97.607693, -78.025883, 0.0], + [-97.520682, -78.02828, 0.0], + [-97.497773, -77.992166, 0.0], + [-97.410987, -77.994529, 0.0], + [-97.399713, -77.976468, 0.0], + [-97.313022, -77.9788, 0.0], + [-97.27979, -77.924608, 0.0], + [-97.193451, -77.926901, 0.0], + [-97.139363, -77.836566, 0.0], + [-96.967859, -77.841038, 0.0], + [-96.946954, -77.804891, 0.0], + [-96.861407, -77.80708, 0.0], + [-96.851127, -77.789004, 0.0], + [-96.765675, -77.791162, 0.0], + [-96.725358, -77.718845, 0.0], + [-96.640377, -77.720964, 0.0], + [-96.620645, -77.6848, 0.0], + [-96.535882, -77.686886, 0.0], + [-96.526184, -77.668801, 0.0], + [-96.441516, -77.670857, 0.0], + [-96.384656, -77.562336, 0.0], + [-96.552494, -77.558236, 0.0], + [-96.514174, -77.485919, 0.0], + [-96.59757, -77.483841, 0.0], + [-96.58794, -77.465766, 0.0], + [-96.671187, -77.463665, 0.0], + [-96.680937, -77.481738, 0.0], + [-97.263693, -77.466276, 0.0], + [-97.253111, -77.448226, 0.0], + [-97.336123, -77.445916, 0.0], + [-97.325453, -77.42787, 0.0], + [-97.491148, -77.423178, 0.0], + [-97.480274, -77.405139, 0.0], + [-97.397559, -77.407495, 0.0], + [-97.376139, -77.371411, 0.0], + [-97.293628, -77.373733, 0.0], + [-97.28308, -77.355688, 0.0], + [-98.433698, -77.320866, 0.0], + [-98.421564, -77.302872, 0.0], + [-98.666926, -77.294764, 0.0], + [-98.642079, -77.2588, 0.0], + [-99.049167, -77.244815, 0.0], + [-99.036233, -77.226854, 0.0], + [-99.522851, -77.209257, 0.0], + [-99.509284, -77.191321, 0.0], + [-99.832489, -77.179101, 0.0], + [-99.818518, -77.161182, 0.0], + [-99.979666, -77.154929, 0.0], + [-99.965515, -77.137019, 0.0], + [-100.447336, -77.117686, 0.0], + [-100.432572, -77.099804, 0.0], + [-100.512625, -77.096499, 0.0], + [-100.483005, -77.060743, 0.0], + [-100.642555, -77.054077, 0.0], + [-100.627593, -77.036208, 0.0], + [-100.707198, -77.032842, 0.0], + [-100.692171, -77.014978, 0.0], + [-100.851044, -77.008182, 0.0], + [-100.835847, -76.990327, 0.0], + [-100.915114, -76.986897, 0.0], + [-100.899853, -76.969047, 0.0], + [-101.058051, -76.962123, 0.0], + [-101.042622, -76.944282, 0.0], + [-101.121553, -76.940788, 0.0], + [-101.090613, -76.905114, 0.0], + [-101.169293, -76.901606, 0.0], + [-101.153783, -76.883774, 0.0], + [-101.232316, -76.880245, 0.0], + [-101.216746, -76.862418, 0.0], + [-101.295133, -76.85887, 0.0], + [-101.217404, -76.769752, 0.0], + [-101.295238, -76.766205, 0.0], + [-101.279717, -76.748385, 0.0], + [-101.357407, -76.744819, 0.0], + [-101.310795, -76.691373, 0.0], + [-101.388141, -76.687797, 0.0], + [-101.372587, -76.669986, 0.0], + [-101.449791, -76.666392, 0.0], + [-101.326063, -76.523929, 0.0], + [-101.402436, -76.52035, 0.0], + [-101.341168, -76.449131, 0.0], + [-101.265184, -76.45269, 0.0], + [-101.175067, -76.345822, 0.0], + [-101.250474, -76.342292, 0.0], + [-101.190803, -76.27106, 0.0], + [-101.265793, -76.267525, 0.0], + [-101.250878, -76.249721, 0.0], + [-101.325735, -76.246168, 0.0], + [-101.280944, -76.192769, 0.0], + [-101.429978, -76.185621, 0.0], + [-101.399941, -76.150039, 0.0], + [-101.474214, -76.14644, 0.0], + [-101.459161, -76.128654, 0.0], + [-101.533304, -76.125037, 0.0], + [-101.518198, -76.107255, 0.0], + [-101.59221, -76.10362, 0.0], + [-101.577051, -76.085842, 0.0], + [-101.650932, -76.082189, 0.0], + [-101.635722, -76.064416, 0.0], + [-101.709473, -76.060745, 0.0], + [-101.694211, -76.042976, 0.0], + [-101.767832, -76.039287, 0.0], + [-101.752518, -76.021523, 0.0], + [-101.899461, -76.014086, 0.0], + [-101.837882, -75.943066, 0.0], + [-101.910936, -75.939333, 0.0], + [-101.89555, -75.921582, 0.0], + [-101.968477, -75.917832, 0.0], + [-101.953041, -75.900085, 0.0], + [-102.02584, -75.896317, 0.0], + [-102.010356, -75.878575, 0.0], + [-102.083027, -75.87479, 0.0], + [-102.067494, -75.857052, 0.0], + [-102.140038, -75.853249, 0.0], + [-102.124457, -75.835516, 0.0], + [-102.196874, -75.831696, 0.0], + [-102.181245, -75.813967, 0.0], + [-102.253535, -75.810129, 0.0], + [-102.237859, -75.792406, 0.0], + [-102.310023, -75.78855, 0.0], + [-102.294299, -75.770832, 0.0], + [-102.366338, -75.766959, 0.0], + [-102.350567, -75.749245, 0.0], + [-102.494353, -75.741443, 0.0], + [-102.478451, -75.723738, 0.0], + [-102.693572, -75.711884, 0.0], + [-102.70973, -75.729573, 0.0], + [-102.853113, -75.72155, 0.0], + [-102.869482, -75.739229, 0.0], + [-102.941198, -75.735179, 0.0], + [-102.957693, -75.752851, 0.0], + [-103.029452, -75.748774, 0.0], + [-103.012872, -75.731107, 0.0], + [-103.227644, -75.718758, 0.0], + [-103.210852, -75.701106, 0.0], + [-103.282275, -75.696951, 0.0], + [-103.265441, -75.679303, 0.0], + [-103.336738, -75.675132, 0.0], + [-103.303027, -75.639846, 0.0], + [-103.445162, -75.631459, 0.0], + [-103.428203, -75.613826, 0.0], + [-103.923762, -75.583823, 0.0], + [-103.90627, -75.566227, 0.0], + [-103.976811, -75.56186, 0.0], + [-103.941793, -75.526678, 0.0], + [-104.012128, -75.5223, 0.0], + [-103.942283, -75.45195, 0.0], + [-103.914847, -75.426057, 0.0], + [-103.846549, -75.420428, 0.0], + [-103.814359, -75.41156, 0.0], + [-103.74731, -75.394972, 0.0], + [-103.643531, -75.376578, 0.0], + [-103.639472, -75.360155, 0.0], + [-103.549124, -75.339049, 0.0], + [-103.509054, -75.329656, 0.0], + [-103.456714, -75.307204, 0.0], + [-103.37484, -75.273725, 0.0], + [-103.284801, -75.264374, 0.0], + [-103.224839, -75.25812, 0.0], + [-103.182394, -75.249825, 0.0], + [-103.086408, -75.237813, 0.0], + [-103.042136, -75.231576, 0.0], + [-102.981295, -75.215486, 0.0], + [-102.956754, -75.210167, 0.0], + [-102.921448, -75.203018, 0.0], + [-102.898283, -75.198106, 0.0], + [-102.873449, -75.192921, 0.0], + [-102.84957, -75.188785, 0.0], + [-102.825705, -75.184646, 0.0], + [-102.789524, -75.181222, 0.0], + [-102.744295, -75.17242, 0.0], + [-102.656346, -75.16239, 0.0], + [-102.607491, -75.160775, 0.0], + [-102.560626, -75.159773, 0.0], + [-102.511333, -75.159268, 0.0], + [-102.378744, -75.152045, 0.0], + [-102.34262, -75.146716, 0.0], + [-102.266406, -75.132957, 0.0], + [-102.223828, -75.128342, 0.0], + [-102.157455, -75.12945, 0.0], + [-102.113853, -75.130386, 0.0], + [-102.068876, -75.13139, 0.0], + [-102.040635, -75.126691, 0.0], + [-102.013199, -75.12121, 0.0], + [-101.969076, -75.11627, 0.0], + [-101.953576, -75.113073, 0.0], + [-101.923326, -75.111044, 0.0], + [-101.896684, -75.109917, 0.0], + [-101.821333, -75.103337, 0.0], + [-101.766389, -75.098945, 0.0], + [-101.726414, -75.090073, 0.0], + [-101.723655, -75.079577, 0.0], + [-101.631989, -75.054005, 0.0], + [-101.564382, -75.02971, 0.0], + [-101.547244, -75.015213, 0.0], + [-101.531499, -75.000643, 0.0], + [-101.549303, -74.990901, 0.0], + [-101.489949, -74.940509, 0.0], + [-101.469959, -74.921526, 0.0], + [-101.455398, -74.908855, 0.0], + [-101.420557, -74.891146, 0.0], + [-101.399072, -74.882138, 0.0], + [-101.391177, -74.870096, 0.0], + [-101.371447, -74.860874, 0.0], + [-101.363063, -74.853621, 0.0], + [-101.338827, -74.838164, 0.0], + [-101.312982, -74.826333, 0.0], + [-101.29282, -74.816401, 0.0], + [-101.276851, -74.808624, 0.0], + [-101.27464, -74.804247, 0.0], + [-101.259243, -74.798558, 0.0], + [-101.251822, -74.792086, 0.0], + [-101.267741, -74.78708, 0.0], + [-101.256493, -74.781809, 0.0], + [-101.257733, -74.779767, 0.0], + [-101.250447, -74.777156, 0.0], + [-101.240613, -74.770054, 0.0], + [-101.222641, -74.763963, 0.0], + [-101.216307, -74.748673, 0.0], + [-101.212936, -74.740259, 0.0], + [-101.200426, -74.734469, 0.0], + [-101.197349, -74.72643, 0.0], + [-101.188725, -74.7179, 0.0], + [-101.207959, -74.716895, 0.0], + [-101.219968, -74.709239, 0.0], + [-101.232933, -74.706803, 0.0], + [-101.230248, -74.703234, 0.0], + [-101.238372, -74.70027, 0.0], + [-101.254074, -74.700252, 0.0], + [-101.275428, -74.693637, 0.0], + [-101.306089, -74.693851, 0.0], + [-101.351676, -74.691805, 0.0], + [-101.364701, -74.681592, 0.0], + [-101.396392, -74.67954, 0.0], + [-101.416381, -74.679976, 0.0], + [-101.462601, -74.674445, 0.0], + [-101.482989, -74.660146, 0.0], + [-101.530932, -74.656493, 0.0], + [-101.545802, -74.657827, 0.0], + [-101.570915, -74.655354, 0.0], + [-101.627933, -74.648117, 0.0], + [-101.647793, -74.639151, 0.0], + [-101.676385, -74.635907, 0.0], + [-101.678978, -74.633321, 0.0], + [-101.695894, -74.628422, 0.0], + [-101.728673, -74.621731, 0.0], + [-101.781287, -74.617603, 0.0], + [-101.794801, -74.615021, 0.0], + [-101.870395, -74.608983, 0.0], + [-101.933735, -74.601768, 0.0], + [-101.986726, -74.595483, 0.0], + [-102.032573, -74.595827, 0.0], + [-102.026749, -74.590285, 0.0], + [-102.010395, -74.580201, 0.0], + [-102.035597, -74.564212, 0.0], + [-102.090552, -74.553133, 0.0], + [-102.264411, -74.519626, 0.0], + [-102.339743, -74.51083, 0.0], + [-102.411915, -74.510518, 0.0], + [-102.424826, -74.497263, 0.0], + [-102.377212, -74.483896, 0.0], + [-102.280808, -74.473374, 0.0], + [-102.236421, -74.463717, 0.0], + [-102.185211, -74.450043, 0.0], + [-102.150282, -74.438359, 0.0], + [-102.110682, -74.429878, 0.0], + [-102.080455, -74.419386, 0.0], + [-102.029215, -74.421347, 0.0], + [-101.986657, -74.414487, 0.0], + [-101.942992, -74.405238, 0.0], + [-101.914922, -74.383364, 0.0], + [-101.795349, -74.369597, 0.0], + [-101.698034, -74.375051, 0.0], + [-101.572267, -74.390817, 0.0], + [-101.433665, -74.404266, 0.0], + [-101.358339, -74.410301, 0.0], + [-101.276679, -74.412744, 0.0], + [-101.200663, -74.403148, 0.0], + [-101.126055, -74.400282, 0.0], + [-101.050277, -74.385754, 0.0], + [-100.925725, -74.378623, 0.0], + [-100.827076, -74.373988, 0.0], + [-100.786332, -74.316362, 0.0], + [-100.72066, -74.319735, 0.0], + [-100.708238, -74.301973, 0.0], + [-100.642611, -74.305321, 0.0], + [-100.617997, -74.26979, 0.0], + [-100.552486, -74.273111, 0.0], + [-100.528129, -74.237572, 0.0], + [-100.462734, -74.240864, 0.0], + [-100.355131, -74.080906, 0.0], + [-100.290352, -74.084143, 0.0], + [-100.278602, -74.066367, 0.0], + [-100.213868, -74.06958, 0.0], + [-100.190588, -74.03402, 0.0], + [-100.125968, -74.037206, 0.0], + [-100.114438, -74.019422, 0.0], + [-100.049863, -74.022585, 0.0], + [-100.061323, -74.040372, 0.0], + [-99.996651, -74.043518, 0.0], + [-100.008066, -74.061309, 0.0], + [-99.943298, -74.064439, 0.0], + [-99.954667, -74.082234, 0.0], + [-99.889802, -74.085347, 0.0], + [-99.878504, -74.067549, 0.0], + [-99.68397, -74.076757, 0.0], + [-99.672911, -74.058947, 0.0], + [-99.218628, -74.079702, 0.0], + [-99.208094, -74.061869, 0.0], + [-98.688058, -74.08435, 0.0], + [-98.678122, -74.06649, 0.0], + [-98.026778, -74.092735, 0.0], + [-98.035988, -74.110626, 0.0], + [-97.774563, -74.120566, 0.0], + [-97.783502, -74.138469, 0.0], + [-97.521457, -74.148094, 0.0], + [-97.512812, -74.13018, 0.0], + [-97.447324, -74.132532, 0.0], + [-97.438772, -74.114615, 0.0], + [-97.242413, -74.121541, 0.0], + [-97.234101, -74.103616, 0.0], + [-97.103247, -74.108126, 0.0], + [-97.095101, -74.090197, 0.0], + [-97.02972, -74.092418, 0.0], + [-97.021665, -74.074486, 0.0], + [-96.825632, -74.08102, 0.0], + [-96.833465, -74.098959, 0.0], + [-96.768011, -74.101099, 0.0], + [-96.775789, -74.119041, 0.0], + [-96.513501, -74.127404, 0.0], + [-96.506019, -74.109452, 0.0], + [-96.374919, -74.113506, 0.0], + [-96.367602, -74.095549, 0.0], + [-96.302101, -74.097543, 0.0], + [-96.294875, -74.079584, 0.0], + [-96.229432, -74.081555, 0.0], + [-96.222295, -74.063595, 0.0], + [-96.156909, -74.065543, 0.0], + [-96.149863, -74.047581, 0.0], + [-95.95383, -74.053295, 0.0], + [-95.947021, -74.035326, 0.0], + [-95.816402, -74.039029, 0.0], + [-95.809755, -74.021057, 0.0], + [-95.679223, -74.024673, 0.0], + [-95.672738, -74.006697, 0.0], + [-95.542294, -74.010228, 0.0], + [-95.535971, -73.992248, 0.0], + [-95.405616, -73.995692, 0.0], + [-95.399454, -73.97771, 0.0], + [-95.26919, -73.981068, 0.0], + [-95.263189, -73.963082, 0.0], + [-95.133017, -73.966355, 0.0], + [-95.121348, -73.930376, 0.0], + [-95.056388, -73.931978, 0.0], + [-95.050646, -73.913988, 0.0], + [-94.985747, -73.915568, 0.0], + [-94.980091, -73.897576, 0.0], + [-94.915251, -73.899134, 0.0], + [-94.909681, -73.881141, 0.0], + [-94.844902, -73.882677, 0.0], + [-94.839417, -73.864683, 0.0], + [-94.774698, -73.866196, 0.0], + [-94.769297, -73.848201, 0.0], + [-94.704639, -73.849692, 0.0], + [-94.699323, -73.831696, 0.0], + [-94.634725, -73.833165, 0.0], + [-94.629493, -73.815168, 0.0], + [-94.564955, -73.816615, 0.0], + [-94.559808, -73.798617, 0.0], + [-94.430842, -73.801447, 0.0], + [-94.420869, -73.765446, 0.0], + [-94.356514, -73.766828, 0.0], + [-94.351616, -73.748827, 0.0], + [-94.287321, -73.750186, 0.0], + [-94.277701, -73.714183, 0.0], + [-94.213539, -73.715519, 0.0], + [-94.223015, -73.751526, 0.0], + [-94.158698, -73.752845, 0.0], + [-94.168073, -73.788858, 0.0], + [-94.103602, -73.79016, 0.0], + [-94.117527, -73.844188, 0.0], + [-94.052828, -73.845474, 0.0], + [-94.057417, -73.863487, 0.0], + [-93.992635, -73.864754, 0.0], + [-93.997163, -73.882768, 0.0], + [-93.5429, -73.89108, 0.0], + [-93.546925, -73.909105, 0.0], + [-93.416904, -73.911299, 0.0], + [-93.420791, -73.929327, 0.0], + [-93.095219, -73.934459, 0.0], + [-93.098746, -73.952494, 0.0], + [-93.033533, -73.95346, 0.0], + [-93.030081, -73.935424, 0.0], + [-92.117389, -73.946779, 0.0], + [-92.114979, -73.92873, 0.0], + [-92.049815, -73.929387, 0.0], + [-92.05215, -73.947436, 0.0], + [-91.921656, -73.948689, 0.0], + [-91.923848, -73.96674, 0.0], + [-91.793186, -73.967912, 0.0], + [-91.795233, -73.985966, 0.0], + [-91.729821, -73.986521, 0.0], + [-91.731798, -74.004576, 0.0], + [-91.666307, -74.005112, 0.0], + [-91.668214, -74.023169, 0.0], + [-91.077936, -74.027065, 0.0], + [-91.076703, -74.009003, 0.0], + [-91.011175, -74.009332, 0.0], + [-91.01002, -73.991272, 0.0], + [-90.879106, -73.991867, 0.0], + [-90.878103, -73.973806, 0.0], + [-90.812717, -73.974073, 0.0], + [-90.811791, -73.956012, 0.0], + [-90.746478, -73.956258, 0.0], + [-90.74733, -73.974319, 0.0], + [-90.551155, -73.974933, 0.0], + [-90.551785, -73.992995, 0.0], + [-90.486316, -73.993159, 0.0], + [-90.486872, -74.011222, 0.0], + [-90.290232, -74.011589, 0.0], + [-90.290565, -74.029653, 0.0], + [-90.159318, -74.029795, 0.0], + [-90.1595, -74.047861, 0.0], + [-90.028101, -74.04792, 0.0], + [-90.028133, -74.065986, 0.0], + [-89.830808, -74.065919, 0.0], + [-89.830418, -74.102053, 0.0], + [-89.764492, -74.10199, 0.0], + [-89.764221, -74.120058, 0.0], + [-89.69822, -74.119973, 0.0], + [-89.697523, -74.156112, 0.0], + [-89.63137, -74.156006, 0.0], + [-89.630517, -74.192147, 0.0], + [-89.564212, -74.19202, 0.0], + [-89.563707, -74.210092, 0.0], + [-89.430947, -74.209775, 0.0], + [-89.430287, -74.227847, 0.0], + [-89.29738, -74.227445, 0.0], + [-89.296564, -74.245518, 0.0], + [-89.230036, -74.245285, 0.0], + [-89.22914, -74.263358, 0.0], + [-89.162537, -74.263104, 0.0], + [-89.161562, -74.281178, 0.0], + [-89.028207, -74.280607, 0.0], + [-89.02594, -74.316754, 0.0], + [-88.892285, -74.316097, 0.0], + [-88.890991, -74.334171, 0.0], + [-88.82409, -74.333811, 0.0], + [-88.822715, -74.351885, 0.0], + [-88.688766, -74.3511, 0.0], + [-88.687231, -74.369174, 0.0], + [-88.620184, -74.368749, 0.0], + [-88.618567, -74.386824, 0.0], + [-88.484327, -74.38591, 0.0], + [-88.482549, -74.403984, 0.0], + [-88.348167, -74.402984, 0.0], + [-88.346228, -74.421057, 0.0], + [-88.278965, -74.420525, 0.0], + [-88.276942, -74.438598, 0.0], + [-88.142273, -74.437468, 0.0], + [-88.140087, -74.455541, 0.0], + [-88.072681, -74.454944, 0.0], + [-88.07041, -74.473017, 0.0], + [-87.935456, -74.471756, 0.0], + [-87.93302, -74.489828, 0.0], + [-87.865472, -74.489165, 0.0], + [-87.862952, -74.507237, 0.0], + [-87.79533, -74.506552, 0.0], + [-87.792724, -74.524624, 0.0], + [-87.65734, -74.523188, 0.0], + [-87.654567, -74.541259, 0.0], + [-87.586805, -74.540508, 0.0], + [-87.583946, -74.558579, 0.0], + [-87.51611, -74.557806, 0.0], + [-87.513164, -74.575876, 0.0], + [-87.241573, -74.572566, 0.0], + [-87.238298, -74.590633, 0.0], + [-87.034444, -74.587922, 0.0], + [-87.03092, -74.605986, 0.0], + [-86.962905, -74.605038, 0.0], + [-86.955671, -74.641167, 0.0], + [-86.887503, -74.640195, 0.0], + [-86.868859, -74.730522, 0.0], + [-86.800293, -74.729523, 0.0], + [-86.792609, -74.765656, 0.0], + [-86.723889, -74.764633, 0.0], + [-86.716003, -74.800766, 0.0], + [-86.647127, -74.799719, 0.0], + [-86.63091, -74.871988, 0.0], + [-86.561712, -74.870913, 0.0], + [-86.553377, -74.907049, 0.0], + [-86.622742, -74.908126, 0.0], + ] + ) + obs = apifmt._fmt_spatial("polygon", poly) + exp = { + "polygon": "-86.622742,-74.908126,-86.561712,-74.870913,-86.868859,-74.730522,-86.962905,-74.605038,-89.02594,-74.316754,-89.630517,-74.192147,-89.830808,-74.065919,-90.746478,-73.956258,-91.668214,-74.023169,-92.049815,-73.929387,-93.420791,-73.929327,-93.997163,-73.882768,-94.277701,-73.714183,-95.133017,-73.966355,-96.513501,-74.127404,-99.889802,-74.085347,-100.114438,-74.019422,-100.355131,-74.080906,-100.462734,-74.240864,-100.827076,-74.373988,-101.795349,-74.369597,-102.424826,-74.497263,-101.188725,-74.7179,-101.564382,-75.02971,-103.37484,-75.273725,-103.914847,-75.426057,-104.012128,-75.5223,-103.029452,-75.748774,-102.350567,-75.749245,-101.837882,-75.943066,-101.899461,-76.014086,-101.280944,-76.192769,-101.325735,-76.246168,-101.190803,-76.27106,-101.250474,-76.342292,-101.175067,-76.345822,-101.402436,-76.52035,-101.326063,-76.523929,-101.449791,-76.666392,-101.310795,-76.691373,-101.357407,-76.744819,-101.217404,-76.769752,-101.295133,-76.85887,-101.058051,-76.962123,-100.447336,-77.117686,-98.433698,-77.320866,-97.28308,-77.355688,-97.491148,-77.423178,-96.514174,-77.485919,-96.552494,-77.558236,-96.384656,-77.562336,-96.441516,-77.670857,-97.139363,-77.836566,-97.193451,-77.926901,-97.64271,-78.080044,-96.297869,-78.388943,-96.327803,-78.44329,-95.721466,-78.511065,-95.748962,-78.565482,-94.940425,-78.617072,-94.988611,-78.726066,-94.911669,-78.763976,-95.609268,-78.843079,-95.637038,-78.897535,-95.37191,-78.9391,-95.693408,-79.006456,-95.269903,-79.124145,-95.323729,-79.233172,-95.430206,-79.249633,-95.155505,-79.291032,-95.191045,-79.363748,-94.81352,-79.406486,-94.847075,-79.479253,-94.747448,-79.48078,-94.772403,-79.535367,-93.90411,-79.638844,-93.843651,-79.749409,-93.967323,-79.802836,-93.788723,-79.87821,-93.816393,-79.951128,-93.230546,-80.085534,-91.707475,-79.87748,-91.801545,-79.822143,-91.488897,-79.805457,-91.465152,-79.641131,-90.447349,-79.5894,-90.545492,-79.534464,-90.042319,-79.37062,-90.140775,-79.334083,-90.041814,-79.24285,-88.982186,-79.076903,-90.230262,-78.914333,-90.32191,-78.804808,-90.689626,-78.676516,-91.150024,-78.638589,-92.035347,-78.414844,-92.106013,-78.30491,-91.651645,-78.271472,-91.365784,-78.127206,-91.188783,-78.128018,-91.090167,-78.019109,-90.737076,-77.983849,-90.909191,-77.946905,-90.732603,-77.911009,-90.727088,-77.819973,-91.070502,-77.800626,-91.14118,-77.636469,-91.90279,-77.613923,-91.984627,-77.595116,-91.972963,-77.522365,-92.466819,-77.463587,-92.199521,-77.374914,-92.352136,-77.300761,-92.335283,-77.209895,-91.434206,-77.234653,-91.426015,-77.16193,-91.015545,-77.145686,-91.008355,-77.054784,-91.086397,-77.018096,-91.647835,-76.97871,-91.640906,-76.924199,-91.873848,-76.868024,-91.779021,-76.759619,-90.823937,-76.710073,-90.345113,-76.52953,-86.988029,-75.856983,-86.945563,-75.711143,-86.872234,-75.710165,-87.034102,-75.63967,-86.965004,-75.620616,-87.075115,-75.440545,-87.003154,-75.439609,-87.021872,-75.349129,-86.835058,-75.219586,-86.850654,-75.147247,-86.717729,-75.109052,-86.737771,-75.018662,-86.602149,-74.998483,-86.622742,-74.908126" + } assert obs == exp ########## _fmt_var_subset_list ########## def test_var_subset_list_fmt(): - obs = apifmt._fmt_var_subset_list({'atlas_sdp_gps_epoch': ['ancillary_data/atlas_sdp_gps_epoch'], - 'data_end_utc': ['ancillary_data/data_end_utc'], - 'data_start_utc': ['ancillary_data/data_start_utc'], - 'end_delta_time': ['ancillary_data/end_delta_time'], - 'granule_end_utc': ['ancillary_data/granule_end_utc'], - 'granule_start_utc': ['ancillary_data/granule_start_utc'], - 'latitude': ['profile_2/high_rate/latitude', 'profile_2/low_rate/latitude'], - 'sc_orient': ['orbit_info/sc_orient'], - 'start_delta_time': ['ancillary_data/start_delta_time']}) - exp = '/ancillary_data/atlas_sdp_gps_epoch,/ancillary_data/data_end_utc,/ancillary_data/data_start_utc,/ancillary_data/end_delta_time,/ancillary_data/granule_end_utc,/ancillary_data/granule_start_utc,/profile_2/high_rate/latitude,/profile_2/low_rate/latitude,/orbit_info/sc_orient,/ancillary_data/start_delta_time' + obs = apifmt._fmt_var_subset_list( + { + "atlas_sdp_gps_epoch": ["ancillary_data/atlas_sdp_gps_epoch"], + "data_end_utc": ["ancillary_data/data_end_utc"], + "data_start_utc": ["ancillary_data/data_start_utc"], + "end_delta_time": ["ancillary_data/end_delta_time"], + "granule_end_utc": ["ancillary_data/granule_end_utc"], + "granule_start_utc": ["ancillary_data/granule_start_utc"], + "latitude": ["profile_2/high_rate/latitude", "profile_2/low_rate/latitude"], + "sc_orient": ["orbit_info/sc_orient"], + "start_delta_time": ["ancillary_data/start_delta_time"], + } + ) + exp = "/ancillary_data/atlas_sdp_gps_epoch,/ancillary_data/data_end_utc,/ancillary_data/data_start_utc,/ancillary_data/end_delta_time,/ancillary_data/granule_end_utc,/ancillary_data/granule_start_utc,/profile_2/high_rate/latitude,/profile_2/low_rate/latitude,/orbit_info/sc_orient,/ancillary_data/start_delta_time" assert obs == exp ########## combine_params ########## def test_combine_params(): - dict1 = {'key1': 0, 'key2': 1} - dict2 = {'key3':10} - obs = apifmt.combine_params(dict1,dict2) - expected = {'key1': 0, 'key2': 1, 'key3':10} + dict1 = {"key1": 0, "key2": 1} + dict2 = {"key3": 10} + obs = apifmt.combine_params(dict1, dict2) + expected = {"key1": 0, "key2": 1, "key3": 10} assert obs == expected @@ -72,28 +1033,36 @@ def test_combine_params(): # def CMRparams(scope='module'): # return apifmt.Parameters('CMR') + def test_CMRparams_no_other_inputs(): - CMRparams = apifmt.Parameters('CMR') - #TestQuestion: the next statement essentially tests _get_possible_keys as well, so how would I test them independently? - assert CMRparams.poss_keys == {'default': ['short_name','version','temporal'], 'spatial': ['bounding_box','polygon'], 'optional': []} + CMRparams = apifmt.Parameters("CMR") + # TestQuestion: the next statement essentially tests _get_possible_keys as well, so how would I test them independently? + assert CMRparams.poss_keys == { + "default": ["short_name", "version", "temporal"], + "spatial": ["bounding_box", "polygon"], + "optional": [], + } assert CMRparams.fmted_keys == {} assert CMRparams._check_valid_keys - #Note: this test must be done before the next one - if CMRparams.partype == 'required': + # Note: this test must be done before the next one + if CMRparams.partype == "required": assert CMRparams.check_req_values() == False else: assert CMRparams.check_values() == False - - CMRparams.build_params(dataset='ATL06', version='003', - start=dt.datetime(2019, 2, 20, 0, 0), - end=dt.datetime(2019, 2, 24, 23, 59, 59), - extent_type='bounding_box', - spatial_extent=[-55, 68, -48, 71]) + + CMRparams.build_params( + dataset="ATL06", + version="003", + start=dt.datetime(2019, 2, 20, 0, 0), + end=dt.datetime(2019, 2, 24, 23, 59, 59), + extent_type="bounding_box", + spatial_extent=[-55, 68, -48, 71], + ) obs_fmted_params = CMRparams.fmted_keys - exp_fmted_params = {'short_name': 'ATL06', 'version': '003', - 'temporal': '2019-02-20T00:00:00Z,2019-02-24T23:59:59Z', - 'bounding_box': '-55,68,-48,71'} + exp_fmted_params = { + "short_name": "ATL06", + "version": "003", + "temporal": "2019-02-20T00:00:00Z,2019-02-24T23:59:59Z", + "bounding_box": "-55,68,-48,71", + } assert obs_fmted_params == exp_fmted_params - - - \ No newline at end of file diff --git a/icepyx/tests/test_geospatial.py b/icepyx/tests/test_geospatial.py index 31dbd38f3..9d7f86b13 100644 --- a/icepyx/tests/test_geospatial.py +++ b/icepyx/tests/test_geospatial.py @@ -8,15 +8,15 @@ ########## geodataframe ########## def test_gdf_from_bbox(): - obs = geospatial.geodataframe('bounding_box',[-55, 68, -48, 71]) + obs = geospatial.geodataframe("bounding_box", [-55, 68, -48, 71]) geom = [Polygon(list(zip([-55, -55, -48, -48, -55], [68, 71, 71, 68, 68])))] exp = gpd.GeoDataFrame(geometry=geom) - #DevNote: this feels like a questionable test to me, since it specifies the first entry (though there should only be one) + # DevNote: this feels like a questionable test to me, since it specifies the first entry (though there should only be one) assert obs.geometry[0] == exp.geometry[0] -#TestQuestions: 1) Do these need to be tested? -#2) Is the best way to test them with lengthy inputs and seeing if the gdfs are the same? +# TestQuestions: 1) Do these need to be tested? +# 2) Is the best way to test them with lengthy inputs and seeing if the gdfs are the same? # def test_gdf_from_strpoly(): # def test_gdf_from_filepoly(): @@ -24,7 +24,7 @@ def test_gdf_from_bbox(): def test_bad_extent_input(): ermsg = "Your spatial extent type is not an accepted input and a geodataframe cannot be constructed" - #DevNote: can't get the test to pass if the extent_type is included. Not sure why the strings "don't match" + # DevNote: can't get the test to pass if the extent_type is included. Not sure why the strings "don't match" # ermsg = "Your spatial extent type (polybox) is not an accepted input and a geodataframe cannot be constructed" with pytest.raises(TypeError, match=ermsg): - geospatial.geodataframe('polybox',[1,2,3,4]) \ No newline at end of file + geospatial.geodataframe("polybox", [1, 2, 3, 4]) diff --git a/icepyx/tests/test_granules.py b/icepyx/tests/test_granules.py index 8441f41bb..9cc4656ea 100644 --- a/icepyx/tests/test_granules.py +++ b/icepyx/tests/test_granules.py @@ -6,7 +6,6 @@ from icepyx.core.granules import Granules as Granules - # @pytest.fixture # def reg_a(): # return ipd.Icesat2Data('ATL06',[-55, 68, -48, 71],['2019-02-22','2019-02-28']) @@ -18,393 +17,590 @@ # return reg_a._start_earthdata_session('icepyx_devteam', 'icepyx.dev@gmail.com', os.getenv('NSIDC_LOGIN')) -#DevNote: clearly there's a better way that doesn't make the function so long... what is it? +# DevNote: clearly there's a better way that doesn't make the function so long... what is it? def test_granules_info(): # reg_a = ipd.Icesat2Data('ATL06', [-55, 68, -48, 71], ['2019-02-20','2019-02-24'], version='3') # granules = reg_a.granules.avail - grans = [{'producer_granule_id': 'ATL06_20190221121851_08410203_003_01.h5', - 'time_start': '2019-02-21T12:19:05.000Z', - 'orbit': {'ascending_crossing': '-40.35812957405553', - 'start_lat': '59.5', - 'start_direction': 'A', - 'end_lat': '80', - 'end_direction': 'A'}, - 'updated': '2020-05-04T15:43:02.942Z', - 'orbit_calculated_spatial_domains': [{'equator_crossing_date_time': '2019-02-21T12:03:18.922Z', - 'equator_crossing_longitude': '-40.35812957405553', - 'orbit_number': '2429'}], - 'dataset_id': 'ATLAS/ICESat-2 L3A Land Ice Height V003', - 'data_center': 'NSIDC_ECS', - 'title': 'SC:ATL06.003:177534295', - 'coordinate_system': 'ORBIT', - 'time_end': '2019-02-21T12:24:16.000Z', - 'id': 'G1723268629-NSIDC_ECS', - 'original_format': 'ISO-SMAP', - 'granule_size': '50.3300800323', - 'browse_flag': True, - 'polygons': [['60.188087866839815 -48.12471565111877 79.13565976324539 -56.91308349854652 79.82054625244331 -57.75066986682175 79.88471463831527 -55.94835931630358 79.19580392788636 -55.21962622534677 60.21083561664105 -47.47451382423887 60.188087866839815 -48.12471565111877']], - 'collection_concept_id': 'C1706333750-NSIDC_ECS', - 'online_access_flag': True, - 'links': [{'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'type': 'application/x-hdfeos', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.21/ATL06_20190221121851_08410203_003_01.h5'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.default.default1.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.default.default2.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/metadata#', - 'type': 'text/xml', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.21/ATL06_20190221121851_08410203_003_01.iso.xml'}, - {'inherited': True, - 'length': '0.0KB', - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/ATLAS/ATL06.003/'}, - {'inherited': True, - 'length': '0.0KB', - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'hreflang': 'en-US', - 'href': 'https://search.earthdata.nasa.gov/search/granules?p=C1706333750-NSIDC_ECS&q=atl06%20v003&m=-29.109278436791882!-59.86889648437499!1!1!0!0%2C2&tl=1572814258!4!!'}, - {'inherited': True, - 'length': '0.0KB', - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'hreflang': 'en-US', - 'href': 'https://openaltimetry.org/'}, - {'inherited': True, - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/metadata#', - 'hreflang': 'en-US', - 'href': 'https://doi.org/10.5067/ATLAS/ATL06.003'}, - {'inherited': True, - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/documentation#', - 'hreflang': 'en-US', - 'href': 'https://doi.org/10.5067/ATLAS/ATL06.003'}]}, - {'producer_granule_id': 'ATL06_20190222010344_08490205_003_01.h5', - 'time_start': '2019-02-22T01:03:44.000Z', - 'orbit': {'ascending_crossing': '130.68730694092687', - 'start_lat': '80', - 'start_direction': 'D', - 'end_lat': '59.5', - 'end_direction': 'D'}, - 'updated': '2020-05-04T15:35:15.570Z', - 'orbit_calculated_spatial_domains': [{'equator_crossing_date_time': '2019-02-22T00:37:38.252Z', - 'equator_crossing_longitude': '130.68730694092687', - 'orbit_number': '2437'}], - 'dataset_id': 'ATLAS/ICESat-2 L3A Land Ice Height V003', - 'data_center': 'NSIDC_ECS', - 'title': 'SC:ATL06.003:177974050', - 'coordinate_system': 'ORBIT', - 'time_end': '2019-02-22T01:07:47.000Z', - 'id': 'G1725880106-NSIDC_ECS', - 'original_format': 'ISO-SMAP', - 'granule_size': '42.656709671', - 'browse_flag': True, - 'polygons': [['80.11254119920325 -43.315444387475495 64.79892188605879 -52.21277462684438 64.82548575330607 -52.971370058601465 80.17859740110205 -45.168520453661074 80.11254119920325 -43.315444387475495']], - 'collection_concept_id': 'C1706333750-NSIDC_ECS', - 'online_access_flag': True, - 'links': [{'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'type': 'application/x-hdfeos', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.22/ATL06_20190222010344_08490205_003_01.h5'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.default.default1.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.default.default2.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.atl06_quality_summary.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.h_li.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.h_li_sigma.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.n_fit_photons.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/browse#', - 'type': 'image/jpeg', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.signal_selection_source.jpg'}, - {'rel': 'http://esipfed.org/ns/fedsearch/1.1/metadata#', - 'type': 'text/xml', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.22/ATL06_20190222010344_08490205_003_01.iso.xml'}, - {'inherited': True, - 'length': '0.0KB', - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'hreflang': 'en-US', - 'href': 'https://n5eil01u.ecs.nsidc.org/ATLAS/ATL06.003/'}, - {'inherited': True, - 'length': '0.0KB', - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'hreflang': 'en-US', - 'href': 'https://search.earthdata.nasa.gov/search/granules?p=C1706333750-NSIDC_ECS&q=atl06%20v003&m=-29.109278436791882!-59.86889648437499!1!1!0!0%2C2&tl=1572814258!4!!'}, - {'inherited': True, - 'length': '0.0KB', - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/data#', - 'hreflang': 'en-US', - 'href': 'https://openaltimetry.org/'}, - {'inherited': True, - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/metadata#', - 'hreflang': 'en-US', - 'href': 'https://doi.org/10.5067/ATLAS/ATL06.003'}, - {'inherited': True, - 'rel': 'http://esipfed.org/ns/fedsearch/1.1/documentation#', - 'hreflang': 'en-US', - 'href': 'https://doi.org/10.5067/ATLAS/ATL06.003'}]}] + grans = [ + { + "producer_granule_id": "ATL06_20190221121851_08410203_003_01.h5", + "time_start": "2019-02-21T12:19:05.000Z", + "orbit": { + "ascending_crossing": "-40.35812957405553", + "start_lat": "59.5", + "start_direction": "A", + "end_lat": "80", + "end_direction": "A", + }, + "updated": "2020-05-04T15:43:02.942Z", + "orbit_calculated_spatial_domains": [ + { + "equator_crossing_date_time": "2019-02-21T12:03:18.922Z", + "equator_crossing_longitude": "-40.35812957405553", + "orbit_number": "2429", + } + ], + "dataset_id": "ATLAS/ICESat-2 L3A Land Ice Height V003", + "data_center": "NSIDC_ECS", + "title": "SC:ATL06.003:177534295", + "coordinate_system": "ORBIT", + "time_end": "2019-02-21T12:24:16.000Z", + "id": "G1723268629-NSIDC_ECS", + "original_format": "ISO-SMAP", + "granule_size": "50.3300800323", + "browse_flag": True, + "polygons": [ + [ + "60.188087866839815 -48.12471565111877 79.13565976324539 -56.91308349854652 79.82054625244331 -57.75066986682175 79.88471463831527 -55.94835931630358 79.19580392788636 -55.21962622534677 60.21083561664105 -47.47451382423887 60.188087866839815 -48.12471565111877" + ] + ], + "collection_concept_id": "C1706333750-NSIDC_ECS", + "online_access_flag": True, + "links": [ + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "type": "application/x-hdfeos", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.21/ATL06_20190221121851_08410203_003_01.h5", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.default.default1.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.default.default2.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1l.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt1r.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2l.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt2r.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3l.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.16/ATL06_20190221121851_08410203_003_01_BRW.gt3r.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/metadata#", + "type": "text/xml", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.21/ATL06_20190221121851_08410203_003_01.iso.xml", + }, + { + "inherited": True, + "length": "0.0KB", + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/ATLAS/ATL06.003/", + }, + { + "inherited": True, + "length": "0.0KB", + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "hreflang": "en-US", + "href": "https://search.earthdata.nasa.gov/search/granules?p=C1706333750-NSIDC_ECS&q=atl06%20v003&m=-29.109278436791882!-59.86889648437499!1!1!0!0%2C2&tl=1572814258!4!!", + }, + { + "inherited": True, + "length": "0.0KB", + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "hreflang": "en-US", + "href": "https://openaltimetry.org/", + }, + { + "inherited": True, + "rel": "http://esipfed.org/ns/fedsearch/1.1/metadata#", + "hreflang": "en-US", + "href": "https://doi.org/10.5067/ATLAS/ATL06.003", + }, + { + "inherited": True, + "rel": "http://esipfed.org/ns/fedsearch/1.1/documentation#", + "hreflang": "en-US", + "href": "https://doi.org/10.5067/ATLAS/ATL06.003", + }, + ], + }, + { + "producer_granule_id": "ATL06_20190222010344_08490205_003_01.h5", + "time_start": "2019-02-22T01:03:44.000Z", + "orbit": { + "ascending_crossing": "130.68730694092687", + "start_lat": "80", + "start_direction": "D", + "end_lat": "59.5", + "end_direction": "D", + }, + "updated": "2020-05-04T15:35:15.570Z", + "orbit_calculated_spatial_domains": [ + { + "equator_crossing_date_time": "2019-02-22T00:37:38.252Z", + "equator_crossing_longitude": "130.68730694092687", + "orbit_number": "2437", + } + ], + "dataset_id": "ATLAS/ICESat-2 L3A Land Ice Height V003", + "data_center": "NSIDC_ECS", + "title": "SC:ATL06.003:177974050", + "coordinate_system": "ORBIT", + "time_end": "2019-02-22T01:07:47.000Z", + "id": "G1725880106-NSIDC_ECS", + "original_format": "ISO-SMAP", + "granule_size": "42.656709671", + "browse_flag": True, + "polygons": [ + [ + "80.11254119920325 -43.315444387475495 64.79892188605879 -52.21277462684438 64.82548575330607 -52.971370058601465 80.17859740110205 -45.168520453661074 80.11254119920325 -43.315444387475495" + ] + ], + "collection_concept_id": "C1706333750-NSIDC_ECS", + "online_access_flag": True, + "links": [ + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "type": "application/x-hdfeos", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.22/ATL06_20190222010344_08490205_003_01.h5", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.default.default1.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.default.default2.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1l.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt1r.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2l.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt2r.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3l.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.atl06_quality_summary.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.h_li.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.h_li_sigma.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.n_fit_photons.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/browse#", + "type": "image/jpeg", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP0/BRWS/Browse.001/2020.04.22/ATL06_20190222010344_08490205_003_01_BRW.gt3r.signal_selection_source.jpg", + }, + { + "rel": "http://esipfed.org/ns/fedsearch/1.1/metadata#", + "type": "text/xml", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/DP7/ATLAS/ATL06.003/2019.02.22/ATL06_20190222010344_08490205_003_01.iso.xml", + }, + { + "inherited": True, + "length": "0.0KB", + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "hreflang": "en-US", + "href": "https://n5eil01u.ecs.nsidc.org/ATLAS/ATL06.003/", + }, + { + "inherited": True, + "length": "0.0KB", + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "hreflang": "en-US", + "href": "https://search.earthdata.nasa.gov/search/granules?p=C1706333750-NSIDC_ECS&q=atl06%20v003&m=-29.109278436791882!-59.86889648437499!1!1!0!0%2C2&tl=1572814258!4!!", + }, + { + "inherited": True, + "length": "0.0KB", + "rel": "http://esipfed.org/ns/fedsearch/1.1/data#", + "hreflang": "en-US", + "href": "https://openaltimetry.org/", + }, + { + "inherited": True, + "rel": "http://esipfed.org/ns/fedsearch/1.1/metadata#", + "hreflang": "en-US", + "href": "https://doi.org/10.5067/ATLAS/ATL06.003", + }, + { + "inherited": True, + "rel": "http://esipfed.org/ns/fedsearch/1.1/documentation#", + "hreflang": "en-US", + "href": "https://doi.org/10.5067/ATLAS/ATL06.003", + }, + ], + }, + ] obs = granules.info(grans) - exp = {'Number of available granules': 2, - 'Average size of granules (MB)': 46.49339485165, - 'Total size of all granules (MB)': 92.9867897033} + exp = { + "Number of available granules": 2, + "Average size of granules (MB)": 46.49339485165, + "Total size of all granules (MB)": 92.9867897033, + } - assert obs==exp + assert obs == exp def test_no_granules_in_search_results(): ermsg = "Your search returned no results; try different search parameters" with pytest.raises(AssertionError, match=ermsg): - ipd.Icesat2Data('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-20'], version='2').avail_granules() + ipd.Icesat2Data( + "ATL06", [-55, 68, -48, 71], ["2019-02-20", "2019-02-20"], version="2" + ).avail_granules() def test_correct_granule_list_returned(): - reg_a = ipd.Icesat2Data('ATL06',[-55, 68, -48, 71],['2019-02-20','2019-02-28'], version='2') + reg_a = ipd.Icesat2Data( + "ATL06", [-55, 68, -48, 71], ["2019-02-20", "2019-02-28"], version="2" + ) reg_a.avail_granules() - obs_grans = [gran['producer_granule_id'] for gran in reg_a.granules.avail] - exp_grans = ['ATL06_20190221121851_08410203_002_01.h5', 'ATL06_20190222010344_08490205_002_01.h5', 'ATL06_20190225121032_09020203_002_01.h5', 'ATL06_20190226005526_09100205_002_01.h5'] + obs_grans = [gran["producer_granule_id"] for gran in reg_a.granules.avail] + exp_grans = [ + "ATL06_20190221121851_08410203_002_01.h5", + "ATL06_20190222010344_08490205_002_01.h5", + "ATL06_20190225121032_09020203_002_01.h5", + "ATL06_20190226005526_09100205_002_01.h5", + ] assert set(obs_grans) == set(exp_grans) diff --git a/icepyx/tests/test_is2ref.py b/icepyx/tests/test_is2ref.py index 94c0f7bc0..3112be7c2 100644 --- a/icepyx/tests/test_is2ref.py +++ b/icepyx/tests/test_is2ref.py @@ -5,26 +5,28 @@ ########## _validate_dataset ########## def test_lowercase_dataset(): - lcds = 'atl03' + lcds = "atl03" obs = is2ref._validate_dataset(lcds) - expected = 'ATL03' + expected = "ATL03" assert obs == expected + def test_num_dataset(): dsnum = 6 ermsg = "Please enter a dataset string" with pytest.raises(TypeError, match=ermsg): is2ref._validate_dataset(dsnum) - + + def test_bad_dataset(): - wrngds = 'atl-6' + wrngds = "atl-6" ermsg = "Please enter a valid dataset" with pytest.raises(AssertionError, match=ermsg): is2ref._validate_dataset(wrngds) ########## about_dataset ########## -#Note: requires internet connection +# Note: requires internet connection # def test_dataset_info(): # obs = is2ref.about_dataset('ATL06') # print(obs) @@ -151,16 +153,36 @@ def test_bad_dataset(): ########## _get_custom_options ########## -#Note: requires internet connection + active NSIDC session -#Thus, the tests for this function are in the test_behind_NSIDC_API_login suite +# Note: requires internet connection + active NSIDC session +# Thus, the tests for this function are in the test_behind_NSIDC_API_login suite ########## _default_varlists ########## def test_ATL09_default_varlist(): - obs = is2ref._default_varlists('ATL09') - expected = ['delta_time','latitude','longitude', 'bsnow_h','bsnow_dens','bsnow_con','bsnow_psc','bsnow_od', - 'cloud_flag_asr','cloud_fold_flag','cloud_flag_atm', - 'column_od_asr','column_od_asr_qf', - 'layer_attr','layer_bot','layer_top','layer_flag','layer_dens','layer_ib', - 'msw_flag','prof_dist_x','prof_dist_y','apparent_surf_reflec'] - assert obs == expected \ No newline at end of file + obs = is2ref._default_varlists("ATL09") + expected = [ + "delta_time", + "latitude", + "longitude", + "bsnow_h", + "bsnow_dens", + "bsnow_con", + "bsnow_psc", + "bsnow_od", + "cloud_flag_asr", + "cloud_fold_flag", + "cloud_flag_atm", + "column_od_asr", + "column_od_asr_qf", + "layer_attr", + "layer_bot", + "layer_top", + "layer_flag", + "layer_dens", + "layer_ib", + "msw_flag", + "prof_dist_x", + "prof_dist_y", + "apparent_surf_reflec", + ] + assert obs == expected diff --git a/icepyx/tests/test_validate_inputs.py b/icepyx/tests/test_validate_inputs.py index f8bcc918c..c0da6a764 100644 --- a/icepyx/tests/test_validate_inputs.py +++ b/icepyx/tests/test_validate_inputs.py @@ -8,119 +8,176 @@ ########## dset_version ########## def test_version_setting_to_latest(): - obs = val.dset_version('010',None) - expected = '010' + obs = val.dset_version("010", None) + expected = "010" assert obs == expected + def test_neg_version_str_given(): ermesg = "Version number must be positive" with pytest.raises(AssertionError, match=ermesg): - val.dset_version('010', '-12') + val.dset_version("010", "-12") + def test_short_version_str_given(): - obs = val.dset_version('001', '2') - expected = '002' + obs = val.dset_version("001", "2") + expected = "002" assert obs == expected + def test_int_version(): ermesg = "Please enter the version number as a string" with pytest.raises(TypeError, match=ermesg): - val.dset_version('010', 12) + val.dset_version("010", 12) + def test_old_version(): wrng = "You are using an old version of this dataset" with pytest.warns(UserWarning, match=wrng): - val.dset_version('003','001') - + val.dset_version("003", "001") + ########## spatial ########## def test_intlist_bbox(): obs = val.spatial([-64, 66, -55, 72]) - expected = ['bounding_box', [-64, 66, -55, 72], None] + expected = ["bounding_box", [-64, 66, -55, 72], None] for i in range(len(expected)): assert obs[i] == expected[i] + def test_floatlist_bbox(): obs = val.spatial([-64.2, 66.2, -55.5, 72.5]) - expected = ['bounding_box', [-64.2, 66.2, -55.5, 72.5], None] + expected = ["bounding_box", [-64.2, 66.2, -55.5, 72.5], None] for i in range(len(expected)): assert obs[i] == expected[i] + def test_list_latlon_pairs(): out = val.spatial([[-55, 68], [-55, 71], [-48, 71], [-48, 68], [-55, 68]]) - obs = [out[0], out[1].exterior.coords.xy[0].tolist(), out[1].exterior.coords.xy[1].tolist(), out[2]] + obs = [ + out[0], + out[1].exterior.coords.xy[0].tolist(), + out[1].exterior.coords.xy[1].tolist(), + out[2], + ] # expected = ['polygon', [-55.0, 68.0, -55.0, 71.0, -48.0, 71.0, -48.0, 68.0, -55.0, 68.0], None] # expected = ['polygon', [[-55.0, 68.0], [-55.0, 71.0], [-48.0, 71.0], [-48.0, 68.0], [-55.0, 68.0]], None] - expected = ['polygon', [-55.0, -55.0, -48.0, -48.0, -55.0], [68.0, 71.0, 71.0, 68.0, 68.0], None] + expected = [ + "polygon", + [-55.0, -55.0, -48.0, -48.0, -55.0], + [68.0, 71.0, 71.0, 68.0, 68.0], + None, + ] for i in range(len(expected)): assert obs[i] == expected[i] + def test_tuple_latlon_pairs(): out = val.spatial([(-55, 68), (-55, 71), (-48, 71), (-48, 68), (-55, 68)]) - obs = [out[0], out[1].exterior.coords.xy[0].tolist(), out[1].exterior.coords.xy[1].tolist(), out[2]] - expected = ['polygon', [-55.0, -55.0, -48.0, -48.0, -55.0], [68.0, 71.0, 71.0, 68.0, 68.0], None] + obs = [ + out[0], + out[1].exterior.coords.xy[0].tolist(), + out[1].exterior.coords.xy[1].tolist(), + out[2], + ] + expected = [ + "polygon", + [-55.0, -55.0, -48.0, -48.0, -55.0], + [68.0, 71.0, 71.0, 68.0, 68.0], + None, + ] for i in range(len(expected)): assert obs[i] == expected[i] + def test_intlist_latlon_coords(): out = val.spatial([-55, 68, -55, 71, -48, 71, -48, 68, -55, 68]) - obs = [out[0], out[1].exterior.coords.xy[0].tolist(), out[1].exterior.coords.xy[1].tolist(), out[2]] - expected = ['polygon', [-55.0, -55.0, -48.0, -48.0, -55.0], [68.0, 71.0, 71.0, 68.0, 68.0], None] + obs = [ + out[0], + out[1].exterior.coords.xy[0].tolist(), + out[1].exterior.coords.xy[1].tolist(), + out[2], + ] + expected = [ + "polygon", + [-55.0, -55.0, -48.0, -48.0, -55.0], + [68.0, 71.0, 71.0, 68.0, 68.0], + None, + ] for i in range(len(expected)): assert obs[i] == expected[i] + def test_floatlist_latlon_coords(): out = val.spatial([-55.0, 68.7, -55.0, 71, -48, 71, -48, 68.7, -55.0, 68.7]) - obs = [out[0], out[1].exterior.coords.xy[0].tolist(), out[1].exterior.coords.xy[1].tolist(), out[2]] - expected = ['polygon', [-55.0, -55.0, -48.0, -48.0, -55.0], [68.7, 71.0, 71.0, 68.7, 68.7], None] + obs = [ + out[0], + out[1].exterior.coords.xy[0].tolist(), + out[1].exterior.coords.xy[1].tolist(), + out[2], + ] + expected = [ + "polygon", + [-55.0, -55.0, -48.0, -48.0, -55.0], + [68.7, 71.0, 71.0, 68.7, 68.7], + None, + ] for i in range(len(expected)): assert obs[i] == expected[i] + def test_spat_input_type(): - ermsg = 'Your spatial extent does not meet minimum input criteria' + ermsg = "Your spatial extent does not meet minimum input criteria" with pytest.raises(ValueError, match=ermsg): val.spatial([-64, 66, (-55, 72), 72]) + def test_poly_spat_file_input(): ermsg = "Check that the path and filename of your geometry file are correct" with pytest.raises(AssertionError, match=ermsg): - val.spatial('file_path/name/invalid_type.txt') + val.spatial("file_path/name/invalid_type.txt") -#should there be additional tests on the valid file type if-else? If so, is this were we'd use a mock to assume -#a valid (existing) file has been passed? Otherwise we'll never get passed the assert statement... + +# should there be additional tests on the valid file type if-else? If so, is this were we'd use a mock to assume +# a valid (existing) file has been passed? Otherwise we'll never get passed the assert statement... ########## temporal ########## def test_date_range_order(): ermsg = "Your date range is invalid" with pytest.raises(AssertionError, match=ermsg): - val.temporal(['2019-03-22','2019-02-28'], None, None) + val.temporal(["2019-03-22", "2019-02-28"], None, None) + def test_bad_date_range(): ermsg = "Your date range list is the wrong length. It should have start and end dates only." with pytest.raises(ValueError, match=ermsg): - val.temporal(['2019-02-22'], None, None) + val.temporal(["2019-02-22"], None, None) + def test_time_defaults(): - obs_st, obs_end = val.temporal(['2019-02-22','2019-02-28'], None, None) - exp_start = dt.datetime(2019,2,22,00,00,00) - exp_end = dt.datetime(2019,2,28,23,59,59) + obs_st, obs_end = val.temporal(["2019-02-22", "2019-02-28"], None, None) + exp_start = dt.datetime(2019, 2, 22, 00, 00, 00) + exp_end = dt.datetime(2019, 2, 28, 23, 59, 59) assert obs_st == exp_start assert obs_end == exp_end + def test_time_validstr(): - obs_st, obs_end = val.temporal(['2019-02-22','2019-02-28'], '13:50:59', '23:15:00') - exp_start = dt.datetime(2019,2,22,13,50,59) - exp_end = dt.datetime(2019,2,28,23,15) + obs_st, obs_end = val.temporal(["2019-02-22", "2019-02-28"], "13:50:59", "23:15:00") + exp_start = dt.datetime(2019, 2, 22, 13, 50, 59) + exp_end = dt.datetime(2019, 2, 28, 23, 15) assert obs_st == exp_start assert obs_end == exp_end + def test_starttime_validstr(): ermsg = "Please enter your start time as a string" with pytest.raises(TypeError, match=ermsg): - val.temporal(['2019-02-22','2019-02-28'], 121500, None) + val.temporal(["2019-02-22", "2019-02-28"], 121500, None) + def test_endtime_validstr(): ermsg = "Please enter your end time as a string" with pytest.raises(TypeError, match=ermsg): - val.temporal(['2019-02-22','2019-02-28'], '00:15:00', 235959) + val.temporal(["2019-02-22", "2019-02-28"], "00:15:00", 235959) diff --git a/requirements.txt b/requirements.txt index 807d6262d..3fd176fc7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,6 @@ geopandas h5py matplotlib numpy +pre-commit requests shapely From a3cabb079549a9489283b639b98d13613d854585 Mon Sep 17 00:00:00 2001 From: JessicaS11 Date: Thu, 2 Jul 2020 20:58:51 +0000 Subject: [PATCH 2/9] add github action workflow with flake8 on PRs --- .github/workflows/flake8_action.yml | 15 +++++++++++++++ .pre-commit-config.yaml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/flake8_action.yml diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml new file mode 100644 index 000000000..37af7e488 --- /dev/null +++ b/.github/workflows/flake8_action.yml @@ -0,0 +1,15 @@ +# use the flake8 linter to annotate improperly formatted code +# from: https://github.com/marketplace/actions/run-flake8-on-your-pr-with-annotations +name: Run flake8 + +on: + pull_request: + branches: + - development + - master +steps: + - name: Run flake8 on your PR - with annotations! + uses: tayfun/flake8-your-pr@1.0.1 + + + diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ace746317..777350a71 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: -- repo: https://github.com/ambv/black +- repo: https://github.com/psf/black rev: stable hooks: - id: black \ No newline at end of file From 08465ab3f0ea429cf13bc5b1716bbe2beb9f1aac Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 6 Jul 2020 18:32:42 -0400 Subject: [PATCH 3/9] Update flake8_action.yml --- .github/workflows/flake8_action.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index 37af7e488..0f5f85bbb 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -7,9 +7,7 @@ on: branches: - development - master -steps: - - name: Run flake8 on your PR - with annotations! - uses: tayfun/flake8-your-pr@1.0.1 - - - +jobs: + steps: + - name: Run flake8 on your PR - with annotations! + uses: tayfun/flake8-your-pr@1.0.1 From 64ea0c2e3b097252bbcb2b94f1942f091a16448f Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 6 Jul 2020 18:35:39 -0400 Subject: [PATCH 4/9] Update flake8_action.yml --- .github/workflows/flake8_action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index 0f5f85bbb..a59b7d41d 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -9,5 +9,5 @@ on: - master jobs: steps: - - name: Run flake8 on your PR - with annotations! - uses: tayfun/flake8-your-pr@1.0.1 + name: Run flake8 on your PR - with annotations! + uses: tayfun/flake8-your-pr@1.0.1 From ba2cd7a0601fd633bd14d2765c118379b01f6f07 Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 6 Jul 2020 18:37:30 -0400 Subject: [PATCH 5/9] Update flake8_action.yml --- .github/workflows/flake8_action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index a59b7d41d..0f5f85bbb 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -9,5 +9,5 @@ on: - master jobs: steps: - name: Run flake8 on your PR - with annotations! - uses: tayfun/flake8-your-pr@1.0.1 + - name: Run flake8 on your PR - with annotations! + uses: tayfun/flake8-your-pr@1.0.1 From 2371dc281dadaa2e04b9c1ce810a30c512083099 Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 6 Jul 2020 18:43:39 -0400 Subject: [PATCH 6/9] Update flake8_action.yml --- .github/workflows/flake8_action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index 0f5f85bbb..82ac923fb 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -8,6 +8,7 @@ on: - development - master jobs: + runs-on: ubuntu-latest steps: - name: Run flake8 on your PR - with annotations! uses: tayfun/flake8-your-pr@1.0.1 From 60dafa82f7c1c132031f830573b14d307730e8da Mon Sep 17 00:00:00 2001 From: Jessica Date: Mon, 6 Jul 2020 18:44:56 -0400 Subject: [PATCH 7/9] Update flake8_action.yml --- .github/workflows/flake8_action.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index 82ac923fb..13a937b47 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -8,7 +8,8 @@ on: - development - master jobs: - runs-on: ubuntu-latest - steps: - - name: Run flake8 on your PR - with annotations! - uses: tayfun/flake8-your-pr@1.0.1 + build: + runs-on: ubuntu-latest + steps: + - name: Run flake8 on your PR - with annotations! + uses: tayfun/flake8-your-pr@1.0.1 From 35a1c08cb6c20d8874c40794b2d315bfd07c9b9b Mon Sep 17 00:00:00 2001 From: Jessica Date: Tue, 7 Jul 2020 15:03:34 -0400 Subject: [PATCH 8/9] add secret for GITHUB_TOKEN --- .github/workflows/flake8_action.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index 13a937b47..67ed7449c 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -1,6 +1,6 @@ # use the flake8 linter to annotate improperly formatted code # from: https://github.com/marketplace/actions/run-flake8-on-your-pr-with-annotations -name: Run flake8 +name: Run flake8 linter on PRs on: pull_request: @@ -11,5 +11,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Run flake8 on your PR - with annotations! - uses: tayfun/flake8-your-pr@1.0.1 + - name: Annotate PR after running flake8 + # https://github.com/marketplace/actions/run-flake8-on-your-pr-with-annotations?version=1.0.1 + uses: tayfun/flake8-your-pr@master + secrets: ["GITHUB_TOKEN"] From 33e02d10891a22f834430efbfd75c9af78e7bc96 Mon Sep 17 00:00:00 2001 From: Jessica Date: Tue, 7 Jul 2020 15:13:49 -0400 Subject: [PATCH 9/9] try different action --- .github/workflows/flake8_action.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/flake8_action.yml b/.github/workflows/flake8_action.yml index 67ed7449c..ba1fa6d58 100644 --- a/.github/workflows/flake8_action.yml +++ b/.github/workflows/flake8_action.yml @@ -12,6 +12,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Annotate PR after running flake8 + uses: TrueBrain/actions-flake8@master + with: + max_line_length: 90 # https://github.com/marketplace/actions/run-flake8-on-your-pr-with-annotations?version=1.0.1 - uses: tayfun/flake8-your-pr@master - secrets: ["GITHUB_TOKEN"] + # uses: tayfun/flake8-your-pr@master + # secrets: ["GITHUB_TOKEN"]