hydroserverpy 0.5.0b1__tar.gz → 0.5.0b2__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.
Potentially problematic release.
This version of hydroserverpy might be problematic. Click here for more details.
- {hydroserverpy-0.5.0b1/src/hydroserverpy.egg-info → hydroserverpy-0.5.0b2}/PKG-INFO +1 -1
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/setup.cfg +1 -1
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/http.py +0 -2
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/main.py +21 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/__init__.py +3 -0
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/models/etl/data_archive.py +105 -0
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/models/etl/data_source.py +150 -0
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/models/etl/orchestration_configuration.py +35 -0
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/models/etl/orchestration_system.py +78 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/iam/workspace.py +35 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/datastream.py +3 -1
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/__init__.py +3 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/base.py +12 -2
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/services/etl/data_archive.py +196 -0
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/services/etl/data_source.py +196 -0
- hydroserverpy-0.5.0b2/src/hydroserverpy/api/services/etl/orchestration_system.py +74 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/observed_property.py +3 -1
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl_csv/hydroserver_etl_csv.py +49 -34
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2/src/hydroserverpy.egg-info}/PKG-INFO +1 -1
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy.egg-info/SOURCES.txt +7 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/LICENSE +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/README.md +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/pyproject.toml +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/setup.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/base.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/etl/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/iam/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/iam/account.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/iam/collaborator.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/iam/role.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/observed_property.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/processing_level.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/result_qualifier.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/sensor.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/thing.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/unit.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/etl/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/iam/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/iam/workspace.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/datastream.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/processing_level.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/result_qualifier.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/sensor.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/thing.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/services/sta/unit.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/extractors/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/extractors/base.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/extractors/ftp_extractor.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/extractors/http_extractor.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/extractors/local_file_extractor.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/hydroserver_etl.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/loaders/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/loaders/base.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/loaders/hydroserver_loader.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/transformers/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/transformers/base.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/transformers/csv_transformer.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/transformers/json_transformer.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl/types.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl_csv/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/etl_csv/exceptions.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/quality/__init__.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/quality/service.py +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy.egg-info/dependency_links.txt +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy.egg-info/requires.txt +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy.egg-info/top_level.txt +0 -0
- {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy.egg-info/zip-safe +0 -0
|
@@ -10,6 +10,9 @@ from hydroserverpy.api.services import (
|
|
|
10
10
|
ResultQualifierService,
|
|
11
11
|
SensorService,
|
|
12
12
|
DatastreamService,
|
|
13
|
+
OrchestrationSystemService,
|
|
14
|
+
DataSourceService,
|
|
15
|
+
DataArchiveService,
|
|
13
16
|
)
|
|
14
17
|
|
|
15
18
|
|
|
@@ -150,3 +153,21 @@ class HydroServer:
|
|
|
150
153
|
"""Utilities for managing HydroServer datastreams."""
|
|
151
154
|
|
|
152
155
|
return DatastreamService(self)
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def orchestrationsystems(self):
|
|
159
|
+
"""Utilities for managing HydroServer orchestration systems."""
|
|
160
|
+
|
|
161
|
+
return OrchestrationSystemService(self)
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def datasources(self):
|
|
165
|
+
"""Utilities for managing HydroServer data sources."""
|
|
166
|
+
|
|
167
|
+
return DataSourceService(self)
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def dataarchives(self):
|
|
171
|
+
"""Utilities for managing HydroServer data archives."""
|
|
172
|
+
|
|
173
|
+
return DataArchiveService(self)
|
|
@@ -10,6 +10,9 @@ from .sta.result_qualifier import ResultQualifier
|
|
|
10
10
|
from .sta.sensor import Sensor
|
|
11
11
|
from .sta.thing import Thing
|
|
12
12
|
from .sta.unit import Unit
|
|
13
|
+
from .etl.orchestration_system import OrchestrationSystem
|
|
14
|
+
from .etl.data_source import DataSource
|
|
15
|
+
from .etl.data_archive import DataArchive
|
|
13
16
|
|
|
14
17
|
Workspace.model_rebuild()
|
|
15
18
|
Role.model_rebuild()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from typing import Union, Optional, TYPE_CHECKING, List
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from .orchestration_system import OrchestrationSystem
|
|
5
|
+
from .orchestration_configuration import OrchestrationConfigurationFields
|
|
6
|
+
from ..sta.datastream import Datastream
|
|
7
|
+
from ..base import HydroServerModel
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from hydroserverpy import HydroServer
|
|
11
|
+
from hydroserverpy.api.models import Workspace
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DataArchiveFields(BaseModel):
|
|
15
|
+
name: str = Field(..., max_length=255)
|
|
16
|
+
settings: Optional[dict] = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DataArchive(
|
|
20
|
+
HydroServerModel, DataArchiveFields, OrchestrationConfigurationFields
|
|
21
|
+
):
|
|
22
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
23
|
+
super().__init__(
|
|
24
|
+
_connection=_connection, _model_ref="dataarchives", _uid=_uid, **data
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
self._workspace_id = str(data.get("workspace_id") or data["workspaceId"])
|
|
28
|
+
self._orchestration_system_id = str(
|
|
29
|
+
data.get("orchestration_system_id") or data["orchestrationSystem"]["id"]
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
self._workspace = None
|
|
33
|
+
|
|
34
|
+
if data.get("orchestrationSystem"):
|
|
35
|
+
self._orchestration_system = OrchestrationSystem(
|
|
36
|
+
_connection=_connection,
|
|
37
|
+
_uid=self._orchestration_system_id,
|
|
38
|
+
**data["orchestrationSystem"]
|
|
39
|
+
)
|
|
40
|
+
else:
|
|
41
|
+
self._orchestration_system = None
|
|
42
|
+
|
|
43
|
+
if data.get("datastreams"):
|
|
44
|
+
self._datastreams = [
|
|
45
|
+
Datastream(_connection=_connection, _uid=datastream["id"], **datastream)
|
|
46
|
+
for datastream in data["datastreams"]
|
|
47
|
+
]
|
|
48
|
+
else:
|
|
49
|
+
self._datastreams = []
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def workspace(self) -> "Workspace":
|
|
53
|
+
"""The workspace this data archive belongs to."""
|
|
54
|
+
|
|
55
|
+
if self._workspace is None and self._workspace_id:
|
|
56
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
57
|
+
|
|
58
|
+
return self._workspace
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def orchestration_system(self) -> "OrchestrationSystem":
|
|
62
|
+
"""The orchestration system that manages this data archive."""
|
|
63
|
+
|
|
64
|
+
if self._orchestration_system is None and self._orchestration_system_id:
|
|
65
|
+
self._orchestration_system = self._connection.orchestration_systems.get(
|
|
66
|
+
uid=self._orchestration_system_id
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return self._orchestration_system
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def datastreams(self) -> List["Datastream"]:
|
|
73
|
+
"""The datastreams this data archive provides data for."""
|
|
74
|
+
|
|
75
|
+
return self._datastreams
|
|
76
|
+
|
|
77
|
+
def refresh(self):
|
|
78
|
+
"""Refresh this data archive from HydroServer."""
|
|
79
|
+
|
|
80
|
+
super()._refresh()
|
|
81
|
+
self._workspace = None
|
|
82
|
+
|
|
83
|
+
def save(self):
|
|
84
|
+
"""Save changes to this data archive to HydroServer."""
|
|
85
|
+
|
|
86
|
+
super()._save()
|
|
87
|
+
|
|
88
|
+
def delete(self):
|
|
89
|
+
"""Delete this data archive from HydroServer."""
|
|
90
|
+
|
|
91
|
+
super()._delete()
|
|
92
|
+
|
|
93
|
+
def add_datastream(self, datastream: Union["Datastream", UUID, str]):
|
|
94
|
+
"""Add a datastream to this data archive."""
|
|
95
|
+
|
|
96
|
+
self._connection.dataarchives.add_datastream(
|
|
97
|
+
uid=self.uid, datastream=datastream
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def remove_datastream(self, datastream: Union["Datastream", UUID, str]):
|
|
101
|
+
"""Remove a datastream from this data archive."""
|
|
102
|
+
|
|
103
|
+
self._connection.dataarchives.remove_datastream(
|
|
104
|
+
uid=self.uid, datastream=datastream
|
|
105
|
+
)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
from typing import Union, List, Optional, TYPE_CHECKING
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
from urllib.request import urlopen
|
|
6
|
+
from hydroserverpy.etl_csv.hydroserver_etl_csv import HydroServerETLCSV
|
|
7
|
+
from .orchestration_system import OrchestrationSystem
|
|
8
|
+
from .orchestration_configuration import OrchestrationConfigurationFields
|
|
9
|
+
from ..sta.datastream import Datastream
|
|
10
|
+
from ..base import HydroServerModel
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from hydroserverpy import HydroServer
|
|
14
|
+
from hydroserverpy.api.models import Workspace
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DataSourceFields(BaseModel):
|
|
18
|
+
name: str = Field(..., max_length=255)
|
|
19
|
+
settings: Optional[dict] = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DataSource(HydroServerModel, DataSourceFields, OrchestrationConfigurationFields):
|
|
23
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
24
|
+
super().__init__(
|
|
25
|
+
_connection=_connection, _model_ref="datasources", _uid=_uid, **data
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
self._workspace_id = str(data.get("workspace_id") or data["workspaceId"])
|
|
29
|
+
self._orchestration_system_id = str(
|
|
30
|
+
data.get("orchestration_system_id") or data["orchestrationSystem"]["id"]
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
self._workspace = None
|
|
34
|
+
|
|
35
|
+
if data.get("orchestrationSystem"):
|
|
36
|
+
self._orchestration_system = OrchestrationSystem(
|
|
37
|
+
_connection=_connection,
|
|
38
|
+
_uid=self._orchestration_system_id,
|
|
39
|
+
**data["orchestrationSystem"]
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
self._orchestration_system = None
|
|
43
|
+
|
|
44
|
+
if data.get("datastreams"):
|
|
45
|
+
self._datastreams = [
|
|
46
|
+
Datastream(_connection=_connection, _uid=datastream["id"], **datastream)
|
|
47
|
+
for datastream in data["datastreams"]
|
|
48
|
+
]
|
|
49
|
+
else:
|
|
50
|
+
self._datastreams = []
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def workspace(self) -> "Workspace":
|
|
54
|
+
"""The workspace this data source belongs to."""
|
|
55
|
+
|
|
56
|
+
if self._workspace is None and self._workspace_id:
|
|
57
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
58
|
+
|
|
59
|
+
return self._workspace
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def orchestration_system(self) -> "OrchestrationSystem":
|
|
63
|
+
"""The orchestration system that manages this data source."""
|
|
64
|
+
|
|
65
|
+
if self._orchestration_system is None and self._orchestration_system_id:
|
|
66
|
+
self._orchestration_system = self._connection.orchestration_systems.get(
|
|
67
|
+
uid=self._orchestration_system_id
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return self._orchestration_system
|
|
71
|
+
|
|
72
|
+
@orchestration_system.setter
|
|
73
|
+
def orchestration_system(
|
|
74
|
+
self, orchestration_system: Union["OrchestrationSystem", UUID, str]
|
|
75
|
+
):
|
|
76
|
+
if not orchestration_system:
|
|
77
|
+
raise ValueError("Orchestration system of data source cannot be None.")
|
|
78
|
+
if str(getattr(orchestration_system, "uid", orchestration_system)) != str(
|
|
79
|
+
self.orchestration_system.uid
|
|
80
|
+
):
|
|
81
|
+
self._orchestration_system = self._connection.orchestrationsystems.get(
|
|
82
|
+
uid=str(getattr(orchestration_system, "uid", orchestration_system))
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def datastreams(self) -> List["Datastream"]:
|
|
87
|
+
"""The datastreams this data source provides data for."""
|
|
88
|
+
|
|
89
|
+
if self._datastreams is None:
|
|
90
|
+
data_source = self._connection.datasources.get(uid=self.uid)
|
|
91
|
+
self._datastreams = data_source.datastreams
|
|
92
|
+
|
|
93
|
+
return self._datastreams
|
|
94
|
+
|
|
95
|
+
def refresh(self):
|
|
96
|
+
"""Refresh this data source from HydroServer."""
|
|
97
|
+
|
|
98
|
+
super()._refresh()
|
|
99
|
+
self._workspace = None
|
|
100
|
+
self._datastreams = None
|
|
101
|
+
|
|
102
|
+
def save(self):
|
|
103
|
+
"""Save changes to this data source to HydroServer."""
|
|
104
|
+
|
|
105
|
+
super()._save()
|
|
106
|
+
|
|
107
|
+
def delete(self):
|
|
108
|
+
"""Delete this data source from HydroServer."""
|
|
109
|
+
|
|
110
|
+
super()._delete()
|
|
111
|
+
|
|
112
|
+
def add_datastream(self, datastream: Union["Datastream", UUID, str]):
|
|
113
|
+
"""Add a datastream to this data source."""
|
|
114
|
+
|
|
115
|
+
self._connection.datasources.add_datastream(uid=self.uid, datastream=datastream)
|
|
116
|
+
|
|
117
|
+
def remove_datastream(self, datastream: Union["Datastream", UUID, str]):
|
|
118
|
+
"""Remove a datastream from this data source."""
|
|
119
|
+
|
|
120
|
+
self._connection.datasources.remove_datastream(
|
|
121
|
+
uid=self.uid, datastream=datastream
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# TODO: Replace with ETL module.
|
|
125
|
+
def load_data(self):
|
|
126
|
+
"""Load data for this data source."""
|
|
127
|
+
|
|
128
|
+
if self.paused is True:
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
if self.settings["extractor"]["type"] == "local":
|
|
132
|
+
with open(self.settings["extractor"]["path"]) as data_file:
|
|
133
|
+
loader = HydroServerETLCSV(
|
|
134
|
+
self._connection, data_file=data_file, data_source=self
|
|
135
|
+
)
|
|
136
|
+
loader.run()
|
|
137
|
+
elif self.settings["extractor"]["type"] == "HTTP":
|
|
138
|
+
with tempfile.NamedTemporaryFile(mode="w") as temp_file:
|
|
139
|
+
with urlopen(self.settings["extractor"]["urlTemplate"]) as response:
|
|
140
|
+
chunk_size = 1024 * 1024 * 10 # Use a 10mb chunk size.
|
|
141
|
+
while True:
|
|
142
|
+
chunk = response.read(chunk_size)
|
|
143
|
+
if not chunk:
|
|
144
|
+
break
|
|
145
|
+
temp_file.write(chunk)
|
|
146
|
+
temp_file.seek(0)
|
|
147
|
+
loader = HydroServerETLCSV(
|
|
148
|
+
self._connection, data_file=temp_file, data_source=self
|
|
149
|
+
)
|
|
150
|
+
loader.run()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from pydantic import AliasPath
|
|
2
|
+
from typing import Optional, Literal
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class OrchestrationConfigurationFields(BaseModel):
|
|
8
|
+
interval: Optional[int] = Field(
|
|
9
|
+
None, gt=0, validation_alias=AliasPath("schedule", "interval")
|
|
10
|
+
)
|
|
11
|
+
interval_units: Optional[Literal["minutes", "hours", "days"]] = Field(
|
|
12
|
+
None, validation_alias=AliasPath("schedule", "intervalUnits")
|
|
13
|
+
)
|
|
14
|
+
crontab: Optional[str] = Field(
|
|
15
|
+
None, max_length=255, validation_alias=AliasPath("schedule", "crontab")
|
|
16
|
+
)
|
|
17
|
+
start_time: Optional[datetime] = Field(
|
|
18
|
+
None, validation_alias=AliasPath("schedule", "startTime")
|
|
19
|
+
)
|
|
20
|
+
end_time: Optional[datetime] = Field(
|
|
21
|
+
None, validation_alias=AliasPath("schedule", "endTime")
|
|
22
|
+
)
|
|
23
|
+
last_run_successful: Optional[bool] = Field(
|
|
24
|
+
None, validation_alias=AliasPath("status", "lastRunSuccessful")
|
|
25
|
+
)
|
|
26
|
+
last_run_message: Optional[str] = Field(
|
|
27
|
+
None, max_length=255, validation_alias=AliasPath("status", "lastRunMessage")
|
|
28
|
+
)
|
|
29
|
+
last_run: Optional[datetime] = Field(
|
|
30
|
+
None, validation_alias=AliasPath("status", "lastRun")
|
|
31
|
+
)
|
|
32
|
+
next_run: Optional[datetime] = Field(
|
|
33
|
+
None, validation_alias=AliasPath("status", "nextRun")
|
|
34
|
+
)
|
|
35
|
+
paused: bool = Field(False, validation_alias=AliasPath("status", "paused"))
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from typing import Union, List, 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, DataSource, DataArchive
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OrchestrationSystemFields(BaseModel):
|
|
12
|
+
name: str = Field(..., max_length=255)
|
|
13
|
+
orchestration_system_type: str = Field(..., max_length=255, alias="type")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class OrchestrationSystem(HydroServerModel, OrchestrationSystemFields):
|
|
17
|
+
def __init__(self, _connection: "HydroServer", _uid: Union[UUID, str], **data):
|
|
18
|
+
super().__init__(
|
|
19
|
+
_connection=_connection,
|
|
20
|
+
_model_ref="orchestrationsystems",
|
|
21
|
+
_uid=_uid,
|
|
22
|
+
**data
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
self._workspace_id = str(data.get("workspace_id") or data["workspaceId"])
|
|
26
|
+
|
|
27
|
+
self._workspace = None
|
|
28
|
+
self._datasources = None
|
|
29
|
+
self._dataarchives = None
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def workspace(self) -> "Workspace":
|
|
33
|
+
"""The workspace this orchestration system belongs to."""
|
|
34
|
+
|
|
35
|
+
if self._workspace is None and self._workspace_id:
|
|
36
|
+
self._workspace = self._connection.workspaces.get(uid=self._workspace_id)
|
|
37
|
+
|
|
38
|
+
return self._workspace
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def datasources(self) -> List["DataSource"]:
|
|
42
|
+
"""The data sources associated with this workspace."""
|
|
43
|
+
|
|
44
|
+
if self._datasources is None:
|
|
45
|
+
self._datasources = self._connection.datasources.list(
|
|
46
|
+
orchestration_system=self.uid
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return self._datasources
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def dataarchives(self) -> List["DataArchive"]:
|
|
53
|
+
"""The data archives associated with this workspace."""
|
|
54
|
+
|
|
55
|
+
if self._dataarchives is None:
|
|
56
|
+
self._dataarchives = self._connection.dataarchives.list(
|
|
57
|
+
orchestration_system=self.uid
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return self._dataarchives
|
|
61
|
+
|
|
62
|
+
def refresh(self):
|
|
63
|
+
"""Refresh this orchestration system from HydroServer."""
|
|
64
|
+
|
|
65
|
+
super()._refresh()
|
|
66
|
+
self._workspace = None
|
|
67
|
+
self._datasources = None
|
|
68
|
+
self._dataarchives = None
|
|
69
|
+
|
|
70
|
+
def save(self):
|
|
71
|
+
"""Save changes to this orchestration system to HydroServer."""
|
|
72
|
+
|
|
73
|
+
super()._save()
|
|
74
|
+
|
|
75
|
+
def delete(self):
|
|
76
|
+
"""Delete this orchestration system from HydroServer."""
|
|
77
|
+
|
|
78
|
+
super()._delete()
|
{hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/iam/workspace.py
RENAMED
|
@@ -16,6 +16,9 @@ if TYPE_CHECKING:
|
|
|
16
16
|
ProcessingLevel,
|
|
17
17
|
ResultQualifier,
|
|
18
18
|
Datastream,
|
|
19
|
+
OrchestrationSystem,
|
|
20
|
+
DataSource,
|
|
21
|
+
DataArchive,
|
|
19
22
|
)
|
|
20
23
|
|
|
21
24
|
|
|
@@ -41,6 +44,9 @@ class Workspace(HydroServerModel, WorkspaceFields):
|
|
|
41
44
|
self._units = None
|
|
42
45
|
self._sensors = None
|
|
43
46
|
self._datastreams = None
|
|
47
|
+
self._orchestrationsystems = None
|
|
48
|
+
self._datasources = None
|
|
49
|
+
self._dataarchives = None
|
|
44
50
|
|
|
45
51
|
@property
|
|
46
52
|
def roles(self) -> List["Role"]:
|
|
@@ -131,6 +137,35 @@ class Workspace(HydroServerModel, WorkspaceFields):
|
|
|
131
137
|
|
|
132
138
|
return self._datastreams
|
|
133
139
|
|
|
140
|
+
@property
|
|
141
|
+
def orchestrationsystems(self) -> List["OrchestrationSystem"]:
|
|
142
|
+
"""The orchestration systems associated with this workspace."""
|
|
143
|
+
|
|
144
|
+
if self._orchestrationsystems is None:
|
|
145
|
+
self._orchestrationsystems = self._connection.orchestrationsystems.list(
|
|
146
|
+
workspace=self.uid
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return self._orchestrationsystems
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def datasources(self) -> List["DataSource"]:
|
|
153
|
+
"""The data sources associated with this workspace."""
|
|
154
|
+
|
|
155
|
+
if self._datasources is None:
|
|
156
|
+
self._datasources = self._connection.datasources.list(workspace=self.uid)
|
|
157
|
+
|
|
158
|
+
return self._datasources
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def dataarchives(self) -> List["DataArchive"]:
|
|
162
|
+
"""The data archives associated with this workspace."""
|
|
163
|
+
|
|
164
|
+
if self._dataarchives is None:
|
|
165
|
+
self._dataarchives = self._connection.dataarchives.list(workspace=self.uid)
|
|
166
|
+
|
|
167
|
+
return self._dataarchives
|
|
168
|
+
|
|
134
169
|
def refresh(self) -> None:
|
|
135
170
|
"""Refresh the workspace details from HydroServer."""
|
|
136
171
|
|
{hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b2}/src/hydroserverpy/api/models/sta/datastream.py
RENAMED
|
@@ -263,7 +263,9 @@ class Datastream(HydroServerModel, DatastreamFields):
|
|
|
263
263
|
"""The processing level of this datastream."""
|
|
264
264
|
|
|
265
265
|
if self._processing_level is None:
|
|
266
|
-
self._processing_level = self._connection.processinglevels.get(
|
|
266
|
+
self._processing_level = self._connection.processinglevels.get(
|
|
267
|
+
uid=self._processing_level_id
|
|
268
|
+
)
|
|
267
269
|
self._original_data["processing_level"] = self._processing_level
|
|
268
270
|
|
|
269
271
|
return self._processing_level
|
|
@@ -6,3 +6,6 @@ from .sta.processing_level import ProcessingLevelService
|
|
|
6
6
|
from .sta.result_qualifier import ResultQualifierService
|
|
7
7
|
from .sta.sensor import SensorService
|
|
8
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
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Type, Union, Optional
|
|
2
|
+
from datetime import datetime
|
|
2
3
|
from uuid import UUID
|
|
3
4
|
|
|
4
5
|
if TYPE_CHECKING:
|
|
@@ -38,7 +39,7 @@ class EndpointService:
|
|
|
38
39
|
path = f"/{self._api_route}/{self._endpoint_route}"
|
|
39
40
|
headers = {"Content-type": "application/json"}
|
|
40
41
|
response = self._connection.request(
|
|
41
|
-
"post", path, headers=headers, json=kwargs
|
|
42
|
+
"post", path, headers=headers, json=self._to_iso_time(kwargs)
|
|
42
43
|
).json()
|
|
43
44
|
|
|
44
45
|
return self._model(
|
|
@@ -49,7 +50,7 @@ class EndpointService:
|
|
|
49
50
|
path = f"/{self._api_route}/{self._endpoint_route}/{str(uid)}"
|
|
50
51
|
headers = {"Content-type": "application/json"}
|
|
51
52
|
response = self._connection.request(
|
|
52
|
-
"patch", path, headers=headers, json=kwargs
|
|
53
|
+
"patch", path, headers=headers, json=self._to_iso_time(kwargs)
|
|
53
54
|
).json()
|
|
54
55
|
|
|
55
56
|
return self._model(
|
|
@@ -62,6 +63,15 @@ class EndpointService:
|
|
|
62
63
|
|
|
63
64
|
return response
|
|
64
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
|
+
|
|
65
75
|
|
|
66
76
|
class SensorThingsService(EndpointService):
|
|
67
77
|
_sta_route: str
|