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

Feature/new rio tiler #25

Merged
merged 2 commits into from
Oct 23, 2024
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
9 changes: 0 additions & 9 deletions .bumpversion.cfg

This file was deleted.

5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.13.0 (2024-10-23)

* update rio-tiler dependency to `>=7.0,<8.0`
* add `reader-params` options in CLI

## 0.12.1 (2024-04-18)

* fix GET range parsing
Expand Down
18 changes: 17 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dependencies = [
"jinja2>=3.0,<4.0.0",
"loguru",
"rasterio>=1.3.8",
"rio-tiler>=6.0,<7.0",
"rio-tiler>=7.0,<8.0",
"uvicorn[standard]",
]

Expand All @@ -38,6 +38,7 @@ test = [
]
dev = [
"pre-commit",
"bump-my-version",
]

[project.urls]
Expand Down Expand Up @@ -112,3 +113,18 @@ ignore = [

[tool.ruff.lint.mccabe]
max-complexity = 14


[tool.bumpversion]
current_version = "0.12.1"
search = "{current_version}"
replace = "{new_version}"
regex = false
tag = true
commit = true
tag_name = "{new_version}"

[[tool.bumpversion.files]]
filename = "tilebench/__init__.py"
search = '__version__ = "{current_version}"'
replace = '__version__ = "{new_version}"'
110 changes: 89 additions & 21 deletions tilebench/scripts/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,42 @@
from loguru import logger as log
from rasterio._path import _parse_path as parse_path
from rasterio.rio import options
from rio_tiler.io import BaseReader, COGReader, MultiBandReader, MultiBaseReader
from rio_tiler.io import BaseReader, MultiBandReader, MultiBaseReader, Reader

from tilebench import profile as profiler
from tilebench.viz import TileDebug

default_tms = morecantile.tms.get("WebMercatorQuad")


def options_to_dict(ctx, param, value):
"""
click callback to validate `--opt KEY1=VAL1 --opt KEY2=VAL2` and collect
in a dictionary like the one below, which is what the CLI function receives.
If no value or `None` is received then an empty dictionary is returned.

{
'KEY1': 'VAL1',
'KEY2': 'VAL2'
}

Note: `==VAL` breaks this as `str.split('=', 1)` is used.
"""

if not value:
return {}
else:
out = {}
for pair in value:
if "=" not in pair:
raise click.BadParameter(f"Invalid syntax for KEY=VAL arg: {pair}")
else:
k, v = pair.split("=", 1)
out[k] = v

return out


# The CLI command group.
@click.group(help="Command line interface for the tilebench Python package.")
def cli():
Expand Down Expand Up @@ -51,7 +79,7 @@ def cli():
@click.option(
"--reader",
type=str,
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.Reader`",
)
@click.option(
"--tms",
Expand All @@ -66,6 +94,15 @@ def cli():
callback=options._cb_key_val,
help="GDAL configuration options.",
)
@click.option(
"--reader-params",
"-p",
"reader_params",
metavar="NAME=VALUE",
multiple=True,
callback=options_to_dict,
help="Reader Options.",
)
def profile(
input,
tile,
Expand All @@ -77,8 +114,9 @@ def profile(
reader,
tms,
config,
reader_params,
):
"""Profile COGReader Mercator Tile read."""
"""Profile Reader Tile read."""
tilematrixset = default_tms
if tms:
with open(tms, "r") as f:
Expand All @@ -90,15 +128,17 @@ def profile(
if not issubclass(reader, (BaseReader, MultiBandReader, MultiBaseReader)):
warnings.warn(f"Invalid reader type: {type(reader)}", stacklevel=1)

Reader = reader or COGReader
DstReader = reader or Reader

if not tile:
with rasterio.Env(CPL_VSIL_CURL_NON_CACHED=parse_path(input).as_vsi()):
with Reader(input, tms=tilematrixset) as cog:
with Reader(input, tms=tilematrixset, **reader_params) as cog:
if zoom is None:
zoom = randint(cog.minzoom, cog.maxzoom)

w, s, e, n = cog.geographic_bounds
w, s, e, n = cog.get_geographic_bounds(
tilematrixset.rasterio_geographic_crs
)
# Truncate BBox to the TMS bounds
w = max(tilematrixset.bbox.left, w)
s = max(tilematrixset.bbox.bottom, s)
Expand Down Expand Up @@ -128,7 +168,7 @@ def profile(
config=config,
)
def _read_tile(src_path: str, x: int, y: int, z: int, tilesize: int = 256):
with Reader(src_path, tms=tilematrixset) as cog:
with DstReader(src_path, tms=tilematrixset, **reader_params) as cog:
return cog.tile(x, y, z, tilesize=tilesize)

(_, _), stats = _read_tile(input, tile_x, tile_y, tile_z, tilesize)
Expand All @@ -141,14 +181,23 @@ def _read_tile(src_path: str, x: int, y: int, z: int, tilesize: int = 256):
@click.option(
"--reader",
type=str,
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.Reader`",
)
@click.option(
"--tms",
help="Path to TileMatrixSet JSON file.",
type=click.Path(),
)
def get_zooms(input, reader, tms):
@click.option(
"--reader-params",
"-p",
"reader_params",
metavar="NAME=VALUE",
multiple=True,
callback=options_to_dict,
help="Reader Options.",
)
def get_zooms(input, reader, tms, reader_params):
"""Get Mercator Zoom levels."""
tilematrixset = default_tms
if tms:
Expand All @@ -161,9 +210,9 @@ def get_zooms(input, reader, tms):
if not issubclass(reader, (BaseReader, MultiBandReader, MultiBaseReader)):
warnings.warn(f"Invalid reader type: {type(reader)}", stacklevel=1)

Reader = reader or COGReader
DstReader = reader or Reader

with Reader(input, tms=tilematrixset) as cog:
with DstReader(input, tms=tilematrixset, **reader_params) as cog:
click.echo(json.dumps({"minzoom": cog.minzoom, "maxzoom": cog.maxzoom}))


Expand All @@ -173,14 +222,23 @@ def get_zooms(input, reader, tms):
@click.option(
"--reader",
type=str,
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.Reader`",
)
@click.option(
"--tms",
help="Path to TileMatrixSet JSON file.",
type=click.Path(),
)
def random(input, zoom, reader, tms):
@click.option(
"--reader-params",
"-p",
"reader_params",
metavar="NAME=VALUE",
multiple=True,
callback=options_to_dict,
help="Reader Options.",
)
def random(input, zoom, reader, tms, reader_params):
"""Get random tile."""
tilematrixset = default_tms
if tms:
Expand All @@ -193,12 +251,12 @@ def random(input, zoom, reader, tms):
if not issubclass(reader, (BaseReader, MultiBandReader, MultiBaseReader)):
warnings.warn(f"Invalid reader type: {type(reader)}", stacklevel=1)

Reader = reader or COGReader
DstReader = reader or Reader

with Reader(input, tms=tilematrixset) as cog:
with DstReader(input, tms=tilematrixset, **reader_params) as cog:
if zoom is None:
zoom = randint(cog.minzoom, cog.maxzoom)
w, s, e, n = cog.geographic_bounds
w, s, e, n = cog.get_geographic_bounds(tilematrixset.rasterio_geographic_crs)

# Truncate BBox to the TMS bounds
w = max(tilematrixset.bbox.left, w)
Expand Down Expand Up @@ -237,7 +295,7 @@ def random(input, zoom, reader, tms):
@click.option(
"--reader",
type=str,
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.Reader`",
)
@click.option(
"--config",
Expand All @@ -247,21 +305,31 @@ def random(input, zoom, reader, tms):
callback=options._cb_key_val,
help="GDAL configuration options.",
)
def viz(src_path, port, host, server_only, reader, config):
@click.option(
"--reader-params",
"-p",
"reader_params",
metavar="NAME=VALUE",
multiple=True,
callback=options_to_dict,
help="Reader Options.",
)
def viz(src_path, port, host, server_only, reader, config, reader_params):
"""WEB UI to visualize VSI statistics for a web mercator tile requests."""
if reader:
module, classname = reader.rsplit(".", 1)
reader = getattr(importlib.import_module(module), classname) # noqa
if not issubclass(reader, (BaseReader)):
if not issubclass(reader, (BaseReader, MultiBandReader, MultiBaseReader)):
warnings.warn(f"Invalid reader type: {type(reader)}", stacklevel=1)

Reader = reader or COGReader
DstReader = reader or Reader

config = config or {}

application = TileDebug(
src_path=src_path,
reader=Reader,
reader=DstReader,
reader_params=reader_params,
port=port,
host=host,
config=config,
Expand Down
Loading
Loading