gedih3.cliutils#
Attributes#
Functions#
|
Detect the file format of a simplified dataset. |
|
List data files in a simplified dataset directory. |
|
Read column names and geometry flag from a dataset file without loading data. |
|
Return a callable that reads a single file into a DataFrame or GeoDataFrame. |
|
Add Dask-related arguments to an argument parser. |
|
Add verbosity-related arguments to an argument parser. |
|
Add remote storage credential arguments to an argument parser. |
|
Call |
|
Add GEDI product variable arguments to an argument parser. |
|
Parse EGI argument in format 'level' or 'level:partition'. |
|
Configure logging based on verbosity flags and return a logger. |
|
Print a tool banner with centered title. |
|
Print a success message with banner formatting. |
|
Absolutize each path-bearing CLI arg listed in |
|
tqdm wrapper with consistent style + safe logger interleaving. |
|
Standard exception handling context manager for CLI tools. |
|
Configure database path from args or default. |
|
Get spatial index information from a dataset or database. |
|
Load data from H3 database, simplified dataset, or parquet directory. |
|
Check if a column name matches internal/partition column patterns. |
|
Filter out internal/partition columns from a column list. |
|
Get list of numeric columns from a Dask DataFrame. |
Get columns suitable for rasterization from a Dask DataFrame. |
|
Get numeric columns suitable for aggregation from a DataFrame. |
|
|
Filter columns suitable for rasterization, excluding internal columns. |
|
Get H3 column name for a given resolution level. |
|
Find a coordinate column by base name, handling product suffixes. |
|
Parse aggregation spec from CLI string, JSON file, or text file. |
|
|
|
Resolve product variables from CLI args. |
|
Parse GEDI product args from CLI (legacy wrapper around resolve_product_vars). |
|
|
|
One-line summary of a live dask Client's cluster — workers, total threads, total RAM. |
|
Parse region argument into GeoDataFrame or bbox |
|
Collect all requested variables from command line arguments and validate against available columns. |
|
Return quality filter conditions for the selected products and GEDI version. |
|
Build pandas query string from arguments |
|
Apply a pandas query, handling column names with '/' that pandas can't parse. |
Module Contents#
- gedih3.cliutils.VALID_FORMATS = ['parquet', 'feather', 'shp', 'geojson', 'gpkg', 'txt', 'csv', 'h5', 'hdf5']#
- gedih3.cliutils.PIPELINE_FORMATS#
- gedih3.cliutils.FORMAT_EXTENSIONS#
- gedih3.cliutils.detect_dataset_format(dataset_path)[source]#
Detect the file format of a simplified dataset.
Checks DATASET_META_FILENAME for ‘file_format’ field first, then scans directory for known extensions. Defaults to ‘parquet’ for backwards compat.
- Parameters:
- dataset_pathstr
Path to the dataset directory
- Returns:
- str
Detected format (‘parquet’, ‘feather’, or ‘gpkg’)
- Raises:
- GediValidationError
If detected format is not in PIPELINE_FORMATS
- gedih3.cliutils.list_dataset_files(dataset_path, fmt=None)[source]#
List data files in a simplified dataset directory.
- Parameters:
- dataset_pathstr
Path to the dataset directory
- fmtstr, optional
File format. If None, auto-detected via detect_dataset_format().
- Returns:
- list of str
Sorted list of file paths
- Raises:
- FileNotFoundError
If no matching files found
- gedih3.cliutils.read_dataset_schema(filepath, fmt)[source]#
Read column names and geometry flag from a dataset file without loading data.
- Parameters:
- filepathstr
Path to a single data file
- fmtstr
File format (‘parquet’, ‘feather’, or ‘gpkg’)
- Returns:
- tuple
(column_names: list[str], has_geometry: bool)
- gedih3.cliutils.make_dataset_reader(fmt, columns=None, geo=True)[source]#
Return a callable that reads a single file into a DataFrame or GeoDataFrame.
The returned callable supports column selection at read time.
- Parameters:
- fmtstr
File format (‘parquet’, ‘feather’, or ‘gpkg’)
- columnslist, optional
Columns to load
- geobool
If True, use geopandas readers (for files with geometry metadata). If False, use pandas readers (for files without geometry metadata).
- Returns:
- callable
f(filepath) -> DataFrame or GeoDataFrame
- gedih3.cliutils.add_dask_args(parser, profile=None)[source]#
Add Dask-related arguments to an argument parser.
- Parameters:
- parserargparse.ArgumentParser
The argument parser to add arguments to.
- profilestr, optional
Resource profile hint.
'build'uses fewer workers with more memory (suitable for HDF5→parquet pipelines).Noneuses generic defaults.
- gedih3.cliutils.add_verbosity_args(parser)[source]#
Add verbosity-related arguments to an argument parser.
- gedih3.cliutils.add_storage_args(parser)[source]#
Add remote storage credential arguments to an argument parser.
Covers S3, HTTP/HTTPS, FTP, and SFTP/SSH protocols.
- gedih3.cliutils.setup_storage(args, logger=None)[source]#
Call
configure_storage()from parsed CLI arguments.Should be called early in
main()before any data access.
- gedih3.cliutils.add_product_args(parser, include_detail_level=True)[source]#
Add GEDI product variable arguments to an argument parser.
Supports two mutually exclusive modes: 1. Global:
--detail-level <level>applies a detail level to ALL products. 2. Per-product:-l2a <...> -l4a <...>selects specific products.Per-product flags use
nargs='*'so a bare flag (e.g.-l2a) means “dump everything from L2A”, while-l2a defaultuses the standard variable set.- Parameters:
- parserargparse.ArgumentParser
- include_detail_levelbool
Include
--detail-levelflag (only useful for download/build).
- gedih3.cliutils.parse_egi_levels(value)[source]#
Parse EGI argument in format ‘level’ or ‘level:partition’.
This function is used by CLI tools to parse EGI level arguments that specify both an index/aggregation level and an optional output partition level.
EGI levels: 1 = finest (~1m), 12 = coarsest (~160km) Note: This is opposite to H3 where higher numbers mean finer resolution.
- Examples:
‘1’ -> (1, 12) # Level 1, partition at level 12 (default) ‘1:12’ -> (1, 12) # Explicit level:partition ‘6:10’ -> (6, 10) # Level 6, partition at level 10
- Parameters:
- valuestr or None
EGI level specification string
- Returns:
- tuple or None
(level, partition_level) tuple, or None if value is None
- Raises:
- argparse.ArgumentTypeError
If the value cannot be parsed or levels are invalid
- gedih3.cliutils.setup_logging(args, name=None)[source]#
Configure logging based on verbosity flags and return a logger.
Also configures Dask warning suppression for non-DEBUG modes.
- Args:
args: Parsed arguments with ‘quiet’ and ‘verbose’ attributes name: Logger name (defaults to calling module’s __name__)
- Returns:
Configured logger instance
- gedih3.cliutils.print_banner(title, version=None, logger=None)[source]#
Print a tool banner with centered title.
- Args:
title: Tool title string version: Package version (if None, imports from gedih3) logger: Logger to use (if None, uses print)
- gedih3.cliutils.print_success(message, logger=None)[source]#
Print a success message with banner formatting.
- gedih3.cliutils.resolve_path_args(args, names, logger=None)[source]#
Absolutize each path-bearing CLI arg listed in
nameson the driver.Tools that dispatch work to dask workers (
gh3_extract,gh3_aggregate,gh3_from_img,gh3_from_polygon) pass paths fromargsverbatim intomap_partitions/client.map. Workers then resolve any relative path against their own CWD — which on a remote scheduler is almost never the same as the user’s interactive shell. The result is silent and brutal: workers write to (or read from) the wrong location with no error surfaced until much later (empty output dir / “FileNotFoundError” mid-aggregation). Absolutizing on the driver before dispatch closes the footgun.Skips:
None/ empty, already-absolute paths, and URL-style strings (http://,s3://,/vsicurl/,/vsis3/,gs://,gcs://,/vsigs/). Callers should only pass arg names that are known to be paths — keeps bbox / country-code / query args (region, etc.) untouched.
- gedih3.cliutils.progress_iter(iterable, *, desc, total=None, args=None, unit='it')[source]#
tqdm wrapper with consistent style + safe logger interleaving.
Yields a tqdm-wrapped iterator.
logging_redirect_tqdmis used so thatlogger.info/logger.warningcalls made from inside the loop body do not clobber the bar.- Parameters:
- iterableIterable
The items to iterate over.
- descstr
Description shown to the left of the bar.
- totalint, optional
Total item count. Inferred via
len(iterable)when possible.- argsargparse.Namespace, optional
CLI args; used to read
--quietdefensively viagetattr(args, 'quiet', False). PassNoneto always show.- unitstr
Unit label for the bar (default
'it').
- gedih3.cliutils.cli_exception_handler(args, logger=None)[source]#
Standard exception handling context manager for CLI tools.
Provides consistent error handling across CLI tools: - KeyboardInterrupt: Clean exit with message - Other exceptions: Print error message, optionally show traceback in verbose mode
- Args:
args: Parsed arguments with ‘verbose’ attribute for traceback control logger: Optional logger (not currently used, reserved for future use)
Usage:
with cli_exception_handler(args): # CLI main logic here pass
Example:
def main(): args = get_cmd_args() with cli_exception_handler(args): # Main CLI logic client = Client(**dask_kwargs) ...
- gedih3.cliutils.configure_database_path(args, logger=None)[source]#
Configure database path from args or default.
- Args:
args: Parsed arguments with ‘database’ attribute logger: Optional logger for output
- Returns:
Database path string
- gedih3.cliutils.get_dataset_index_info(database)[source]#
Get spatial index information from a dataset or database.
Reads metadata to determine the index type (h3 or egi) and level.
- Parameters:
- databasestr
Path to H3 database or simplified dataset directory
- Returns:
- dict
Dictionary with keys: - ‘source_type’: ‘h3_database’, ‘simplified_dataset’, or ‘parquet_directory’ - ‘index_type’: ‘h3’ or ‘egi’ (or None if unknown) - ‘index_level’: int (or None if unknown) - ‘partition_level’: int (or None if not applicable) - Other metadata fields from the source
- gedih3.cliutils.load_data_from_source(database, columns=None, region=None, query=None, logger=None)[source]#
Load data from H3 database, simplified dataset, or parquet directory.
Auto-detects the data source type and loads accordingly. Delegates to gh3_load() or egi_load() based on index type.
- Args:
database: Path to database directory columns: Columns to load region: Spatial filter (GeoDataFrame or bbox) query: Query string for filtering logger: Optional logger for output
- Returns:
Dask GeoDataFrame
- gedih3.cliutils.INTERNAL_COLUMN_PATTERNS = ['^h3_\\d{2}$', '^egi\\d{2}$', '^_egi_[xy]$', '^shot_number']#
- gedih3.cliutils.is_internal_column(col_name)[source]#
Check if a column name matches internal/partition column patterns.
Internal columns include H3 partition columns (h3_XX), EGI index columns (egiXX), internal EGI coordinates (_egi_x, _egi_y), and shot identifiers.
- Args:
col_name: Column name to check
- Returns:
True if column is internal, False otherwise
- gedih3.cliutils.filter_data_columns(columns, exclude_geometry=True)[source]#
Filter out internal/partition columns from a column list.
- Args:
columns: List of column names exclude_geometry: If True, also exclude ‘geometry’ column
- Returns:
List of user data columns (excluding internal columns)
- gedih3.cliutils.get_numeric_columns(ddf, exclude_internal=True)[source]#
Get list of numeric columns from a Dask DataFrame.
- Args:
ddf: Dask DataFrame exclude_internal: If True (default), exclude internal/partition columns
- Returns:
List of column names with numeric dtypes
- gedih3.cliutils.get_rasterizable_columns(ddf)[source]#
Get columns suitable for rasterization from a Dask DataFrame.
This is a convenience function that returns numeric columns excluding internal columns (h3_XX, egiXX, etc.) and geometry.
- Args:
ddf: Dask DataFrame
- Returns:
List of column names suitable for rasterization
- gedih3.cliutils.get_aggregatable_columns(df)[source]#
Get numeric columns suitable for aggregation from a DataFrame.
This is a convenience function that returns numeric columns excluding internal/partition columns (h3_XX, egiXX, _egi_x, _egi_y, shot_number, etc.).
- This encapsulates the common pattern:
numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist() filtered_cols = filter_data_columns(numeric_cols)
- Args:
df: DataFrame, GeoDataFrame, or Dask DataFrame
- Returns:
List of column names suitable for aggregation
- gedih3.cliutils.filter_raster_columns(columns, geodf)[source]#
Filter columns suitable for rasterization, excluding internal columns.
Internal columns (egi indices, h3 indices, shot_number) should not be rasterized as bands - they’re metadata, not data values. Also excludes the index column since it will become a column after reset_index().
- Args:
columns: List of column names to filter, or None to auto-detect numeric columns geodf: GeoDataFrame to get numeric columns and index name from
- Returns:
List of filtered column names suitable for rasterization, or None if empty
- gedih3.cliutils.h3_col_name(level)[source]#
Get H3 column name for a given resolution level.
- Args:
level: H3 resolution level (0-15)
- Returns:
Column name string, e.g. ‘h3_06’ for level 6
- gedih3.cliutils.find_coordinate_column(columns, base_name)[source]#
Find a coordinate column by base name, handling product suffixes.
In the H3 database, coordinate columns may have product suffixes (e.g., ‘lon_lowestmode_l2a’ instead of ‘lon_lowestmode’).
- Args:
columns: list-like of available column names base_name: Base column name to search for (e.g., ‘lon_lowestmode’)
- Returns:
Actual column name if found, None otherwise
- Examples:
>>> find_coordinate_column(['lon_lowestmode_l2a', 'lat_lowestmode_l2a'], 'lon_lowestmode') 'lon_lowestmode_l2a' >>> find_coordinate_column(['lon', 'lat'], 'lon') 'lon'
- gedih3.cliutils.parse_aggregation(agg_str)[source]#
Parse aggregation spec from CLI string, JSON file, or text file.
Supports:
Single function: ‘mean’ → ‘mean’
Percentile shorthand: ‘p25’, ‘p50’, ‘p95’ → named percentile callable
List of functions: “[‘mean’, ‘std’, ‘p25’, ‘p75’]” → mixed list
Column-specific dict: “{‘col’:[‘mean’,’p50’]}” → dict with callables
JSON file (.json): parsed as dict or list
Text file: one function name per line → list (single line → string)
Percentile patterns (p25, p90, etc.) are expanded into named callable functions that work with pandas .agg() and produce clean column names like ‘agbd_l4a_percentile_25’.
- gedih3.cliutils.resolve_product_vars(args)[source]#
Resolve product variables from CLI args.
Two modes (mutually exclusive for L2A/L2B/L4A/L4C): 1. Global:
--detail-level <level>applies level to L2A/L2B/L4A/L4C (not L1B). 2. Per-product:-l2a <...> -l4a <...>selects specific products.L1B is always specified separately via
-l1band can be combined with either mode.Per-product flag semantics (with
nargs='*'): - Flag absent →args.l2a = None(product not selected) - Bare flag (-l2a) →args.l2a = [](dump everything) - With keyword:-l2a default→['default']- With vars:-l2a rh agbd→['rh', 'agbd']- Returns:
- dict
Product code → variable list mapping.
- Raises:
- GediValidationError
If
--detail-levelis combined with non-L1B per-product flags.
- gedih3.cliutils.parse_gedi_args(args)[source]#
Parse GEDI product args from CLI (legacy wrapper around resolve_product_vars).
Supports both the new
-lglobal flag and legacy per-product flags. Falls back to legacy parsing whendetail_levelattribute is absent.
- gedih3.cliutils.format_dask_cluster_info(client) str[source]#
One-line summary of a live dask Client’s cluster — workers, total threads, total RAM.
Use after Client(…) is up so that external –dask-scheduler connections report the cluster’s real shape instead of the local-cluster CLI defaults.
- gedih3.cliutils.parse_region(region_str: str | None)[source]#
Parse region argument into GeoDataFrame or bbox
- gedih3.cliutils.collect_columns(args, available_columns=None)[source]#
Collect all requested variables from command line arguments and validate against available columns. Returns: (column_list, product_map)
- gedih3.cliutils.get_product_quality_conditions(selected_products, version, available_columns)[source]#
Return quality filter conditions for the selected products and GEDI version.
- Parameters:
- selected_productslist[str]
Product keys that were requested (e.g. [‘L2A’, ‘L4A’]).
- versionint or None
GEDI data version from build log (e.g. 2 or 3). None defaults to 2.
- available_columnslist[str]
Columns present in the database (suffixed form e.g. ‘quality_flag_l2a’).
- Returns:
- list[tuple[str, str]]
Pairs of (column_name, condition_str) to use in the quality filter query, e.g.
[('quality_flag_l2a', '== 1'), ('degrade_flag_l2a', '== 0')].
- gedih3.cliutils.build_query_string(args, available_columns=None)[source]#
Build pandas query string from arguments
- gedih3.cliutils.safe_query(df, query_str)[source]#
Apply a pandas query, handling column names with ‘/’ that pandas can’t parse.
pandas.DataFrame.query() fails on backtick-quoted names containing ‘/’ because it converts the slash to an unresolvable internal token. This function works around the limitation by temporarily renaming such columns.