geobox 2.2.1__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {geobox-2.2.1 → geobox-2.2.2}/PKG-INFO +1 -1
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/feature.py +20 -7
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/task.py +4 -1
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/vectorlayer.py +3 -2
- {geobox-2.2.1 → geobox-2.2.2}/geobox/feature.py +21 -7
- {geobox-2.2.1 → geobox-2.2.2}/geobox/task.py +4 -1
- {geobox-2.2.1 → geobox-2.2.2}/geobox/vectorlayer.py +3 -2
- {geobox-2.2.1 → geobox-2.2.2}/geobox.egg-info/PKG-INFO +1 -1
- {geobox-2.2.1 → geobox-2.2.2}/pyproject.toml +1 -1
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_feature.py +56 -3
- {geobox-2.2.1 → geobox-2.2.2}/LICENSE +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/README.md +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/__init__.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/__init__.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/api.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/apikey.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/attachment.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/base.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/basemap.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/dashboard.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/field.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/file.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/layout.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/log.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/map.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/model3d.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/mosaic.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/plan.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/query.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/raster.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/raster_analysis.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/route.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/scene.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/settings.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/tile3d.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/tileset.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/usage.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/user.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/vector_tool.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/version.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/view.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/aio/workflow.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/api.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/apikey.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/attachment.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/base.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/basemap.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/dashboard.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/enums.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/exception.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/field.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/file.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/layout.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/log.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/map.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/model3d.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/mosaic.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/plan.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/query.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/raster.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/raster_analysis.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/route.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/scene.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/settings.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/tile3d.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/tileset.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/usage.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/user.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/utils.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/vector_tool.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/version.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/view.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox/workflow.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox.egg-info/SOURCES.txt +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox.egg-info/dependency_links.txt +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox.egg-info/requires.txt +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/geobox.egg-info/top_level.txt +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/setup.cfg +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_api.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_apikey.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_attachment.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_basemap.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_dashboard.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_field.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_file.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_layout.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_log.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_map.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_model3d.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_mosaic.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_plan.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_query.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_raster.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_raster_analysis.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_route.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_scene.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_settings.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_task.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_tile3d.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_tileset.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_usage.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_user.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_vector_tool.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_vectorlayer.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_version.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_view.py +0 -0
- {geobox-2.2.1 → geobox-2.2.2}/tests/test_workflow.py +0 -0
|
@@ -29,7 +29,11 @@ class AsyncFeature(AsyncBase):
|
|
|
29
29
|
super().__init__(api=layer.api)
|
|
30
30
|
self.layer = layer
|
|
31
31
|
self._srid = srid
|
|
32
|
-
self.data = data or {
|
|
32
|
+
self.data = data or {
|
|
33
|
+
"type": "Feature",
|
|
34
|
+
"geometry": {},
|
|
35
|
+
"properties": {}
|
|
36
|
+
}
|
|
33
37
|
self.original_geometry = self.data.get('geometry')
|
|
34
38
|
self.endpoint = urljoin(layer.endpoint, f'features/{self.data.get("id")}/') if self.data.get('id') else None
|
|
35
39
|
|
|
@@ -277,13 +281,14 @@ class AsyncFeature(AsyncBase):
|
|
|
277
281
|
|
|
278
282
|
|
|
279
283
|
@classmethod
|
|
280
|
-
async def create_feature(cls, layer: 'VectorLayer', geojson: Dict) -> 'AsyncFeature':
|
|
284
|
+
async def create_feature(cls, layer: 'VectorLayer', geojson: Dict, srid: int = 3857) -> 'AsyncFeature':
|
|
281
285
|
"""
|
|
282
286
|
[async] Create a new feature in the vector layer.
|
|
283
287
|
|
|
284
288
|
Args:
|
|
285
289
|
layer (VectorLayer): The vector layer to create the feature in
|
|
286
290
|
geojson (Dict): The GeoJSON data for the feature
|
|
291
|
+
srid (int, optional): the feature srid. default: 3857
|
|
287
292
|
|
|
288
293
|
Returns:
|
|
289
294
|
AsyncFeature: The created feature instance
|
|
@@ -299,8 +304,19 @@ class AsyncFeature(AsyncBase):
|
|
|
299
304
|
... }
|
|
300
305
|
>>> feature = await Feature.create_feature(layer, geojson)
|
|
301
306
|
"""
|
|
307
|
+
feature = AsyncFeature(layer, srid=srid, data=geojson)
|
|
308
|
+
data = feature.data.copy()
|
|
309
|
+
srid = feature.srid
|
|
310
|
+
|
|
311
|
+
if feature.srid != feature.BASE_SRID:
|
|
312
|
+
feature = feature.transform(feature.BASE_SRID)
|
|
313
|
+
|
|
302
314
|
endpoint = urljoin(layer.endpoint, 'features/')
|
|
303
|
-
|
|
315
|
+
|
|
316
|
+
feature = await cls._create(layer.api, endpoint, feature.data, factory_func=lambda api, item: AsyncFeature(layer, data=item))
|
|
317
|
+
feature.data['geometry'] = data['geometry']
|
|
318
|
+
feature._srid = srid
|
|
319
|
+
return feature
|
|
304
320
|
|
|
305
321
|
|
|
306
322
|
@classmethod
|
|
@@ -360,10 +376,7 @@ class AsyncFeature(AsyncBase):
|
|
|
360
376
|
"Install it with: pip install geobox[geometry]"
|
|
361
377
|
)
|
|
362
378
|
|
|
363
|
-
if not self.data:
|
|
364
|
-
return None
|
|
365
|
-
|
|
366
|
-
elif not self.data.get('geometry'):
|
|
379
|
+
if not self.data.get('geometry'):
|
|
367
380
|
raise ValueError("Geometry is not present in the feature data")
|
|
368
381
|
|
|
369
382
|
elif not isinstance(self.data['geometry'], dict):
|
|
@@ -2,6 +2,7 @@ import time
|
|
|
2
2
|
import asyncio
|
|
3
3
|
from urllib.parse import urljoin
|
|
4
4
|
from typing import Optional, Dict, List, Optional, Union, TYPE_CHECKING
|
|
5
|
+
import logging
|
|
5
6
|
|
|
6
7
|
from .base import AsyncBase
|
|
7
8
|
from ..enums import TaskStatus
|
|
@@ -16,6 +17,8 @@ if TYPE_CHECKING:
|
|
|
16
17
|
from ..api import GeoboxClient
|
|
17
18
|
from ..task import Task
|
|
18
19
|
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
19
22
|
|
|
20
23
|
class AsyncTask(AsyncBase):
|
|
21
24
|
|
|
@@ -233,7 +236,7 @@ class AsyncTask(AsyncBase):
|
|
|
233
236
|
return await self._wait(timeout, interval, progress_bar)
|
|
234
237
|
except Exception as e:
|
|
235
238
|
last_exception = e
|
|
236
|
-
|
|
239
|
+
logger.warning(f"[Retry {attempt}/{retry}] Task wait failed: {e}")
|
|
237
240
|
time.sleep(interval)
|
|
238
241
|
raise last_exception
|
|
239
242
|
|
|
@@ -755,12 +755,13 @@ class AsyncVectorLayer(AsyncBase):
|
|
|
755
755
|
return feature
|
|
756
756
|
|
|
757
757
|
|
|
758
|
-
async def create_feature(self, geojson: Dict)-> 'AsyncFeature':
|
|
758
|
+
async def create_feature(self, geojson: Dict, srid: int = AsyncFeature.BASE_SRID)-> 'AsyncFeature':
|
|
759
759
|
"""
|
|
760
760
|
[async] Create a new feature in the layer.
|
|
761
761
|
|
|
762
762
|
Args:
|
|
763
763
|
geojson (Dict): The feature data including properties and geometry.
|
|
764
|
+
srid (int, optional): the feature srid. default: 3857
|
|
764
765
|
|
|
765
766
|
Returns:
|
|
766
767
|
Feature: The newly created feature instance.
|
|
@@ -780,7 +781,7 @@ class AsyncVectorLayer(AsyncBase):
|
|
|
780
781
|
... }
|
|
781
782
|
>>> feature = await layer.create_feature(geojson=geojson)
|
|
782
783
|
"""
|
|
783
|
-
return await AsyncFeature.create_feature(self, geojson)
|
|
784
|
+
return await AsyncFeature.create_feature(self, geojson, srid=srid)
|
|
784
785
|
|
|
785
786
|
|
|
786
787
|
async def delete_features(self,
|
|
@@ -34,7 +34,7 @@ class Feature(Base):
|
|
|
34
34
|
... "type": "Feature",
|
|
35
35
|
... "geometry": {
|
|
36
36
|
... "type": "Point",
|
|
37
|
-
... "coordinates": [
|
|
37
|
+
... "coordinates": [10.0, 10.0]
|
|
38
38
|
... },
|
|
39
39
|
... "properties": {
|
|
40
40
|
... "name": "Test feature"
|
|
@@ -46,7 +46,11 @@ class Feature(Base):
|
|
|
46
46
|
super().__init__(api=layer.api)
|
|
47
47
|
self.layer = layer
|
|
48
48
|
self._srid = srid
|
|
49
|
-
self.data = data or {
|
|
49
|
+
self.data = data or {
|
|
50
|
+
"type": "Feature",
|
|
51
|
+
"geometry": {},
|
|
52
|
+
"properties": {}
|
|
53
|
+
}
|
|
50
54
|
self.original_geometry = self.data.get('geometry')
|
|
51
55
|
self.endpoint = urljoin(layer.endpoint, f'features/{self.data.get("id")}/') if self.data.get('id') else None
|
|
52
56
|
|
|
@@ -295,13 +299,14 @@ class Feature(Base):
|
|
|
295
299
|
|
|
296
300
|
|
|
297
301
|
@classmethod
|
|
298
|
-
def create_feature(cls, layer: 'VectorLayer', geojson: Dict) -> 'Feature':
|
|
302
|
+
def create_feature(cls, layer: 'VectorLayer', geojson: Dict, srid: int = 3857) -> 'Feature':
|
|
299
303
|
"""
|
|
300
304
|
Create a new feature in the vector layer.
|
|
301
305
|
|
|
302
306
|
Args:
|
|
303
307
|
layer (VectorLayer): The vector layer to create the feature in
|
|
304
308
|
geojson (Dict): The GeoJSON data for the feature
|
|
309
|
+
srid (int, optional): the feature srid. default: 3857
|
|
305
310
|
|
|
306
311
|
Returns:
|
|
307
312
|
Feature: The created feature instance
|
|
@@ -318,8 +323,19 @@ class Feature(Base):
|
|
|
318
323
|
... }
|
|
319
324
|
>>> feature = Feature.create_feature(layer, geojson)
|
|
320
325
|
"""
|
|
326
|
+
feature = Feature(layer, srid=srid, data=geojson)
|
|
327
|
+
data = feature.data.copy()
|
|
328
|
+
srid = feature.srid
|
|
329
|
+
|
|
330
|
+
if feature.srid != feature.BASE_SRID:
|
|
331
|
+
feature = feature.transform(feature.BASE_SRID)
|
|
332
|
+
|
|
321
333
|
endpoint = urljoin(layer.endpoint, 'features/')
|
|
322
|
-
|
|
334
|
+
|
|
335
|
+
feature = cls._create(layer.api, endpoint, feature.data, factory_func=lambda api, item: Feature(layer, data=item))
|
|
336
|
+
feature.data['geometry'] = data['geometry']
|
|
337
|
+
feature._srid = srid
|
|
338
|
+
return feature
|
|
323
339
|
|
|
324
340
|
|
|
325
341
|
@classmethod
|
|
@@ -380,10 +396,8 @@ class Feature(Base):
|
|
|
380
396
|
"Install it with: pip install geobox[geometry]"
|
|
381
397
|
)
|
|
382
398
|
|
|
383
|
-
if not self.data:
|
|
384
|
-
return None
|
|
385
399
|
|
|
386
|
-
|
|
400
|
+
if not self.data.get('geometry'):
|
|
387
401
|
raise ValueError("Geometry is not present in the feature data")
|
|
388
402
|
|
|
389
403
|
elif not isinstance(self.data['geometry'], dict):
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from urllib.parse import urljoin, urlencode
|
|
2
2
|
from typing import Optional, Dict, List, Optional, Union, TYPE_CHECKING
|
|
3
3
|
import time
|
|
4
|
+
import logging
|
|
4
5
|
|
|
5
6
|
from .base import Base
|
|
6
7
|
from .enums import TaskStatus
|
|
@@ -15,6 +16,8 @@ if TYPE_CHECKING:
|
|
|
15
16
|
from .aio import AsyncGeoboxClient
|
|
16
17
|
from .aio.task import AsyncTask
|
|
17
18
|
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
class Task(Base):
|
|
20
23
|
|
|
@@ -230,7 +233,7 @@ class Task(Base):
|
|
|
230
233
|
return self._wait(timeout, interval, progress_bar)
|
|
231
234
|
except Exception as e:
|
|
232
235
|
last_exception = e
|
|
233
|
-
|
|
236
|
+
logger.warning(f"[Retry {attempt}/{retry}] Task wait failed: {e}")
|
|
234
237
|
time.sleep(interval)
|
|
235
238
|
raise last_exception
|
|
236
239
|
|
|
@@ -756,12 +756,13 @@ class VectorLayer(Base):
|
|
|
756
756
|
return feature
|
|
757
757
|
|
|
758
758
|
|
|
759
|
-
def create_feature(self, geojson: Dict)-> 'Feature':
|
|
759
|
+
def create_feature(self, geojson: Dict, srid: int = Feature.BASE_SRID)-> 'Feature':
|
|
760
760
|
"""
|
|
761
761
|
Create a new feature in the layer.
|
|
762
762
|
|
|
763
763
|
Args:
|
|
764
764
|
geojson (Dict): The feature data including properties and geometry.
|
|
765
|
+
srid (int, optional): the feature srid. default: 3857
|
|
765
766
|
|
|
766
767
|
Returns:
|
|
767
768
|
Feature: The newly created feature instance.
|
|
@@ -781,7 +782,7 @@ class VectorLayer(Base):
|
|
|
781
782
|
... }
|
|
782
783
|
>>> feature = layer.create_feature(geojson=geojson)
|
|
783
784
|
"""
|
|
784
|
-
return Feature.create_feature(self, geojson)
|
|
785
|
+
return Feature.create_feature(self, geojson, srid=srid)
|
|
785
786
|
|
|
786
787
|
|
|
787
788
|
def delete_features(self, q: str = None, bbox: str = None, bbox_srid: int = None, feature_ids: List[int] = None,
|
|
@@ -107,6 +107,26 @@ def test_save_srid(api, mock_vector_data, mock_feature_data, feature_type):
|
|
|
107
107
|
assert feature.srid == 3857
|
|
108
108
|
assert feature.coordinates == coords
|
|
109
109
|
|
|
110
|
+
# without id
|
|
111
|
+
feature_id = feature_data['id']
|
|
112
|
+
del feature_data['id']
|
|
113
|
+
# Mock response should include the id as the API returns the created feature with id
|
|
114
|
+
response_data = feature_data.copy()
|
|
115
|
+
response_data['id'] = feature_id
|
|
116
|
+
api.post.return_value = response_data
|
|
117
|
+
feature = Feature(layer, srid=3857, data=feature_data)
|
|
118
|
+
feature.transform(4326)
|
|
119
|
+
coords = feature.coordinates
|
|
120
|
+
feature.save()
|
|
121
|
+
assert feature.srid == 4326
|
|
122
|
+
assert feature.coordinates == coords
|
|
123
|
+
|
|
124
|
+
feature = Feature(layer, srid=3857, data=feature_data)
|
|
125
|
+
coords = feature.coordinates
|
|
126
|
+
feature.save()
|
|
127
|
+
assert feature.srid == 3857
|
|
128
|
+
assert feature.coordinates == coords
|
|
129
|
+
|
|
110
130
|
|
|
111
131
|
@pytest.mark.parametrize("feature_type", [type.value for type in FeatureType])
|
|
112
132
|
def test_delete(api, mock_vector_data, mock_feature_data, feature_type):
|
|
@@ -159,7 +179,7 @@ def test_create_feature(api, mock_vector_data, mock_feature_data, feature_type):
|
|
|
159
179
|
|
|
160
180
|
feature = Feature.create_feature(
|
|
161
181
|
layer=layer,
|
|
162
|
-
geojson=expected_request
|
|
182
|
+
geojson=expected_request,
|
|
163
183
|
)
|
|
164
184
|
api.post.assert_called_once_with(f'{layer.endpoint}features/', expected_request)
|
|
165
185
|
assert isinstance(feature, Feature)
|
|
@@ -168,6 +188,39 @@ def test_create_feature(api, mock_vector_data, mock_feature_data, feature_type):
|
|
|
168
188
|
assert feature.data == api_response
|
|
169
189
|
|
|
170
190
|
|
|
191
|
+
@pytest.mark.parametrize("feature_type", [type.value for type in FeatureType])
|
|
192
|
+
def test_create_feature_with_srid(api, mock_vector_data, mock_feature_data, feature_type):
|
|
193
|
+
"""Test creating a feature for different geometry types"""
|
|
194
|
+
layer = VectorLayer(api, uuid=mock_vector_data['uuid'], layer_type=LayerType.MultiPoint, data=mock_vector_data)
|
|
195
|
+
feature_data = mock_feature_data[feature_type]
|
|
196
|
+
|
|
197
|
+
expected_request = {
|
|
198
|
+
'type': 'Feature',
|
|
199
|
+
'geometry': feature_data['geometry'],
|
|
200
|
+
'properties': {'name': f'test_{feature_type.lower()}'}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
api_response = {
|
|
204
|
+
'type': 'Feature',
|
|
205
|
+
'geometry': feature_data['geometry'],
|
|
206
|
+
'properties': {'name': f'test_{feature_type.lower()}'},
|
|
207
|
+
'id': feature_data['id'],
|
|
208
|
+
'bbox': feature_data['bbox']
|
|
209
|
+
}
|
|
210
|
+
api.post.return_value = api_response
|
|
211
|
+
|
|
212
|
+
feature = Feature.create_feature(
|
|
213
|
+
layer=layer,
|
|
214
|
+
geojson=expected_request,
|
|
215
|
+
srid=4326
|
|
216
|
+
)
|
|
217
|
+
api.post.assert_called_once_with(f'{layer.endpoint}features/', expected_request)
|
|
218
|
+
assert isinstance(feature, Feature)
|
|
219
|
+
assert feature.layer == layer
|
|
220
|
+
assert feature.srid == 4326
|
|
221
|
+
assert feature.data == api_response
|
|
222
|
+
|
|
223
|
+
|
|
171
224
|
@pytest.mark.parametrize("feature_type", [type.value for type in FeatureType])
|
|
172
225
|
def test_get_feature(api, mock_vector_data, mock_feature_data, feature_type):
|
|
173
226
|
"""Test getting a feature for different geometry types"""
|
|
@@ -200,8 +253,8 @@ def test_geometry_no_data(api, mock_vector_data):
|
|
|
200
253
|
layer = VectorLayer(api, uuid=mock_vector_data['uuid'], layer_type=LayerType('Point'), data=mock_vector_data)
|
|
201
254
|
feature = Feature(layer, srid=3857, data=None) # No data
|
|
202
255
|
|
|
203
|
-
|
|
204
|
-
|
|
256
|
+
with pytest.raises(ValueError, match="Geometry is not present in the feature data"):
|
|
257
|
+
feature.geometry
|
|
205
258
|
|
|
206
259
|
|
|
207
260
|
def test_geometry_no_geometry_field(api, mock_vector_data):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|