geoservercloud 0.7.3.dev4__tar.gz → 0.7.4.dev4__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.
Files changed (87) hide show
  1. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/PKG-INFO +1 -1
  2. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/geoservercloud.py +222 -26
  3. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/geoservercloudsync.py +2 -2
  4. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/datastore.py +3 -3
  5. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/layergroup.py +4 -0
  6. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/services/restservice.py +9 -24
  7. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/pyproject.toml +1 -1
  8. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/LICENSE +0 -0
  9. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/README.md +0 -0
  10. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/.gitignore +0 -0
  11. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/README.md +0 -0
  12. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/__init__.py +0 -0
  13. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/cli.py +0 -0
  14. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/compose/example.compose.yaml +0 -0
  15. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/compose/geodatabase/001_create_schemas.sql +0 -0
  16. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/config.py +0 -0
  17. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/data/sampledata.tgz +0 -0
  18. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/example.config.yaml +0 -0
  19. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/__init__.py +0 -0
  20. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/conftest.py +0 -0
  21. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/__init__.py +0 -0
  22. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/__init__.py +0 -0
  23. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_None_expected.png +0 -0
  24. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language__expected.png +0 -0
  25. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_de_expected.png +0 -0
  26. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_fr_expected.png +0 -0
  27. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/default_value/language_it_expected.png +0 -0
  28. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_None_expected.png +0 -0
  29. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language__expected.png +0 -0
  30. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/default_locale/no_default_value/language_it_expected.png +0 -0
  31. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_None_expected.png +0 -0
  32. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language__expected.png +0 -0
  33. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_de_expected.png +0 -0
  34. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_fr_expected.png +0 -0
  35. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/default_value/language_it_expected.png +0 -0
  36. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language_None_expected.png +0 -0
  37. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language__expected.png +0 -0
  38. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/labels/no_default_locale/no_default_value/language_it_expected.png +0 -0
  39. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/localized_labels.sld +0 -0
  40. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/localized_no_default.sld +0 -0
  41. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/i18n/localized_with_default.sld +0 -0
  42. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/wfs/__init__.py +0 -0
  43. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/wfs/wfs_delete_payload.xml +0 -0
  44. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/wfs/wfs_insert_payload.xml +0 -0
  45. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/wms/__init__.py +0 -0
  46. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/resources/wms/getmap_expected.png +0 -0
  47. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_cascaded_stores.py +0 -0
  48. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_cog.py +0 -0
  49. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_datastore.py +0 -0
  50. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_get_version.py +0 -0
  51. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_gwc.py +0 -0
  52. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_i18n.py +0 -0
  53. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_imagemosaic.py +0 -0
  54. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_imagemosaic_cog.py +0 -0
  55. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_wfs.py +0 -0
  56. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_wms.py +0 -0
  57. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/test_workspace.py +0 -0
  58. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoserver_acceptance_tests/tests/utils.py +0 -0
  59. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/__init__.py +0 -0
  60. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/gridsets/2056.xml +0 -0
  61. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/gridsets/21781.xml +0 -0
  62. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/gridsets/3857.xml +0 -0
  63. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/__init__.py +0 -0
  64. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/abstractlayer.py +0 -0
  65. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/common.py +0 -0
  66. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/coverage.py +0 -0
  67. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/coverages.py +0 -0
  68. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/coveragestore.py +0 -0
  69. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/datastores.py +0 -0
  70. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/featuretype.py +0 -0
  71. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/featuretypes.py +0 -0
  72. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/layer.py +0 -0
  73. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/layergroups.py +0 -0
  74. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/resourcedirectory.py +0 -0
  75. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/style.py +0 -0
  76. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/styles.py +0 -0
  77. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/wmslayer.py +0 -0
  78. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/wmssettings.py +0 -0
  79. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/wmsstore.py +0 -0
  80. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/workspace.py +0 -0
  81. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/models/workspaces.py +0 -0
  82. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/services/__init__.py +0 -0
  83. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/services/owsservice.py +0 -0
  84. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/services/restclient.py +0 -0
  85. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/services/restlogger.py +0 -0
  86. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/templates.py +0 -0
  87. {geoservercloud-0.7.3.dev4 → geoservercloud-0.7.4.dev4}/geoservercloud/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: geoservercloud
