hydroserverpy 0.5.0b1__tar.gz → 0.5.0b3__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.

Files changed (72) hide show
  1. {hydroserverpy-0.5.0b1/src/hydroserverpy.egg-info → hydroserverpy-0.5.0b3}/PKG-INFO +1 -1
  2. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/setup.cfg +1 -1
  3. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/http.py +0 -2
  4. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/main.py +21 -0
  5. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/__init__.py +3 -0
  6. hydroserverpy-0.5.0b3/src/hydroserverpy/api/models/etl/data_archive.py +105 -0
  7. hydroserverpy-0.5.0b3/src/hydroserverpy/api/models/etl/data_source.py +150 -0
  8. hydroserverpy-0.5.0b3/src/hydroserverpy/api/models/etl/orchestration_configuration.py +35 -0
  9. hydroserverpy-0.5.0b3/src/hydroserverpy/api/models/etl/orchestration_system.py +78 -0
  10. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/iam/workspace.py +35 -0
  11. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/datastream.py +3 -1
  12. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/__init__.py +3 -0
  13. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/base.py +12 -2
  14. hydroserverpy-0.5.0b3/src/hydroserverpy/api/services/etl/data_archive.py +196 -0
  15. hydroserverpy-0.5.0b3/src/hydroserverpy/api/services/etl/data_source.py +196 -0
  16. hydroserverpy-0.5.0b3/src/hydroserverpy/api/services/etl/orchestration_system.py +74 -0
  17. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/observed_property.py +3 -1
  18. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl_csv/hydroserver_etl_csv.py +48 -34
  19. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3/src/hydroserverpy.egg-info}/PKG-INFO +1 -1
  20. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy.egg-info/SOURCES.txt +7 -0
  21. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/LICENSE +0 -0
  22. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/README.md +0 -0
  23. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/pyproject.toml +0 -0
  24. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/setup.py +0 -0
  25. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/__init__.py +0 -0
  26. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/__init__.py +0 -0
  27. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/base.py +0 -0
  28. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/etl/__init__.py +0 -0
  29. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/iam/__init__.py +0 -0
  30. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/iam/account.py +0 -0
  31. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/iam/collaborator.py +0 -0
  32. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/iam/role.py +0 -0
  33. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/__init__.py +0 -0
  34. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/observed_property.py +0 -0
  35. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/processing_level.py +0 -0
  36. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/result_qualifier.py +0 -0
  37. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/sensor.py +0 -0
  38. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/thing.py +0 -0
  39. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/models/sta/unit.py +0 -0
  40. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/etl/__init__.py +0 -0
  41. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/iam/__init__.py +0 -0
  42. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/iam/workspace.py +0 -0
  43. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/__init__.py +0 -0
  44. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/datastream.py +0 -0
  45. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/processing_level.py +0 -0
  46. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/result_qualifier.py +0 -0
  47. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/sensor.py +0 -0
  48. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/thing.py +0 -0
  49. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/api/services/sta/unit.py +0 -0
  50. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/__init__.py +0 -0
  51. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/extractors/__init__.py +0 -0
  52. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/extractors/base.py +0 -0
  53. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/extractors/ftp_extractor.py +0 -0
  54. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/extractors/http_extractor.py +0 -0
  55. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/extractors/local_file_extractor.py +0 -0
  56. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/hydroserver_etl.py +0 -0
  57. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/loaders/__init__.py +0 -0
  58. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/loaders/base.py +0 -0
  59. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/loaders/hydroserver_loader.py +0 -0
  60. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/transformers/__init__.py +0 -0
  61. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/transformers/base.py +0 -0
  62. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/transformers/csv_transformer.py +0 -0
  63. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/transformers/json_transformer.py +0 -0
  64. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl/types.py +0 -0
  65. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl_csv/__init__.py +0 -0
  66. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/etl_csv/exceptions.py +0 -0
  67. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/quality/__init__.py +0 -0
  68. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy/quality/service.py +0 -0
  69. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy.egg-info/dependency_links.txt +0 -0
  70. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy.egg-info/requires.txt +0 -0
  71. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy.egg-info/top_level.txt +0 -0
  72. {hydroserverpy-0.5.0b1 → hydroserverpy-0.5.0b3}/src/hydroserverpy.egg-info/zip-safe +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hydroserverpy
3
- Version: 0.5.0b1
3
+ Version: 0.5.0b3
4
4
  Requires-Python: <4,>=3.9
5
5
  License-File: LICENSE
6
6
  Requires-Dist: requests>=2
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = hydroserverpy
3
- version = 0.5.0b1
3
+ version = 0.5.0b3
4
4
 
5
5
  [options]
6
6
  package_dir =
@@ -3,8 +3,6 @@ from requests import HTTPError
3
3
 
4
4
 
5
5
  def raise_for_hs_status(response):
6
- """"""
7
-
8
6
  try:
9
7
  response.raise_for_status()
10
8
  except HTTPError as e:
@@ -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()
@@ -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
 
@@ -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(uid=self._processing_level_id)
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