"""$ fio cat""" import json import logging import warnings import click import cligj import fiona from fiona.transform import transform_geom from fiona.fio import options, with_context_env warnings.simplefilter('default') # Cat command @click.command(short_help="Concatenate and print the features of datasets") @click.argument('files', nargs=-1, required=True, metavar="INPUTS...") @click.option('--layer', default=None, multiple=True, callback=options.cb_multilayer, help="Input layer(s), specified as 'fileindex:layer` " "For example, '1:foo,2:bar' will concatenate layer foo " "from file 1 and layer bar from file 2") @cligj.precision_opt @cligj.indent_opt @cligj.compact_opt @click.option('--ignore-errors/--no-ignore-errors', default=False, help="log errors but do not stop serialization.") @options.dst_crs_opt @cligj.use_rs_opt @click.option( "--bbox", default=None, metavar="w,s,e,n", help="filter for features intersecting a bounding box", ) @click.option( "--cut-at-antimeridian", is_flag=True, default=False, help="Optionally cut geometries at the anti-meridian. To be used only for a geographic destination CRS.", ) @click.pass_context @with_context_env def cat( ctx, files, precision, indent, compact, ignore_errors, dst_crs, use_rs, bbox, cut_at_antimeridian, layer, ): """ Concatenate and print the features of input datasets as a sequence of GeoJSON features. When working with a multi-layer dataset the first layer is used by default. Use the '--layer' option to select a different layer. """ logger = logging.getLogger(__name__) dump_kwds = {'sort_keys': True} if indent: dump_kwds['indent'] = indent if compact: dump_kwds['separators'] = (',', ':') # Validate file idexes provided in --layer option # (can't pass the files to option callback) if layer: options.validate_multilayer_file_index(files, layer) # first layer is the default for i in range(1, len(files) + 1): if str(i) not in layer.keys(): layer[str(i)] = [0] try: if bbox: try: bbox = tuple(map(float, bbox.split(','))) except ValueError: bbox = json.loads(bbox) for i, path in enumerate(files, 1): for lyr in layer[str(i)]: with fiona.open(path, layer=lyr) as src: for i, feat in src.items(bbox=bbox): if dst_crs or precision >= 0: g = transform_geom( src.crs, dst_crs, feat['geometry'], antimeridian_cutting=cut_at_antimeridian, precision=precision) feat['geometry'] = g feat['bbox'] = fiona.bounds(g) if use_rs: click.echo(u'\u001e', nl=False) click.echo(json.dumps(feat, **dump_kwds)) except Exception: logger.exception("Exception caught during processing") raise click.Abort()