From 7c06bd52edba112039eddbafc484a53f6fa1e07b Mon Sep 17 00:00:00 2001 From: Owen Littlejohns Date: Fri, 24 Jan 2025 17:01:58 -0500 Subject: [PATCH] TRT-571 - Update net2cog to process multiple variables. --- net2cog/netcdf_convert.py | 214 ++++++++++++++---------------- net2cog/netcdf_convert_harmony.py | 130 ++++++++++-------- poetry.lock | 202 +++++++++++++++++++++++++--- pyproject.toml | 2 +- 4 files changed, 361 insertions(+), 187 deletions(-) diff --git a/net2cog/netcdf_convert.py b/net2cog/netcdf_convert.py index 586b1ab..b2a6de0 100644 --- a/net2cog/netcdf_convert.py +++ b/net2cog/netcdf_convert.py @@ -11,14 +11,15 @@ import os import pathlib import subprocess -import tempfile from os.path import join as pjoin, basename, dirname, exists, splitext from subprocess import check_call +from tempfile import TemporaryDirectory from typing import List import rasterio import rioxarray # noqa import xarray as xr +from harmony_service_lib.util import generate_output_filename from rasterio import CRS from rio_cogeo.cogeo import cog_translate from rio_cogeo.profiles import cog_profiles @@ -37,46 +38,21 @@ def __init__(self, msg): super().__init__(msg) -def run_command(command, work_dir): - """ - A simple utility to execute a subprocess command. - """ - try: - out_call = check_call(command, stderr=subprocess.STDOUT, cwd=work_dir) - return out_call - except subprocess.CalledProcessError as err: - LOGGER.error("command '%s' return with error (code %s): %s", - err.cmd, err.returncode, err.output) - raise - - -def check_dir(fname): - """ - To return filename and path without file extension - """ - file_name = fname.split('/') - rel_path = pjoin(*file_name[-2:]) - file_wo_extension, _ = splitext(rel_path) - return file_wo_extension +def _rioxr_swapdims(netcdf_xarray): + netcdf_xarray.coords['y'] = ('lat', netcdf_xarray.lat) + netcdf_xarray.coords['x'] = ('lon', netcdf_xarray.lon) + return netcdf_xarray.swap_dims({'lat': 'y', 'lon': 'x'}) -def get_gtiff_name(output_file): - """ - To create tmp filename to convert to COG and create a filename - just as source but without '.TIF' extension - """ - outf = os.path.basename(output_file) - dir_path = dirname(output_file) - rel_path = check_dir(outf) - out_fname = pjoin(dir_path, rel_path) - if not exists(out_fname): - os.makedirs(out_fname) - return pjoin(out_fname, rel_path) - -def _write_cogtiff(out_f_name, nc_xarray): +def _write_cogtiff( + output_directory: str, + nc_xarray: xr.Dataset, + variable_name: str, + input_filename: str +) -> str | None: """ - This function converts each variable inside a NetCDF file into a + This function converts a variable inside a NetCDF file into a cloud optimized geotiff. Parameters @@ -94,81 +70,89 @@ def _write_cogtiff(out_f_name, nc_xarray): Assumption that 0 is always on the prime meridian/equator. """ - cogs_generated = [] - with tempfile.TemporaryDirectory() as tempdir: - - # variables in netcdf - for var in nc_xarray.variables: - if var in EXCLUDE_VARS: - continue - LOGGER.debug("NetCDF Var: %s", var) - - def rioxr_swapdims(netcdf_xarray): - netcdf_xarray.coords['y'] = ('lat', netcdf_xarray.lat) - netcdf_xarray.coords['x'] = ('lon', netcdf_xarray.lon) - - return netcdf_xarray.swap_dims({'lat': 'y', 'lon': 'x'}) - - # copy to a tempfolder - out_fname = out_f_name + '_' + var + '.tif' - temp_fname = pjoin(tempdir, basename(out_fname)) - + LOGGER.debug("NetCDF Var: %s", variable_name) + + if variable_name in EXCLUDE_VARS: + LOGGER.debug(f"Variable {variable_name} is excluded. Will not produce COG") + return None + + output_basename = generate_output_filename( + input_filename, + ext='tif', + variable_subset=[variable_name], + is_reformatted=True, + ) + output_file_name = output_directory.pathjoin(output_basename) + + with TemporaryDirectory() as tempdir: + temp_file_name = os.path.join(tempdir, output_basename) + + # copy to a tempfolder + # out_fname = out_f_name + '_' + var + '.tif' + # temp_fname = pjoin(tempdir, basename(out_fname)) + + try: + nc_xarray[variable_name].rio.to_raster(temp_file_name) + except LookupError as err: + LOGGER.info("Variable %s cannot be converted to tif: %s", variable_name, err) + return None + except DimensionError as dmerr: try: - nc_xarray[var].rio.to_raster(temp_fname) - except LookupError as err: - LOGGER.info("Variable %s cannot be converted to tif: %s", var, err) - continue - except DimensionError as dmerr: - try: - LOGGER.info("%s: No x or y xarray dimensions, adding them...", dmerr) - nc_xarray_tmp = rioxr_swapdims(nc_xarray) - nc_xarray_tmp[var].rio.to_raster(temp_fname) - except RuntimeError as runerr: - LOGGER.info("Variable %s cannot be converted to tif: %s", var, runerr) - continue - except Exception as aerr: # pylint: disable=broad-except - LOGGER.info("Variable %s cannot be converted to tif: %s", var, aerr) - continue - - # Option to add additional GDAL config settings - # config = dict(GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_OVR_BLOCKSIZE="128") - # with rasterio.Env(**config): - - LOGGER.info("Starting conversion... %s", out_fname) - - # default CRS setting - # crs = rasterio.crs.CRS({"init": "epsg:3857"}) - - with rasterio.open(temp_fname, mode='r+') as src_dataset: - # if src_dst.crs is None: - # src_dst.crs = crs - src_dataset.crs = CRS.from_proj4(proj="+proj=latlong") - dst_profile = cog_profiles.get("deflate") - cog_translate(src_dataset, out_fname, dst_profile, use_cog_driver=True) - - cogs_generated.append(out_fname) - LOGGER.info("Finished conversion, writing variable: %s", out_fname) - LOGGER.info("NetCDF conversion complete. Returning COGs generated.") - return cogs_generated - - -def netcdf_converter(input_nc_file: pathlib.Path, output_cog_pathname: pathlib.Path, var_list: list = ()) -> List[str]: - """ - Primary function for beginning NetCDF conversion using rasterio, + LOGGER.info("%s: No x or y xarray dimensions, adding them...", dmerr) + nc_xarray_tmp = _rioxr_swapdims(nc_xarray) + nc_xarray_tmp[variable_name].rio.to_raster(temp_file_name) + except RuntimeError as runerr: + LOGGER.info("Variable %s cannot be converted to tif: %s", variable_name, runerr) + return None + except Exception as aerr: # pylint: disable=broad-except + LOGGER.info("Variable %s cannot be converted to tif: %s", variable_name, aerr) + return None + + # Option to add additional GDAL config settings + # config = dict(GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_OVR_BLOCKSIZE="128") + # with rasterio.Env(**config): + + LOGGER.info("Starting conversion... %s", output_file_name) + + # default CRS setting + # crs = rasterio.crs.CRS({"init": "epsg:3857"}) + + with rasterio.open(temp_file_name, mode='r+') as src_dataset: + # if src_dst.crs is None: + # src_dst.crs = crs + src_dataset.crs = CRS.from_proj4(proj="+proj=latlong") + dst_profile = cog_profiles.get("deflate") + cog_translate( + src_dataset, + output_file_name, + dst_profile, + use_cog_driver=True + ) + + LOGGER.info("Finished conversion, writing variable: %s", output_file_name) + LOGGER.info("NetCDF conversion complete. Returning COG generated.") + return output_file_name + + +def netcdf_converter( + input_nc_file: pathlib.Path, + output_directory: pathlib.Path, + var_list: list[str] | None +) -> List[str]: + """Primary function for beginning NetCDF conversion using rasterio, rioxarray and xarray Parameters ---------- input_nc_file : pathlib.Path Path to NetCDF file to process - output_cog_pathname : pathlib.Path - COG Output path and NetCDF filename, filename converted to cog variable - filename (.tif) - ex: tests/data/tmpygj2vgxf/ - RSS_smap_SSS_L3_8day_running_2020_005_FNL_v04.0.nc - var_list : list + output_directory : pathlib.Path + Path to temporary directory into which results will be placed before + staging in S3. + var_list : str | None List of variable names to be converted to various single band cogs, - ex: ['gland', 'fland', 'sss_smap'] + ex: ['gland', 'fland', 'sss_smap']. If a Harmony request asks for "all" + variables, the input value will be None. Notes ----- @@ -178,11 +162,8 @@ def netcdf_converter(input_nc_file: pathlib.Path, output_cog_pathname: pathlib.P netcdf_file = os.path.abspath(input_nc_file) LOGGER.debug('NetCDF Path: %s', netcdf_file) - gtiff_fname = get_gtiff_name(output_cog_pathname) - if netcdf_file.endswith('.nc'): LOGGER.info("Reading %s", basename(netcdf_file)) - LOGGER.info('Tmp GTiff filename: %s', gtiff_fname) xds = xr.open_dataset(netcdf_file) @@ -192,13 +173,18 @@ def netcdf_converter(input_nc_file: pathlib.Path, output_cog_pathname: pathlib.P or ({"x", "y"}.issubset(set(xds.dims)))): # used to invert y axis # xds_reversed = xds.reindex(lat=xds.lat[::-1]) - LOGGER.info("Writing COG to %s", basename(gtiff_fname)) - if var_list: - try: - xds = xds[var_list] - except KeyError as error: - raise Net2CogError(f"Variable {error} not found in dataset") from error - return _write_cogtiff(gtiff_fname, xds) + + if var_list is None: + var_list = list(xds.data_vars.keys()) + + try: + return [ + _write_cogtiff(output_directory, xds, variable_name, input_nc_file) + for variable_name in var_list + ] + except KeyError as error: + raise Net2CogError(f"Variable {error} not found in dataset") from error + LOGGER.error("%s: NetCDF file does not contain spatial dimensions such as lat / lon " "or x / y", netcdf_file) return [] diff --git a/net2cog/netcdf_convert_harmony.py b/net2cog/netcdf_convert_harmony.py index fb43c5f..9ff8052 100644 --- a/net2cog/netcdf_convert_harmony.py +++ b/net2cog/netcdf_convert_harmony.py @@ -15,10 +15,13 @@ import shutil import tempfile -import harmony +import harmony_service_lib import pystac -from harmony.exceptions import HarmonyException -from pystac import Asset +from harmony_service_lib import BaseHarmonyAdapter +from harmony_service_lib.exceptions import HarmonyException +from harmony_service_lib.message import Source +from harmony_service_lib.util import download, stage +from pystac import Asset, Item from net2cog import netcdf_convert from net2cog.netcdf_convert import Net2CogError @@ -26,7 +29,7 @@ DATA_DIRECTORY_ENV = "DATA_DIRECTORY" -class NetcdfConverterService(harmony.BaseHarmonyAdapter): +class NetcdfConverterService(BaseHarmonyAdapter): """ See https://github.com/nasa/harmony-service-lib-py for documentation and examples. @@ -41,7 +44,7 @@ def __init__(self, message, catalog=None, config=None): # Create temp directory self.job_data_dir = tempfile.mkdtemp(prefix=message.requestId, dir=self.data_dir) - def process_item(self, item: pystac.Item, source: harmony.message.Source) -> pystac.Item: + def process_item(self, item: pystac.Item, source: Source) -> pystac.Item: """ Performs net2cog on input STAC Item's data, returning an output STAC item @@ -50,7 +53,7 @@ def process_item(self, item: pystac.Item, source: harmony.message.Source) -> pys ---------- item : pystac.Item the item that should be coggified - source : harmony.message.Source + source : harmony_service_lib.message.Source the input source defining the item Returns @@ -58,8 +61,6 @@ def process_item(self, item: pystac.Item, source: harmony.message.Source) -> pys pystac.Item a STAC item describing the output """ - result = item.clone() - result.assets = {} output_dir = self.job_data_dir try: self.logger.info('Input item: %s', json.dumps(item.to_dict())) @@ -67,35 +68,30 @@ def process_item(self, item: pystac.Item, source: harmony.message.Source) -> pys # Get the data file asset = next(v for k, v in item.assets.items() if 'data' in (v.roles or [])) self.logger.info('Downloading %s to %s', asset.href, output_dir) - input_filename = harmony.adapter.util.download(asset.href, - output_dir, - logger=self.logger, - access_token=self.message.accessToken, - cfg=self.config) - - # Generate output filename - output_filename, output_file_ext = os.path.splitext( - harmony.adapter.util.generate_output_filename(asset.href, ext='tif')) - output_filename = f'{output_filename}_converted{output_file_ext}' + input_filename = download( + asset.href, + output_dir, + logger=self.logger, + access_token=self.message.accessToken, + cfg=self.config + ) # Determine variables that need processing - self.logger.info('Generating COG(s) for %s output will be saved to %s', input_filename, output_filename) var_list = source.process('variables') - if not isinstance(var_list, list): - var_list = [var_list] - if len(var_list) != 1: - raise HarmonyException( - 'net2cog harmony adapter currently only supports processing one variable at a time. ' - 'Please specify a single variable in your Harmony request.') - var_list = list(map(lambda var: var.name, var_list)) - self.logger.info('Processing variables %s', var_list) + + if var_list is not None: + var_list = list(map(lambda var: var.name, var_list)) + self.logger.info('Processing variables %s', var_list) + else: + self.logger.info('Processing all variables.') # Run the netcdf converter for the complete netcdf granule try: - cog_generated = next(iter(netcdf_convert.netcdf_converter(pathlib.Path(input_filename), - pathlib.Path(output_dir).joinpath( - output_filename), - var_list=var_list)), []) + generated_cogs = netcdf_convert.netcdf_converter( + pathlib.Path(input_filename), + pathlib.Path(output_dir), + var_list, + ) except Net2CogError as error: raise HarmonyException( f'net2cog failed to convert {asset.title}: {error}') from error @@ -104,28 +100,58 @@ def process_item(self, item: pystac.Item, source: harmony.message.Source) -> pys f'Notify net2cog service provider. ' f'Message: {uncaught_exception}')) from uncaught_exception - # Stage the output file with a conventional filename - self.logger.info('Generated COG %s', cog_generated) - staged_filename = os.path.basename(cog_generated) - url = harmony.adapter.util.stage(cog_generated, - staged_filename, - pystac.MediaType.COG, - location=self.message.stagingLocation, - logger=self.logger, - cfg=self.config) - self.logger.info('Staged %s to %s', cog_generated, url) - - # Update the STAC record - result.assets['visual'] = Asset(url, title=staged_filename, media_type=pystac.MediaType.COG, - roles=['visual']) - - # Return the STAC record - self.logger.info('Processed item %s', json.dumps(result.to_dict())) - return result + return self.stage_output_and_create_output_stac(generated_cogs: list[str], input_stac_item: Item) finally: # Clean up any intermediate resources shutil.rmtree(self.job_data_dir) + def stage_output_and_create_output_stac(self, output_files: list[str], input_stac_item: Item) -> Item: + """Iterate through all generated COGs and stage the results in S3. Also + add a unique pystac.Asset for each COG to the pystac.Item returned to + Harmony. + + Parameters + ---------- + output_files : list[str] + the filenames of generated COGs to be staged + input_stac_item : pystac.Item + the input STAC for the request. This is the basis of the output + STAC, which will replace the pystac.Assets with generated COGs. + + Returns + ------- + pystac.Item + a STAC item describing the output. If there are multiple variables, + this STAC item will have multiple assets. + + """ + + output_stac = item.clone() + output_stac.assets = {} + + for output_file in output_files: + output_basename = os.path.basename(output_file) + + staged_url = stage( + output_file, + output_basename, + pystac.MediaType.COG, + location=self.message.stagingLocation, + logger=self.logger, + cfg=self.config + ) + self.logger.info('Staged %s to %s', output_file, staged_url) + + # Each asset needs a unique key, so the filename of the COG is used + output_stac.assets[output_basename] = Asset( + staged_url, + title=output_basename, + media_type=pystac.MediaType.COG, + roles=['visual'], + ) + + return output_stac + def main(): """Parse command line arguments and invoke the service to respond to @@ -138,9 +164,9 @@ def main(): """ parser = argparse.ArgumentParser(prog='net2cog_harmony', description='Run the netcdf converter service') - harmony.setup_cli(parser) + harmony_service_lib.setup_cli(parser) args = parser.parse_args() - if harmony.is_harmony_cli(args): - harmony.run_cli(parser, args, NetcdfConverterService) + if harmony_service_lib.is_harmony_cli(args): + harmony_service_lib.run_cli(parser, args, NetcdfConverterService) else: parser.error("Only --harmony CLIs are supported") diff --git a/poetry.lock b/poetry.lock index fdc0a0f..280bf23 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "affine" @@ -6,6 +6,8 @@ version = "2.4.0" description = "Matrices describing affine transformation of the plane" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "affine-2.4.0-py3-none-any.whl", hash = "sha256:8a3df80e2b2378aef598a83c1392efd47967afec4242021a0b06b4c7cbc61a92"}, {file = "affine-2.4.0.tar.gz", hash = "sha256:a24d818d6a836c131976d22f8c27b8d3ca32d0af64c1d8d29deb7bafa4da1eea"}, @@ -21,6 +23,8 @@ version = "0.7.16" description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, @@ -32,6 +36,8 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -43,6 +49,8 @@ version = "2.15.8" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.7.2" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, @@ -52,8 +60,8 @@ files = [ lazy-object-proxy = ">=1.4.0" typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} wrapt = [ - {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, ] [[package]] @@ -62,6 +70,8 @@ version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, @@ -81,6 +91,8 @@ version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, @@ -95,6 +107,8 @@ version = "1.34.159" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "boto3-1.34.159-py3-none-any.whl", hash = "sha256:21120d23cc37c0e80dc4f64434bc5664d2a5645dcd9bf8a8fa97ed5c82164ca0"}, {file = "boto3-1.34.159.tar.gz", hash = "sha256:ffe7bbb88ba81b5d54bc8fa0cfb2f3b7fe63a6cffa0f9207df2ef5c22a1c0587"}, @@ -114,6 +128,8 @@ version = "1.34.159" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "botocore-1.34.159-py3-none-any.whl", hash = "sha256:7633062491457419a49f5860c014251ae85689f78266a3ce020c2c8688a76b97"}, {file = "botocore-1.34.159.tar.gz", hash = "sha256:dc28806eb21e3c8d690c422530dff8b4b242ac033cbe98f160a9d37796c09cb1"}, @@ -133,6 +149,8 @@ version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, @@ -144,6 +162,8 @@ version = "1.17.0" description = "Foreign Function Interface for Python calling C code." optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, @@ -223,6 +243,8 @@ version = "1.6.4" description = "Time-handling functionality from netcdf4-python" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "cftime-1.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ee70074df4bae0d9ee98f201cf5f11fd302791cf1cdeb73c34f685d6b632e17d"}, {file = "cftime-1.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e5456fd58d4cc6b8d7b4932b749617ee142b62a52bc5d8e3c282ce69ce3a20ba"}, @@ -258,8 +280,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0b1", markers = "python_version >= \"3.12.0.rc1\""}, {version = ">1.13.3", markers = "python_version < \"3.12.0.rc1\""}, + {version = ">=1.26.0b1", markers = "python_version >= \"3.12.0.rc1\""}, ] [[package]] @@ -268,6 +290,8 @@ version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["main", "dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -367,6 +391,8 @@ version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, @@ -381,6 +407,8 @@ version = "1.1.1" description = "An extension module for click to enable registering CLI commands via setuptools entry-points." optional = false python-versions = "*" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, @@ -398,6 +426,8 @@ version = "0.7.2" description = "Click params for commmand line interfaces to GeoJSON" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df"}, {file = "cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27"}, @@ -415,10 +445,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "(python_version <= \"3.11\" or python_version >= \"3.12\") and platform_system == \"Windows\"", dev = "(python_version <= \"3.11\" or python_version >= \"3.12\") and sys_platform == \"win32\""} [[package]] name = "coverage" @@ -426,6 +458,8 @@ version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, @@ -513,6 +547,8 @@ version = "2.1.0" description = "A library to handle automated deprecations" optional = true python-versions = "*" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, @@ -527,6 +563,8 @@ version = "0.3.8" description = "serialize all of Python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, @@ -542,6 +580,8 @@ version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, @@ -553,6 +593,8 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -567,6 +609,8 @@ version = "6.1.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, @@ -579,30 +623,37 @@ pyflakes = ">=3.1.0,<3.2.0" [[package]] name = "harmony-service-lib" -version = "1.0.27" -description = "A library for Python-based Harmony services to parse incoming messages, fetch data, stage data, and call back to Harmony" +version = "2.4.0" +description = "A library for Python-based Harmony services to parse incoming message, fetch data, stage data, and call back to Harmony." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ - {file = "harmony_service_lib-1.0.27-py3-none-any.whl", hash = "sha256:edf3aaa4b6f18addbfc4b54c20746d16ffe365a55ebaab0f4df47296b5900af3"}, - {file = "harmony_service_lib-1.0.27.tar.gz", hash = "sha256:7992bbed205e02ad15dcc35526e7a827e6c3054a65d5eb5b59ddfec160950ca1"}, + {file = "harmony_service_lib-2.4.0-py3-none-any.whl", hash = "sha256:ec4678ee392de229007791d0c73e16b4ec795acb984144965ee0cc84b29234ff"}, + {file = "harmony_service_lib-2.4.0.tar.gz", hash = "sha256:1b97d92b23e24b6a5ea54125776e6b7ac0d2e239021dda9fbdbda5543577c908"}, ] [package.dependencies] boto3 = ">=1.14,<2.0" deprecation = ">=2.1.0,<2.2.0" pynacl = ">=1.4,<2.0" -pystac = ">=0.5.3,<0.6.0" +pystac = ">=1.0.0" python-json-logger = ">=2.0.1,<2.1.0" requests = ">=2.24,<3.0" urllib3 = ">=1.26.9,<1.27.0" +[package.extras] +dev = ["Faker (>=8.1.3,<8.2.0)", "autopep8 (>=1.5,<2.0)", "debugpy (>=1.2,<2.0)", "flake8 (>=6.1.0)", "ipython (>=8.10.0,<8.11.0)", "jedi (>=0.17.2,<0.18.0)", "packaging (>=24.1,<25.0)", "parameterized (>=0.7,<1.0)", "pycodestyle (>=2.9.1)", "pytest (>=7.2.0,<7.3.0)", "pytest-cov (>=2.11,<3.0)", "pytest-mock (>=3.5,<4.0)", "python-language-server (>=0.35,<1.0)", "responses (>=0.22.0,<0.23.0)", "safety (==3.2.3)", "safety-schemas (==0.0.5)", "setuptools (==70.0.0)"] + [[package]] name = "idna" version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" +groups = ["main", "dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, @@ -614,6 +665,8 @@ version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, @@ -625,6 +678,8 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -636,6 +691,8 @@ version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, @@ -650,6 +707,8 @@ version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, @@ -667,6 +726,8 @@ version = "1.0.1" description = "JSON Matching Expressions" optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, @@ -678,6 +739,8 @@ version = "1.10.0" description = "A fast and thorough lazy object proxy." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"}, {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"}, @@ -724,6 +787,8 @@ version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -793,6 +858,8 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -804,6 +871,8 @@ version = "5.3.1" description = "Construct and use map tile grids (a.k.a TileMatrixSet / TMS)." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "morecantile-5.3.1-py3-none-any.whl", hash = "sha256:35785988b8f6f1699e2c0136bfda4815dcaf8ae1200b035ba5eb1cb1f0453650"}, {file = "morecantile-5.3.1.tar.gz", hash = "sha256:49a1d4239f30a033a3188e32ea1d218c7fd05c00821311b3797e1e7d56b67a40"}, @@ -826,6 +895,8 @@ version = "1.7.1.post2" description = "Provides an object-oriented python interface to the netCDF version 4 library" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "netCDF4-1.7.1.post2-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:a1006ae117a754e3cf41a9e704032bf3837cbf53a695cd71deaad3e02e93d570"}, {file = "netCDF4-1.7.1.post2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:7530d60cf6450d997ea0607f8b68b9b088f2382c42648cddf5e66e6f1280b692"}, @@ -868,6 +939,8 @@ version = "2.0.1" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, {file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, @@ -922,6 +995,8 @@ version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, @@ -933,6 +1008,8 @@ version = "2.2.2" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"}, {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"}, @@ -967,8 +1044,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, ] python-dateutil = ">=2.8.2" @@ -1006,6 +1083,8 @@ version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -1022,6 +1101,8 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1037,6 +1118,8 @@ version = "2.11.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, @@ -1048,6 +1131,8 @@ version = "2.22" description = "C parser in Python" optional = true python-versions = ">=3.8" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1059,6 +1144,8 @@ version = "2.8.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, @@ -1068,8 +1155,8 @@ files = [ annotated-types = ">=0.4.0" pydantic-core = "2.20.1" typing-extensions = [ - {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, {version = ">=4.6.1", markers = "python_version < \"3.13\""}, + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, ] [package.extras] @@ -1081,6 +1168,8 @@ version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, @@ -1182,6 +1271,8 @@ version = "3.1.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, @@ -1193,6 +1284,8 @@ version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -1207,6 +1300,8 @@ version = "2.17.7" description = "python code static checker" optional = false python-versions = ">=3.7.2" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"}, {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"}, @@ -1216,8 +1311,8 @@ files = [ astroid = ">=2.15.8,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ - {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, ] isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" @@ -1235,6 +1330,8 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = true python-versions = ">=3.6" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -1261,6 +1358,8 @@ version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, @@ -1275,6 +1374,8 @@ version = "3.6.1" description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pyproj-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ab7aa4d9ff3c3acf60d4b285ccec134167a948df02347585fdd934ebad8811b4"}, {file = "pyproj-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc0472302919e59114aa140fd7213c2370d848a7249d09704f10f5b062031fe"}, @@ -1310,20 +1411,25 @@ certifi = "*" [[package]] name = "pystac" -version = "0.5.6" -description = "Python library for working with Spatiotemporal Asset Catalog (STAC)." +version = "1.12.0" +description = "Python library for working with the SpatioTemporal Asset Catalog (STAC) specification" optional = true -python-versions = "*" +python-versions = ">=3.10" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ - {file = "pystac-0.5.6-py3-none-any.whl", hash = "sha256:3dfb9068169570714276e54a80832e555a136595a4d5316e6998bcc55cc2d639"}, - {file = "pystac-0.5.6.tar.gz", hash = "sha256:ee0da32e65e93b240dcdcf68f5a16fa2f3f9e937477161f574b04fc48682e84a"}, + {file = "pystac-1.12.0-py3-none-any.whl", hash = "sha256:911f2d3b045416e85e26b93cd5b9e7fab489fdbd39c49efc621617e4eccfc2f1"}, + {file = "pystac-1.12.0.tar.gz", hash = "sha256:1a9d7502ed899e32916a9e101a225b2be3608290bcf343e04a7c40f726c72994"}, ] [package.dependencies] python-dateutil = ">=2.7.0" [package.extras] -validation = ["jsonschema (==3.2.0)"] +jinja2 = ["jinja2 (<4.0)"] +orjson = ["orjson (>=3.5)"] +urllib3 = ["urllib3 (>=1.26)"] +validation = ["jsonschema (>=4.18,<5.0)"] [[package]] name = "pytest" @@ -1331,6 +1437,8 @@ version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, @@ -1353,6 +1461,8 @@ version = "4.1.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, @@ -1371,6 +1481,8 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1385,6 +1497,8 @@ version = "2.0.7" description = "A python library adding a json log formatter" optional = true python-versions = ">=3.6" +groups = ["main"] +markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and extra == \"harmony\"" files = [ {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, @@ -1396,6 +1510,8 @@ version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, @@ -1407,6 +1523,8 @@ version = "1.3.10" description = "Fast and direct raster I/O for use with Numpy and SciPy" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "rasterio-1.3.10-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2ef27c3eff6f44f8b5d5de228003367c1843593edf648d85c0dc1319c00dc57d"}, {file = "rasterio-1.3.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c711b497e9ef0c4f5e1c01e34ba910708e066e1c4a69c25df18d1bcc04481287"}, @@ -1456,6 +1574,8 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -1477,6 +1597,8 @@ version = "5.3.3" description = "Cloud Optimized GeoTIFF (COGEO) creation plugin for rasterio" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "rio_cogeo-5.3.3-py3-none-any.whl", hash = "sha256:0f3e35dda551e6c7c8afe53ef405ab5c95984a0c06a83bea843856cbaa35408b"}, {file = "rio_cogeo-5.3.3.tar.gz", hash = "sha256:dde35024ad2512027ce6c1269183d4e42a904a776aad0d4ddb6f87aacffc7a23"}, @@ -1499,6 +1621,8 @@ version = "0.17.0" description = "geospatial xarray extension powered by rasterio" optional = false python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "rioxarray-0.17.0-py3-none-any.whl", hash = "sha256:cf31a0674b9e6abd0cc2f0b4d847869eb23065835827d0018d17bde8047d448c"}, {file = "rioxarray-0.17.0.tar.gz", hash = "sha256:46c29938827fff268d497f7ae277077066fcfbac4e53132ed3d4e2b96455be62"}, @@ -1521,6 +1645,8 @@ version = "0.10.2" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "s3transfer-0.10.2-py3-none-any.whl", hash = "sha256:eca1c20de70a39daee580aef4986996620f365c4e0fda6a86100231d62f1bf69"}, {file = "s3transfer-0.10.2.tar.gz", hash = "sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6"}, @@ -1538,6 +1664,8 @@ version = "72.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, @@ -1554,6 +1682,8 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -1565,6 +1695,8 @@ version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." optional = false python-versions = "*" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, @@ -1576,6 +1708,8 @@ version = "1.4.7" description = "Snuggs are s-expressions for Numpy" optional = false python-versions = "*" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "snuggs-1.4.7-py3-none-any.whl", hash = "sha256:988dde5d4db88e9d71c99457404773dabcc7a1c45971bfbe81900999942d9f07"}, {file = "snuggs-1.4.7.tar.gz", hash = "sha256:501cf113fe3892e14e2fee76da5cd0606b7e149c411c271898e6259ebde2617b"}, @@ -1594,6 +1728,8 @@ version = "7.4.7" description = "Python documentation generator" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, @@ -1629,6 +1765,8 @@ version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, @@ -1645,6 +1783,8 @@ version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, @@ -1661,6 +1801,8 @@ version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, @@ -1677,6 +1819,8 @@ version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, @@ -1691,6 +1835,8 @@ version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, @@ -1707,6 +1853,8 @@ version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, @@ -1723,6 +1871,8 @@ version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -1734,6 +1884,8 @@ version = "0.13.0" description = "Style preserving TOML library" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"}, {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"}, @@ -1745,10 +1897,12 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +markers = {main = "python_version >= \"3.12\" or python_version <= \"3.11\"", dev = "python_version < \"3.11\""} [[package]] name = "tzdata" @@ -1756,6 +1910,8 @@ version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, @@ -1767,6 +1923,8 @@ version = "1.26.19" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main", "dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, @@ -1783,6 +1941,8 @@ version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, @@ -1862,6 +2022,8 @@ version = "2024.7.0" description = "N-D labeled arrays and datasets in Python" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ {file = "xarray-2024.7.0-py3-none-any.whl", hash = "sha256:1b0fd51ec408474aa1f4a355d75c00cc1c02bd425d97b2c2e551fd21810e7f64"}, {file = "xarray-2024.7.0.tar.gz", hash = "sha256:4cae512d121a8522d41e66d942fb06c526bc1fd32c2c181d5fe62fe65b671638"}, @@ -1884,6 +2046,6 @@ viz = ["matplotlib", "nc-time-axis", "seaborn"] harmony = ["harmony-service-lib"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = ">=3.10,<4.0" -content-hash = "161a76b2c499c39fc7442a582053b5d0c191c376362b26c6edbb68902dc54fa8" +content-hash = "bd5689061f68fcc4fba8d1d16bb7ef2571a88cb83a5b533266ce2407a463667c" diff --git a/pyproject.toml b/pyproject.toml index 878aa2a..073119d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ rio-cogeo = "^5.3.3" rasterio = "^1.3.8" rioxarray = "^0.17.0" numpy = "^2.0.1" -harmony-service-lib = { version = "^1.0.22", optional = true } +harmony-service-lib = { version = "^2.4.0", optional = true } [tool.poetry.group.dev.dependencies] pytest = "^7.4.0"