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

Update datasets hash and add first cli #9

Merged
merged 3 commits into from
Dec 3, 2023
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
2 changes: 2 additions & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ dependencies:
- python>=3.8
- pip>=21.3 # https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/#editable-installation
- git # for pip install, due to setuptools_scm
- click>=7.0
- h5py>=1.10
- numpy>=1.20
- pooch>=1.7
- pyproj>=3.3
- shapely>=1.8
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Changelog = "https://github.com/opera-adt/opera-utils/releases"

# Entry points for the command line interface
[project.scripts]
opera_utils = "opera_utils.cli:main"
opera-utils = "opera_utils.cli:cli_app"

[tool.setuptools.dynamic]
dependencies = { file = ["requirements.txt"] }
Expand Down
12 changes: 12 additions & 0 deletions src/opera_utils/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from itertools import chain, combinations
from typing import Any, Iterable, Mapping

from ._types import Bbox


def flatten(list_of_lists: Iterable[Iterable[Any]]) -> chain[Any]:
"""Flatten one level of nesting."""
Expand All @@ -25,3 +27,13 @@ def powerset(iterable: Iterable[Any]) -> chain[tuple[Any, ...]]:
"""
s = list(iterable)
return flatten(combinations(s, r) for r in range(len(s) + 1))


def reproject_bounds(bounds: Bbox, src_epsg: int, dst_epsg: int) -> Bbox:
"""Reproject the (left, bottom, right top) from `src_epsg to `dst_epsg`."""
from pyproj import Transformer

t = Transformer.from_crs(src_epsg, dst_epsg, always_xy=True)
left, bottom, right, top = bounds
bbox: Bbox = (*t.transform(left, bottom), *t.transform(right, top)) # type: ignore
return bbox
4 changes: 2 additions & 2 deletions src/opera_utils/burst_frame_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ def get_burst_id_geojson(
def _form_where_in_query(values: Sequence[str], column_name):
# Example:
# "burst_id_jpl in ('t005_009471_iw2','t007_013706_iw2','t008_015794_iw1')"
burst_str = ",".join(f"'{b}'" for b in values)
return f"{column_name} IN ({burst_str})"
where_in_str = ",".join(f"'{b}'" for b in values)
return f"{column_name} IN ({where_in_str})"


def _get_geojson(
Expand Down
54 changes: 54 additions & 0 deletions src/opera_utils/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Command-line interface for opera-utils."""
from __future__ import annotations

import json
import logging

import click

from .burst_frame_db import get_frame_bbox


@click.group()
@click.version_option()
@click.option("--debug", is_flag=True, default=False)
@click.pass_context
def cli_app(ctx, debug):
"""Orca command-line interface."""
level = logging.DEBUG if debug else logging.INFO
handler = logging.StreamHandler()
logging.basicConfig(level=level, handlers=[handler])


@cli_app.command()
@click.argument("frame_id")
@click.option(
"--latlon",
"-l",
is_flag=True,
help="Output the bounding box in latitude/longitude (EPSG:4326)",
)
@click.option(
"--bounds-only",
"-b",
is_flag=True,
help="Output only (left, bottom, right, top) and omit EPSG",
)
def frame_bbox(frame_id, latlon: bool, bounds_only: bool):
"""Look up the EPSG/bounding box for FRAME_ID.

Outputs as JSON string to stdout like
{"epsg": 32618, "bbox": [157140.0, 4145220.0, 440520.0, 4375770.0]}

Unless `--bounds-only` is given
"""
epsg, bounds = get_frame_bbox(frame_id=frame_id)
if latlon:
from opera_utils._helpers import reproject_bounds

bounds = reproject_bounds(bounds, epsg, 4326)
if bounds_only:
click.echo(list(bounds))
else:
obj = dict(epsg=epsg, bbox=bounds)
click.echo(json.dumps(obj))
4 changes: 2 additions & 2 deletions src/opera_utils/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
# are their respective SHA256 hashes. Files will be downloaded
# automatically when needed.
registry={
f"frame-geometries-simple-{BURST_DB_VERSION}.geojson.zip": "f0094f4cdc287d56d7a126a42f1e3075e50309afe8a431f49df1ecd8d8b26c8b",
f"burst-id-geometries-simple-{BURST_DB_VERSION}.geojson.zip": "d9cfe71ec836facd5a782ea82625c30a824b78f2b2689106c4d6808bbfce0898",
f"frame-geometries-simple-{BURST_DB_VERSION}.geojson.zip": "963f63577221a3baa20f3a2101c7a01eefb0cc853f6f111708a5bb35bebfc0ed",
f"burst-id-geometries-simple-{BURST_DB_VERSION}.geojson.zip": "e75cc27809448d7ace2164879626fb0b5616b16981a6b2d6d234e3b17cb615fa",
f"opera-s1-disp-burst-to-frame-{BURST_DB_VERSION}.json.zip": "436cce345378dc31e81ed661497bab2e744217a5d63c0bb92817dc837786cd22",
f"opera-s1-disp-frame-to-burst-{BURST_DB_VERSION}.json.zip": "a48382afcb89f0ff681982b0fc24476ec9c6c1b8a67ae1a26cf380a450ffadc0",
},
Expand Down
16 changes: 16 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from click.testing import CliRunner

from opera_utils.cli import cli_app


def test_cli_help():
runner = CliRunner()
result = runner.invoke(cli_app, ["--help"])
assert result.exit_code == 0
assert result.output.startswith("Usage:")


def test_frame_bbox_help():
runner = CliRunner()
result = runner.invoke(cli_app, ["frame-bbox", "--help"])
assert result.exit_code == 0