hydroserverpy 1.2.0__py3-none-any.whl → 1.3.0b1__py3-none-any.whl

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.

Potentially problematic release.


This version of hydroserverpy might be problematic. Click here for more details.

Files changed (47) hide show
  1. hydroserverpy/__init__.py +1 -1
  2. hydroserverpy/api/{main.py → client.py} +52 -22
  3. hydroserverpy/api/models/__init__.py +1 -2
  4. hydroserverpy/api/models/base.py +180 -47
  5. hydroserverpy/api/models/etl/data_archive.py +31 -59
  6. hydroserverpy/api/models/etl/data_source.py +34 -76
  7. hydroserverpy/api/models/etl/orchestration_system.py +21 -36
  8. hydroserverpy/api/models/iam/apikey.py +57 -38
  9. hydroserverpy/api/models/iam/collaborator.py +55 -19
  10. hydroserverpy/api/models/iam/role.py +32 -4
  11. hydroserverpy/api/models/iam/workspace.py +58 -86
  12. hydroserverpy/api/models/sta/datastream.py +122 -214
  13. hydroserverpy/api/models/sta/observation.py +101 -0
  14. hydroserverpy/api/models/sta/observed_property.py +18 -53
  15. hydroserverpy/api/models/sta/processing_level.py +16 -31
  16. hydroserverpy/api/models/sta/result_qualifier.py +16 -31
  17. hydroserverpy/api/models/sta/sensor.py +27 -88
  18. hydroserverpy/api/models/sta/thing.py +48 -152
  19. hydroserverpy/api/models/sta/unit.py +16 -29
  20. hydroserverpy/api/services/__init__.py +1 -0
  21. hydroserverpy/api/services/base.py +92 -76
  22. hydroserverpy/api/services/etl/data_archive.py +42 -72
  23. hydroserverpy/api/services/etl/data_source.py +42 -72
  24. hydroserverpy/api/services/etl/orchestration_system.py +25 -33
  25. hydroserverpy/api/services/iam/role.py +38 -0
  26. hydroserverpy/api/services/iam/workspace.py +96 -99
  27. hydroserverpy/api/services/sta/datastream.py +151 -210
  28. hydroserverpy/api/services/sta/observed_property.py +31 -49
  29. hydroserverpy/api/services/sta/processing_level.py +30 -36
  30. hydroserverpy/api/services/sta/result_qualifier.py +24 -34
  31. hydroserverpy/api/services/sta/sensor.py +34 -48
  32. hydroserverpy/api/services/sta/thing.py +96 -89
  33. hydroserverpy/api/services/sta/unit.py +30 -34
  34. hydroserverpy/api/utils.py +22 -0
  35. hydroserverpy/etl/extractors/base.py +3 -5
  36. hydroserverpy/etl/loaders/hydroserver_loader.py +1 -0
  37. hydroserverpy/etl/timestamp_parser.py +82 -48
  38. hydroserverpy/etl/transformers/base.py +6 -10
  39. hydroserverpy/etl_csv/hydroserver_etl_csv.py +1 -1
  40. {hydroserverpy-1.2.0.dist-info → hydroserverpy-1.3.0b1.dist-info}/METADATA +1 -1
  41. hydroserverpy-1.3.0b1.dist-info/RECORD +70 -0
  42. hydroserverpy/api/http.py +0 -22
  43. hydroserverpy-1.2.0.dist-info/RECORD +0 -68
  44. {hydroserverpy-1.2.0.dist-info → hydroserverpy-1.3.0b1.dist-info}/WHEEL +0 -0
  45. {hydroserverpy-1.2.0.dist-info → hydroserverpy-1.3.0b1.dist-info}/licenses/LICENSE +0 -0
  46. {hydroserverpy-1.2.0.dist-info → hydroserverpy-1.3.0b1.dist-info}/top_level.txt +0 -0
  47. {hydroserverpy-1.2.0.dist-info → hydroserverpy-1.3.0b1.dist-info}/zip-safe +0 -0
@@ -1,55 +1,54 @@
1
1
  from typing import Optional, Union, List, TYPE_CHECKING
2
2
  from uuid import UUID
3
- from ..base import EndpointService
4
3
  from hydroserverpy.api.models import OrchestrationSystem
