Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding raster compression option #106

Merged
merged 37 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
71b3cc5
adding compression option
Antsalacia Nov 28, 2024
c7dbb65
Adding modification and verification in method
Antsalacia Nov 29, 2024
7ac2f6c
Add argument in method
Antsalacia Nov 29, 2024
ba57e0c
rename and add docstring
Antsalacia Nov 29, 2024
a3ae236
Add `raster_compression` type in docstring
AdrienWehrle Nov 29, 2024
5bbc9d5
fix None bug and rename
Antsalacia Nov 29, 2024
a706f43
Merge branch 'fix/34' of https://github.com/Antsalacia/earthspy into …
Antsalacia Nov 29, 2024
f584b99
change argument
Antsalacia Nov 29, 2024
40366a1
CodeQL issue
Antsalacia Dec 2, 2024
2c8c688
pre-commit issues
Antsalacia Dec 2, 2024
37f5765
Address CodeQL alert
AdrienWehrle Dec 2, 2024
3727118
test with pre-commit
Antsalacia Dec 3, 2024
582b681
Merge branch 'fix/34' of https://github.com/Antsalacia/earthspy into …
Antsalacia Dec 3, 2024
a3d8c28
Merge branch 'main' into fix/34
AdrienWehrle Dec 3, 2024
e9c5cf2
change in metadata
Antsalacia Dec 3, 2024
0a9d2cc
add pre-commit
Antsalacia Dec 3, 2024
ad78deb
resolve merge conflict
Antsalacia Dec 3, 2024
e34429c
pre-commit change
Antsalacia Dec 3, 2024
f65d35a
modify `get_raster_compression` docstring
AdrienWehrle Dec 3, 2024
468020c
modify line length on docstring
AdrienWehrle Dec 3, 2024
d8512b1
Problem with self and variables env
Antsalacia Dec 6, 2024
d8cb87f
Adding conftest and test
Antsalacia Dec 12, 2024
4ea9306
Merge branch 'main' into fix/34
AdrienWehrle Dec 12, 2024
74cb8b0
rename filepath for authfile
AdrienWehrle Dec 12, 2024
bf94c1a
fix authfile fixture
AdrienWehrle Dec 12, 2024
3f242d8
try and fix authfile writing in Github action
AdrienWehrle Dec 12, 2024
b6bc469
modify compression methods
AdrienWehrle Dec 12, 2024
f6acfc7
fix authfile
AdrienWehrle Dec 12, 2024
9d722c2
fix authfile
AdrienWehrle Dec 12, 2024
7ec7f3d
add assert for authentification
AdrienWehrle Dec 12, 2024
2dd7d8a
remove assert
AdrienWehrle Dec 12, 2024
533c2f9
change None check and add test for comp
Antsalacia Dec 16, 2024
239bfb2
Add comments
Antsalacia Dec 16, 2024
92c6479
comply with github_adv_sec
Antsalacia Dec 16, 2024
0ebfcc6
fix typo
Antsalacia Dec 16, 2024
7ade2d3
forgot pre-commit
AdrienWehrle Dec 17, 2024
80b174b
add Antsalacia in author list
AdrienWehrle Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion earthspy/earthspy.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def set_query_parameters(
download_mode: str = "SM",
remove_splitboxes: bool = True,
verbose: bool = True,
raster_compression: str = None,
) -> None:
"""Define a set of parameters used for the API request.

Expand Down Expand Up @@ -144,6 +145,11 @@ def set_query_parameters(
:param verbose: Whether to print processing status or not, defaults
to True.
:type verbose: bool, optional


:param raster_compression: Raster compression to apply following methods
available in rasterio, defaults to None.
:type raster_compression: Union[None, str], optional
"""

# set processing attributes
Expand Down Expand Up @@ -171,6 +177,9 @@ def set_query_parameters(
# set and correct resolution
self.set_correct_resolution()

# set compress mode
self.get_raster_compression(raster_compression)

# set post-processing attributes
self.get_evaluation_script(evaluation_script)
self.get_store_folder(store_folder)
Expand All @@ -187,6 +196,31 @@ def set_query_parameters(

return None

def get_raster_compression(self, raster_compression: Union[None, str]) -> str:
"""Get raster compression based on rasterio's available methods

:return: Raster compression method
:rtype: Union[None, str]
"""

if raster_compression in [
"DEFLATE",
"LZW",
"PACKBITS",
"JPEG",
"WEBP",
"LZMA",
"ZSTD",
]:

self.raster_compression = raster_compression
elif raster_compression is None:
self.raster_compression = None
else:
raise KeyError("Compression mode not found")

return self.raster_compression

def get_data_collection(self) -> shb.DataCollection:
"""Get Sentinel Hub DataCollection object from data collection name.

Expand Down Expand Up @@ -294,7 +328,6 @@ def get_raw_data_collection_resolution(self) -> int:

:return: Data collection resolution.
:rtype: int

"""

# set default satellite resolution
Expand Down Expand Up @@ -1072,11 +1105,19 @@ def merge_rasters(self) -> None:
"transform": output_transform,
}
)

# update dictionary if compression set
if self.raster_compression is not None:
output_meta.update({"compress": self.raster_compression})