3
- Version: 0.7.3.dev4
3
+ Version: 0.7.4.dev4
4
4
  Summary: Lightweight Python client to interact with GeoServer Cloud REST API, GeoServer ACL and OGC services
5
5
  License: BSD-2-Clause
6
6
  Author: Camptocamp
@@ -10,7 +10,7 @@ from geoservercloud import utils
10
10
  from geoservercloud.models.common import TimeDimensionInfo
11
11
  from geoservercloud.models.coverage import Coverage
12
12
  from geoservercloud.models.coveragestore import CoverageStore
13
- from geoservercloud.models.datastore import PostGisDataStore
13
+ from geoservercloud.models.datastore import DataStore
14
14
  from geoservercloud.models.featuretype import FeatureType
15
15
  from geoservercloud.models.layer import Layer
16
16
  from geoservercloud.models.layergroup import LayerGroup
@@ -272,19 +272,94 @@ class GeoServerCloud:
272
272
  return datastores, status_code
273
273
  return datastores.aslist(), status_code
274
274
 
275
- def get_pg_datastore(
275
+ def get_datastore(
276
276
  self, workspace_name: str, datastore_name: str
277
277
  ) -> tuple[dict[str, Any] | str, int]:
278
278
  """
279
279
  Get a datastore by workspace and name
280
280
  """
281
- datastore, status_code = self.rest_service.get_pg_datastore(
281
+ datastore, status_code = self.rest_service.get_datastore(
282
282
  workspace_name, datastore_name
283
283
  )
284
284
  if isinstance(datastore, str):
285
285
  return datastore, status_code
286
286
  return datastore.asdict(), status_code
287
287
 
288
+ def get_pg_datastore(
289
+ self, workspace_name: str, datastore_name: str
290
+ ) -> tuple[dict[str, Any] | str, int]:
291
+ """
292
+ Get a datastore by workspace and name
293
+ """
294
+ return self.get_datastore(workspace_name, datastore_name)
295
+
296
+ def create_datastore(
297
+ self,
298
+ workspace_name: str,
299
+ datastore_name: str,
300
+ datastore_type: str,
301
+ connection_parameters: dict[str, Any],
302
+ description: str | None = None,
303
+ enabled: bool = True,
304
+ set_default_datastore: bool = False,
305
+ ) -> tuple[str, int]:
306
+ """
307
+ Create a generic datastore of any type in GeoServer, or update if it already exists. This method
308
+ accepts flexible connection parameters, allowing to create any type of datastore.
309
+
310
+ :param workspace_name: Name of the workspace
311
+ :type workspace_name: str
312
+ :param datastore_name: Name for the datastore
313
+ :type datastore_name: str
314
+ :param datastore_type: Type of datastore (e.g., "PostGIS", "Shapefile", "Directory of spatial files (shapefiles)")
315
+ :type datastore_type: str
316
+ :param connection_parameters: Dict of connection parameters specific to the datastore type
317
+ :type connection_parameters: dict
318
+ :param description: Optional description
319
+ :type description: str, optional
320
+ :param enabled: Whether the datastore should be enabled (default: True)
321
+ :type enabled: bool, optional
322
+ :param set_default_datastore: Whether to set as default datastore (default: False)
323
+ :type set_default_datastore: bool, optional
324
+
325
+ :return: Tuple of (datastore_name, status_code)
326
+ :rtype: tuple
327
+
328
+ :Example:
329
+
330
+ >>> create_datastore(
331
+ ... workspace_name="myworkspace",
332
+ ... datastore_name="my_store",
333
+ ... datastore_type="PostGIS",
334
+ ... connection_parameters={
335
+ ... "dbtype": "postgis",
336
+ ... "host": "localhost",
337
+ ... "port": 5432,
338
+ ... "database": "mydb",
339
+ ... "user": "user",
340
+ ... "passwd": "password",
341
+ ... "schema": "public",
342
+ ... "Expose primary keys": "true",
343
+ ... }
344
+ ... )
345
+ """
346
+ datastore = DataStore(
347
+ workspace_name,
348
+ datastore_name,
349
+ connection_parameters=connection_parameters,
350
+ type=datastore_type,
351
+ description=description,
352
+ enabled=enabled,
353
+ )
354
+ content, status_code = self.rest_service.create_datastore(
355
+ workspace_name, datastore
356
+ )
357
+
358
+ if set_default_datastore:
359
+ self.default_datastore = datastore_name
360
+
361
+ return content, status_code
362
+
288
363
  def create_pg_datastore(
289
364
  self,
290
365
  workspace_name: str,
@@ -301,7 +376,7 @@ class GeoServerCloud:
301
376
  """
302
377
  Create a PostGIS datastore from the DB connection parameters, or update it if it already exist.
303
378
  """
304
- datastore = PostGisDataStore(
379
+ datastore = DataStore(
305
380
  workspace_name,
306
381
  datastore_name,
307
382
  connection_parameters={
@@ -318,7 +393,7 @@ class GeoServerCloud:
318
393
  type="PostGIS",
319
394
  description=description,
320
395
  )
321
- content, status_code = self.rest_service.create_pg_datastore(
396
+ content, status_code = self.rest_service.create_datastore(
322
397
  workspace_name, datastore
323
398
  )
324
399
 
@@ -339,7 +414,7 @@ class GeoServerCloud:
339
414
  """
340
415
  Create a PostGIS datastore from JNDI resource, or update it if it already exist.
341
416
  """
342
- datastore = PostGisDataStore(
417
+ datastore = DataStore(
343
418
  workspace_name,
344
419
  datastore_name,
345
420
  connection_parameters={
@@ -352,15 +427,104 @@ class GeoServerCloud:
352
427
  type="PostGIS (JNDI)",
353
428
  description=description,
354
429
  )
355
- content, code = self.rest_service.create_jndi_datastore(
356
- workspace_name, datastore
357
- )
430
+ content, code = self.rest_service.create_datastore(workspace_name, datastore)
358
431
 
359
432
  if set_default_datastore:
360
433
  self.default_datastore = datastore_name
361
434
 
362
435
  return content, code
363
436
 
437
+ def create_pmtiles_datastore(
438
+ self,
439
+ workspace_name: str,
440
+ datastore_name: str,
441
+ pmtiles_url: str,
442
+ description: str | None = None,
443
+ range_reader_provider: str = "file",
444
+ caching_enabled: bool = True,
445
+ caching_block_aligned: bool = True,
446
+ http_timeout_millis: int = 5000,
447
+ http_trust_all_certificates: bool = False,
448
+ s3_use_default_credentials_provider: bool = False,
449
+ s3_force_path_style: bool = True,
450
+ gcs_default_credentials_chain: bool = False,
451
+ ) -> tuple[str, int]:
452
+ """
453
+ Create a PMTiles datastore, or update it if it already exists.
454
+
455
+ :param workspace_name: Name of the workspace
456
+ :type workspace_name: str
457
+ :param datastore_name: Name for the PMTiles datastore
458
+ :type datastore_name: str
459
+ :param pmtiles_url: URL or path to the PMTiles file
460
+ :type pmtiles_url: str
461
+ :param description: Optional description for the datastore
462
+ :type description: str, optional
463
+ :param range_reader_provider: Range reader provider type (default: "file")
464
+ :type range_reader_provider: str, optional
465
+ :param caching_enabled: Enable caching for range reader (default: True)
466
+ :type caching_enabled: bool, optional
467
+ :param caching_block_aligned: Enable block-aligned caching (default: True)
468
+ :type caching_block_aligned: bool, optional
469
+ :param http_timeout_millis: HTTP timeout in milliseconds (default: 5000)
470
+ :type http_timeout_millis: int, optional
471
+ :param http_trust_all_certificates: Trust all SSL certificates for HTTP (default: False)
472
+ :type http_trust_all_certificates: bool, optional
473
+ :param s3_use_default_credentials_provider: Use default AWS credentials provider for S3 (default: False)
474
+ :type s3_use_default_credentials_provider: bool, optional
475
+ :param s3_force_path_style: Force path-style access for S3 (default: True)
476
+ :type s3_force_path_style: bool, optional
477
+ :param gcs_default_credentials_chain: Use default credentials chain for Google Cloud Storage (default: False)
478
+ :type gcs_default_credentials_chain: bool, optional
479
+
480
+ :return: Tuple of (datastore_name, status_code)
481
+ :rtype: tuple
482
+
483
+ :Example:
484
+
485
+ >>> create_pmtiles_datastore(
486
+ ... workspace_name="pmtiles_workspace",
487
+ ... datastore_name="pmtiles_store",
488
+ ... pmtiles_url="file:///mnt/pmtiles/mypmtilesfile.pmtiles",
489
+ ... description="My PMTiles datastore",
490
+ ... range_reader_provider="file",
491
+ ... )
492
+ """
493
+
494
+ datastore = DataStore(
495
+ workspace_name,
496
+ datastore_name,
497
+ connection_parameters={
498
+ "pmtiles": pmtiles_url,
499
+ "namespace": f"http://{workspace_name}",
500
+ "io.tileverse.rangereader.provider": range_reader_provider,
501
+ "io.tileverse.rangereader.caching.enabled": str(
502
+ caching_enabled
503
+ ).lower(),
504
+ "io.tileverse.rangereader.caching.blockaligned": str(
505
+ caching_block_aligned
506
+ ).lower(),
507
+ "io.tileverse.rangereader.http.timeout-millis": str(
508
+ http_timeout_millis
509
+ ),
510
+ "io.tileverse.rangereader.http.trust-all-certificates": str(
511
+ http_trust_all_certificates
512
+ ).lower(),
513
+ "io.tileverse.rangereader.s3.use-default-credentials-provider": str(
514
+ s3_use_default_credentials_provider
515
+ ).lower(),
516
+ "io.tileverse.rangereader.s3.force-path-style": str(
517
+ s3_force_path_style
518
+ ).lower(),
519
+ "io.tileverse.rangereader.gcs.default-credentials-chain": str(
520
+ gcs_default_credentials_chain
521
+ ).lower(),
522
+ },
523
+ type="PMTiles",
524
+ description=description,
525
+ )
526
+ return self.rest_service.create_datastore(workspace_name, datastore)
527
+
364
528
  def get_wms_store(
365
529
  self, workspace_name: str, datastore_name: str
366
530
  ) -> tuple[dict[str, Any] | str, int]:
@@ -650,8 +814,8 @@ class GeoServerCloud:
650
814
  layer_name: str,
651
815
  workspace_name: str | None = None,
652
816
  datastore_name: str | None = None,
653
- title: str | dict = "Default title",
654
- abstract: str | dict = "Default abstract",
817
+ title: str | dict | None = None,
818
+ abstract: str | dict | None = None,
655
819
  attributes: dict | None = None,
656
820
  epsg: int = 4326,
657
821
  keywords: list[str] = [],
@@ -719,9 +883,10 @@ class GeoServerCloud:
719
883
  self,
720
884
  group: str,
721
885
  workspace_name: str | None,
722
- layers: list[str],
723
- title: str | dict,
724
- abstract: str | dict,
886
+ layers: list[str] | None = None,
887
+ styles: list[str] | None = None,
888
+ title: str | dict | None = None,
889
+ abstract: str | dict | None = None,
725
890
  epsg: int = 4326,
726
891
  mode: str = "SINGLE",
727
892
  enabled: bool = True,
@@ -733,10 +898,15 @@ class GeoServerCloud:
733
898
  workspace_name = workspace_name or self.default_workspace
734
899
  if not workspace_name:
735
900
  raise ValueError("Workspace not provided")
736
- if not mode in LayerGroup.modes:
901
+ if mode not in LayerGroup.modes:
737
902
  raise ValueError(
738
903
  f"Invalid mode: {mode}, possible values are: {LayerGroup.modes}"
739
904
  )
905
+ if not layers and not styles:
906
+ raise ValueError(
907
+ "Either layers or styles must be provided for a layer group"
908
+ )
909
+
740
910
  bounds = {
741
911
  "minx": utils.EPSG_BBOX[epsg]["nativeBoundingBox"]["minx"],
742
912
  "maxx": utils.EPSG_BBOX[epsg]["nativeBoundingBox"]["maxx"],
@@ -744,13 +914,23 @@ class GeoServerCloud:
744
914
  "maxy": utils.EPSG_BBOX[epsg]["nativeBoundingBox"]["maxy"],
745
915
  "crs": f"EPSG:{epsg}",
746
916
  }
917
+
918
+ publishables = None
919
+ if layers:
920
+ publishables = [f"{workspace_name}:{layer}" for layer in layers]
921
+
922
+ formatted_styles = None
923
+ if styles:
924
+ formatted_styles = [f"{workspace_name}:{style}" for style in styles]
925
+
747
926
  layer_group = LayerGroup(
748
927
  name=group,
749
928
  mode=mode,
750
929
  workspace_name=workspace_name,
751
930
  title=title,
752
931
  abstract=abstract,
753
- publishables=[f"{workspace_name}:{layer}" for layer in layers],
932
+ publishables=publishables,
933
+ styles=formatted_styles,
754
934
  bounds=bounds,
755
935
  enabled=enabled,
756
936
  advertised=advertised,
@@ -830,9 +1010,15 @@ class GeoServerCloud:
830
1010
  style_name: str,
831
1011
  filename: str,
832
1012
  workspace_name: str | None = None,
1013
+ format: str = "sld",
833
1014
  ) -> tuple[str, int]:
834
1015
  """Create a style definition"""
835
- style = Style(name=style_name, filename=filename, workspace_name=workspace_name)
1016
+ style = Style(
1017
+ name=style_name,
1018
+ filename=filename,
1019
+ workspace_name=workspace_name,
1020
+ format=format,
1021
+ )
836
1022
  return self.rest_service.create_style_definition(
837
1023
  style_name=style_name, style=style, workspace_name=workspace_name
838
1024
  )
@@ -859,21 +1045,31 @@ class GeoServerCloud:
859
1045
  file: str,
860
1046
  workspace_name: str | None = None,
861
1047
  ) -> tuple[str, int]:
862
- """Create a style (SLD) from a file, or update it if it already exists.
863
- Supported file extensions are .sld and .zip."""
864
- file_base_name = Path(file).name
865
- file_ext = Path(file).suffix
866
- content, code = self.create_style_definition(
867
- style_name, f"{file_base_name}.sld", workspace_name
868
- )
869
- if code >= 400:
870
- return content, code
1048
+ """Create a style from a file, or update it if it already exists.
1049
+ Supported file extensions are .sld, .zip and .mbstyle."""
1050
+ file_ext = Path(file).suffix.lower()
871
1051
  if file_ext == ".sld":
1052
+ style_format = "sld"
1053
+ style_definition_filename = f"{style_name}.sld"
872
1054
  file_format = "sld"
873
1055
  elif file_ext == ".zip":
1056
+ style_format = "sld"
1057
+ style_definition_filename = f"{style_name}.sld"
874
1058
  file_format = "zip"
1059
+ elif file_ext == ".mbstyle":
1060
+ style_format = "mbstyle"
1061
+ style_definition_filename = f"{style_name}.mbstyle"
1062
+ file_format = "mbstyle"
875
1063
  else:
876
1064
  raise ValueError(f"Unsupported file extension: {file_ext}")
1065
+ content, code = self.create_style_definition(
1066
+ style_name,
1067
+ style_definition_filename,
1068
+ workspace_name,
1069
+ format=style_format,
1070
+ )
1071
+ if code >= 400:
1072
+ return content, code
877
1073
  with open(f"{file}", "rb") as fs:
878
1074
  style: bytes = fs.read()
879
1075
  return self.rest_service.create_style(
@@ -106,12 +106,12 @@ class GeoServerCloudSync:
106
106
  Copy a datastore from source to destination GeoServer instance
107
107
  If deep_copy is True, copy all feature types and the corresponding layers
108
108
  """
109
- datastore, status_code = self.src_instance.get_pg_datastore(
109
+ datastore, status_code = self.src_instance.get_datastore(
110
110
  workspace_name, datastore_name
111
111
  )
112
112
  if isinstance(datastore, str):
113
113
  return datastore, status_code
114
- new_ds, new_ds_status_code = self.dst_instance.create_pg_datastore(
114
+ new_ds, new_ds_status_code = self.dst_instance.create_datastore(
115
115
  workspace_name, datastore
116
116
  )
117
117
  if self.not_ok(new_ds_status_code):
@@ -8,13 +8,13 @@ from geoservercloud.models.common import (
8
8
  )
9
9
 
10
10
 
11
- class PostGisDataStore(EntityModel):
11
+ class DataStore(EntityModel):
12
12
  def __init__(
13
13
  self,
14
14
  workspace_name: str,
15
15
  name: str,
16
16
  connection_parameters: dict,
17
- type: str = "PostGIS",
17
+ type: str,
18
18
  enabled: bool = True,
19
19
  description: str | None = None,
20
20
  default: bool | None = None,
@@ -73,7 +73,7 @@ class PostGisDataStore(EntityModel):
73
73
  data_store["workspace"]["name"],
74
74
  data_store["name"],
75
75
  connection_parameters,
76
- data_store.get("type", "PostGIS"),
76
+ data_store["type"],
77
77
  data_store.get("enabled", True),
78
78
  data_store.get("description", None),
79
79
  data_store.get("_default", None),
@@ -93,6 +93,10 @@ class LayerGroup(EntityModel):
93
93
  {"@type": "layer", "name": p.name} for p in self.publishables
94
94
  ]
95
95
  }
96
+ elif self.styles:
97
+ # Style group: empty publishables with styles
98
+ content["publishables"] = {"published": ""}
99
+
96
100
  if self.styles:
97
101
  content["styles"] = {"style": [s.asdict() for s in self.styles]}
98
102
  elif self.publishables:
@@ -9,7 +9,7 @@ from geoservercloud.models.common import BaseModel
9
9
  from geoservercloud.models.coverage import Coverage
10
10
  from geoservercloud.models.coverages import Coverages
11
11
  from geoservercloud.models.coveragestore import CoverageStore
12
- from geoservercloud.models.datastore import PostGisDataStore
12
+ from geoservercloud.models.datastore import DataStore
13
13
  from geoservercloud.models.datastores import DataStores
14
14
  from geoservercloud.models.featuretype import FeatureType
15
15
  from geoservercloud.models.featuretypes import FeatureTypes
@@ -113,33 +113,16 @@ class RestService:
113
113
  )
114
114
  return self.deserialize_response(response, DataStores)
115
115
 
116
- def get_pg_datastore(
116
+ def get_datastore(
117
117
  self, workspace_name: str, datastore_name: str
118
- ) -> tuple[PostGisDataStore | str, int]:
118
+ ) -> tuple[DataStore | str, int]:
119
119
  response: Response = self.rest_client.get(
120
120
  self.rest_endpoints.datastore(workspace_name, datastore_name)
121
121
  )
122
- return self.deserialize_response(response, PostGisDataStore)
122
+ return self.deserialize_response(response, DataStore)
123
123
 
124
- def create_pg_datastore(
125
- self, workspace_name: str, datastore: PostGisDataStore
126
- ) -> tuple[str, int]:
127
- if not self.resource_exists(
128
- self.rest_endpoints.datastore(workspace_name, datastore.name)
129
- ):
130
- response: Response = self.rest_client.post(
131
- self.rest_endpoints.datastores(workspace_name),
132
- json=datastore.post_payload(),
133
- )
134
- else:
135
- response = self.rest_client.put(
136
- self.rest_endpoints.datastore(workspace_name, datastore.name),
137
- json=datastore.put_payload(),
138
- )
139
- return response.content.decode(), response.status_code
140
-
141
- def create_jndi_datastore(
142
- self, workspace_name: str, datastore: PostGisDataStore
124
+ def create_datastore(
125
+ self, workspace_name: str, datastore: DataStore
143
126
  ) -> tuple[str, int]:
144
127
  if not self.resource_exists(
145
128
  self.rest_endpoints.datastore(workspace_name, datastore.name)
@@ -620,6 +603,8 @@ class RestService:
620
603
  headers = {"Content-Type": "application/vnd.ogc.sld+xml"}
621
604
  elif format == "zip":
622
605
  headers = {"Content-Type": "application/zip"}
606
+ elif format == "mbstyle":
607
+ headers = {"Content-Type": "application/vnd.geoserver.mbstyle+json"}
623
608
  # Do not check for existence because GeoServer throws a 500 if the style definition exists and not
624
609
  # the SLD. Besides PUT is also supported on creation
625
610
  response: Response = self.rest_client.put(
@@ -932,7 +917,7 @@ class RestService:
932
917
  url: str = f"{self.base_url}/styles/{style_name}"
933
918
  else:
934
919
  url = f"{self.base_url}/workspaces/{workspace_name}/styles/{style_name}"
935
- if format in ("json", "sld"):
920
+ if format in ("json", "sld", "mbstyle"):
936
921
  return f"{url}.{format}"
937
922
  return url
938
923
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "geoservercloud"
3
- version = "0.7.3.dev4"
3
+ version = "0.7.4.dev4"
4
4
  description = "Lightweight Python client to interact with GeoServer Cloud REST API, GeoServer ACL and OGC services"
5
5
  authors = ["Camptocamp <info@camptocamp.com>"]
6
6
  license = "BSD-2-Clause"