diff --git a/openeo_driver/dummy/dummy_backend.py b/openeo_driver/dummy/dummy_backend.py index 844c6e55..21c11a59 100644 --- a/openeo_driver/dummy/dummy_backend.py +++ b/openeo_driver/dummy/dummy_backend.py @@ -900,7 +900,7 @@ def get_result_assets(self, job_id: str, user_id: str) -> Dict[str, dict]: "subfolder/output.tiff": { "output_dir": f"{self._output_root()}/{job_id}", "href": f"{self._output_root()}/{job_id}/subfolder/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "roles": ["data"], "bands": [Band(name="NDVI", wavelength_um=1.23)], "nodata": 123, @@ -915,7 +915,7 @@ def get_result_assets(self, job_id: str, user_id: str) -> Dict[str, dict]: elif job_id == "j-26032411111111111111111111111111": default_json = { "output_dir": f"{self._output_root()}/{job_id}", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "roles": ["data"], "bands": [Band(name="NDVI", wavelength_um=1.23)], "nodata": 123, @@ -939,7 +939,7 @@ def get_result_assets(self, job_id: str, user_id: str) -> Dict[str, dict]: "output.tiff": { "output_dir": f"{self._output_root()}/{job_id}", "href": f"{self._output_root()}/{job_id}/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "roles": ["data"], "bands": [Band(name="B02", common_name="blue", wavelength_um=0.665)], "nodata": 123, diff --git a/openeo_driver/util/ioformats.py b/openeo_driver/util/ioformats.py index 43ee7974..fda9ec9f 100644 --- a/openeo_driver/util/ioformats.py +++ b/openeo_driver/util/ioformats.py @@ -42,7 +42,7 @@ def get_mimetype(self, format: str, default="application/octet-stream") -> str: IOFORMATS = _FormatDb([ - FormatInfo("GTiff", "image/tiff; application=geotiff", extension="geotiff"), + FormatInfo("GTiff", "image/tiff; application=geotiff; profile=cloud-optimized", extension="geotiff"), FormatInfo("COG", "image/tiff; application=geotiff; profile=cloud-optimized"), FormatInfo("NetCDF", "application/x-netcdf", extension="nc"), FormatInfo("PNG", "image/png"), diff --git a/tests/test_views.py b/tests/test_views.py index d7e4c40f..f74d1fc9 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1905,7 +1905,7 @@ def test_get_job_results_100(self, api100): "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.0.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "eo:bands": [{"name": "B02", "common_name": "blue", "center_wavelength": 0.665}], }, "output.nc": { @@ -1975,7 +1975,7 @@ def test_get_job_results_100(self, api100): "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.0.0/jobs/53c71345-09b4-46b4-b6b0-03fd6fe1f199/results/assets/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "proj:epsg": 4326, "proj:code": "EPSG:4326", "proj:shape": [300, 600], @@ -2079,7 +2079,7 @@ def test_get_job_results_110(self, api110): "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.1.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "eo:bands": [{"name": "B02", "common_name": "blue", "center_wavelength": 0.665}], }, "output.nc": { @@ -2161,7 +2161,7 @@ def test_get_job_results_110(self, api110): "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.1.0/jobs/53c71345-09b4-46b4-b6b0-03fd6fe1f199/results/assets/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "proj:epsg": 4326, "proj:code": "EPSG:4326", "proj:shape": [300, 600], @@ -2351,7 +2351,7 @@ def test_get_job_results_signed_100(self, api100, flask_app, backend_config_over "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.0.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/50afb0cad129e61d415278c4ffcd8a83/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "eo:bands": [{"name": "B02", "common_name": "blue", "center_wavelength": 0.665}], }, "output.nc": { @@ -2492,7 +2492,7 @@ def test_get_job_results_signed_110(self, api110, flask_app, backend_config_over "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.1.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/50afb0cad129e61d415278c4ffcd8a83/output.tiff", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "eo:bands": [{"name": "B02", "common_name": "blue", "center_wavelength": 0.665}], }, "output.nc": { @@ -2635,7 +2635,7 @@ def test_get_job_results_signed_with_expiration_100(self, api100, flask_app, bac "roles": ["data"], "title": "output.tiff", "href": "http://oeo.net/openeo/1.0.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/fd0ca65e29c6d223da05b2e73a875683/output.tiff?expires=2234", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "eo:bands": [{"name": "B02", "common_name": "blue", "center_wavelength": 0.665}], }, "output.nc": { @@ -2820,7 +2820,7 @@ def test_get_job_results_signed_with_expiration_110(self, api110, flask_app, bac "output.tiff": { "title": "output.tiff", "href": "http://oeo.net/openeo/1.1.0/jobs/53c71345-09b4-46b4-b6b0-03fd6fe1f199/results/assets/TXIuVGVzdA==/f5d336336d36e3e987ba6a34b87cde01/output.tiff?expires=2234", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "proj:epsg": 4326, "proj:code": "EPSG:4326", "proj:shape": [300, 600], @@ -2984,7 +2984,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri }, "href": "openEO_20231231T214100Z.tif", "nodata": "nan", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "bands": [ {"name": "LST", "common_name": "surface_temperature", "aliases": ["LST_in:LST"]} ], @@ -3025,7 +3025,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri "href": "s3://openeo-data-staging-waw4-1/batch_jobs/j-250605095828442799fdde3c29b5b047/openEO_20231231T214100Z_abs.tif", "output_dir" : "s3://openeo-data-staging-waw4-1/batch_jobs/j-250605095828442799fdde3c29b5b047", "nodata": "nan", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "bands": [ {"name": "LST", "common_name": "surface_temperature", "aliases": ["LST_in:LST"]} ], @@ -3084,7 +3084,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri }, "href": "openEO_20231230T214100Z.tif", "nodata": "nan", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "bands": [ {"name": "LST", "common_name": "surface_temperature", "aliases": ["LST_in:LST"]} ], @@ -3128,7 +3128,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri ], "roles": ["data"], "title": "openEO_20231230T214100Z.tif", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", }, '5d2db643-5cc3-4b27-8ef3-11f7d203b221_2023-12-31T21:41:00Z_openEO_rel':{ 'href': 'http://oeo.net/openeo/1.1.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/d58330c450ed1695361301efe130faf2/openEO_20231231T214100Z.tif', @@ -3144,7 +3144,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri }], 'roles': ['data'], 'title': 'openEO_20231231T214100Z.tif', - 'type': 'image/tiff; application=geotiff' + 'type': 'image/tiff; application=geotiff; profile=cloud-optimized' }, '5d2db643-5cc3-4b27-8ef3-11f7d203b221_2023-12-31T21:41:00Z_openEO_abs': { 'href': 'http://oeo.net/openeo/1.1.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/43241f3f756544ac5eb004268c3aa56a/openEO_20231231T214100Z_abs.tif', @@ -3160,7 +3160,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri }], 'roles': ['data'], 'title': 'openEO_20231231T214100Z_abs.tif', - 'type': 'image/tiff; application=geotiff' + 'type': 'image/tiff; application=geotiff; profile=cloud-optimized' } } assert resp.get("item_assets") == { @@ -3172,7 +3172,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri } ], "roles": ["data"], - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", }, "openEO_abs": { "bands": [ @@ -3189,7 +3189,7 @@ def test_get_job_results_from_stac_1_1_items(self, api110, backend_config_overri } ], "roles": ["data"], - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", }, } assert resp.get("stac_version") == "1.1.0" @@ -3248,7 +3248,7 @@ def test_get_stac_1_1_item(self, api110, backend_implementation, backend_config_ "href": "s3://openeo-data-staging-waw4-1/batch_jobs/j-250605095828442799fdde3c29b5b047/openEO_20231231T214100Z.tif", "output_dir":"s3://openeo-data-staging-waw4-1/batch_jobs/j-250605095828442799fdde3c29b5b047", "nodata": "nan", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "bands": [ {"name": "LST", "common_name": "surface_temperature", "aliases": ["LST_in:LST"]} ], @@ -3291,7 +3291,7 @@ def test_get_stac_1_1_item(self, api110, backend_implementation, backend_config_ 'openEO': DictSubSet({ 'href': 'http://oeo.net/openeo/1.1.0/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/d58330c450ed1695361301efe130faf2/openEO_20231231T214100Z.tif', 'roles': ['data'], - 'type': 'image/tiff; application=geotiff', + 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'title': 'openEO_20231231T214100Z.tif', "bands": [ { @@ -3405,7 +3405,7 @@ def test_download_job_auxiliary_file_signed_with_expiration(self, api110, tmp_pa }, "href": "s3://openeo-data-staging-waw4-1/batch_jobs/j-250605095828442799fdde3c29b5b047/openEO_20231231T214100Z.tif", "nodata": "nan", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "bands": [ {"name": "LST", "common_name": "surface_temperature", "aliases": ["LST_in:LST"]} ], @@ -3519,7 +3519,7 @@ def test_download_result(self, api, tmp_path): "/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/output.tiff", headers=self.AUTH_HEADER ) assert resp.assert_status_code(200).data == b"tiffdata" - assert resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" def test_download_result_nested_path(self, api110, tmp_path): output_root = Path(tmp_path) @@ -3534,7 +3534,7 @@ def test_download_result_nested_path(self, api110, tmp_path): headers=self.AUTH_HEADER, ) assert resp.assert_status_code(200).data == b"tiffdata" - assert resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" def test_download_result_including_raw_stac(self, api110, tmp_path): output_root = Path(tmp_path) @@ -3608,7 +3608,7 @@ def test_download_result_with_s3_object_storage(self, api, mock_s3_resource, swi resp = api.get(f"/jobs/{job_id}/results/assets/output.tiff", headers=self.AUTH_HEADER) assert resp.assert_status_code(200).data == large_tiff_data - assert resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" @pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#")}]) def test_download_result_signed(self, api, tmp_path, flask_app, backend_config_overrides): @@ -3623,7 +3623,7 @@ def test_download_result_signed(self, api, tmp_path, flask_app, backend_config_o "/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/50afb0cad129e61d415278c4ffcd8a83/output.tiff" ) assert resp.assert_status_code(200).data == b"tiffdata" - assert resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" @pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#")}]) def test_download_result_signed_invalid(self, api, flask_app, backend_config_overrides): @@ -3646,7 +3646,7 @@ def test_download_result_signed_with_expiration(self, api, tmp_path, flask_app, "/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/fd0ca65e29c6d223da05b2e73a875683/output.tiff?expires=2234" ) assert resp.assert_status_code(200).data == b"tiffdata" - assert resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" @mock.patch("time.time", mock.MagicMock(return_value=1234)) @pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}]) @@ -3665,7 +3665,7 @@ def test_download_result_signed_with_expiration_supports_range_request( "/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/fd0ca65e29c6d223da05b2e73a875683/output.tiff?expires=2234" ) assert head_resp.assert_status_code(200).data == b"" - assert head_resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert head_resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" assert head_resp.headers["Accept-Ranges"] == "bytes" assert head_resp.headers["Content-Length"] == "8" @@ -3707,7 +3707,7 @@ def test_download_result_with_s3_object_storage_with_expiration_supports_range_r "/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results/assets/TXIuVGVzdA==/fd0ca65e29c6d223da05b2e73a875683/output.tiff?expires=2234" ) assert head_resp.assert_status_code(200).data == b"" - assert head_resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert head_resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" assert head_resp.headers["Accept-Ranges"] == "bytes" assert head_resp.headers["Content-Length"] == "8" @@ -3821,7 +3821,7 @@ def test_download_result_stac_1_1_item(self, api110, tmp_path, backend_config_ov "href": f"{output_root}/{job_id}/{filename}", "output_dir": f"{output_root}/{job_id}", "nodata": "nan", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "bands": [ {"name": "LST", "common_name": "surface_temperature", "aliases": ["LST_in:LST"]} ], @@ -3858,7 +3858,7 @@ def test_download_result_stac_1_1_item(self, api110, tmp_path, backend_config_ov f"/jobs/{job_id}/results/assets/TXIuVGVzdA==/dec8e6bb06c8f0cdaa6f62188b3e022f/{filename}?expires=2234" ) assert resp.assert_status_code(200).data == b"tiffdata" - assert resp.headers["Content-Type"] == "image/tiff; application=geotiff" + assert resp.headers["Content-Type"] == "image/tiff; application=geotiff; profile=cloud-optimized" @mock.patch("time.time", mock.MagicMock(return_value=1234)) @pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}]) @@ -3907,7 +3907,7 @@ def test_get_job_result_item(self, flask_app, api110, backend_config_overrides): "output.tiff": { "title": "output.tiff", "href": "http://oeo.net/openeo/1.1.0/jobs/53c71345-09b4-46b4-b6b0-03fd6fe1f199/results/assets/TXIuVGVzdA==/f5d336336d36e3e987ba6a34b87cde01/output.tiff?expires=2234", - "type": "image/tiff; application=geotiff", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", "proj:epsg": 4326, "proj:code": "EPSG:4326", "proj:shape": [300, 600], diff --git a/tests/test_views_execute.py b/tests/test_views_execute.py index faa522a0..eea3607f 100644 --- a/tests/test_views_execute.py +++ b/tests/test_views_execute.py @@ -3412,7 +3412,7 @@ def test_add_dimension_duplicate(api): @pytest.mark.parametrize(["format", "expected"], [ - ("GTiff", "image/tiff; application=geotiff"), + ("GTiff", "image/tiff; application=geotiff; profile=cloud-optimized"), ("NetCDF", "application/x-netcdf"), ("PNG", "image/png"), ("CovJSON", "application/json"), diff --git a/tests/util/test_ioformats.py b/tests/util/test_ioformats.py index a055821a..1f65bee2 100644 --- a/tests/util/test_ioformats.py +++ b/tests/util/test_ioformats.py @@ -7,7 +7,7 @@ def test_ioformats_gtiff(format): format_info = IOFORMATS.get(format) assert format_info.format == "GTiff" - assert format_info.mimetype == "image/tiff; application=geotiff" + assert format_info.mimetype == "image/tiff; application=geotiff; profile=cloud-optimized" assert format_info.extension == "geotiff" assert format_info.fiona_driver == "GTiff"