5
-
4
+ from hydroserverpy.api.utils import normalize_uuid
5
+ from ..base import HydroServerBaseService
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from hydroserverpy import HydroServer
9
9
  from hydroserverpy.api.models import Workspace
10
10
 
11
11
 
12
- class OrchestrationSystemService(EndpointService):
13
- def __init__(self, connection: "HydroServer"):
14
- self._model = OrchestrationSystem
15
- self._api_route = "api/data"
16
- self._endpoint_route = "orchestration-systems"
17
-
18
- super().__init__(connection)
12
+ class OrchestrationSystemService(HydroServerBaseService):
13
+ def __init__(self, client: "HydroServer"):
14
+ self.model = OrchestrationSystem
15
+ super().__init__(client)
19
16
 
20
17
  def list(
21
18
  self,
22
- workspace: Optional[Union["Workspace", UUID, str]] = None,
19
+ page: int = ...,
20
+ page_size: int = ...,
21
+ order_by: List[str] = ...,
22
+ workspace: Optional[Union["Workspace", UUID, str]] = ...,
23
+ orchestration_system_type: str = ...,
24
+ fetch_all: bool = False,
23
25
  ) -> List["OrchestrationSystem"]:
24
26
  """Fetch a collection of orchestration systems."""
25
27
 
26
- workspace_id = getattr(workspace, "uid", workspace)
27
- workspace_id = str(workspace_id) if workspace_id else None
28
-
29
- return super()._list(
30
- params={"workspace_id": workspace_id} if workspace_id else {},
28
+ return super().list(
29
+ page=page,
30
+ page_size=page_size,
31
+ order_by=order_by,
32
+ workspace_id=normalize_uuid(workspace),
33
+ type=orchestration_system_type,
34
+ fetch_all=fetch_all,
31
35
  )
32
36
 
33
- def get(self, uid: Union[UUID, str]) -> "OrchestrationSystem":
34
- """Get an orchestration system by ID."""
35
-
36
- return super()._get(uid=str(uid))
37
-
38
37
  def create(
39
38
  self,
40
- workspace: Union["Workspace", UUID, str],
41
39
  name: str,
42
40
  orchestration_system_type: str,
41
+ workspace: Optional[Union["Workspace", UUID, str]] = None,
43
42
  ) -> "OrchestrationSystem":
44
43
  """Create a new orchestration system."""
45
44
 
46
- kwargs = {
45
+ body = {
47
46
  "name": name,
48
47
  "type": orchestration_system_type,
49
- "workspaceId": str(getattr(workspace, "uid", workspace)),
48
+ "workspaceId": normalize_uuid(workspace),
50
49
  }
51
50
 
52
- return super()._create(**kwargs)
51
+ return super().create(**body)
53
52
 
54
53
  def update(
55
54
  self,
@@ -59,16 +58,9 @@ class OrchestrationSystemService(EndpointService):
59
58
  ) -> "OrchestrationSystem":
60
59
  """Update an orchestration system."""
61
60
 
62
- kwargs = {
61
+ body = {
63
62
  "name": name,
64
63
  "type": orchestration_system_type,
65
64
  }
66
65
 
67
- return super()._update(
68
- uid=str(uid), **{k: v for k, v in kwargs.items() if v is not ...}
69
- )
70
-
71
- def delete(self, uid: Union[UUID, str]) -> None:
72
- """Delete an orchestration system."""
73
-
74
- super()._delete(uid=str(uid))
66
+ return super().update(uid=str(uid), **body)
@@ -0,0 +1,38 @@
1
+ from typing import TYPE_CHECKING, Union, List, Optional
2
+ from uuid import UUID
3
+ from hydroserverpy.api.models import Role
4
+ from hydroserverpy.api.utils import normalize_uuid
5
+ from ..base import HydroServerBaseService
6
+
7
+
8
+ if TYPE_CHECKING:
9
+ from hydroserverpy import HydroServer
10
+ from hydroserverpy.api.models import Workspace
11
+
12
+
13
+ class RoleService(HydroServerBaseService):
14
+ def __init__(self, client: "HydroServer"):
15
+ self.model = Role
16
+ super().__init__(client)
17
+
18
+ def list(
19
+ self,
20
+ page: int = ...,
21
+ page_size: int = ...,
22
+ order_by: List[str] = ...,
23
+ workspace: Optional[Union["Workspace", UUID, str]] = ...,
24
+ is_user_role: bool = ...,
25
+ is_apikey_role: bool = ...,
26
+ fetch_all: bool = False,
27
+ ) -> List["Role"]:
28
+ """Fetch a collection of HydroServer roles."""
29
+
30
+ return super().list(
31
+ page=page,
32
+ page_size=page_size,
33
+ order_by=order_by,
34
+ fetch_all=fetch_all,
35
+ workspace_id=normalize_uuid(workspace),
36
+ is_user_role=is_user_role,
37
+ is_apikey_role=is_apikey_role,
38
+ )
@@ -1,72 +1,69 @@
1
+ import json
1
2
  from typing import TYPE_CHECKING, Union, List, Tuple, Optional
2
3
  from pydantic import EmailStr
3
4
  from uuid import UUID
4
5
  from datetime import datetime
5
6
  from hydroserverpy.api.models import Workspace, Role, Collaborator, APIKey
6
- from ..base import EndpointService
7
+ from hydroserverpy.api.utils import normalize_uuid
8
+ from ..base import HydroServerBaseService
7
9
 
8
10
 
9
11
  if TYPE_CHECKING:
10
12
  from hydroserverpy import HydroServer
11
13
 
12
14
 
13
- class WorkspaceService(EndpointService):
14
- def __init__(self, connection: "HydroServer"):
15
- self._model = Workspace
16
- self._api_route = "api/auth"
17
- self._endpoint_route = "workspaces"
15
+ class WorkspaceService(HydroServerBaseService):
16
+ def __init__(self, client: "HydroServer"):
17
+ self.model = Workspace
18
+ super().__init__(client)
18
19
 
19
- super().__init__(connection)
20
-
21
- def list(self, associated_only: bool = False) -> List["Workspace"]:
22
- """Fetch a collection of HydroServer resources."""
23
-
24
- return super()._list(params={"associated_only": associated_only})
25
-
26
- def get(self, uid: Union[UUID, str]) -> "Workspace":
27
- """Get a workspace by ID."""
28
-
29
- return super()._get(uid=str(uid))
20
+ def list(
21
+ self,
22
+ page: int = ...,
23
+ page_size: int = ...,
24
+ order_by: List[str] = ...,
25
+ is_private: bool = ...,
26
+ is_associated: bool = ...,
27
+ fetch_all: bool = False,
28
+ ) -> List["Workspace"]:
29
+ """Fetch a collection of HydroServer workspaces."""
30
+
31
+ return super().list(
32
+ page=page,
33
+ page_size=page_size,
34
+ order_by=order_by,
35
+ fetch_all=fetch_all,
36
+ is_private=is_private,
37
+ is_associated=is_associated,
38
+ )
30
39
 
31
40
  def create(self, name: str, is_private: bool, **_) -> "Workspace":
32
41
  """Create a new workspace."""
33
42
 
34
- kwargs = {"name": name, "isPrivate": is_private}
35
-
36
- return super()._create(**kwargs)
43
+ return super().create(
44
+ name=name,
45
+ is_private=is_private,
46
+ )
37
47
 
38
48
  def update(
39
49
  self, uid: Union[UUID, str], name: str = ..., is_private: bool = ..., **_
40
50
  ) -> "Workspace":
41
51
  """Update a workspace."""
42
52
 
43
- kwargs = {"name": name, "isPrivate": is_private}
44
-
45
- return super()._update(
46
- uid=str(uid), **{k: v for k, v in kwargs.items() if v is not ...}
53
+ return super().update(
54
+ uid=uid,
55
+ name=name,
56
+ is_private=is_private,
47
57
  )
48
58
 
49
- def delete(self, uid: Union[UUID, str]) -> None:
50
- """Delete a workspace."""
51
-
52
- super()._delete(uid=str(uid))
53
-
54
- def list_roles(self, uid: Union[UUID, str]) -> List["Role"]:
55
- """Get all roles that can be assigned within a workspace."""
56
-
57
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/roles"
58
- response = self._connection.request("get", path)
59
-
60
- return [Role(**obj) for obj in response.json()]
61
-
62
59
  def list_collaborators(self, uid: Union[UUID, str]) -> List["Collaborator"]:
63
60
  """Get all collaborators associated with a workspace."""
64
61
 
65
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/collaborators"
66
- response = self._connection.request("get", path)
62
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/collaborators"
63
+ response = self.client.request("get", path)
67
64
 
68
65
  return [
69
- Collaborator(_connection=self._connection, workspace_id=uid, **obj)
66
+ Collaborator(client=self.client, uid=None, workspace_id=uid, **obj)
70
67
  for obj in response.json()
71
68
  ]
72
69
 
@@ -75,15 +72,18 @@ class WorkspaceService(EndpointService):
75
72
  ) -> "Collaborator":
76
73
  """Add a collaborator to a workspace."""
77
74
 
78
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/collaborators"
79
- response = self._connection.request(
80
- "post",
81
- path,
82
- json={"email": email, "roleId": str(getattr(role, "uid", role))},
83
- )
75
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/collaborators"
76
+ headers = {"Content-type": "application/json"}
77
+ body = {
78
+ "email": email,
79
+ "roleId": normalize_uuid(role)
80
+ }
81
+ response = self.client.request(
82
+ "post", path, headers=headers, data=json.dumps(body, default=self.default_serializer)
83
+ ).json()
84
84
 
85
85
  return Collaborator(
86
- _connection=self._connection, workspace_id=uid, **response.json()
86
+ client=self.client, uid=None, workspace_id=uid, **response
87
87
  )
88
88
 
89
89
  def edit_collaborator_role(
@@ -91,66 +91,73 @@ class WorkspaceService(EndpointService):
91
91
  ) -> "Collaborator":
92
92
  """Edit the role of a collaborator in a workspace."""
93
93
 
94
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/collaborators"
95
- response = self._connection.request(
96
- "put",
97
- path,
98
- json={"email": email, "roleId": str(getattr(role, "uid", role))},
94
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/collaborators"
95
+ headers = {"Content-type": "application/json"}
96
+ body = {
97
+ "email": email,
98
+ "roleId": normalize_uuid(role)
99
+ }
100
+
101
+ response = self.client.request(
102
+ "put", path, headers=headers, data=json.dumps(body, default=self.default_serializer)
99
103
  )
100
104
 
101
105
  return Collaborator(
102
- _connection=self._connection, workspace_id=uid, **response.json()
106
+ client=self.client, uid=None, workspace_id=uid, **response.json()
103
107
  )
104
108
 
105
109
  def remove_collaborator(self, uid: Union[UUID, str], email: EmailStr) -> None:
106
110
  """Remove a collaborator from a workspace."""
107
111
 
108
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/collaborators"
109
- self._connection.request("delete", path, json={"email": email})
112
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/collaborators"
113
+ self.client.request("delete", path, json={"email": email})
110
114
 
111
115
  def list_api_keys(self, uid: Union[UUID, str]) -> List["APIKey"]:
112
116
  """Get all API keys associated with a workspace."""
113
117
 
114
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/api-keys"
115
- response = self._connection.request("get", path)
118
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/api-keys"
119
+ response = self.client.request("get", path)
116
120
 
117
- return [APIKey(_connection=self._connection, _uid=UUID(str(obj.pop("id"))), **obj) for obj in response.json()]
121
+ return [
122
+ APIKey(client=self.client, **obj)
123
+ for obj in response.json()
124
+ ]
118
125
 
119
126
  def get_api_key(self, uid: Union[UUID, str], api_key_id: Union[UUID, str]) -> "APIKey":
120
127
  """Get an API key associated with a workspace."""
121
128
 
122
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/api-keys/{api_key_id}"
123
- response = self._connection.request("get", path).json()
129
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/api-keys/{api_key_id}"
130
+ response = self.client.request("get", path)
124
131
 
125
- return APIKey(_connection=self._connection, _uid=UUID(str(response.pop("id"))), **response)
132
+ return APIKey(client=self.client, **response.json())
126
133
 
127
134
  def create_api_key(
128
135
  self,
129
136
  uid: Union[UUID, str],
130
- role: Union["Role", UUID, str],
131
137
  name: str,
138
+ role: Union["Role", UUID, str],
132
139
  description: Optional[str] = None,
133
140
  is_active: bool = True,
134
141
  expires_at: Optional[datetime] = None
135
142
  ) -> Tuple["APIKey", str]:
136
143
  """Create an API key for a workspace."""
137
144
 
138
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/api-keys"
139
- kwargs = {
140
- "roleId": str(getattr(role, "uid", role)),
145
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/api-keys"
146
+ headers = {"Content-type": "application/json"}
147
+ body = {
148
+ "roleId": normalize_uuid(role),
141
149
  "name": name,
142
150
  "description": description,
143
151
  "isActive": is_active,
144
152
  "expiresAt": expires_at
145
153
  }
146
- headers = {"Content-type": "application/json"}
147
154
 
148
- response = self._connection.request(
149
- "post", path, headers=headers, json=self._to_iso_time(kwargs)
155
+ response = self.client.request(
156
+ "post", path, headers=headers, data=json.dumps(body, default=self.default_serializer),
150
157
  ).json()
151
158
 
152
159
  return APIKey(
153
- _connection=self._connection, _uid=UUID(str(response.pop("id"))), **response
160
+ client=self.client, **response
154
161
  ), response["key"]
155
162
 
156
163
  def update_api_key(
@@ -165,32 +172,22 @@ class WorkspaceService(EndpointService):
165
172
  ) -> "APIKey":
166
173
  """Update an existing API key."""
167
174
 
168
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/api-keys/{str(api_key_id)}"
169
- kwargs = {
170
- "roleId": ... if role is ... else str(getattr(role, "uid", role)),
175
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/api-keys/{api_key_id}"
176
+ headers = {"Content-type": "application/json"}
177
+ body = {
178
+ "roleId": normalize_uuid(role),
171
179
  "name": name,
172
180
  "description": description,
173
181
  "isActive": is_active,
174
- "expiresAt": (
175
- expires_at.isoformat()
176
- if expires_at
177
- not in (
178
- None,
179
- ...,
180
- )
181
- else expires_at
182
- )
182
+ "expiresAt": expires_at
183
183
  }
184
- headers = {"Content-type": "application/json"}
184
+ body = {k: v for k, v in body.items() if v is not ...}
185
185
 
186
- response = self._connection.request(
187
- "patch", path, headers=headers,
188
- json={k: v for k, v in kwargs.items() if v is not ...}
186
+ response = self.client.request(
187
+ "patch", path, headers=headers, data=json.dumps(body, default=self.default_serializer),
189
188
  ).json()
190
189
 
191
- return APIKey(
192
- _connection=self._connection, _uid=UUID(str(response.pop("id"))), **response
193
- )
190
+ return APIKey(client=self.client, **response)
194
191
 
195
192
  def delete_api_key(
196
193
  self,
@@ -199,8 +196,8 @@ class WorkspaceService(EndpointService):
199
196
  ):
200
197
  """Delete an existing API key."""
201
198
 
202
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/api-keys/{str(api_key_id)}"
203
- self._connection.request("delete", path)
199
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/api-keys/{api_key_id}"
200
+ self.client.request("delete", path)
204
201
 
205
202
  def regenerate_api_key(
206
203
  self,
@@ -209,27 +206,27 @@ class WorkspaceService(EndpointService):
209
206
  ):
210
207
  """Regenerate an existing API key."""
211
208
 
212
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/api-keys/{str(api_key_id)}/regenerate"
213
- response = self._connection.request("put", path).json()
209
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/api-keys/{api_key_id}/regenerate"
210
+ response = self.client.request("put", path).json()
214
211
 
215
212
  return APIKey(
216
- _connection=self._connection, _uid=UUID(str(response.pop("id"))), **response
213
+ client=self.client, **response
217
214
  ), response["key"]
218
215
 
219
216
  def transfer_ownership(self, uid: Union[UUID, str], email: str) -> None:
220
217
  """Transfer ownership of a workspace to another HydroServer user."""
221
218
 
222
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/transfer"
223
- self._connection.request("post", path, json={"newOwner": email})
219
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/transfer"
220
+ self.client.request("post", path, json={"newOwner": email})
224
221
 
225
222
  def accept_ownership_transfer(self, uid: Union[UUID, str]) -> None:
226
223
  """Accept ownership transfer of a workspace."""
227
224
 
228
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/transfer"
229
- self._connection.request("put", path)
225
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/transfer"
226
+ self.client.request("put", path)
230
227
 
231
228
  def cancel_ownership_transfer(self, uid: Union[UUID, str]) -> None:
232
229
  """Cancel ownership transfer of a workspace."""
233
230
 
234
- path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}/transfer"
235
- self._connection.request("delete", path)
231
+ path = f"/{self.client.base_route}/{self.model.get_route()}/{str(uid)}/transfer"
232
+ self.client.request("delete", path)