Skip to content

Commit

Permalink
Merge pull request #656 from ungarj/fix_655_guess_multipolygon
Browse files Browse the repository at this point in the history
fix error where guess_geometry fails on multipolygons
  • Loading branch information
ungarj authored Nov 4, 2024
2 parents 759b119 + 8c40817 commit 474cc0a
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 14 deletions.
38 changes: 26 additions & 12 deletions mapchete/config/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
from shapely import wkt
from shapely.geometry import Point, shape
from shapely.geometry.base import BaseGeometry
from shapely.ops import unary_union

from mapchete.bounds import Bounds
from mapchete.config.models import ProcessConfig, ZoomParameters
from mapchete.errors import GeometryTypeError
from mapchete.geometry import is_type, reproject_geometry
from mapchete.io.vector import fiona_open
from mapchete.geometry.types import Polygon, MultiPolygon
from mapchete.io.vector.indexed_features import IndexedFeatures
from mapchete.path import MPath
from mapchete.tile import BufferedTilePyramid
from mapchete.types import BoundsLike, MPathLike, ZoomLevelsLike
Expand Down Expand Up @@ -148,8 +148,8 @@ def bounds_from_opts(
reproj = reproject_geometry(
Point(x, y), src_crs=point_crs, dst_crs=tp.crs
)
x = reproj.x
y = reproj.y
x = reproj.x # type: ignore
y = reproj.y # type: ignore
zoom_levels = get_zoom_levels(
process_zoom_levels=raw_conf["zoom_levels"], init_zoom_levels=zoom
)
Expand Down Expand Up @@ -205,14 +205,28 @@ def guess_geometry(
crs = None
# WKT or path:
if isinstance(some_input, (str, MPath)):
if str(some_input).upper().startswith(("POLYGON ", "MULTIPOLYGON ")):
geom = wkt.loads(some_input)
if (
str(some_input)
.upper()
.startswith(
(
"POINT ",
"MULTIPOINT ",
"LINESTRING ",
"MULTILINESTRING ",
"POLYGON ",
"MULTIPOLYGON ",
"GEOMETRYCOLLECTION ",
)
)
):
geom = wkt.loads(str(some_input))
else:
path = MPath.from_inp(some_input)
with path.fio_env():
with fiona_open(str(path.absolute_path(base_dir))) as src:
geom = unary_union([shape(f["geometry"]) for f in src])
crs = src.crs
features = IndexedFeatures.from_file(
MPath.from_inp(some_input).absolute_path(base_dir)
)
geom = features.read_union_geometry()
crs = features.crs
# GeoJSON mapping
elif isinstance(some_input, dict):
geom = shape(some_input)
Expand All @@ -226,7 +240,7 @@ def guess_geometry(
)
if not geom.is_valid: # pragma: no cover
raise TypeError("area is not a valid geometry")
if not is_type(geom, "Polygon", singlepart_equivalent_matches=True):
if not is_type(geom, target_type=(Polygon, MultiPolygon)):
raise GeometryTypeError(
f"area must either be a Polygon or a MultiPolygon, not {geom.geom_type}"
)
Expand Down
2 changes: 1 addition & 1 deletion mapchete/geometry/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def omit_empty_geometries(geometry: Geometry) -> Generator[Geometry, None, None]

def is_type(
geometry: Geometry,
target_type: Union[GeometryTypeLike, Tuple[GeometryTypeLike]],
target_type: Union[GeometryTypeLike, Tuple[GeometryTypeLike, ...]],
singlepart_equivalent_matches: bool = True,
multipart_equivalent_matches: bool = True,
) -> bool:
Expand Down
28 changes: 27 additions & 1 deletion test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from mapchete.config.models import DaskAdaptOptions, DaskSpecs
from mapchete.config.parse import bounds_from_opts, guess_geometry
from mapchete.config.process_func import ProcessFunc
from mapchete.errors import MapcheteConfigError
from mapchete.errors import GeometryTypeError, MapcheteConfigError
from mapchete.io import fiona_open, rasterio_open
from mapchete.path import MPath
from mapchete.bounds import Bounds
Expand Down Expand Up @@ -412,6 +412,32 @@ def test_guess_geometry(aoi_br_geojson):
guess_geometry(area.centroid)


@pytest.mark.parametrize(
"geometry",
[
lazy_fixture("polygon"),
lazy_fixture("multipolygon"),
],
)
def test_guess_geometry_types(geometry):
assert guess_geometry(geometry.wkt)[0].is_valid


@pytest.mark.parametrize(
"geometry",
[
lazy_fixture("point"),
lazy_fixture("multipoint"),
lazy_fixture("linestring"),
lazy_fixture("multilinestring"),
lazy_fixture("geometrycollection"),
],
)
def test_guess_geometry_types_errors(geometry):
with pytest.raises(GeometryTypeError):
guess_geometry(geometry.wkt)


def test_bounds_from_opts_wkt(wkt_geom):
# WKT
assert isinstance(bounds_from_opts(wkt_geometry=wkt_geom), Bounds)
Expand Down

6 comments on commit 474cc0a

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

missing coverage
FileStmtsMissCoverMissing
__init__.py330100% 
_deprecated.py180100% 
bounds.py980100% 
enums.py310100% 
errors.py170100% 
grid.py350100% 
index.py1790100% 
log.py500100% 
path.py3850100% 
pretty.py160100% 
protocols.py140100% 
registered.py50100% 
settings.py320100% 
stac.py1470100% 
testing.py1010100% 
tile.py1970100% 
timer.py370100% 
types.py390100% 
validate.py650100% 
zoom_levels.py980100% 
cli
   __init__.py00100% 
   main.py90100% 
   mpath.py820100% 
   options.py1280100% 
   progress_bar.py370100% 
cli/default
   __init__.py00100% 
   convert.py630100% 
   cp.py330100% 
   create.py360100% 
   execute.py420100% 
   formats.py190100% 
   index.py420100% 
   processes.py180100% 
   rm.py250100% 
   serve.py690100% 
   stac.py600100% 
commands
   __init__.py60100% 
   convert.py780100% 
   cp.py650100% 
   execute.py700100% 
   index.py340100% 
   observer.py90100% 
   parser.py910100% 
   rm.py440100% 
config
   __init__.py40100% 
   base.py3570100% 
   models.py1800100% 
   parse.py760100% 
   process_func.py890100% 
executor
   __init__.py170100% 
   base.py770100% 
   concurrent_futures.py700100% 
   dask.py1050100% 
   future.py820100% 
   sequential.py330100% 
   types.py130100% 
formats
   __init__.py30100% 
   base.py1740100% 
   drivers.py00100% 
   loaders.py430100% 
   protocols.py130100% 
   tools.py1530100% 
formats/default
   __init__.py00100% 
   _fiona_base.py510100% 
   flatgeobuf.py140100% 
   geojson.py120100% 
   gtiff.py1950100% 
   mapchete_input.py160100% 
   png.py660100% 
   png_hillshade.py560100% 
   raster_file.py850100% 
   tile_directory.py1010100% 
   vector_file.py1170100% 
geometry
   __init__.py100100% 
   clip.py410100% 
   filter.py350100% 
   footprints.py390100% 
   latlon.py300100% 
   repair.py120100% 
   reproject.py660100% 
   segmentize.py230100% 
   shape.py120100% 
   transform.py280100% 
   types.py240100% 
io
   __init__.py70100% 
   _json.py60100% 
   _misc.py780100% 
   _path.py00100% 
   profiles.py60100% 
io/raster
   __init__.py80100% 
   array.py1050100% 
   convert.py230100% 
   mosaic.py1030100% 
   open.py140100% 
   read.py1680100% 
   referenced_raster.py970100% 
   write.py1000100% 
io/vector
   __init__.py90100% 
   convert.py260100% 
   indexed_features.py1810100% 
   open.py150100% 
   read.py740100% 
   types.py80100% 
   write.py980100% 
processes
   __init__.py170100% 
   clip.py160100% 
   contours.py520100% 
   convert.py380100% 
   hillshade.py490100% 
processes/examples
   __init__.py00100% 
   example_process.py60100% 
processing
   __init__.py30100% 
   base.py2710100% 
   execute.py710100% 
   mp.py260100% 
   tasks.py2910100% 
   types.py450100% 
processing/profilers
   __init__.py50100% 
   memory.py600100% 
   requests.py250100% 
   time.py220100% 
static
   __init__.py00100% 
   process_template.py10100% 
TOTAL73030100% 

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

missing coverage
FileStmtsMissCoverMissing
__init__.py330100% 
_deprecated.py180100% 
bounds.py980100% 
enums.py310100% 
errors.py170100% 
grid.py350100% 
index.py1790100% 
log.py500100% 
path.py3850100% 
pretty.py160100% 
protocols.py140100% 
registered.py50100% 
settings.py320100% 
stac.py1470100% 
testing.py1010100% 
tile.py1970100% 
timer.py370100% 
types.py390100% 
validate.py650100% 
zoom_levels.py980100% 
cli
   __init__.py00100% 
   main.py90100% 
   mpath.py820100% 
   options.py1280100% 
   progress_bar.py370100% 
cli/default
   __init__.py00100% 
   convert.py630100% 
   cp.py330100% 
   create.py360100% 
   execute.py420100% 
   formats.py190100% 
   index.py420100% 
   processes.py180100% 
   rm.py250100% 
   serve.py690100% 
   stac.py600100% 
commands
   __init__.py60100% 
   convert.py780100% 
   cp.py650100% 
   execute.py700100% 
   index.py340100% 
   observer.py90100% 
   parser.py910100% 
   rm.py440100% 
config
   __init__.py40100% 
   base.py3570100% 
   models.py1800100% 
   parse.py760100% 
   process_func.py890100% 
executor
   __init__.py170100% 
   base.py770100% 
   concurrent_futures.py700100% 
   dask.py1050100% 
   future.py820100% 
   sequential.py330100% 
   types.py130100% 
formats
   __init__.py30100% 
   base.py1740100% 
   drivers.py00100% 
   loaders.py430100% 
   protocols.py130100% 
   tools.py1530100% 
formats/default
   __init__.py00100% 
   _fiona_base.py510100% 
   flatgeobuf.py140100% 
   geojson.py120100% 
   gtiff.py1950100% 
   mapchete_input.py160100% 
   png.py660100% 
   png_hillshade.py560100% 
   raster_file.py850100% 
   tile_directory.py1010100% 
   vector_file.py1170100% 
geometry
   __init__.py100100% 
   clip.py410100% 
   filter.py350100% 
   footprints.py390100% 
   latlon.py300100% 
   repair.py120100% 
   reproject.py660100% 
   segmentize.py230100% 
   shape.py120100% 
   transform.py280100% 
   types.py240100% 
io
   __init__.py70100% 
   _json.py60100% 
   _misc.py780100% 
   _path.py00100% 
   profiles.py60100% 
io/raster
   __init__.py80100% 
   array.py1050100% 
   convert.py230100% 
   mosaic.py1030100% 
   open.py140100% 
   read.py1680100% 
   referenced_raster.py970100% 
   write.py1000100% 
io/vector
   __init__.py90100% 
   convert.py260100% 
   indexed_features.py1810100% 
   open.py150100% 
   read.py740100% 
   types.py80100% 
   write.py980100% 
processes
   __init__.py170100% 
   clip.py160100% 
   contours.py520100% 
   convert.py380100% 
   hillshade.py490100% 
processes/examples
   __init__.py00100% 
   example_process.py60100% 
processing
   __init__.py30100% 
   base.py2710100% 
   execute.py710100% 
   mp.py260100% 
   tasks.py2910100% 
   types.py450100% 
processing/profilers
   __init__.py50100% 
   memory.py600100% 
   requests.py250100% 
   time.py220100% 
static
   __init__.py00100% 
   process_template.py10100% 
TOTAL73030100% 

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

missing coverage
FileStmtsMissCoverMissing
__init__.py330100% 
_deprecated.py180100% 
bounds.py980100% 
enums.py310100% 
errors.py170100% 
grid.py350100% 
index.py1790100% 
log.py500100% 
path.py3850100% 
pretty.py160100% 
protocols.py140100% 
registered.py50100% 
settings.py320100% 
stac.py1470100% 
testing.py1010100% 
tile.py1970100% 
timer.py370100% 
types.py390100% 
validate.py650100% 
zoom_levels.py980100% 
cli
   __init__.py00100% 
   main.py90100% 
   mpath.py820100% 
   options.py1280100% 
   progress_bar.py370100% 
cli/default
   __init__.py00100% 
   convert.py630100% 
   cp.py330100% 
   create.py360100% 
   execute.py420100% 
   formats.py190100% 
   index.py420100% 
   processes.py180100% 
   rm.py250100% 
   serve.py690100% 
   stac.py600100% 
commands
   __init__.py60100% 
   convert.py780100% 
   cp.py650100% 
   execute.py700100% 
   index.py340100% 
   observer.py90100% 
   parser.py910100% 
   rm.py440100% 
config
   __init__.py40100% 
   base.py3570100% 
   models.py1800100% 
   parse.py760100% 
   process_func.py890100% 
executor
   __init__.py170100% 
   base.py770100% 
   concurrent_futures.py700100% 
   dask.py1050100% 
   future.py820100% 
   sequential.py330100% 
   types.py130100% 
formats
   __init__.py30100% 
   base.py1740100% 
   drivers.py00100% 
   loaders.py430100% 
   protocols.py130100% 
   tools.py1530100% 
formats/default
   __init__.py00100% 
   _fiona_base.py510100% 
   flatgeobuf.py140100% 
   geojson.py120100% 
   gtiff.py1950100% 
   mapchete_input.py160100% 
   png.py660100% 
   png_hillshade.py560100% 
   raster_file.py850100% 
   tile_directory.py1010100% 
   vector_file.py1170100% 
geometry
   __init__.py100100% 
   clip.py410100% 
   filter.py350100% 
   footprints.py390100% 
   latlon.py300100% 
   repair.py120100% 
   reproject.py660100% 
   segmentize.py230100% 
   shape.py120100% 
   transform.py280100% 
   types.py240100% 
io
   __init__.py70100% 
   _json.py60100% 
   _misc.py780100% 
   _path.py00100% 
   profiles.py60100% 
io/raster
   __init__.py80100% 
   array.py1050100% 
   convert.py230100% 
   mosaic.py1030100% 
   open.py140100% 
   read.py1680100% 
   referenced_raster.py970100% 
   write.py1000100% 
io/vector
   __init__.py90100% 
   convert.py260100% 
   indexed_features.py1810100% 
   open.py150100% 
   read.py740100% 
   types.py80100% 
   write.py980100% 
processes
   __init__.py170100% 
   clip.py160100% 
   contours.py520100% 
   convert.py380100% 
   hillshade.py490100% 
processes/examples
   __init__.py00100% 
   example_process.py60100% 
processing
   __init__.py30100% 
   base.py2710100% 
   execute.py710100% 
   mp.py260100% 
   tasks.py2910100% 
   types.py450100% 
processing/profilers
   __init__.py50100% 
   memory.py600100% 
   requests.py250100% 
   time.py220100% 
static
   __init__.py00100% 
   process_template.py10100% 
TOTAL73030100% 

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

missing coverage
FileStmtsMissCoverMissing
__init__.py330100% 
_deprecated.py180100% 
bounds.py980100% 
enums.py310100% 
errors.py170100% 
grid.py350100% 
index.py1790100% 
log.py500100% 
path.py3850100% 
pretty.py160100% 
protocols.py140100% 
registered.py50100% 
settings.py320100% 
stac.py1470100% 
testing.py1010100% 
tile.py1970100% 
timer.py370100% 
types.py390100% 
validate.py650100% 
zoom_levels.py980100% 
cli
   __init__.py00100% 
   main.py90100% 
   mpath.py820100% 
   options.py1280100% 
   progress_bar.py370100% 
cli/default
   __init__.py00100% 
   convert.py630100% 
   cp.py330100% 
   create.py360100% 
   execute.py420100% 
   formats.py190100% 
   index.py420100% 
   processes.py180100% 
   rm.py250100% 
   serve.py690100% 
   stac.py600100% 
commands
   __init__.py60100% 
   convert.py780100% 
   cp.py650100% 
   execute.py700100% 
   index.py340100% 
   observer.py90100% 
   parser.py910100% 
   rm.py440100% 
config
   __init__.py40100% 
   base.py3570100% 
   models.py1800100% 
   parse.py760100% 
   process_func.py890100% 
executor
   __init__.py170100% 
   base.py770100% 
   concurrent_futures.py700100% 
   dask.py1050100% 
   future.py820100% 
   sequential.py330100% 
   types.py130100% 
formats
   __init__.py30100% 
   base.py1740100% 
   drivers.py00100% 
   loaders.py430100% 
   protocols.py130100% 
   tools.py1530100% 
formats/default
   __init__.py00100% 
   _fiona_base.py510100% 
   flatgeobuf.py140100% 
   geojson.py120100% 
   gtiff.py1950100% 
   mapchete_input.py160100% 
   png.py660100% 
   png_hillshade.py560100% 
   raster_file.py850100% 
   tile_directory.py1010100% 
   vector_file.py1170100% 
geometry
   __init__.py100100% 
   clip.py410100% 
   filter.py350100% 
   footprints.py390100% 
   latlon.py300100% 
   repair.py120100% 
   reproject.py660100% 
   segmentize.py230100% 
   shape.py120100% 
   transform.py280100% 
   types.py240100% 
io
   __init__.py70100% 
   _json.py60100% 
   _misc.py780100% 
   _path.py00100% 
   profiles.py60100% 
io/raster
   __init__.py80100% 
   array.py1050100% 
   convert.py230100% 
   mosaic.py1030100% 
   open.py140100% 
   read.py1680100% 
   referenced_raster.py970100% 
   write.py1000100% 
io/vector
   __init__.py90100% 
   convert.py260100% 
   indexed_features.py1810100% 
   open.py150100% 
   read.py740100% 
   types.py80100% 
   write.py980100% 
processes
   __init__.py170100% 
   clip.py160100% 
   contours.py520100% 
   convert.py380100% 
   hillshade.py490100% 
processes/examples
   __init__.py00100% 
   example_process.py60100% 
processing
   __init__.py30100% 
   base.py2710100% 
   execute.py710100% 
   mp.py260100% 
   tasks.py2910100% 
   types.py450100% 
processing/profilers
   __init__.py50100% 
   memory.py600100% 
   requests.py250100% 
   time.py220100% 
static
   __init__.py00100% 
   process_template.py10100% 
TOTAL73030100% 

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

missing coverage
FileStmtsMissCoverMissing
__init__.py330100% 
_deprecated.py180100% 
bounds.py980100% 
enums.py310100% 
errors.py170100% 
grid.py350100% 
index.py1790100% 
log.py500100% 
path.py3850100% 
pretty.py160100% 
protocols.py140100% 
registered.py50100% 
settings.py320100% 
stac.py1470100% 
testing.py1010100% 
tile.py1970100% 
timer.py370100% 
types.py390100% 
validate.py650100% 
zoom_levels.py980100% 
cli
   __init__.py00100% 
   main.py90100% 
   mpath.py820100% 
   options.py1280100% 
   progress_bar.py370100% 
cli/default
   __init__.py00100% 
   convert.py630100% 
   cp.py330100% 
   create.py360100% 
   execute.py420100% 
   formats.py190100% 
   index.py420100% 
   processes.py180100% 
   rm.py250100% 
   serve.py690100% 
   stac.py600100% 
commands
   __init__.py60100% 
   convert.py780100% 
   cp.py650100% 
   execute.py700100% 
   index.py340100% 
   observer.py90100% 
   parser.py910100% 
   rm.py440100% 
config
   __init__.py40100% 
   base.py3570100% 
   models.py1800100% 
   parse.py760100% 
   process_func.py890100% 
executor
   __init__.py170100% 
   base.py770100% 
   concurrent_futures.py700100% 
   dask.py1050100% 
   future.py820100% 
   sequential.py330100% 
   types.py130100% 
formats
   __init__.py30100% 
   base.py1740100% 
   drivers.py00100% 
   loaders.py430100% 
   protocols.py130100% 
   tools.py1530100% 
formats/default
   __init__.py00100% 
   _fiona_base.py510100% 
   flatgeobuf.py140100% 
   geojson.py120100% 
   gtiff.py1950100% 
   mapchete_input.py160100% 
   png.py660100% 
   png_hillshade.py560100% 
   raster_file.py850100% 
   tile_directory.py1010100% 
   vector_file.py1170100% 
geometry
   __init__.py100100% 
   clip.py410100% 
   filter.py350100% 
   footprints.py390100% 
   latlon.py300100% 
   repair.py120100% 
   reproject.py660100% 
   segmentize.py230100% 
   shape.py120100% 
   transform.py280100% 
   types.py240100% 
io
   __init__.py70100% 
   _json.py60100% 
   _misc.py780100% 
   _path.py00100% 
   profiles.py60100% 
io/raster
   __init__.py80100% 
   array.py1050100% 
   convert.py230100% 
   mosaic.py1030100% 
   open.py140100% 
   read.py1680100% 
   referenced_raster.py970100% 
   write.py1000100% 
io/vector
   __init__.py90100% 
   convert.py260100% 
   indexed_features.py1810100% 
   open.py150100% 
   read.py740100% 
   types.py80100% 
   write.py980100% 
processes
   __init__.py170100% 
   clip.py160100% 
   contours.py520100% 
   convert.py380100% 
   hillshade.py490100% 
processes/examples
   __init__.py00100% 
   example_process.py60100% 
processing
   __init__.py30100% 
   base.py2710100% 
   execute.py710100% 
   mp.py260100% 
   tasks.py2910100% 
   types.py450100% 
processing/profilers
   __init__.py50100% 
   memory.py600100% 
   requests.py250100% 
   time.py220100% 
static
   __init__.py00100% 
   process_template.py10100% 
TOTAL73030100% 

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

missing coverage
FileStmtsMissCoverMissing
__init__.py330100% 
_deprecated.py180100% 
bounds.py980100% 
enums.py310100% 
errors.py170100% 
grid.py350100% 
index.py1790100% 
log.py500100% 
path.py3850100% 
pretty.py160100% 
protocols.py140100% 
registered.py50100% 
settings.py320100% 
stac.py1470100% 
testing.py1010100% 
tile.py1970100% 
timer.py370100% 
types.py390100% 
validate.py650100% 
zoom_levels.py980100% 
cli
   __init__.py00100% 
   main.py90100% 
   mpath.py820100% 
   options.py1280100% 
   progress_bar.py370100% 
cli/default
   __init__.py00100% 
   convert.py630100% 
   cp.py330100% 
   create.py360100% 
   execute.py420100% 
   formats.py190100% 
   index.py420100% 
   processes.py180100% 
   rm.py250100% 
   serve.py690100% 
   stac.py600100% 
commands
   __init__.py60100% 
   convert.py780100% 
   cp.py650100% 
   execute.py700100% 
   index.py340100% 
   observer.py90100% 
   parser.py910100% 
   rm.py440100% 
config
   __init__.py40100% 
   base.py3570100% 
   models.py1800100% 
   parse.py760100% 
   process_func.py890100% 
executor
   __init__.py170100% 
   base.py770100% 
   concurrent_futures.py700100% 
   dask.py1050100% 
   future.py820100% 
   sequential.py330100% 
   types.py130100% 
formats
   __init__.py30100% 
   base.py1740100% 
   drivers.py00100% 
   loaders.py430100% 
   protocols.py130100% 
   tools.py1530100% 
formats/default
   __init__.py00100% 
   _fiona_base.py510100% 
   flatgeobuf.py140100% 
   geojson.py120100% 
   gtiff.py1950100% 
   mapchete_input.py160100% 
   png.py660100% 
   png_hillshade.py560100% 
   raster_file.py850100% 
   tile_directory.py1010100% 
   vector_file.py1170100% 
geometry
   __init__.py100100% 
   clip.py410100% 
   filter.py350100% 
   footprints.py390100% 
   latlon.py300100% 
   repair.py120100% 
   reproject.py660100% 
   segmentize.py230100% 
   shape.py120100% 
   transform.py280100% 
   types.py240100% 
io
   __init__.py70100% 
   _json.py60100% 
   _misc.py780100% 
   _path.py00100% 
   profiles.py60100% 
io/raster
   __init__.py80100% 
   array.py1050100% 
   convert.py230100% 
   mosaic.py1030100% 
   open.py140100% 
   read.py1680100% 
   referenced_raster.py970100% 
   write.py1000100% 
io/vector
   __init__.py90100% 
   convert.py260100% 
   indexed_features.py1810100% 
   open.py150100% 
   read.py740100% 
   types.py80100% 
   write.py980100% 
processes
   __init__.py170100% 
   clip.py160100% 
   contours.py520100% 
   convert.py380100% 
   hillshade.py490100% 
processes/examples
   __init__.py00100% 
   example_process.py60100% 
processing
   __init__.py30100% 
   base.py2710100% 
   execute.py710100% 
   mp.py260100% 
   tasks.py2910100% 
   types.py450100% 
processing/profilers
   __init__.py50100% 
   memory.py600100% 
   requests.py250100% 
   time.py220100% 
static
   __init__.py00100% 
   process_template.py10100% 
TOTAL73030100% 

Please sign in to comment.