hydroserverpy 0.4.0__py3-none-any.whl → 0.5.0b2__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.
- hydroserverpy/__init__.py +2 -3
- hydroserverpy/api/http.py +22 -0
- hydroserverpy/api/main.py +173 -0
- hydroserverpy/api/models/__init__.py +21 -0
- hydroserverpy/api/models/base.py +74 -0
- hydroserverpy/api/models/etl/__init__.py +0 -0
- hydroserverpy/api/models/etl/data_archive.py +105 -0
- hydroserverpy/api/models/etl/data_source.py +150 -0
- hydroserverpy/api/models/etl/orchestration_configuration.py +35 -0
- hydroserverpy/api/models/etl/orchestration_system.py +78 -0
- hydroserverpy/api/models/iam/__init__.py +0 -0
- hydroserverpy/api/models/iam/account.py +12 -0
- hydroserverpy/api/models/iam/collaborator.py +34 -0
- hydroserverpy/api/models/iam/role.py +10 -0
- hydroserverpy/api/models/iam/workspace.py +238 -0
- hydroserverpy/api/models/sta/__init__.py +0 -0
- hydroserverpy/api/models/sta/datastream.py +338 -0
- hydroserverpy/api/models/sta/observed_property.py +72 -0
- hydroserverpy/api/models/sta/processing_level.py +50 -0
- hydroserverpy/api/models/sta/result_qualifier.py +49 -0
- hydroserverpy/api/models/sta/sensor.py +105 -0
- hydroserverpy/api/models/sta/thing.py +217 -0
- hydroserverpy/api/models/sta/unit.py +49 -0
- hydroserverpy/api/services/__init__.py +11 -0
- hydroserverpy/api/services/base.py +102 -0
- hydroserverpy/api/services/etl/__init__.py +0 -0
- hydroserverpy/api/services/etl/data_archive.py +196 -0
- hydroserverpy/api/services/etl/data_source.py +196 -0
- hydroserverpy/api/services/etl/orchestration_system.py +74 -0
- hydroserverpy/api/services/iam/__init__.py +0 -0
- hydroserverpy/api/services/iam/workspace.py +126 -0
- hydroserverpy/api/services/sta/__init__.py +0 -0
- hydroserverpy/api/services/sta/datastream.py +354 -0
- hydroserverpy/api/services/sta/observed_property.py +100 -0
- hydroserverpy/api/services/sta/processing_level.py +78 -0
- hydroserverpy/api/services/sta/result_qualifier.py +74 -0
- hydroserverpy/api/services/sta/sensor.py +116 -0
- hydroserverpy/api/services/sta/thing.py +188 -0
- hydroserverpy/api/services/sta/unit.py +82 -0
- hydroserverpy/etl/loaders/hydroserver_loader.py +1 -1
- hydroserverpy/etl_csv/hydroserver_etl_csv.py +49 -34
- {hydroserverpy-0.4.0.dist-info → hydroserverpy-0.5.0b2.dist-info}/METADATA +4 -3
- hydroserverpy-0.5.0b2.dist-info/RECORD +66 -0
- {hydroserverpy-0.4.0.dist-info → hydroserverpy-0.5.0b2.dist-info}/WHEEL +1 -1
- hydroserverpy/core/endpoints/__init__.py +0 -9
- hydroserverpy/core/endpoints/base.py +0 -146
- hydroserverpy/core/endpoints/data_loaders.py +0 -93
- hydroserverpy/core/endpoints/data_sources.py +0 -93
- hydroserverpy/core/endpoints/datastreams.py +0 -225
- hydroserverpy/core/endpoints/observed_properties.py +0 -111
- hydroserverpy/core/endpoints/processing_levels.py +0 -111
- hydroserverpy/core/endpoints/result_qualifiers.py +0 -111
- hydroserverpy/core/endpoints/sensors.py +0 -111
- hydroserverpy/core/endpoints/things.py +0 -261
- hydroserverpy/core/endpoints/units.py +0 -111
- hydroserverpy/core/schemas/__init__.py +0 -9
- hydroserverpy/core/schemas/base.py +0 -124
- hydroserverpy/core/schemas/data_loaders.py +0 -73
- hydroserverpy/core/schemas/data_sources.py +0 -223
- hydroserverpy/core/schemas/datastreams.py +0 -330
- hydroserverpy/core/schemas/observed_properties.py +0 -43
- hydroserverpy/core/schemas/processing_levels.py +0 -31
- hydroserverpy/core/schemas/result_qualifiers.py +0 -26
- hydroserverpy/core/schemas/sensors.py +0 -68
- hydroserverpy/core/schemas/things.py +0 -346
- hydroserverpy/core/schemas/units.py +0 -29
- hydroserverpy/core/service.py +0 -200
- hydroserverpy-0.4.0.dist-info/RECORD +0 -51
- /hydroserverpy/{core → api}/__init__.py +0 -0
- {hydroserverpy-0.4.0.dist-info → hydroserverpy-0.5.0b2.dist-info/licenses}/LICENSE +0 -0
- {hydroserverpy-0.4.0.dist-info → hydroserverpy-0.5.0b2.dist-info}/top_level.txt +0 -0
- {hydroserverpy-0.4.0.dist-info → hydroserverpy-0.5.0b2.dist-info}/zip-safe +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from typing import Union, Optional, TYPE_CHECKING
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from ..base import HydroServerModel
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from hydroserverpy import HydroServer
|
|
8
|
+
from hydroserverpy.api.models import Workspace
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProcessingLevelFields(BaseModel):
|
|
12
|
+
code: str = Field(..., max_length=255)
|
|
13
|
+
definition: Optional[str] = None
|
|
14
|
+
explanation: Optional[str] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ProcessingLevel(HydroServerModel, ProcessingLevelFields):
|
|
18
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
19
|
+
super().__init__(
|
|
20
|
+
_connection=_connection, _model_ref="processinglevels", _uid=_uid, **data
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
self._workspace_id = str(data.get("workspace_id") or data["workspaceId"])
|
|
24
|
+
|
|
25
|
+
self._workspace = None
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def workspace(self) -> "Workspace":
|
|
29
|
+
"""The workspace this processing level belongs to."""
|
|
30
|
+
|
|
31
|
+
if self._workspace is None and self._workspace_id:
|
|
32
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
33
|
+
|
|
34
|
+
return self._workspace
|
|
35
|
+
|
|
36
|
+
def refresh(self):
|
|
37
|
+
"""Refresh this processing level from HydroServer."""
|
|
38
|
+
|
|
39
|
+
super()._refresh()
|
|
40
|
+
self._workspace = None
|
|
41
|
+
|
|
42
|
+
def save(self):
|
|
43
|
+
"""Save changes to this processing level to HydroServer."""
|
|
44
|
+
|
|
45
|
+
super()._save()
|
|
46
|
+
|
|
47
|
+
def delete(self):
|
|
48
|
+
"""Delete this processing level from HydroServer."""
|
|
49
|
+
|
|
50
|
+
super()._delete()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Union, Optional, TYPE_CHECKING
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from ..base import HydroServerModel
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from hydroserverpy import HydroServer
|
|
8
|
+
from hydroserverpy.api.models import Workspace
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ResultQualifierFields(BaseModel):
|
|
12
|
+
code: str = Field(..., max_length=255)
|
|
13
|
+
description: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ResultQualifier(HydroServerModel, ResultQualifierFields):
|
|
17
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
18
|
+
super().__init__(
|
|
19
|
+
_connection=_connection, _model_ref="resultqualifiers", _uid=_uid, **data
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
self._workspace_id = str(data.get("workspace_id") or data["workspaceId"])
|
|
23
|
+
|
|
24
|
+
self._workspace = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def workspace(self) -> "Workspace":
|
|
28
|
+
"""The workspace this result qualifier belongs to."""
|
|
29
|
+
|
|
30
|
+
if self._workspace is None and self._workspace_id:
|
|
31
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
32
|
+
|
|
33
|
+
return self._workspace
|
|
34
|
+
|
|
35
|
+
def refresh(self):
|
|
36
|
+
"""Refresh this result qualifier from HydroServer."""
|
|
37
|
+
|
|
38
|
+
super()._refresh()
|
|
39
|
+
self._workspace = None
|
|
40
|
+
|
|
41
|
+
def save(self):
|
|
42
|
+
"""Save changes to this result qualifier to HydroServer."""
|
|
43
|
+
|
|
44
|
+
super()._save()
|
|
45
|
+
|
|
46
|
+
def delete(self):
|
|
47
|
+
"""Delete this result qualifier from HydroServer."""
|
|
48
|
+
|
|
49
|
+
super()._delete()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from typing import Union, Optional, TYPE_CHECKING
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from pydantic import BaseModel, Field, AliasChoices, AliasPath
|
|
4
|
+
from ..base import HydroServerModel
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from hydroserverpy import HydroServer
|
|
8
|
+
from hydroserverpy.api.models import Workspace
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SensorFields(BaseModel):
|
|
12
|
+
name: str = Field(..., max_length=255)
|
|
13
|
+
description: str
|
|
14
|
+
encoding_type: str = Field(..., max_length=255)
|
|
15
|
+
manufacturer: Optional[str] = Field(
|
|
16
|
+
None,
|
|
17
|
+
max_length=255,
|
|
18
|
+
validation_alias=AliasChoices(
|
|
19
|
+
"manufacturer", AliasPath("metadata", "sensorModel", "sensorManufacturer")
|
|
20
|
+
),
|
|
21
|
+
)
|
|
22
|
+
sensor_model: Optional[str] = Field(
|
|
23
|
+
None,
|
|
24
|
+
max_length=255,
|
|
25
|
+
alias="model",
|
|
26
|
+
validation_alias=AliasChoices(
|
|
27
|
+
"model", AliasPath("metadata", "sensorModel", "sensorModelName")
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
sensor_model_link: Optional[str] = Field(
|
|
31
|
+
None,
|
|
32
|
+
max_length=500,
|
|
33
|
+
alias="modelLink",
|
|
34
|
+
validation_alias=AliasChoices(
|
|
35
|
+
"modelLink", AliasPath("metadata", "sensorModel", "sensorModelUrl")
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
method_type: str = Field(
|
|
39
|
+
...,
|
|
40
|
+
max_length=100,
|
|
41
|
+
validation_alias=AliasChoices(
|
|
42
|
+
"methodType", AliasPath("metadata", "methodType")
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
method_link: Optional[str] = Field(
|
|
46
|
+
None,
|
|
47
|
+
max_length=500,
|
|
48
|
+
validation_alias=AliasChoices(
|
|
49
|
+
"methodLink", AliasPath("metadata", "methodLink")
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
method_code: Optional[str] = Field(
|
|
53
|
+
None,
|
|
54
|
+
max_length=50,
|
|
55
|
+
validation_alias=AliasChoices(
|
|
56
|
+
"methodCode", AliasPath("metadata", "methodCode")
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Sensor(HydroServerModel, SensorFields):
|
|
62
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
63
|
+
super().__init__(
|
|
64
|
+
_connection=_connection, _model_ref="sensors", _uid=_uid, **data
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
self._workspace_id = (
|
|
68
|
+
data.get("workspace_id")
|
|
69
|
+
or data.get("workspaceId")
|
|
70
|
+
or (
|
|
71
|
+
None
|
|
72
|
+
if data.get("properties", {}).get("workspace") is None
|
|
73
|
+
else data.get("properties", {}).get("workspace", {}).get("id")
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
self._workspace_id = (
|
|
77
|
+
str(self._workspace_id) if self._workspace_id is not None else None
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
self._workspace = None
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def workspace(self) -> "Workspace":
|
|
84
|
+
"""The workspace this sensor belongs to."""
|
|
85
|
+
|
|
86
|
+
if self._workspace is None and self._workspace_id:
|
|
87
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
88
|
+
|
|
89
|
+
return self._workspace
|
|
90
|
+
|
|
91
|
+
def refresh(self):
|
|
92
|
+
"""Refresh this sensor from HydroServer."""
|
|
93
|
+
|
|
94
|
+
super()._refresh()
|
|
95
|
+
self._workspace = None
|
|
96
|
+
|
|
97
|
+
def save(self):
|
|
98
|
+
"""Save changes to this sensor to HydroServer."""
|
|
99
|
+
|
|
100
|
+
super()._save()
|
|
101
|
+
|
|
102
|
+
def delete(self):
|
|
103
|
+
"""Delete this sensor from HydroServer."""
|
|
104
|
+
|
|
105
|
+
super()._delete()
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
from typing import Optional, Union, List, Dict, IO, TYPE_CHECKING
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from pydantic import (
|
|
4
|
+
BaseModel,
|
|
5
|
+
Field,
|
|
6
|
+
AliasChoices,
|
|
7
|
+
AliasPath,
|
|
8
|
+
AnyHttpUrl,
|
|
9
|
+
field_validator,
|
|
10
|
+
)
|
|
11
|
+
from ..base import HydroServerModel
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from hydroserverpy import HydroServer
|
|
15
|
+
from hydroserverpy.api.models import Workspace, Datastream
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ThingFields(BaseModel):
|
|
19
|
+
name: str = Field(..., max_length=200)
|
|
20
|
+
description: str
|
|
21
|
+
sampling_feature_type: str = Field(
|
|
22
|
+
...,
|
|
23
|
+
max_length=200,
|
|
24
|
+
validation_alias=AliasChoices(
|
|
25
|
+
"samplingFeatureType", AliasPath("properties", "samplingFeatureType")
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
sampling_feature_code: str = Field(
|
|
29
|
+
...,
|
|
30
|
+
max_length=200,
|
|
31
|
+
validation_alias=AliasChoices(
|
|
32
|
+
"samplingFeatureCode", AliasPath("properties", "samplingFeatureCode")
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
site_type: str = Field(
|
|
36
|
+
...,
|
|
37
|
+
max_length=200,
|
|
38
|
+
validation_alias=AliasChoices("siteType", AliasPath("properties", "siteType")),
|
|
39
|
+
)
|
|
40
|
+
tags: Dict[str, str] = Field(
|
|
41
|
+
...,
|
|
42
|
+
json_schema_extra={"editable": False, "read_only": True},
|
|
43
|
+
validation_alias=AliasChoices("tags", AliasPath("properties", "tags")),
|
|
44
|
+
)
|
|
45
|
+
photos: Dict[str, AnyHttpUrl] = Field(
|
|
46
|
+
...,
|
|
47
|
+
json_schema_extra={"editable": False, "read_only": True},
|
|
48
|
+
validation_alias=AliasChoices("photos", AliasPath("properties", "photos")),
|
|
49
|
+
)
|
|
50
|
+
data_disclaimer: Optional[str] = Field(
|
|
51
|
+
None,
|
|
52
|
+
validation_alias=AliasChoices(
|
|
53
|
+
"dataDisclaimer", AliasPath("properties", "dataDisclaimer")
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
is_private: bool = Field(
|
|
57
|
+
...,
|
|
58
|
+
validation_alias=AliasChoices(
|
|
59
|
+
"isPrivate", AliasPath("properties", "isPrivate")
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
@field_validator("tags", mode="before")
|
|
64
|
+
def convert_tags(
|
|
65
|
+
cls, value: Union[List[Dict[str, str]], Dict[str, str]]
|
|
66
|
+
) -> Dict[str, str]:
|
|
67
|
+
if isinstance(value, list):
|
|
68
|
+
return {item["key"]: item["value"] for item in value}
|
|
69
|
+
return value
|
|
70
|
+
|
|
71
|
+
@field_validator("photos", mode="before")
|
|
72
|
+
def convert_photos(
|
|
73
|
+
cls, value: Union[List[Dict[str, str]], Dict[str, str]]
|
|
74
|
+
) -> Dict[str, str]:
|
|
75
|
+
if isinstance(value, list):
|
|
76
|
+
return {item["name"]: item["link"] for item in value}
|
|
77
|
+
return value
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class LocationFields(BaseModel):
|
|
81
|
+
latitude: float = Field(
|
|
82
|
+
...,
|
|
83
|
+
ge=-90,
|
|
84
|
+
le=90,
|
|
85
|
+
validation_alias=AliasChoices(
|
|
86
|
+
"latitude",
|
|
87
|
+
AliasPath("Locations", 0, "location", "geometry", "coordinates", 0),
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
longitude: float = Field(
|
|
91
|
+
...,
|
|
92
|
+
ge=-180,
|
|
93
|
+
le=180,
|
|
94
|
+
validation_alias=AliasChoices(
|
|
95
|
+
"longitude",
|
|
96
|
+
AliasPath("Locations", 0, "location", "geometry", "coordinates", 1),
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
elevation_m: Optional[float] = Field(
|
|
100
|
+
None,
|
|
101
|
+
ge=-99999,
|
|
102
|
+
le=99999,
|
|
103
|
+
validation_alias=AliasChoices(
|
|
104
|
+
"elevation_m", AliasPath("Locations", 0, "properties", "elevation_m")
|
|
105
|
+
),
|
|
106
|
+
)
|
|
107
|
+
elevation_datum: Optional[str] = Field(
|
|
108
|
+
None,
|
|
109
|
+
max_length=255,
|
|
110
|
+
validation_alias=AliasChoices(
|
|
111
|
+
"elevationDatum", AliasPath("Locations", 0, "properties", "elevationDatum")
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
state: Optional[str] = Field(
|
|
115
|
+
None,
|
|
116
|
+
max_length=200,
|
|
117
|
+
validation_alias=AliasChoices(
|
|
118
|
+
"state", AliasPath("Locations", 0, "properties", "state")
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
county: Optional[str] = Field(
|
|
122
|
+
None,
|
|
123
|
+
max_length=200,
|
|
124
|
+
validation_alias=AliasChoices(
|
|
125
|
+
"county", AliasPath("Locations", 0, "properties", "county")
|
|
126
|
+
),
|
|
127
|
+
)
|
|
128
|
+
country: Optional[str] = Field(
|
|
129
|
+
None,
|
|
130
|
+
max_length=2,
|
|
131
|
+
validation_alias=AliasChoices(
|
|
132
|
+
"country", AliasPath("Locations", 0, "properties", "country")
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class Thing(HydroServerModel, ThingFields, LocationFields):
|
|
138
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
139
|
+
super().__init__(
|
|
140
|
+
_connection=_connection, _model_ref="things", _uid=_uid, **data
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
self._workspace_id = str(
|
|
144
|
+
data.get("workspace_id")
|
|
145
|
+
or data.get("workspaceId")
|
|
146
|
+
or data["properties"]["workspace"]["id"]
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
self._workspace = None
|
|
150
|
+
self._datastreams = None
|
|
151
|
+
self._photos = None
|
|
152
|
+
self._tags = None
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def workspace(self) -> "Workspace":
|
|
156
|
+
"""The workspace this thing belongs to."""
|
|
157
|
+
|
|
158
|
+
if self._workspace is None:
|
|
159
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
160
|
+
|
|
161
|
+
return self._workspace
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def datastreams(self) -> List["Datastream"]:
|
|
165
|
+
"""The datastreams collected at this thing."""
|
|
166
|
+
|
|
167
|
+
if self._datastreams is None:
|
|
168
|
+
self._datastreams = self._connection.datastreams.list(thing=self.uid)
|
|
169
|
+
|
|
170
|
+
return self._datastreams
|
|
171
|
+
|
|
172
|
+
def refresh(self):
|
|
173
|
+
"""Refresh this thing from HydroServer."""
|
|
174
|
+
|
|
175
|
+
super()._refresh()
|
|
176
|
+
self._workspace = None
|
|
177
|
+
self._datastreams = None
|
|
178
|
+
|
|
179
|
+
def save(self):
|
|
180
|
+
"""Save changes to this thing to HydroServer."""
|
|
181
|
+
|
|
182
|
+
super()._save()
|
|
183
|
+
|
|
184
|
+
def delete(self):
|
|
185
|
+
"""Delete this thing from HydroServer."""
|
|
186
|
+
|
|
187
|
+
super()._delete()
|
|
188
|
+
|
|
189
|
+
def add_tag(self, key: str, value: str):
|
|
190
|
+
"""Add a tag to this thing."""
|
|
191
|
+
|
|
192
|
+
self._connection.things.add_tag(uid=self.uid, key=key, value=value)
|
|
193
|
+
self.tags[key] = value
|
|
194
|
+
|
|
195
|
+
def update_tag(self, key: str, value: str):
|
|
196
|
+
"""Edit a tag of this thing."""
|
|
197
|
+
|
|
198
|
+
self._connection.things.update_tag(uid=self.uid, key=key, value=value)
|
|
199
|
+
self.tags[key] = value
|
|
200
|
+
|
|
201
|
+
def delete_tag(self, key: str):
|
|
202
|
+
"""Delete a tag of this thing."""
|
|
203
|
+
|
|
204
|
+
self._connection.things.delete_tag(uid=self.uid, key=key)
|
|
205
|
+
del self.tags[key]
|
|
206
|
+
|
|
207
|
+
def add_photo(self, file: IO[bytes]):
|
|
208
|
+
"""Add a photo of this thing."""
|
|
209
|
+
|
|
210
|
+
photo = self._connection.things.add_photo(uid=self.uid, file=file)
|
|
211
|
+
self.photos[photo["name"]] = photo["link"]
|
|
212
|
+
|
|
213
|
+
def delete_photo(self, name: str):
|
|
214
|
+
"""Delete a photo of this thing."""
|
|
215
|
+
|
|
216
|
+
self._connection.things.delete_photo(uid=self.uid, name=name)
|
|
217
|
+
del self.photos[name]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Union, TYPE_CHECKING
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from ..base import HydroServerModel
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from hydroserverpy import HydroServer
|
|
8
|
+
from hydroserverpy.api.models import Workspace
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UnitFields(BaseModel):
|
|
12
|
+
name: str = Field(..., max_length=255)
|
|
13
|
+
symbol: str = Field(..., max_length=255)
|
|
14
|
+
definition: str
|
|
15
|
+
unit_type: str = Field(..., max_length=255, alias="type")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Unit(HydroServerModel, UnitFields):
|
|
19
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
20
|
+
super().__init__(_connection=_connection, _model_ref="units", _uid=_uid, **data)
|
|
21
|
+
|
|
22
|
+
self._workspace_id = str(data.get("workspace_id") or data["workspaceId"])
|
|
23
|
+
|
|
24
|
+
self._workspace = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def workspace(self) -> "Workspace":
|
|
28
|
+
"""The workspace this unit belongs to."""
|
|
29
|
+
|
|
30
|
+
if self._workspace is None and self._workspace_id:
|
|
31
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
32
|
+
|
|
33
|
+
return self._workspace
|
|
34
|
+
|
|
35
|
+
def refresh(self):
|
|
36
|
+
"""Refresh this unit from HydroServer."""
|
|
37
|
+
|
|
38
|
+
super()._refresh()
|
|
39
|
+
self._workspace = None
|
|
40
|
+
|
|
41
|
+
def save(self):
|
|
42
|
+
"""Save changes to this unit to HydroServer."""
|
|
43
|
+
|
|
44
|
+
super()._save()
|
|
45
|
+
|
|
46
|
+
def delete(self):
|
|
47
|
+
"""Delete this unit from HydroServer."""
|
|
48
|
+
|
|
49
|
+
super()._delete()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .iam.workspace import WorkspaceService
|
|
2
|
+
from .sta.thing import ThingService
|
|
3
|
+
from .sta.observed_property import ObservedPropertyService
|
|
4
|
+
from .sta.unit import UnitService
|
|
5
|
+
from .sta.processing_level import ProcessingLevelService
|
|
6
|
+
from .sta.result_qualifier import ResultQualifierService
|
|
7
|
+
from .sta.sensor import SensorService
|
|
8
|
+
from .sta.datastream import DatastreamService
|
|
9
|
+
from .etl.orchestration_system import OrchestrationSystemService
|
|
10
|
+
from .etl.data_source import DataSourceService
|
|
11
|
+
from .etl.data_archive import DataArchiveService
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Type, Union, Optional
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from hydroserverpy import HydroServer
|
|
7
|
+
from hydroserverpy.api.models.base import HydroServerModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EndpointService:
|
|
11
|
+
_model: Type["HydroServerModel"]
|
|
12
|
+
_api_route: str
|
|
13
|
+
_endpoint_route: str
|
|
14
|
+
|
|
15
|
+
def __init__(self, connection: "HydroServer") -> None:
|
|
16
|
+
self._connection = connection
|
|
17
|
+
|
|
18
|
+
def _list(self, params: Optional[dict] = None):
|
|
19
|
+
path = f"/{self._api_route}/{self._endpoint_route}"
|
|
20
|
+
|
|
21
|
+
response = self._connection.request("get", path, params=params).json()
|
|
22
|
+
|
|
23
|
+
return [
|
|
24
|
+
self._model(
|
|
25
|
+
_connection=self._connection, _uid=UUID(str(obj.pop("id"))), **obj
|
|
26
|
+
)
|
|
27
|
+
for obj in response
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
def _get(self, uid: Union[UUID, str]):
|
|
31
|
+
path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}"
|
|
32
|
+
response = self._connection.request("get", path).json()
|
|
33
|
+
|
|
34
|
+
return self._model(
|
|
35
|
+
_connection=self._connection, _uid=UUID(str(response.pop("id"))), **response
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def _create(self, **kwargs):
|
|
39
|
+
path = f"/{self._api_route}/{self._endpoint_route}"
|
|
40
|
+
headers = {"Content-type": "application/json"}
|
|
41
|
+
response = self._connection.request(
|
|
42
|
+
"post", path, headers=headers, json=self._to_iso_time(kwargs)
|
|
43
|
+
).json()
|
|
44
|
+
|
|
45
|
+
return self._model(
|
|
46
|
+
_connection=self._connection, _uid=UUID(str(response.pop("id"))), **response
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def _update(self, uid: Union[UUID, str], **kwargs):
|
|
50
|
+
path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}"
|
|
51
|
+
headers = {"Content-type": "application/json"}
|
|
52
|
+
response = self._connection.request(
|
|
53
|
+
"patch", path, headers=headers, json=self._to_iso_time(kwargs)
|
|
54
|
+
).json()
|
|
55
|
+
|
|
56
|
+
return self._model(
|
|
57
|
+
_connection=self._connection, _uid=UUID(str(response.pop("id"))), **response
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def _delete(self, uid: Union[UUID, str]):
|
|
61
|
+
path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}"
|
|
62
|
+
response = self._connection.request("delete", path)
|
|
63
|
+
|
|
64
|
+
return response
|
|
65
|
+
|
|
66
|
+
def _to_iso_time(self, obj):
|
|
67
|
+
if isinstance(obj, dict):
|
|
68
|
+
return {k: self._to_iso_time(v) for k, v in obj.items()}
|
|
69
|
+
elif isinstance(obj, list):
|
|
70
|
+
return [self._to_iso_time(i) for i in obj]
|
|
71
|
+
elif isinstance(obj, datetime):
|
|
72
|
+
return obj.isoformat()
|
|
73
|
+
return obj
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SensorThingsService(EndpointService):
|
|
77
|
+
_sta_route: str
|
|
78
|
+
|
|
79
|
+
def __init__(self, connection) -> None:
|
|
80
|
+
super().__init__(connection)
|
|
81
|
+
|
|
82
|
+
def _list(self, path: Optional[str] = None, params: Optional[dict] = None):
|
|
83
|
+
path = path or f"/{self._sta_route}"
|
|
84
|
+
response = self._connection.request("get", path, params=params)
|
|
85
|
+
|
|
86
|
+
return [
|
|
87
|
+
self._model(_connection=self._connection, _uid=obj.pop("@iot.id"), **obj)
|
|
88
|
+
for obj in response.json()["value"]
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
def _get(
|
|
92
|
+
self,
|
|
93
|
+
uid: Union[UUID, str],
|
|
94
|
+
path: Optional[str] = None,
|
|
95
|
+
params: Optional[dict] = None,
|
|
96
|
+
):
|
|
97
|
+
path = path or f"/{self._sta_route}('{str(uid)}')"
|
|
98
|
+
response = self._connection.request("get", path, params=params).json()
|
|
99
|
+
|
|
100
|
+
return self._model(
|
|
101
|
+
_connection=self._connection, _uid=response.pop("@iot.id"), **response
|
|
102
|
+
)
|
|
File without changes
|