# extract scene id
id_dict = {k: self.metadata[date][0][k] for k in ["id"]}

# write mosaic
with rasterio.open(date_output_filename, "w", **output_meta) as dst:
dst.write(mosaic)
dst.update_tags(**id_dict)

# save file name of merged raster
self.output_filenames_renamed.append(date_output_filename)

Expand Down
185 changes: 185 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/usr/bin/env python3
"""

@author: Adrien Wehrlé, University of Zurich, Switzerland

"""

import os

import pytest

import earthspy.earthspy as es


def pytest_addoption(parser):
"""Add option to pass local path to authentication file"""
parser.addoption(
"--authfile",
action="store",
default="./auth.txt",
help="Full path to Sentinel Hub credential file containing ID and password",
)


# if running in Github action
if os.getenv("CI") is not None:

# create local variables from environment secrets for convenience
SH_CLIENT_ID = os.environ["SH_CLIENT_ID"]
SH_CLIENT_SECRET = os.environ["SH_CLIENT_SECRET"]

# path to credential file to be created
@pytest.fixture(scope="session")
def authfile():
"""Set credential file name"""
authfile = "auth.txt"
return authfile

# path to credential file to be created
@pytest.fixture(scope="session")
def write_authfile(authfile):
"""Create file containing credentials for testing"""
with open(authfile, "w") as out:
out.write(f"{SH_CLIENT_ID}\n{SH_CLIENT_SECRET}")
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed

return None


# if running locally
else:

@pytest.fixture(scope="session")
def authfile(pytestconfig):
"""Get option from command line call"""
return pytestconfig.getoption("authfile")

@pytest.fixture(scope="session")
def credentials(authfile):
"""Read credentials stored in text file"""

with open(authfile) as file:
credentials = file.read().splitlines()
return credentials

@pytest.fixture(scope="session")
def SH_CLIENT_ID(credentials) -> None:
"""Extract client id from line"""
SH_CLIENT_ID = credentials[0]
return SH_CLIENT_ID

@pytest.fixture(scope="session")
def SH_CLIENT_SECRET(credentials) -> None:
"""Extract client secret from line"""
SH_CLIENT_SECRET = credentials[1]
return SH_CLIENT_SECRET


@pytest.fixture(scope="session")
def test_evalscript():
"""Set a test evalscript for Sentinel-2"""
test_evalscript = """
//VERSION=3
function setup(){
return{
input: ["B02", "B03", "B04", "dataMask"],
output: {bands: 4}
}
}
function evaluatePixel(sample){
// Set gain for visualisation
let gain = 2.5;
// Return RGB
return [sample.B04 * gain, sample.B03 * gain, sample.B02 * gain,
sample.dataMask];
}
"""
return test_evalscript


@pytest.fixture(scope="session")
def test_url():
"""Set a test evalscript pointing to Sentinel-2 True Color"""
test_url = (
"https://custom-scripts.sentinel-hub.com/custom-scripts/"
+ "sentinel-2/true_color/script.js"
)
return test_url


@pytest.fixture(scope="session")
def test_collection():
"""Set a test data collection"""
test_collection = "SENTINEL2_L2A"
return test_collection


@pytest.fixture(scope="session")
def test_bounding_box():
"""Set a test footprint area (bounding box)"""
test_bounding_box = [-51.13, 69.204, -51.06, 69.225]
return test_bounding_box


@pytest.fixture(scope="session")
def test_area_name():
"""Set a test area available as geojson file"""
test_area_name = "Ilulissat"
return test_area_name


@pytest.fixture(scope="session")
def t1(authfile, test_evalscript, test_collection, test_bounding_box):
"""Set a test query with default parameters"""
t1 = es.EarthSpy(authfile)
t1.set_query_parameters(
bounding_box=test_bounding_box,
time_interval=["2019-08-23"],
evaluation_script=test_evalscript,
data_collection=test_collection,
download_mode="SM",
)
return t1


@pytest.fixture(scope="session")
def t2(authfile, test_evalscript, test_collection, test_area_name):
"""Set a test query with area name"""
t2 = es.EarthSpy(authfile)
t2.set_query_parameters(
bounding_box=test_area_name,
time_interval=["2019-08-23"],
evaluation_script=test_evalscript,
data_collection=test_collection,
download_mode="SM",
)
return t2


@pytest.fixture(scope="session")
def t3(authfile, test_evalscript, test_collection, test_bounding_box):
"""Set a test query with direct download mode"""
t3 = es.EarthSpy(authfile)
t3.set_query_parameters(
bounding_box=test_bounding_box,
time_interval=["2019-08-23"],
evaluation_script=test_evalscript,
data_collection=test_collection,
download_mode="D",
)
return t3


@pytest.fixture(scope="session")
def t4(authfile, test_evalscript, test_collection, test_bounding_box):
"""Set a test query with LZW raster compression"""
t4 = es.EarthSpy(authfile)
t4.set_query_parameters(
bounding_box=test_bounding_box,
time_interval=["2019-08-23"],
evaluation_script=test_evalscript,
data_collection=test_collection,
download_mode="SM",
raster_compression="LZW",
)
return t4
Loading
Loading