Skip to content

Commit ce1f335

Browse files
authored
Preserve iterator coordinates during location validation (#2299)
* Fix coordinate loss when validating single-pass iterators * Test iterator preservation in location validators
1 parent 4b80e22 commit ce1f335

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

‎folium/utilities.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ def _validate_locations_basics(locations: TypeMultiLine) -> None:
122122
def validate_locations(locations: TypeLine) -> list[list[float]]:
123123
"""Validate an iterable with lat/lon coordinate pairs."""
124124
locations = if_pandas_df_convert_to_numpy(locations)
125+
if isinstance(locations, Iterator):
126+
locations = list(locations)
125127
_validate_locations_basics(locations)
126128
return [validate_location(coord_pair) for coord_pair in locations]
127129

@@ -131,7 +133,12 @@ def validate_multi_locations(
131133
) -> Union[list[list[float]], list[list[list[float]]]]:
132134
"""Validate an iterable with possibly nested lists of coordinate pairs."""
133135
locations = if_pandas_df_convert_to_numpy(locations)
136+
if isinstance(locations, Iterator):
137+
locations = list(locations)
134138
_validate_locations_basics(locations)
139+
# Keep the nesting check below from consuming a point from an inner iterator.
140+
if isinstance(next(iter(locations)), Iterator):
141+
locations = [list(line) for line in locations]
135142
try:
136143
float(next(iter(next(iter(next(iter(locations))))))) # type: ignore
137144
except (TypeError, StopIteration):

‎tests/test_utilities.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ def test_validate_locations(locations):
8080
assert outcome == [[0.0, 5.0], [1.0, 6.0], [2.0, 7.0]]
8181

8282

83+
@pytest.mark.parametrize("validator", [validate_locations, validate_multi_locations])
84+
@pytest.mark.parametrize("count", [1, 3])
85+
@pytest.mark.parametrize("iterator_type", [iter, lambda points: (p for p in points)])
86+
def test_validate_locations_iterators(validator, count, iterator_type):
87+
points = [[i, i + 5] for i in range(count)]
88+
assert validator(iterator_type(points)) == points
89+
90+
91+
@pytest.mark.parametrize("validator", [validate_locations, validate_multi_locations])
92+
def test_validate_locations_empty_iterator(validator):
93+
with pytest.raises(ValueError, match="Locations is empty"):
94+
validator(iter([]))
95+
96+
8397
@pytest.mark.parametrize(
8498
"locations",
8599
[
@@ -91,6 +105,15 @@ def test_validate_multi_locations(locations):
91105
assert outcome == [[[0, 5], [1, 6], [2, 7]], [[3, 8], [4, 9]]]
92106

93107

108+
@pytest.mark.parametrize("outer_iterator", [False, True])
109+
def test_validate_multi_locations_iterators(outer_iterator):
110+
lines = [[[0, 5], [1, 6], [2, 7]], [[3, 8], [4, 9]]]
111+
locations = [iter(line) for line in lines]
112+
if outer_iterator:
113+
locations = iter(locations)
114+
assert validate_multi_locations(locations) == lines
115+
116+
94117
@pytest.mark.parametrize(
95118
"locations",
96119
[

0 commit comments

Comments
 (0)