Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 16 additions & 1 deletion raster_loader/cli/bigquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import click
from functools import wraps, partial

from raster_loader.utils import get_default_table_name
from raster_loader.lib.utils import get_default_table_name
from raster_loader.io.bigquery import BigQueryConnection, AccessTokenCredentials
from raster_loader.lib.valuelabels import validate_band_valuelabels


def catch_exception(func=None, *, handle=Exception):
Expand Down Expand Up @@ -101,6 +102,18 @@ def bigquery(args=None):
type=int,
default=6,
)
@click.option(
"--band-valuelabels",
help="Custom data for valuelabels in JSON format, or 'None'. "
"i.e: '{<value_1>: <label_1>, <value_2>: <label_2>, ...}'. "
"Could repeat --band-valuelabels to specify multiple bands data. "
"They will be considered in the order they appear in the file. "
"Note that you can set any value to 'None' to omit valuelabels for that band. ",
type=str,
default=[],
multiple=True,
callback=validate_band_valuelabels,
)
@catch_exception()
def upload(
file_path,
Expand All @@ -119,6 +132,7 @@ def upload(
exact_stats=False,
basic_stats=False,
compression_level=6,
band_valuelabels=[],
):
from raster_loader.io.common import (
get_number_of_blocks,
Expand Down Expand Up @@ -194,6 +208,7 @@ def upload(
basic_stats=basic_stats,
compress=compress,
compression_level=compression_level,
band_valuelabels=band_valuelabels,
)

click.echo("Raster file uploaded to Google BigQuery")
Expand Down
17 changes: 16 additions & 1 deletion raster_loader/cli/databricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import click
from functools import wraps, partial

from raster_loader.utils import get_default_table_name
from raster_loader.lib.utils import get_default_table_name
from raster_loader.io.databricks import DatabricksConnection
from raster_loader.lib.valuelabels import validate_band_valuelabels


def catch_exception(func=None, *, handle=Exception):
Expand Down Expand Up @@ -115,6 +116,18 @@ def databricks(args=None):
type=int,
default=6,
)
@click.option(
"--band-valuelabels",
help="Custom data for valuelabels in JSON format, or 'None'. "
"i.e: '{<value_1>: <label_1>, <value_2>: <label_2>, ...}'. "
"Could repeat --band-valuelabels to specify multiple bands data. "
"They will be considered in the order they appear in the file. "
"Note that you can set any value to 'None' to omit valuelabels for that band. ",
type=str,
default=[],
multiple=True,
callback=validate_band_valuelabels,
)
@catch_exception()
def upload(
server_hostname,
Expand All @@ -136,6 +149,7 @@ def upload(
exact_stats=False,
basic_stats=False,
compression_level=6,
band_valuelabels=[],
):
from raster_loader.io.common import (
get_number_of_blocks,
Expand Down Expand Up @@ -213,6 +227,7 @@ def upload(
basic_stats=basic_stats,
compress=compress,
compression_level=compression_level,
band_valuelabels=band_valuelabels,
)

click.echo("Raster file uploaded to Databricks")
Expand Down
17 changes: 16 additions & 1 deletion raster_loader/cli/snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import click
from functools import wraps, partial

from raster_loader.utils import get_default_table_name, check_private_key
from raster_loader.lib.utils import get_default_table_name, check_private_key
from raster_loader.io.snowflake import SnowflakeConnection
from raster_loader.lib.valuelabels import validate_band_valuelabels


def catch_exception(func=None, *, handle=Exception):
Expand Down Expand Up @@ -123,6 +124,18 @@ def snowflake(args=None):
type=int,
default=6,
)
@click.option(
"--band-valuelabels",
help="Custom data for valuelabels in JSON format, or 'None'. "
"i.e: '{<value_1>: <label_1>, <value_2>: <label_2>, ...}'. "
"Could repeat --band-valuelabels to specify multiple bands data. "
"They will be considered in the order they appear in the file. "
"Note that you can set any value to 'None' to omit valuelabels for that band. ",
type=str,
default=[],
multiple=True,
callback=validate_band_valuelabels,
)
@catch_exception()
def upload(
account,
Expand All @@ -148,6 +161,7 @@ def upload(
exact_stats=False,
basic_stats=False,
compression_level=6,
band_valuelabels=[],
):
from raster_loader.io.common import (
get_number_of_blocks,
Expand Down Expand Up @@ -255,6 +269,7 @@ def upload(
basic_stats=basic_stats,
compress=compress,
compression_level=compression_level,
band_valuelabels=band_valuelabels,
)

click.echo("Raster file uploaded to Snowflake")
Expand Down
8 changes: 5 additions & 3 deletions raster_loader/io/bigquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

from itertools import chain
from raster_loader import __version__
from raster_loader.errors import import_error_bigquery, IncompatibleRasterException
from raster_loader.utils import ask_yes_no_question, batched
from raster_loader.lib.errors import import_error_bigquery, IncompatibleRasterException
from raster_loader.lib.utils import ask_yes_no_question, batched
from raster_loader.io.common import (
check_metadata_is_compatible,
get_number_of_blocks,
Expand All @@ -18,7 +18,7 @@
update_metadata,
)

from typing import Iterable, List, Tuple
from typing import Dict, Iterable, List, Tuple
from functools import partial

try:
Expand Down Expand Up @@ -111,6 +111,7 @@ def upload_raster(
basic_stats: bool = False,
compress: bool = False,
compression_level: int = 6,
band_valuelabels: List[Dict[int, str]] = [],
):
"""Write a raster file to a BigQuery table."""
print("Loading raster file to BigQuery...")
Expand Down Expand Up @@ -139,6 +140,7 @@ def upload_raster(
exact_stats,
basic_stats,
compress=compress,
band_valuelabels=band_valuelabels,
)

overviews_records_gen = rasterio_overview_to_records(
Expand Down
17 changes: 12 additions & 5 deletions raster_loader/io/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@
from typing import Dict, Callable, Iterable, List, Tuple, Union
from affine import Affine
from shapely import wkt # Can not use directly from shapely.wkt
from raster_loader.lib.valuelabels import get_band_valuelabels

import rio_cogeo
import rasterio
import quadbin

from raster_loader.geo import raster_bounds
from raster_loader.errors import (
from raster_loader.lib.geo import raster_bounds
from raster_loader.lib.errors import (
error_not_google_compatible,
)
from raster_loader.utils import warnings
from raster_loader.lib.utils import warnings


DEFAULT_COG_BLOCK_SIZE = 256

Expand Down Expand Up @@ -210,6 +212,7 @@ def rasterio_metadata(
exact_stats: bool = False,
basic_stats: bool = False,
compress: bool = False,
band_valuelabels: List[Dict[int, str]] = [],
):
"""Open a raster file with rasterio."""
raster_info = rio_cogeo.cog_info(file_path).dict()
Expand Down Expand Up @@ -278,12 +281,14 @@ def rasterio_metadata(
band_nodata = band_value_as_string(
raster_dataset, band, band_nodata_value(raster_dataset, band)
)

meta = {
"band": band,
"type": raster_band_type(raster_dataset, band),
"name": band_field_name(band_name, band, band_rename_function),
"colorinterp": band_colorinterp,
"colortable": get_color_table(raster_dataset, band),
"valuelabels": get_band_valuelabels(file_path, band, band_valuelabels),
"stats": stats,
"nodata": band_nodata,
}
Expand Down Expand Up @@ -311,6 +316,7 @@ def rasterio_metadata(
"colorinterp": e["colorinterp"],
"nodata": e["nodata"],
"colortable": e["colortable"],
"valuelabels": e["valuelabels"],
}
for e in bands_metadata
]
Expand Down Expand Up @@ -506,7 +512,7 @@ def compute_quantiles(data: List[Union[int, float]], cast_function: Callable) ->

def get_stats(
raster_dataset: rasterio.io.DatasetReader, band: int
) -> rasterio.Statistics:
) -> rasterio._io.Statistics:
"""Get statistics for a raster band."""
try:
# stats method is supported since rasterio 1.4.0 and statistics
Expand Down Expand Up @@ -937,7 +943,8 @@ def is_valid_raster_dataset(raster_dataset: rasterio.io.DatasetReader) -> bool:
def band_without_stats(band):
return {
k: band[k]
for k in set(list(band.keys())) - set(["stats", "colorinterp", "colortable"])
for k in set(list(band.keys()))
- set(["stats", "colorinterp", "colortable", "valuelabels"])
}


Expand Down
11 changes: 8 additions & 3 deletions raster_loader/io/databricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import rasterio

from itertools import chain
from raster_loader.errors import import_error_databricks, IncompatibleRasterException
from raster_loader.utils import ask_yes_no_question, batched
from raster_loader.lib.errors import (
import_error_databricks,
IncompatibleRasterException,
)
from raster_loader.lib.utils import ask_yes_no_question, batched
from raster_loader.io.common import (
check_metadata_is_compatible,
get_number_of_blocks,
Expand All @@ -15,7 +18,7 @@
update_metadata,
)

from typing import Iterable, List, Tuple
from typing import Dict, Iterable, List, Tuple

try:
from databricks.connect import DatabricksSession
Expand Down Expand Up @@ -141,6 +144,7 @@ def upload_raster(
basic_stats: bool = False,
compress: bool = False,
compression_level: int = 6,
band_valuelabels: List[Dict[int, str]] = [],
):
"""Write a raster file to a Databricks table."""
# Wait for cluster to be ready before starting the upload
Expand Down Expand Up @@ -174,6 +178,7 @@ def upload_raster(
exact_stats,
basic_stats,
compress=compress,
band_valuelabels=band_valuelabels,
)

overviews_records_gen = rasterio_overview_to_records(
Expand Down
8 changes: 5 additions & 3 deletions raster_loader/io/snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import pandas as pd

from itertools import chain
from typing import Iterable, List, Tuple
from typing import Dict, Iterable, List, Tuple

from raster_loader.errors import (
from raster_loader.lib.errors import (
IncompatibleRasterException,
import_error_snowflake,
)

from raster_loader.utils import ask_yes_no_question, batched
from raster_loader.lib.utils import ask_yes_no_question, batched

from raster_loader.io.common import (
rasterio_metadata,
Expand Down Expand Up @@ -208,6 +208,7 @@ def upload_raster(
basic_stats: bool = False,
compress: bool = False,
compression_level: int = 6,
band_valuelabels: List[Dict[int, str]] = [],
) -> bool:
"""Write a raster file to a Snowflake table."""

Expand Down Expand Up @@ -243,6 +244,7 @@ def band_rename_function(x):
exact_stats,
basic_stats,
compress,
band_valuelabels,
)

overviews_records_gen = rasterio_overview_to_records(
Expand Down
Empty file added raster_loader/lib/__init__.py
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions raster_loader/lib/valuelabels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import json
import click
from typing import Dict, List, Optional


def get_band_valuelabels(
file_path: str, band: int, band_valuelabels: List[Dict[int, str]]
) -> Optional[Dict[int, str]]:
valuelabels = None
if len(band_valuelabels) >= band and band_valuelabels[band - 1] is not None:
print(f"Using the provided valuelabels for band {band}")
valuelabels = band_valuelabels[band - 1]
return valuelabels


def validate_band_valuelabels(_, __, value):
"""
Validate the band valuelabels parameter for click library callback.
"""
try:
return [json.loads(item) if item != "None" else None for item in value]
except json.JSONDecodeError:
raise click.BadParameter(
"Invalid JSON format. Please provide a valid JSON object."
)
27 changes: 27 additions & 0 deletions raster_loader/tests/bigquery/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,33 @@ def test_bigquery_describe(*args, **kwargs):
assert result.exit_code == 0


@patch(
"raster_loader.cli.bigquery.BigQueryConnection.upload_records", return_value=None
)
@patch("raster_loader.cli.bigquery.BigQueryConnection.__init__", return_value=None)
def test_bigquery_upload_custom_valuelabels(*args, **kwargs):
runner = CliRunner()
result = runner.invoke(
main,
[
"bigquery",
"upload",
"--file_path",
f"{tiff}",
"--project",
"project",
"--dataset",
"dataset",
"--table",
"table",
"--band-valuelabels",
'{"90": "Woody Wetlands", "52": "Shrub/Scrub"}',
],
)
assert result.exit_code == 1
assert "Using the provided valuelabels for band 1" in result.output


def test_info(*args, **kwargs):
runner = CliRunner()
result = runner.invoke(main, ["info"])
Expand Down
Loading