44
55from openeo .extra .job_management ._job_splitting import (
66 JobSplittingFailure ,
7- PredefinedTileGrid ,
8- SizeBasedTileGrid ,
9- TileGridInterface ,
7+ _PredefinedTileGrid ,
8+ _SizeBasedTileGrid ,
9+ _TileGridInterface ,
1010 split_area ,
1111)
1212from openeo .util import BBoxDict
1313
1414
1515class TestSizeBasedTileGrid :
1616 def test_from_size_projection (self ):
17- splitter = SizeBasedTileGrid .from_size_projection (size = 0.1 , projection = "EPSG:4326" )
17+ splitter = _SizeBasedTileGrid .from_size_projection (size = 0.1 , projection = "EPSG:4326" )
1818 assert splitter .crs == 4326
1919 assert splitter .size == 0.1
2020
2121 def test_constructor_rejects_unparseable_epsg (self ):
2222 """An invalid CRS string should be caught and raised as JobSplittingFailure."""
2323 with pytest .raises (JobSplittingFailure , match = "Failed to normalize EPSG code" ):
24- SizeBasedTileGrid (epsg = "not_a_crs" , size = 1.0 )
24+ _SizeBasedTileGrid (epsg = "not_a_crs" , size = 1.0 )
2525
2626 def test_constructor_rejects_unknown_epsg (self ):
2727 """An EPSG code unknown to pyproj is caught at construction time."""
2828 with pytest .raises (JobSplittingFailure , match = "Failed to normalize EPSG code" ):
29- SizeBasedTileGrid (epsg = 999999 , size = 1.0 )
29+ _SizeBasedTileGrid (epsg = 999999 , size = 1.0 )
3030
3131 def test_get_tiles_raises_exception (self ):
3232 """test get_tiles when the input geometry is not a dict or shapely.geometry.Polygon"""
33- tile_grid = SizeBasedTileGrid (epsg = 4326 , size = 0.1 )
33+ tile_grid = _SizeBasedTileGrid (epsg = 4326 , size = 0.1 )
3434 with pytest .raises (JobSplittingFailure ):
3535 tile_grid .get_tiles ("invalid_geometry" )
3636
3737 def test_get_tiles_returns_geodataframe (self ):
3838 aoi = {"west" : 0.0 , "south" : 0.0 , "east" : 1.0 , "north" : 1.0 , "crs" : "EPSG:4326" }
39- tile_grid = SizeBasedTileGrid (epsg = 4326 , size = 1.0 )
39+ tile_grid = _SizeBasedTileGrid (epsg = 4326 , size = 1.0 )
4040 result = tile_grid .get_tiles (aoi )
4141 assert isinstance (result , gpd .GeoDataFrame )
4242 assert result .crs is not None
@@ -45,55 +45,55 @@ def test_get_tiles_returns_geodataframe(self):
4545 def test_simple_get_tiles_dict (self ):
4646 """tile grid size equals input geometry size -> single tile returned."""
4747 aoi = {"west" : 0.0 , "south" : 0.0 , "east" : 100_000.0 , "north" : 100_000.0 , "crs" : "EPSG:3857" }
48- tile_grid = SizeBasedTileGrid (epsg = 3857 , size = 100_000 )
48+ tile_grid = _SizeBasedTileGrid (epsg = 3857 , size = 100_000 )
4949 result = tile_grid .get_tiles (aoi )
5050 assert len (result ) == 1
5151 assert result .geometry [0 ].equals (shapely .geometry .box (0.0 , 0.0 , 100_000.0 , 100_000.0 ))
5252
5353 def test_multiple_get_tile_dict (self ):
5454 """tile grid smaller than input -> multiple tiles."""
5555 aoi = {"west" : 0.0 , "south" : 0.0 , "east" : 100_000.0 , "north" : 100_000.0 , "crs" : "EPSG:3857" }
56- tile_grid = SizeBasedTileGrid (epsg = 3857 , size = 20_000 )
56+ tile_grid = _SizeBasedTileGrid (epsg = 3857 , size = 20_000 )
5757 result = tile_grid .get_tiles (aoi )
5858 assert len (result ) == 25
5959 assert result .geometry [0 ].equals (shapely .geometry .box (0.0 , 0.0 , 20_000.0 , 20_000.0 ))
6060
6161 def test_larger_get_tile_dict (self ):
6262 """tile grid larger than input -> single tile clipped to input."""
6363 aoi = {"west" : 0.0 , "south" : 0.0 , "east" : 100_000.0 , "north" : 100_000.0 , "crs" : "EPSG:3857" }
64- tile_grid = SizeBasedTileGrid (epsg = 3857 , size = 200_000 )
64+ tile_grid = _SizeBasedTileGrid (epsg = 3857 , size = 200_000 )
6565 result = tile_grid .get_tiles (aoi )
6666 assert len (result ) == 1
6767 assert result .geometry [0 ].equals (shapely .geometry .box (0.0 , 0.0 , 100_000.0 , 100_000.0 ))
6868
6969 def test_get_tiles_polygon_wgs (self ):
7070 """polygon in WGS84 with WGS84 tile grid."""
7171 polygon = shapely .geometry .box (0.0 , 0.0 , 1.0 , 1.0 )
72- tile_grid = SizeBasedTileGrid (epsg = 4326 , size = 0.1 )
72+ tile_grid = _SizeBasedTileGrid (epsg = 4326 , size = 0.1 )
7373 result = tile_grid .get_tiles (polygon )
7474 assert len (result ) == 100
7575 assert result .geometry [0 ].equals (shapely .geometry .box (0.0 , 0.0 , 0.1 , 0.1 ))
7676
7777 def test_simple_get_tiles_polygon (self ):
7878 """tile grid size equals polygon size -> single tile."""
7979 polygon = shapely .geometry .box (0.0 , 0.0 , 100_000.0 , 100_000.0 )
80- tile_grid = SizeBasedTileGrid (epsg = 3857 , size = 100_000.0 )
80+ tile_grid = _SizeBasedTileGrid (epsg = 3857 , size = 100_000.0 )
8181 result = tile_grid .get_tiles (polygon )
8282 assert len (result ) == 1
8383 assert result .geometry [0 ].equals (polygon )
8484
8585 def test_larger_get_tiles_polygon (self ):
8686 """tile grid larger than polygon -> single tile clipped to polygon."""
8787 polygon = shapely .geometry .box (0.0 , 0.0 , 100_000.0 , 100_000.0 )
88- tile_grid = SizeBasedTileGrid (epsg = 3857 , size = 200_000.0 )
88+ tile_grid = _SizeBasedTileGrid (epsg = 3857 , size = 200_000.0 )
8989 result = tile_grid .get_tiles (polygon )
9090 assert len (result ) == 1
9191 assert result .geometry [0 ].equals (polygon )
9292
9393 def test_edge_tiles_clipped_to_aoi (self ):
9494 """When the AOI is not a multiple of tile_size, edge tiles are smaller."""
9595 aoi = {"west" : 0.0 , "south" : 0.0 , "east" : 150_000.0 , "north" : 150_000.0 , "crs" : "EPSG:3857" }
96- grid = SizeBasedTileGrid (epsg = 3857 , size = 100_000 )
96+ grid = _SizeBasedTileGrid (epsg = 3857 , size = 100_000 )
9797 result = grid .get_tiles (aoi )
9898 assert len (result ) == 4 # 2x2 grid
9999 # The right/top edge tiles should be 50k wide/tall, not 100k
@@ -107,7 +107,7 @@ def test_reprojects_bbox_when_crs_differs(self):
107107 """AOI in EPSG:4326 should be reprojected to the tile grid's CRS (EPSG:3857) before splitting."""
108108 # A small bbox around lon=0, lat=0 in WGS84
109109 aoi = {"west" : - 1.0 , "south" : - 1.0 , "east" : 1.0 , "north" : 1.0 , "crs" : "EPSG:4326" }
110- grid = SizeBasedTileGrid (epsg = 3857 , size = 500_000 )
110+ grid = _SizeBasedTileGrid (epsg = 3857 , size = 500_000 )
111111 result = grid .get_tiles (aoi )
112112 assert result .crs .to_epsg () == 3857
113113 # AOI-relative tiling: ~222 km bbox fits in one 500 km tile
@@ -120,7 +120,7 @@ def test_reprojects_bbox_when_crs_differs(self):
120120 def test_no_reprojection_when_crs_matches (self ):
121121 """When AOI CRS matches the tile grid CRS, no reprojection should happen."""
122122 aoi = {"west" : 0.0 , "south" : 0.0 , "east" : 100_000.0 , "north" : 100_000.0 , "crs" : "EPSG:3857" }
123- grid = SizeBasedTileGrid (epsg = 3857 , size = 100_000 )
123+ grid = _SizeBasedTileGrid (epsg = 3857 , size = 100_000 )
124124 result = grid .get_tiles (aoi )
125125 assert len (result ) == 1
126126 assert result .geometry [0 ].equals (shapely .geometry .box (0.0 , 0.0 , 100_000.0 , 100_000.0 ))
@@ -129,7 +129,7 @@ def test_no_reprojection_when_crs_matches(self):
129129class TestPredefinedTileGrid :
130130 def test_basic_from_list (self ):
131131 tiles = [shapely .geometry .box (0 , 0 , 1 , 1 ), shapely .geometry .box (1 , 0 , 2 , 1 )]
132- grid = PredefinedTileGrid (tiles = tiles , crs = 4326 )
132+ grid = _PredefinedTileGrid (tiles = tiles , crs = 4326 )
133133 result = grid .get_tiles (shapely .geometry .box (0.5 , 0.5 , 1.5 , 0.75 ))
134134 assert isinstance (result , gpd .GeoDataFrame )
135135 assert len (result ) == 2
@@ -139,7 +139,7 @@ def test_from_geodataframe(self):
139139 geometry = [shapely .geometry .box (0 , 0 , 1 , 1 ), shapely .geometry .box (1 , 0 , 2 , 1 )],
140140 crs = "EPSG:4326" ,
141141 )
142- grid = PredefinedTileGrid (tiles = gdf )
142+ grid = _PredefinedTileGrid (tiles = gdf )
143143 result = grid .get_tiles (shapely .geometry .box (0.5 , 0.5 , 1.5 , 0.75 ))
144144 assert len (result ) == 2
145145 assert result .crs .to_epsg () == 4326
@@ -149,14 +149,14 @@ def test_from_geoseries(self):
149149 [shapely .geometry .box (0 , 0 , 1 , 1 ), shapely .geometry .box (1 , 0 , 2 , 1 )],
150150 crs = "EPSG:4326" ,
151151 )
152- grid = PredefinedTileGrid (tiles = gs )
152+ grid = _PredefinedTileGrid (tiles = gs )
153153 result = grid .get_tiles (shapely .geometry .box (0.5 , 0.5 , 1.5 , 0.75 ))
154154 assert len (result ) == 2
155155
156156 def test_multipolygon_tiles (self ):
157157 """Tiles may be MultiPolygons."""
158158 mp = shapely .geometry .MultiPolygon ([shapely .geometry .box (0 , 0 , 1 , 1 ), shapely .geometry .box (2 , 2 , 3 , 3 )])
159- grid = PredefinedTileGrid (tiles = [mp ], crs = 4326 )
159+ grid = _PredefinedTileGrid (tiles = [mp ], crs = 4326 )
160160 result = grid .get_tiles (shapely .geometry .box (0.5 , 0.5 , 0.8 , 0.8 ))
161161 assert len (result ) == 1
162162
@@ -166,7 +166,7 @@ def test_preserves_extra_columns(self):
166166 {"name" : ["A" , "B" ], "geometry" : [shapely .geometry .box (0 , 0 , 1 , 1 ), shapely .geometry .box (5 , 5 , 6 , 6 )]},
167167 crs = "EPSG:4326" ,
168168 )
169- grid = PredefinedTileGrid (tiles = gdf )
169+ grid = _PredefinedTileGrid (tiles = gdf )
170170 result = grid .get_tiles (shapely .geometry .box (0 , 0 , 2 , 2 ))
171171 assert len (result ) == 1
172172 assert result ["name" ].iloc [0 ] == "A"
@@ -177,65 +177,65 @@ def test_filters_non_intersecting(self):
177177 shapely .geometry .box (1 , 0 , 2 , 1 ),
178178 shapely .geometry .box (5 , 5 , 6 , 6 ),
179179 ]
180- grid = PredefinedTileGrid (tiles = tiles , crs = 4326 )
180+ grid = _PredefinedTileGrid (tiles = tiles , crs = 4326 )
181181 result = grid .get_tiles (shapely .geometry .box (0.5 , 0.5 , 1.5 , 0.75 ))
182182 assert len (result ) == 2
183183
184184 def test_reprojects_query_geometry_when_crs_differs (self ):
185185 """AOI dict in EPSG:4326 with tile grid in EPSG:3857 should reproject before intersection."""
186186 # Tile covering roughly lon [-1, 1], lat [-1, 1] in 3857 meters
187187 tile_3857 = shapely .geometry .box (- 111_320 , - 111_325 , 111_320 , 111_325 )
188- grid = PredefinedTileGrid (tiles = [tile_3857 ], crs = 3857 )
188+ grid = _PredefinedTileGrid (tiles = [tile_3857 ], crs = 3857 )
189189 # Query in WGS84 degrees — overlaps the tile after reprojection
190190 result = grid .get_tiles ({"west" : - 0.5 , "south" : - 0.5 , "east" : 0.5 , "north" : 0.5 , "crs" : "EPSG:4326" })
191191 assert len (result ) == 1
192192
193193 def test_no_match_after_reprojection (self ):
194194 """AOI that doesn't overlap tiles after reprojection should return empty."""
195195 tile_3857 = shapely .geometry .box (- 111_320 , - 111_325 , 111_320 , 111_325 )
196- grid = PredefinedTileGrid (tiles = [tile_3857 ], crs = 3857 )
196+ grid = _PredefinedTileGrid (tiles = [tile_3857 ], crs = 3857 )
197197 # Query far away from the tile
198198 result = grid .get_tiles ({"west" : 50 , "south" : 50 , "east" : 51 , "north" : 51 , "crs" : "EPSG:4326" })
199199 assert len (result ) == 0
200200
201201 def test_dict_geometry (self ):
202202 tiles = [shapely .geometry .box (0 , 0 , 1 , 1 ), shapely .geometry .box (2 , 2 , 3 , 3 )]
203- grid = PredefinedTileGrid (tiles = tiles , crs = 4326 )
203+ grid = _PredefinedTileGrid (tiles = tiles , crs = 4326 )
204204 result = grid .get_tiles ({"west" : 0.5 , "south" : 0.5 , "east" : 0.8 , "north" : 0.8 })
205205 assert len (result ) == 1
206206 assert result .geometry [0 ].equals (shapely .geometry .box (0 , 0 , 1 , 1 ))
207207
208208 def test_empty_list_raises (self ):
209209 with pytest .raises (JobSplittingFailure , match = "At least one tile" ):
210- PredefinedTileGrid (tiles = [], crs = 4326 )
210+ _PredefinedTileGrid (tiles = [], crs = 4326 )
211211
212212 def test_empty_geodataframe_raises (self ):
213213 gdf = gpd .GeoDataFrame (geometry = [], crs = "EPSG:4326" )
214214 with pytest .raises (JobSplittingFailure , match = "at least one row" ):
215- PredefinedTileGrid (tiles = gdf )
215+ _PredefinedTileGrid (tiles = gdf )
216216
217217 def test_invalid_tile_type_raises (self ):
218218 with pytest .raises (JobSplittingFailure , match = "All tiles must be" ):
219- PredefinedTileGrid (tiles = ["not_a_polygon" ], crs = 4326 )
219+ _PredefinedTileGrid (tiles = ["not_a_polygon" ], crs = 4326 )
220220
221221 def test_list_without_crs_raises (self ):
222222 with pytest .raises (JobSplittingFailure , match = "'crs' is required" ):
223- PredefinedTileGrid (tiles = [shapely .geometry .box (0 , 0 , 1 , 1 )])
223+ _PredefinedTileGrid (tiles = [shapely .geometry .box (0 , 0 , 1 , 1 )])
224224
225225 def test_geodataframe_without_crs_and_no_crs_arg_raises (self ):
226226 gdf = gpd .GeoDataFrame (geometry = [shapely .geometry .box (0 , 0 , 1 , 1 )])
227227 with pytest .raises (JobSplittingFailure , match = "no CRS set" ):
228- PredefinedTileGrid (tiles = gdf )
228+ _PredefinedTileGrid (tiles = gdf )
229229
230230 def test_geodataframe_without_crs_uses_crs_arg (self ):
231231 gdf = gpd .GeoDataFrame (geometry = [shapely .geometry .box (0 , 0 , 1 , 1 )])
232- grid = PredefinedTileGrid (tiles = gdf , crs = 4326 )
232+ grid = _PredefinedTileGrid (tiles = gdf , crs = 4326 )
233233 result = grid .get_tiles (shapely .geometry .box (0 , 0 , 1 , 1 ))
234234 assert result .crs .to_epsg () == 4326
235235
236236 def test_invalid_geometry_type_raises (self ):
237237 tiles = [shapely .geometry .box (0 , 0 , 1 , 1 )]
238- grid = PredefinedTileGrid (tiles = tiles , crs = 4326 )
238+ grid = _PredefinedTileGrid (tiles = tiles , crs = 4326 )
239239 with pytest .raises (JobSplittingFailure , match = "Expected a bounding-box dict" ):
240240 grid .get_tiles ("invalid" )
241241
@@ -270,13 +270,13 @@ def test_no_projection_no_crs_raises(self):
270270 split_area (aoi , tile_size = 1.0 )
271271
272272 def test_tile_grid_mutually_exclusive (self ):
273- grid = PredefinedTileGrid (tiles = [shapely .geometry .box (0 , 0 , 1 , 1 )], crs = 4326 )
273+ grid = _PredefinedTileGrid (tiles = [shapely .geometry .box (0 , 0 , 1 , 1 )], crs = 4326 )
274274 with pytest .raises (JobSplittingFailure , match = "Cannot combine" ):
275275 split_area (shapely .geometry .box (0 , 0 , 1 , 1 ), projection = "EPSG:4326" , tile_grid = grid )
276276
277277 def test_with_predefined_tile_grid (self ):
278278 grid_tiles = [shapely .geometry .box (0 , 0 , 0.5 , 0.5 ), shapely .geometry .box (0.5 , 0 , 1 , 0.5 )]
279- grid = PredefinedTileGrid (tiles = grid_tiles , crs = 4326 )
279+ grid = _PredefinedTileGrid (tiles = grid_tiles , crs = 4326 )
280280 aoi = shapely .geometry .box (0 , 0 , 1 , 0.5 )
281281 result = split_area (aoi , tile_grid = grid )
282282 assert len (result ) == 2
0 commit comments