Skip to content

Commit c6c8568

Browse files
committed
make sure geo_interface takes precedence over iterable, fixes #110
1 parent 37766d3 commit c6c8568

3 files changed

Lines changed: 55 additions & 5 deletions

File tree

src/rasterstats/io.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,15 @@ def fiona_generator(obj):
102102
elif isinstance(obj, bytes):
103103
# Single binary object, probably a wkb
104104
features_iter = [parse_feature(obj)]
105-
elif isinstance(obj, Iterable):
106-
# Iterable of feature-like objects
107-
features_iter = (parse_feature(x) for x in obj)
108105
elif hasattr(obj, '__geo_interface__'):
109106
mapping = obj.__geo_interface__
110107
if mapping['type'] == 'FeatureCollection':
111108
features_iter = mapping['features']
112109
else:
113110
features_iter = [parse_feature(mapping)]
111+
elif isinstance(obj, Iterable):
112+
# Iterable of feature-like objects
113+
features_iter = (parse_feature(x) for x in obj)
114114

115115
if not features_iter:
116116
raise ValueError("Object is not a recognized source of Features")

tests/test_io.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,48 @@ def test_Raster_context():
283283
assert r2.src.closed
284284

285285

286+
def test_geointerface():
287+
class MockGeo(object):
288+
def __init__(self, features):
289+
self.__geo_interface__ = {
290+
'type': "FeatureCollection",
291+
'features': features}
292+
293+
# Make it iterable just to ensure that geo interface
294+
# takes precendence over iterability
295+
def __iter__(self):
296+
pass
297+
298+
def __next__(self):
299+
pass
300+
301+
def next(self):
302+
pass
303+
304+
features = [{
305+
"type": "Feature",
306+
"properties": {},
307+
"geometry": {
308+
"type": "Point",
309+
"coordinates": [0, 0]}
310+
}, {
311+
"type": "Feature",
312+
"properties": {},
313+
"geometry": {
314+
"type": "Polygon",
315+
"coordinates": [[[-50, -10], [-40, 10], [-30, -10], [-50, -10]]]}}]
316+
317+
geothing = MockGeo(features)
318+
assert list(read_features(geothing)) == features
319+
320+
286321
# Optional tests
287322
def test_geodataframe():
288323
try:
289324
import geopandas as gpd
290-
df = gpd.GeoDataFrame.from_file(polygons)
325+
df = gpd.read_file(polygons)
291326
if not hasattr(df, '__geo_interface__'):
292327
pytest.skip("This version of geopandas doesn't support df.__geo_interface__")
293328
except ImportError:
294329
pytest.skip("Can't import geopands")
295-
assert read_features(df)
330+
assert list(read_features(df))

tests/test_zonal.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,18 @@ def test_geojson_out():
404404
assert feature['type'] == 'Feature'
405405
assert 'id' in feature['properties'] # from orig
406406
assert 'count' in feature['properties'] # from zonal stats
407+
408+
# Optional tests
409+
def test_geodataframe_zonal():
410+
polygons = os.path.join(DATA, 'polygons.shp')
411+
412+
try:
413+
import geopandas as gpd
414+
df = gpd.read_file(polygons)
415+
if not hasattr(df, '__geo_interface__'):
416+
pytest.skip("This version of geopandas doesn't support df.__geo_interface__")
417+
except ImportError:
418+
pytest.skip("Can't import geopands")
419+
420+
expected = zonal_stats(polygons, raster)
421+
assert zonal_stats(df, raster) == expected

0 commit comments

Comments
 (0)