From e4160647c344d48b4b1d10279484515aae6eacfa Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Tue, 23 Nov 2021 13:08:50 -0800 Subject: [PATCH] fix(geospatial_utils.py): added pyshp and shapely imports check to geospatial_utils.py * reorganized code order to enforce import checks --- flopy/utils/geospatial_utils.py | 137 +++++++++++++++++--------------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/flopy/utils/geospatial_utils.py b/flopy/utils/geospatial_utils.py index 9c34ecf4fc..afd279791c 100644 --- a/flopy/utils/geospatial_utils.py +++ b/flopy/utils/geospatial_utils.py @@ -3,17 +3,6 @@ from ..utils.geometry import Shape, Collection from ..utils import import_optional_dependency -shapely = import_optional_dependency("shapely", errors="silent") -if shapely is not None: - from shapely.geometry import ( - MultiPolygon, - Polygon, - Point, - MultiPoint, - LineString, - MultiLineString, - ) - geojson = import_optional_dependency("geojson", errors="silent") geojson_classes = {} if geojson is not None: @@ -72,10 +61,7 @@ def __init__(self, obj, shapetype=None): if shapetype is not None: shapetype = shapetype.lower() - if isinstance(obj, self.__shapefile.Shape): - self.__geo_interface = self.__obj.__geo_interface__ - - elif isinstance(obj, (Shape, Collection)): + if isinstance(obj, (Shape, Collection)): geo_interface = obj.__geo_interface__ if geo_interface["type"] == "GeometryCollection": raise TypeError("GeometryCollections are not supported") @@ -94,6 +80,10 @@ def __init__(self, obj, shapetype=None): "coordinates": list(obj), } + if self.__shapefile is not None: + if isinstance(obj, self.__shapefile.Shape): + self.__geo_interface = self.__obj.__geo_interface__ + if geojson is not None: if isinstance(obj, geojson.Feature): self.__geo_interface = { @@ -118,18 +108,24 @@ def __init__(self, obj, shapetype=None): } shapely_geo = import_optional_dependency("shapely.geometry") - if isinstance( - obj, - ( - shapely_geo.Point, - shapely_geo.MultiPoint, - shapely_geo.Polygon, - shapely_geo.MultiPolygon, - shapely_geo.LineString, - shapely_geo.MultiLineString, - ), - ): - self.__geo_interface = obj.__geo_interface__ + if shapely_geo is not None: + if isinstance( + obj, + ( + shapely_geo.Point, + shapely_geo.MultiPoint, + shapely_geo.Polygon, + shapely_geo.MultiPolygon, + shapely_geo.LineString, + shapely_geo.MultiLineString, + ), + ): + self.__geo_interface = obj.__geo_interface__ + + if not self.__geo_interface: + raise AssertionError( + f"Reader is not installed for collection type: {type(obj)}" + ) @property def __geo_interface__(self): @@ -204,11 +200,12 @@ def shape(self): ------- shapefile.shape """ - if self._shape is None: - self._shape = self.__shapefile.Shape._from_geojson( - self.__geo_interface - ) - return self._shape + if self.__shapefile is not None: + if self._shape is None: + self._shape = self.__shapefile.Shape._from_geojson( + self.__geo_interface + ) + return self._shape @property def flopy_geometry(self): @@ -265,29 +262,21 @@ def __init__(self, obj, shapetype=None): self._points = None self.__shapetype = None - if isinstance(obj, str): - with self.__shapefile.Reader(obj) as r: - for shape in r.shapes(): - self.__collection.append(GeoSpatialUtil(shape)) - - elif isinstance(obj, self.__shapefile.Reader): - for shape in obj.shapes(): - self.__collection.append(GeoSpatialUtil(shape)) - - elif isinstance(obj, self.__shapefile.Shapes): - for shape in obj: - self.__collection.append(GeoSpatialUtil(shape)) - - elif isinstance(obj, Collection): + if isinstance(obj, Collection): for shape in obj: self.__collection.append(GeoSpatialUtil(shape)) elif isinstance(obj, (np.ndarray, list, tuple)): - if isinstance(obj[0], (Shape, Collection, self.__shapefile.Shape)): + if isinstance(obj[0], (Shape, Collection)): for shape in obj: self.__collection.append(GeoSpatialUtil(shape)) - else: + elif self.__shapefile is not None: + if isinstance(obj[0], self.__shapefile.Shape): + for shape in obj: + self.__collection.append(GeoSpatialUtil(shape)) + + if not self.__collection: if shapetype is None: err = "a list of shapetypes must be provided" raise AssertionError(err) @@ -300,6 +289,20 @@ def __init__(self, obj, shapetype=None): GeoSpatialUtil(geom, shapetype[ix]) ) + elif self.__shapefile is not None: + if isinstance(obj, str): + with self.__shapefile.Reader(obj) as r: + for shape in r.shapes(): + self.__collection.append(GeoSpatialUtil(shape)) + + elif isinstance(obj, self.__shapefile.Reader): + for shape in obj.shapes(): + self.__collection.append(GeoSpatialUtil(shape)) + + elif isinstance(obj, self.__shapefile.Shapes): + for shape in obj: + self.__collection.append(GeoSpatialUtil(shape)) + if geojson is not None: if isinstance( obj, @@ -314,18 +317,24 @@ def __init__(self, obj, shapetype=None): for geom in obj.geometries: self.__collection.append(GeoSpatialUtil(geom)) - shapely_loc = import_optional_dependency("shapely.geometry") - if isinstance( - obj, - ( - shapely_loc.collection.GeometryCollection, - shapely_loc.MultiPoint, - shapely_loc.MultiLineString, - shapely_loc.MultiPolygon, - ), - ): - for geom in obj.geoms: - self.__collection.append(GeoSpatialUtil(geom)) + shapely_geo = import_optional_dependency("shapely.geometry") + if shapely_geo is not None: + if isinstance( + obj, + ( + shapely_geo.collection.GeometryCollection, + shapely_geo.MultiPoint, + shapely_geo.MultiLineString, + shapely_geo.MultiPolygon, + ), + ): + for geom in obj.geoms: + self.__collection.append(GeoSpatialUtil(geom)) + + if not self.__collection: + raise AssertionError( + f"Reader is not installed for collection type: {type(obj)}" + ) def __iter__(self): """ @@ -374,8 +383,8 @@ def shapely(self): ------- shapely.geometry.collection.GeometryCollection object """ - shapely_loc = import_optional_dependency("shapely.geometry") - self._shapely = shapely_loc.collection.GeometryCollection( + shapely_geo = import_optional_dependency("shapely.geometry") + self._shapely = shapely_geo.collection.GeometryCollection( [i.shapely for i in self.__collection] ) return self._shapely @@ -389,8 +398,8 @@ def geojson(self): ------- geojson.GeometryCollection """ - geojson_loc = import_optional_dependency("geojson") - self._geojson = geojson_loc.GeometryCollection( + geojson = import_optional_dependency("geojson") + self._geojson = geojson.GeometryCollection( [i.geojson for i in self.__collection] ) return self._geojson