geoservercloud 0.2.3.dev3__tar.gz → 0.2.4.dev2__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.
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/PKG-INFO +1 -1
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/geoservercloud.py +188 -10
- geoservercloud-0.2.4.dev2/geoservercloud/gridsets/21781.xml +83 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/pyproject.toml +1 -1
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/LICENSE +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/README.md +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/__init__.py +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/gridsets/2056.xml +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/gridsets/3857.xml +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/restservice.py +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/templates.py +0 -0
- {geoservercloud-0.2.3.dev3 → geoservercloud-0.2.4.dev2}/geoservercloud/utils.py +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os.path
|
|
2
|
+
from json import JSONDecodeError
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
@@ -92,6 +93,9 @@ class GeoServerCloud:
|
|
|
92
93
|
return response
|
|
93
94
|
|
|
94
95
|
def delete_workspace(self, workspace: str) -> Response:
|
|
96
|
+
"""
|
|
97
|
+
Delete a GeoServer workspace (recursively)
|
|
98
|
+
"""
|
|
95
99
|
path: str = f"/rest/workspaces/{workspace}.json?recurse=true"
|
|
96
100
|
response: Response = self.delete_request(path)
|
|
97
101
|
if self.default_workspace == workspace:
|
|
@@ -112,6 +116,9 @@ class GeoServerCloud:
|
|
|
112
116
|
)
|
|
113
117
|
|
|
114
118
|
def publish_workspace(self, workspace) -> Response:
|
|
119
|
+
"""
|
|
120
|
+
Publish the WMS service for a given workspace
|
|
121
|
+
"""
|
|
115
122
|
path: str = f"{self.workspace_wms_settings_path(workspace)}"
|
|
116
123
|
|
|
117
124
|
data: dict[str, dict[str, Any]] = Templates.workspace_wms(workspace)
|
|
@@ -120,6 +127,9 @@ class GeoServerCloud:
|
|
|
120
127
|
def set_default_locale_for_service(
|
|
121
128
|
self, workspace: str, locale: str | None
|
|
122
129
|
) -> Response:
|
|
130
|
+
"""
|
|
131
|
+
Set a default language for localized WMS requests
|
|
132
|
+
"""
|
|
123
133
|
path: str = self.workspace_wms_settings_path(workspace)
|
|
124
134
|
data: dict[str, dict[str, Any]] = {
|
|
125
135
|
"wms": {
|
|
@@ -129,6 +139,9 @@ class GeoServerCloud:
|
|
|
129
139
|
return self.put_request(path, json=data)
|
|
130
140
|
|
|
131
141
|
def unset_default_locale_for_service(self, workspace) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Remove the default language for localized WMS requests
|
|
144
|
+
"""
|
|
132
145
|
self.set_default_locale_for_service(workspace, None)
|
|
133
146
|
|
|
134
147
|
def create_pg_datastore(
|
|
@@ -447,6 +460,9 @@ class GeoServerCloud:
|
|
|
447
460
|
styles: list[str] | None = None,
|
|
448
461
|
language: str | None = None,
|
|
449
462
|
) -> ResponseWrapper | None:
|
|
463
|
+
"""
|
|
464
|
+
WMS GetMap request
|
|
465
|
+
"""
|
|
450
466
|
if not self.wms:
|
|
451
467
|
self.create_wms()
|
|
452
468
|
params: dict[str, Any] = {
|
|
@@ -478,6 +494,9 @@ class GeoServerCloud:
|
|
|
478
494
|
styles: list[str] | None = None,
|
|
479
495
|
xy: list[float] = [0, 0],
|
|
480
496
|
) -> ResponseWrapper | None:
|
|
497
|
+
"""
|
|
498
|
+
WMS GetFeatureInfo request
|
|
499
|
+
"""
|
|
481
500
|
if not self.wms:
|
|
482
501
|
self.create_wms()
|
|
483
502
|
params = {
|
|
@@ -504,6 +523,9 @@ class GeoServerCloud:
|
|
|
504
523
|
style: str | None = None,
|
|
505
524
|
workspace: str | None = None,
|
|
506
525
|
) -> Response:
|
|
526
|
+
"""
|
|
527
|
+
WMS GetLegendGraphic request
|
|
528
|
+
"""
|
|
507
529
|
path: str
|
|
508
530
|
if not workspace:
|
|
509
531
|
path = "/wms"
|
|
@@ -526,6 +548,9 @@ class GeoServerCloud:
|
|
|
526
548
|
def get_tile(
|
|
527
549
|
self, layer, format, tile_matrix_set, tile_matrix, row, column
|
|
528
550
|
) -> ResponseWrapper | None:
|
|
551
|
+
"""
|
|
552
|
+
WMTS GetTile request
|
|
553
|
+
"""
|
|
529
554
|
if not self.wmts:
|
|
530
555
|
self.create_wmts()
|
|
531
556
|
if self.wmts:
|
|
@@ -539,18 +564,108 @@ class GeoServerCloud:
|
|
|
539
564
|
)
|
|
540
565
|
return None
|
|
541
566
|
|
|
567
|
+
def get_feature(
|
|
568
|
+
self,
|
|
569
|
+
workspace: str,
|
|
570
|
+
type_name: str,
|
|
571
|
+
feature_id: int | None = None,
|
|
572
|
+
max_feature: int | None = None,
|
|
573
|
+
format: str = "application/json",
|
|
574
|
+
) -> dict[str, Any] | bytes:
|
|
575
|
+
"""WFS GetFeature request
|
|
576
|
+
Return the feature(s) as dict if found, otherwise return the raw response content as bytes
|
|
577
|
+
"""
|
|
578
|
+
path = f"/{workspace}/wfs"
|
|
579
|
+
params = {
|
|
580
|
+
"service": "WFS",
|
|
581
|
+
"version": "1.1.0",
|
|
582
|
+
"request": "GetFeature",
|
|
583
|
+
"typeName": type_name,
|
|
584
|
+
"outputFormat": format,
|
|
585
|
+
}
|
|
586
|
+
if feature_id:
|
|
587
|
+
params["featureID"] = str(feature_id)
|
|
588
|
+
if max_feature:
|
|
589
|
+
params["maxFeatures"] = str(max_feature)
|
|
590
|
+
response = self.get_request(path, params=params)
|
|
591
|
+
try:
|
|
592
|
+
return response.json()
|
|
593
|
+
except JSONDecodeError:
|
|
594
|
+
return response.content
|
|
595
|
+
|
|
596
|
+
def describe_feature_type(
|
|
597
|
+
self,
|
|
598
|
+
workspace: str,
|
|
599
|
+
type_name: str | None = None,
|
|
600
|
+
format: str = "application/json",
|
|
601
|
+
) -> dict[str, Any] | bytes:
|
|
602
|
+
"""WFS DescribeFeatureType request
|
|
603
|
+
Return the feature type(s) as dict if found, otherwise return the raw response content as bytes
|
|
604
|
+
"""
|
|
605
|
+
path = f"/{workspace}/wfs"
|
|
606
|
+
params = {
|
|
607
|
+
"service": "WFS",
|
|
608
|
+
"version": "1.1.0",
|
|
609
|
+
"request": "DescribeFeatureType",
|
|
610
|
+
"outputFormat": format,
|
|
611
|
+
}
|
|
612
|
+
if type_name:
|
|
613
|
+
params["typeName"] = type_name
|
|
614
|
+
response = self.get_request(path, params=params)
|
|
615
|
+
try:
|
|
616
|
+
return response.json()
|
|
617
|
+
except JSONDecodeError:
|
|
618
|
+
return response.content
|
|
619
|
+
|
|
620
|
+
def get_property_value(
|
|
621
|
+
self,
|
|
622
|
+
workspace: str,
|
|
623
|
+
type_name: str,
|
|
624
|
+
property: str,
|
|
625
|
+
) -> dict | list | bytes:
|
|
626
|
+
"""WFS GetPropertyValue request
|
|
627
|
+
Return the properties as dict (if one feature was found), a list (if multiple features were found)
|
|
628
|
+
or an empty dict if no feature was found. Otherwise throw a requests.exceptions.HTTPError
|
|
629
|
+
"""
|
|
630
|
+
path = f"/{workspace}/wfs"
|
|
631
|
+
params = {
|
|
632
|
+
"service": "WFS",
|
|
633
|
+
"version": "2.0.0",
|
|
634
|
+
"request": "GetPropertyValue",
|
|
635
|
+
"typeNames": type_name,
|
|
636
|
+
"valueReference": property,
|
|
637
|
+
}
|
|
638
|
+
response = self.get_request(path, params=params)
|
|
639
|
+
value_collection = xmltodict.parse(response.content).get("wfs:ValueCollection")
|
|
640
|
+
if not value_collection:
|
|
641
|
+
return response.content
|
|
642
|
+
else:
|
|
643
|
+
return value_collection.get("wfs:member", {})
|
|
644
|
+
|
|
542
645
|
def create_role(self, role_name: str) -> Response:
|
|
646
|
+
"""
|
|
647
|
+
Create a GeoServer role
|
|
648
|
+
"""
|
|
543
649
|
return self.post_request(f"/rest/security/roles/role/{role_name}")
|
|
544
650
|
|
|
545
651
|
def delete_role(self, role_name: str) -> Response:
|
|
652
|
+
"""
|
|
653
|
+
Delete a GeoServer role
|
|
654
|
+
"""
|
|
546
655
|
return self.delete_request(f"/rest/security/roles/role/{role_name}")
|
|
547
656
|
|
|
548
657
|
def create_role_if_not_exists(self, role_name: str) -> Response | None:
|
|
658
|
+
"""
|
|
659
|
+
Create a GeoServer role if it does not yet exist
|
|
660
|
+
"""
|
|
549
661
|
if self.role_exists(role_name):
|
|
550
662
|
return None
|
|
551
663
|
return self.create_role(role_name)
|
|
552
664
|
|
|
553
665
|
def role_exists(self, role_name: str) -> bool:
|
|
666
|
+
"""
|
|
667
|
+
Check if a GeoServer role exists
|
|
668
|
+
"""
|
|
554
669
|
response = self.get_request(
|
|
555
670
|
f"/rest/security/roles", headers={"Accept": "application/json"}
|
|
556
671
|
)
|
|
@@ -565,6 +680,9 @@ class GeoServerCloud:
|
|
|
565
680
|
user: str | None = None,
|
|
566
681
|
workspace: str | None = None,
|
|
567
682
|
) -> Response:
|
|
683
|
+
"""
|
|
684
|
+
Create a GeoServer ACL admin rule
|
|
685
|
+
"""
|
|
568
686
|
path = "/acl/api/adminrules"
|
|
569
687
|
return self.post_request(
|
|
570
688
|
path,
|
|
@@ -578,44 +696,101 @@ class GeoServerCloud:
|
|
|
578
696
|
)
|
|
579
697
|
|
|
580
698
|
def delete_acl_admin_rule(self, id: int) -> Response:
|
|
699
|
+
"""
|
|
700
|
+
Delete a GeoServer ACL admin rule by id
|
|
701
|
+
"""
|
|
581
702
|
path = f"/acl/api/adminrules/id/{id}"
|
|
582
703
|
return self.delete_request(path)
|
|
583
704
|
|
|
584
705
|
def delete_all_acl_admin_rules(self) -> Response:
|
|
706
|
+
"""
|
|
707
|
+
Delete all existing GeoServer ACL admin rules
|
|
708
|
+
"""
|
|
585
709
|
path = "/acl/api/adminrules"
|
|
586
710
|
return self.delete_request(path)
|
|
587
711
|
|
|
712
|
+
def get_acl_rules(self) -> dict[str, Any]:
|
|
713
|
+
"""
|
|
714
|
+
Return all GeoServer ACL data rules
|
|
715
|
+
"""
|
|
716
|
+
path = "/acl/api/rules"
|
|
717
|
+
response = self.get_request(path)
|
|
718
|
+
return response.json()
|
|
719
|
+
|
|
720
|
+
def create_acl_rules_for_requests(
|
|
721
|
+
self,
|
|
722
|
+
requests: list[str],
|
|
723
|
+
priority: int = 0,
|
|
724
|
+
access: str = "DENY",
|
|
725
|
+
role: str | None = None,
|
|
726
|
+
service: str | None = None,
|
|
727
|
+
workspace: str | None = None,
|
|
728
|
+
) -> list[Response]:
|
|
729
|
+
"""
|
|
730
|
+
Create ACL rules for multiple type of OGC requests
|
|
731
|
+
"""
|
|
732
|
+
responses = []
|
|
733
|
+
for request in requests:
|
|
734
|
+
responses.append(
|
|
735
|
+
self.create_acl_rule(
|
|
736
|
+
priority=priority,
|
|
737
|
+
access=access,
|
|
738
|
+
role=role,
|
|
739
|
+
request=request,
|
|
740
|
+
service=service,
|
|
741
|
+
workspace=workspace,
|
|
742
|
+
)
|
|
743
|
+
)
|
|
744
|
+
return responses
|
|
745
|
+
|
|
588
746
|
def create_acl_rule(
|
|
589
747
|
self,
|
|
590
748
|
priority: int = 0,
|
|
591
749
|
access: str = "DENY",
|
|
592
750
|
role: str | None = None,
|
|
751
|
+
user: str | None = None,
|
|
593
752
|
service: str | None = None,
|
|
753
|
+
request: str | None = None,
|
|
594
754
|
workspace: str | None = None,
|
|
595
755
|
) -> Response:
|
|
756
|
+
"""
|
|
757
|
+
Create a GeoServer ACL data rule
|
|
758
|
+
"""
|
|
596
759
|
path = "/acl/api/rules"
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
json=
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
760
|
+
json = {"priority": priority, "access": access}
|
|
761
|
+
if role:
|
|
762
|
+
json["role"] = role
|
|
763
|
+
if user:
|
|
764
|
+
json["user"] = user
|
|
765
|
+
if service:
|
|
766
|
+
json["service"] = service
|
|
767
|
+
if request:
|
|
768
|
+
json["request"] = request
|
|
769
|
+
if workspace:
|
|
770
|
+
json["workspace"] = workspace
|
|
771
|
+
return self.post_request(path, json=json)
|
|
607
772
|
|
|
608
773
|
def delete_all_acl_rules(self) -> Response:
|
|
774
|
+
"""
|
|
775
|
+
Delete all existing GeoServer ACL data rules
|
|
776
|
+
"""
|
|
609
777
|
path = "/acl/api/rules"
|
|
610
778
|
return self.delete_request(path)
|
|
611
779
|
|
|
612
780
|
def create_or_update_resource(self, path, resource_path, payload) -> Response:
|
|
781
|
+
"""
|
|
782
|
+
Create a GeoServer resource or update it if it already exists
|
|
783
|
+
"""
|
|
613
784
|
if not self.resource_exists(resource_path):
|
|
614
785
|
return self.post_request(path, json=payload)
|
|
615
786
|
else:
|
|
616
787
|
return self.put_request(resource_path, json=payload)
|
|
617
788
|
|
|
618
789
|
def create_gridset(self, epsg: int) -> Response | None:
|
|
790
|
+
"""
|
|
791
|
+
Create a gridset for GeoWebCache for a given projection
|
|
792
|
+
Supported EPSG codes are 2056, 21781 and 3857
|
|
793
|
+
"""
|
|
619
794
|
resource_path: str = f"/gwc/rest/gridsets/EPSG:{epsg}.xml"
|
|
620
795
|
if self.resource_exists(resource_path):
|
|
621
796
|
return None
|
|
@@ -628,6 +803,9 @@ class GeoServerCloud:
|
|
|
628
803
|
return self.put_request(resource_path, data=data, headers=headers)
|
|
629
804
|
|
|
630
805
|
def resource_exists(self, path: str) -> bool:
|
|
806
|
+
"""
|
|
807
|
+
Check if a resource (given its path) exists in GeoServer
|
|
808
|
+
"""
|
|
631
809
|
# GeoServer raises a 500 when posting to a datastore or feature type that already exists, so first do
|
|
632
810
|
# a get request
|
|
633
811
|
response = self.get_request(path)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<gridSet>
|
|
3
|
+
<name>EPSG:21781</name>
|
|
4
|
+
<srs>
|
|
5
|
+
<number>21781</number>
|
|
6
|
+
</srs>
|
|
7
|
+
<extent>
|
|
8
|
+
<coords>
|
|
9
|
+
<double>420000.0</double>
|
|
10
|
+
<double>-674000.0</double>
|
|
11
|
+
<double>1444000.0</double>
|
|
12
|
+
<double>350000.0</double>
|
|
13
|
+
</coords>
|
|
14
|
+
</extent>
|
|
15
|
+
<resolutions>
|
|
16
|
+
<double>4000.0</double>
|
|
17
|
+
<double>3750.0</double>
|
|
18
|
+
<double>3500.0</double>
|
|
19
|
+
<double>3250.0</double>
|
|
20
|
+
<double>3000.0</double>
|
|
21
|
+
<double>2750.0</double>
|
|
22
|
+
<double>2500.0</double>
|
|
23
|
+
<double>2250.0</double>
|
|
24
|
+
<double>2000.0</double>
|
|
25
|
+
<double>1750.0</double>
|
|
26
|
+
<double>1500.0</double>
|
|
27
|
+
<double>1250.0</double>
|
|
28
|
+
<double>1000.0</double>
|
|
29
|
+
<double>750.0</double>
|
|
30
|
+
<double>650.0</double>
|
|
31
|
+
<double>500.0</double>
|
|
32
|
+
<double>250.0</double>
|
|
33
|
+
<double>100.0</double>
|
|
34
|
+
<double>50.0</double>
|
|
35
|
+
<double>20.0</double>
|
|
36
|
+
<double>10.0</double>
|
|
37
|
+
<double>5.0</double>
|
|
38
|
+
<double>2.5</double>
|
|
39
|
+
<double>2.0</double>
|
|
40
|
+
<double>1.5</double>
|
|
41
|
+
<double>1.0</double>
|
|
42
|
+
<double>0.5</double>
|
|
43
|
+
<double>0.25</double>
|
|
44
|
+
<double>0.1</double>
|
|
45
|
+
</resolutions>
|
|
46
|
+
<scaleNames>
|
|
47
|
+
<string>EPSG:21781:0</string>
|
|
48
|
+
<string>EPSG:21781:1</string>
|
|
49
|
+
<string>EPSG:21781:2</string>
|
|
50
|
+
<string>EPSG:21781:3</string>
|
|
51
|
+
<string>EPSG:21781:4</string>
|
|
52
|
+
<string>EPSG:21781:5</string>
|
|
53
|
+
<string>EPSG:21781:6</string>
|
|
54
|
+
<string>EPSG:21781:7</string>
|
|
55
|
+
<string>EPSG:21781:8</string>
|
|
56
|
+
<string>EPSG:21781:9</string>
|
|
57
|
+
<string>EPSG:21781:10</string>
|
|
58
|
+
<string>EPSG:21781:11</string>
|
|
59
|
+
<string>EPSG:21781:12</string>
|
|
60
|
+
<string>EPSG:21781:13</string>
|
|
61
|
+
<string>EPSG:21781:14</string>
|
|
62
|
+
<string>EPSG:21781:15</string>
|
|
63
|
+
<string>EPSG:21781:16</string>
|
|
64
|
+
<string>EPSG:21781:17</string>
|
|
65
|
+
<string>EPSG:21781:18</string>
|
|
66
|
+
<string>EPSG:21781:19</string>
|
|
67
|
+
<string>EPSG:21781:20</string>
|
|
68
|
+
<string>EPSG:21781:21</string>
|
|
69
|
+
<string>EPSG:21781:22</string>
|
|
70
|
+
<string>EPSG:21781:23</string>
|
|
71
|
+
<string>EPSG:21781:24</string>
|
|
72
|
+
<string>EPSG:21781:25</string>
|
|
73
|
+
<string>EPSG:21781:26</string>
|
|
74
|
+
<string>EPSG:21781:27</string>
|
|
75
|
+
<string>EPSG:21781:28</string>
|
|
76
|
+
</scaleNames>
|
|
77
|
+
<tileHeight>256</tileHeight>
|
|
78
|
+
<tileWidth>256</tileWidth>
|
|
79
|
+
<yCoordinateFirst>false</yCoordinateFirst>
|
|
80
|
+
<alignTopLeft>false</alignTopLeft>
|
|
81
|
+
<metersPerUnit>1.0</metersPerUnit>
|
|
82
|
+
<pixelSize>2.8E-4</pixelSize>
|
|
83
|
+
</gridSet>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "geoservercloud"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4.dev2"
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|