Source code for bmi_topography.cli

"""Command-line interface for bmi-topography"""

import click

from .config import load_config
from .topography import Topography

# Names of options that are mutually exclusive with --config-file
_CONFIG_FILE_EXCLUSIVE = {
    "dem_type",
    "south",
    "north",
    "west",
    "east",
    "output_format",
    "cache_dir",
    "api_key",
}


# Based on https://stackoverflow.com/a/37491504/1563298.
[docs] class MutuallyExclusiveOption(click.Option): """A Click option that is mutually exclusive with --config-file.""" def __init__(self, *args, **kwargs): self.mutually_exclusive_with = kwargs.pop("mutually_exclusive_with", []) super().__init__(*args, **kwargs) def handle_parse_result(self, ctx, opts, args): current = self.name in opts and opts[self.name] is not None for mutex_opt in self.mutually_exclusive_with: if mutex_opt in opts and opts[mutex_opt] is not None: if current: raise click.UsageError( f"'--{self.name.replace('_', '-')}' cannot be used together " f"with '--{mutex_opt.replace('_', '-')}'." ) return super().handle_parse_result(ctx, opts, args)
@click.command() @click.version_option() @click.option("-q", "--quiet", is_flag=True, help="Enables quiet mode.") @click.option( "--config-file", type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), default=None, help=( "Path to a YAML configuration file. " "Mutually exclusive with --dem-type, --south, --north, --west, --east, " "--output-format, --cache-dir, and --api-key." ), cls=MutuallyExclusiveOption, mutually_exclusive_with=list(_CONFIG_FILE_EXCLUSIVE), ) @click.option( "--dem-type", type=click.Choice(Topography.VALID_DEM_TYPES, case_sensitive=True), default=None, help="The global raster dataset.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--south", type=click.FloatRange(-90, 90), default=None, help="WGS 84 bounding box south coordinate, in degrees.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--north", type=click.FloatRange(-90, 90), default=None, help="WGS 84 bounding box north coordinate, in degrees.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--west", type=click.FloatRange(-180, 180), default=None, help="WGS 84 bounding box west coordinate, in degrees.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--east", type=click.FloatRange(-180, 180), default=None, help="WGS 84 bounding box east coordinate, in degrees.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--output-format", type=click.Choice(Topography.VALID_OUTPUT_FORMATS.keys(), case_sensitive=True), default=None, help="Output file format.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--cache-dir", type=click.Path( exists=False, file_okay=False, dir_okay=True, readable=True, writable=True ), default=None, help="Directory to store data files downloaded from OpenTopography.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option( "--api-key", type=str, default=None, help="OpenTopography API key.", show_default=True, cls=MutuallyExclusiveOption, mutually_exclusive_with=["config_file"], ) @click.option("--no-fetch", is_flag=True, help="Do not fetch data from server.") def main( quiet, config_file, dem_type, south, north, west, east, output_format, cache_dir, api_key, no_fetch, ): """Fetch and cache land elevation data from OpenTopography Some datasets require an OpenTopography API key. You can find instructions on how to obtain one from the OpenTopography website: https://opentopography.org/blog/introducing-api-keys-access-opentopography-global-datasets Once you have a key, you can pass it to the `bmi-topography` command in one of three ways: 1) through the environment variable OPENTOPOGRAPHY_API_KEY, or 2) as the contents of the file ".opentopography.txt" located either in your current directory or your home directory, or 3) through the `--api-key` option. """ if config_file is not None: params = load_config(config_file) else: defaults = Topography.DEFAULT params = { "dem_type": dem_type if dem_type is not None else defaults["dem_type"], "south": south if south is not None else defaults["south"], "north": north if north is not None else defaults["north"], "west": west if west is not None else defaults["west"], "east": east if east is not None else defaults["east"], "output_format": ( output_format if output_format is not None else defaults["output_format"] ), "cache_dir": cache_dir if cache_dir is not None else defaults["cache_dir"], "api_key": api_key, } topo = Topography(**params) if not no_fetch: if not quiet: click.secho("Fetching data...", fg="yellow", err=True) path_to_dem = topo.fetch() if not quiet: click.secho( f"File downloaded to {getattr(topo, 'cache_dir')}", fg="green", err=True, ) print(path_to_dem)