wizata-dsapi 2.1.0.dev18__tar.gz → 2.1.0.dev20__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.
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/PKG-INFO +1 -1
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/api_config.py +34 -6
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/api_interface.py +20 -3
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/deployment.py +6 -0
- wizata_dsapi-2.1.0.dev20/wizata_dsapi/version.py +1 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/wizata_dsapi_client.py +384 -34
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi.egg-info/PKG-INFO +1 -1
- wizata_dsapi-2.1.0.dev18/wizata_dsapi/version.py +0 -1
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/LICENSE.txt +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/README.rst +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/setup.cfg +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/setup.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/__init__.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/api_dto.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/bucket.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/business_label.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/context.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/dashboard.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/dataframe_toolkit.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/datapoint.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/datastore.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/ds_dataframe.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/dsapi_json_encoder.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/edge_config.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/edge_device.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/edge_module.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/evaluation.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/execution.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/execution_log.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/experiment.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/graylog_log.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/group_system.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/ilogger.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/insight.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/mlmodel.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/mobile_asset.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/model_toolkit.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/models/__init__.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/models/common.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/notification.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/paged_query_result.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/pipeline.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/pipeline_image.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/plot.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/plots/__init__.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/plots/common.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/plots/theme.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/request.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/script.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/scripts/__init__.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/scripts/common.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/search.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/solution_component.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/streamlit_utils.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/template.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/template_config.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/trigger.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/twin.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/twinregistration.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/user.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/wizard_function.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/wizard_request.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi/words.py +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi.egg-info/SOURCES.txt +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi.egg-info/dependency_links.txt +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi.egg-info/requires.txt +0 -0
- {wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi.egg-info/top_level.txt +0 -0
|
@@ -17,10 +17,33 @@ from .trigger import Trigger
|
|
|
17
17
|
from .twin import Twin, TwinType
|
|
18
18
|
from .pipeline import Pipeline
|
|
19
19
|
from .pipeline_image import PipelineImage
|
|
20
|
+
from .deployment import Deployment
|
|
20
21
|
from .insight import Insight
|
|
21
22
|
from .edge_device import EdgeDevice
|
|
22
23
|
|
|
23
24
|
|
|
25
|
+
# Entities withdrawn from the client, and what to say instead.
|
|
26
|
+
#
|
|
27
|
+
# Removing one from `_registry` alone would fail with "Api entity triggers is not
|
|
28
|
+
# supported", which reads as a bug in the client. These messages name the
|
|
29
|
+
# replacement, so the first person to hit it can act instead of filing.
|
|
30
|
+
#
|
|
31
|
+
# The DTO itself is NOT removed — `wizata_dsapi.Trigger` is still imported and used
|
|
32
|
+
# by the platform internally (the 12.1 adopt-triggers migration reads them through
|
|
33
|
+
# `ApiDataManager.backend_api`, which never consults this registry). What goes is
|
|
34
|
+
# the ability to schedule through the public client.
|
|
35
|
+
_retired = {
|
|
36
|
+
"triggers": (
|
|
37
|
+
Trigger,
|
|
38
|
+
"triggers are no longer managed through this client (12.1). A schedule now "
|
|
39
|
+
"belongs to a Deployment, which owns its trigger and knows how to pause, "
|
|
40
|
+
"resume and remove it: use api.deploy(...) and the deployment methods. "
|
|
41
|
+
"Deleting a trigger on its own would leave a Deployment record claiming a "
|
|
42
|
+
"schedule that no longer exists, and nothing would find it again."
|
|
43
|
+
),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
24
47
|
# init APIs supported operations
|
|
25
48
|
_registry = {
|
|
26
49
|
"business_labels":
|
|
@@ -41,6 +64,17 @@ _registry = {
|
|
|
41
64
|
"cloud_dsapi": ['lists', 'get_by_id', 'get_by_key', 'create', 'update', 'delete', 'search'],
|
|
42
65
|
"cloud_context": ['get_by_id', 'get_by_key', 'create', 'update', 'delete', 'search']
|
|
43
66
|
},
|
|
67
|
+
"deployments":
|
|
68
|
+
{
|
|
69
|
+
"class": Deployment,
|
|
70
|
+
# No 'create': a deployment is not posted into existence, it is the
|
|
71
|
+
# RESULT of deploying a pipeline — see WizataDSAPIClient.deploy, which
|
|
72
|
+
# runs merge, release, image and trigger as one call and returns the
|
|
73
|
+
# record to poll. Offering create here would invite a half-built record
|
|
74
|
+
# with no schedule behind it.
|
|
75
|
+
"cloud_dsapi": ['lists', 'get_by_id', 'update', 'delete', 'search'],
|
|
76
|
+
"cloud_context": []
|
|
77
|
+
},
|
|
44
78
|
"datastores":
|
|
45
79
|
{
|
|
46
80
|
"class": DataStore,
|
|
@@ -137,12 +171,6 @@ _registry = {
|
|
|
137
171
|
"cloud_dsapi": ['lists', 'get_by_id', 'create', 'update', 'delete'],
|
|
138
172
|
"cloud_context": []
|
|
139
173
|
},
|
|
140
|
-
"triggers":
|
|
141
|
-
{
|
|
142
|
-
"class": Trigger,
|
|
143
|
-
"cloud_dsapi": ['lists', 'get_by_id', 'create', 'update', 'delete'],
|
|
144
|
-
"cloud_context": ['get_by_id']
|
|
145
|
-
},
|
|
146
174
|
"twins":
|
|
147
175
|
{
|
|
148
176
|
"class": Twin,
|
|
@@ -134,14 +134,31 @@ class ApiInterface:
|
|
|
134
134
|
if entity in self._dto_registry.keys():
|
|
135
135
|
self._verify_operation(entity, operation)
|
|
136
136
|
return self._dto_registry[entity]["class"]
|
|
137
|
-
|
|
138
|
-
raise TypeError(f"Api entity {entity} is not supported.")
|
|
137
|
+
self._refuse(entity)
|
|
139
138
|
else:
|
|
140
139
|
for entity_name in self._dto_registry:
|
|
141
140
|
if self._dto_registry[entity_name]["class"] == entity:
|
|
142
141
|
self._verify_operation(entity_name, operation)
|
|
143
142
|
return entity
|
|
144
|
-
|
|
143
|
+
self._refuse(entity)
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def _refuse(entity):
|
|
147
|
+
"""
|
|
148
|
+
Raise for an entity this client does not serve, saying WHY when it is one
|
|
149
|
+
that was withdrawn rather than one that never existed.
|
|
150
|
+
|
|
151
|
+
"Api entity triggers is not supported" reads as a bug in the client, and the
|
|
152
|
+
person reading it has no way to know a schedule is now a Deployment. Both
|
|
153
|
+
the plural name and the DTO class are matched, since callers reach the
|
|
154
|
+
registry through either.
|
|
155
|
+
"""
|
|
156
|
+
from .api_config import _retired
|
|
157
|
+
|
|
158
|
+
for name, (dto, message) in _retired.items():
|
|
159
|
+
if entity == name or entity is dto:
|
|
160
|
+
raise TypeError(f"Api entity {name} is no longer supported: {message}")
|
|
161
|
+
raise TypeError(f"Api entity {entity} is not supported.")
|
|
145
162
|
|
|
146
163
|
def _verify_operation(self,
|
|
147
164
|
entity,
|
|
@@ -210,6 +210,12 @@ class Deployment(ApiDto):
|
|
|
210
210
|
if "updatedDate" in obj.keys() and obj["updatedDate"] is not None:
|
|
211
211
|
self.updatedDate = obj["updatedDate"]
|
|
212
212
|
|
|
213
|
+
def to_dict(self) -> dict:
|
|
214
|
+
"""Serialize the Deployment. Alias of :meth:`to_json`, which is the
|
|
215
|
+
canonical implementation here — the DTO convention accepts either
|
|
216
|
+
spelling, and the client calls ``to_dict``."""
|
|
217
|
+
return self.to_json()
|
|
218
|
+
|
|
213
219
|
def to_json(self, target: str = None):
|
|
214
220
|
obj = {
|
|
215
221
|
"id": str(self.deployment_id),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.0.dev20"
|
|
@@ -53,6 +53,7 @@ from .api_interface import ApiInterface
|
|
|
53
53
|
from .mobile_asset import MobileAssetTile, MobileAssetConfig
|
|
54
54
|
from .version import __version__
|
|
55
55
|
import ast
|
|
56
|
+
from .deployment import Deployment, DeploymentStatus
|
|
56
57
|
from .api_config import _registry
|
|
57
58
|
|
|
58
59
|
from .streamlit_utils import get_streamlit_token, get_streamlit_domain
|
|
@@ -713,39 +714,28 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
|
|
|
713
714
|
else:
|
|
714
715
|
return self.create(obj)
|
|
715
716
|
|
|
716
|
-
def
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
"""
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
:
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
:param interval: interval in milliseconds.
|
|
739
|
-
:param template: template to fetch.
|
|
740
|
-
:param twin: hardware ID of twin to fetch based on template.
|
|
741
|
-
:param null: By default at 'drop' and dropping NaN values. If not intended behavior please set it to 'ignore' or 'all'.
|
|
742
|
-
:param group: can be use to set group system and event retrieving instructions (dict or list[dict]).
|
|
743
|
-
:param filters: dict of filters.
|
|
744
|
-
:param options: dict of options.
|
|
745
|
-
:param field: by default 'value' if none, accept str or list (e.g. value, reliability, eventId, ...)
|
|
746
|
-
:param bucket: specify on which bucket the query applies.
|
|
747
|
-
:param scopes: list of scope filters for SCOPED datapoints (e.g. ["normal", {"vibration": {"gte": 0.6}}]).
|
|
748
|
-
:return: dataframe
|
|
717
|
+
def _build_request(self,
|
|
718
|
+
datapoints: list = None,
|
|
719
|
+
start: datetime = None,
|
|
720
|
+
end: datetime = None,
|
|
721
|
+
interval: int = None,
|
|
722
|
+
agg_method: str = "mean",
|
|
723
|
+
template: str = None,
|
|
724
|
+
twin: str = None,
|
|
725
|
+
null: str = None,
|
|
726
|
+
filters: dict = None,
|
|
727
|
+
options: dict = None,
|
|
728
|
+
group=None,
|
|
729
|
+
field=None,
|
|
730
|
+
bucket: str = None,
|
|
731
|
+
tags: dict = None,
|
|
732
|
+
scopes: list = None) -> Request:
|
|
733
|
+
"""
|
|
734
|
+
Build the Request behind a time-series query.
|
|
735
|
+
|
|
736
|
+
Shared by :meth:`query` and :meth:`query_json` so the two cannot disagree
|
|
737
|
+
about what an argument means. They differ only in what they ask the server
|
|
738
|
+
to send back — a DataFrame or described JSON — never in what they ask for.
|
|
749
739
|
"""
|
|
750
740
|
request = Request()
|
|
751
741
|
|
|
@@ -796,7 +786,47 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
|
|
|
796
786
|
if bucket is not None:
|
|
797
787
|
request.bucket = bucket
|
|
798
788
|
|
|
799
|
-
return
|
|
789
|
+
return request
|
|
790
|
+
|
|
791
|
+
def query(self,
|
|
792
|
+
datapoints: list = None,
|
|
793
|
+
start: datetime = None,
|
|
794
|
+
end: datetime = None,
|
|
795
|
+
interval: int = None,
|
|
796
|
+
agg_method: str = "mean",
|
|
797
|
+
template: str = None,
|
|
798
|
+
twin: str = None,
|
|
799
|
+
null: str = None,
|
|
800
|
+
filters: dict = None,
|
|
801
|
+
options: dict = None,
|
|
802
|
+
group = None,
|
|
803
|
+
field=None,
|
|
804
|
+
bucket: str = None,
|
|
805
|
+
tags: dict = None,
|
|
806
|
+
scopes: list = None) -> pandas.DataFrame:
|
|
807
|
+
"""
|
|
808
|
+
Query a dataframe from API.
|
|
809
|
+
:param agg_method:
|
|
810
|
+
:param datapoints: list of datapoints to fetch.
|
|
811
|
+
:param start: start datetime of range to fetch
|
|
812
|
+
:param end: end datetime of range to fetch
|
|
813
|
+
:param interval: interval in milliseconds.
|
|
814
|
+
:param template: template to fetch.
|
|
815
|
+
:param twin: hardware ID of twin to fetch based on template.
|
|
816
|
+
:param null: By default at 'drop' and dropping NaN values. If not intended behavior please set it to 'ignore' or 'all'.
|
|
817
|
+
:param group: can be use to set group system and event retrieving instructions (dict or list[dict]).
|
|
818
|
+
:param filters: dict of filters.
|
|
819
|
+
:param options: dict of options.
|
|
820
|
+
:param field: by default 'value' if none, accept str or list (e.g. value, reliability, eventId, ...)
|
|
821
|
+
:param bucket: specify on which bucket the query applies.
|
|
822
|
+
:param scopes: list of scope filters for SCOPED datapoints (e.g. ["normal", {"vibration": {"gte": 0.6}}]).
|
|
823
|
+
:return: dataframe
|
|
824
|
+
"""
|
|
825
|
+
return self._query(request=self._build_request(
|
|
826
|
+
datapoints=datapoints, start=start, end=end, interval=interval,
|
|
827
|
+
agg_method=agg_method, template=template, twin=twin, null=null,
|
|
828
|
+
filters=filters, options=options, group=group, field=field,
|
|
829
|
+
bucket=bucket, tags=tags, scopes=scopes))
|
|
800
830
|
|
|
801
831
|
def batch_query(self,
|
|
802
832
|
step: timedelta,
|
|
@@ -1179,6 +1209,38 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
|
|
|
1179
1209
|
raise ValueError("a pipeline key, UUID or Pipeline is required")
|
|
1180
1210
|
return urllib.parse.quote(str(reference), safe="")
|
|
1181
1211
|
|
|
1212
|
+
def _pipeline_uuid(self, pipeline) -> str:
|
|
1213
|
+
"""
|
|
1214
|
+
Path segment for a route that addresses a pipeline by UUID only.
|
|
1215
|
+
|
|
1216
|
+
Distinct from :meth:`_pipeline_ref`, and the difference is not cosmetic: the
|
|
1217
|
+
live-plot route resolves a key OR a UUID (DEV-6027), while the branch, deploy
|
|
1218
|
+
and preview routes parse the segment with ``uuid.UUID(id)`` and answer
|
|
1219
|
+
``400 badly formed hexadecimal UUID string`` for a key.
|
|
1220
|
+
|
|
1221
|
+
Callers hold keys — that is what a pipeline is called everywhere a person
|
|
1222
|
+
reads one — so the key is resolved here rather than refused.
|
|
1223
|
+
|
|
1224
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
1225
|
+
:return: the pipeline's UUID as a path segment.
|
|
1226
|
+
"""
|
|
1227
|
+
if isinstance(pipeline, Pipeline):
|
|
1228
|
+
if pipeline.pipeline_id is not None:
|
|
1229
|
+
return str(pipeline.pipeline_id)
|
|
1230
|
+
pipeline = pipeline.key
|
|
1231
|
+
if pipeline is None:
|
|
1232
|
+
raise ValueError("a pipeline key, UUID or Pipeline is required")
|
|
1233
|
+
if isinstance(pipeline, uuid.UUID):
|
|
1234
|
+
return str(pipeline)
|
|
1235
|
+
try:
|
|
1236
|
+
return str(uuid.UUID(str(pipeline)))
|
|
1237
|
+
except (ValueError, AttributeError, TypeError):
|
|
1238
|
+
pass
|
|
1239
|
+
resolved = self.get(pipeline_key=str(pipeline))
|
|
1240
|
+
if resolved is None or resolved.pipeline_id is None:
|
|
1241
|
+
raise ValueError(f"pipeline {pipeline!r} could not be resolved to an id")
|
|
1242
|
+
return str(resolved.pipeline_id)
|
|
1243
|
+
|
|
1182
1244
|
def deployed_plots(self, pipeline, twin: str = None) -> list:
|
|
1183
1245
|
"""
|
|
1184
1246
|
list a deployed pipeline's LIVE plots - what its deployments are currently
|
|
@@ -2013,6 +2075,294 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
|
|
|
2013
2075
|
)
|
|
2014
2076
|
return response.text
|
|
2015
2077
|
|
|
2078
|
+
def query_json(self, include_format: bool = True, **kwargs) -> dict:
|
|
2079
|
+
"""
|
|
2080
|
+
query time-series as JSON, described.
|
|
2081
|
+
|
|
2082
|
+
Takes the same arguments as :meth:`query`. Where ``query`` hands back a
|
|
2083
|
+
DataFrame, this returns the rows as JSON — and by default wraps them in a
|
|
2084
|
+
description of their own shape, so a caller that is not pandas can render
|
|
2085
|
+
them without guessing:
|
|
2086
|
+
|
|
2087
|
+
{"columns": [...], "pivot": ..., "data": [...]}
|
|
2088
|
+
|
|
2089
|
+
That is what the front-end's query form is built on: an aggregated query
|
|
2090
|
+
comes back pivoted with one column per datapoint, a raw one comes back long
|
|
2091
|
+
with a 'value' column, and only the envelope says which you got (DEV-6031).
|
|
2092
|
+
|
|
2093
|
+
A separate method rather than a flag on :meth:`query`, deliberately — a
|
|
2094
|
+
parameter that changes the return type between a DataFrame and a dict makes
|
|
2095
|
+
every caller branch on what it asked for.
|
|
2096
|
+
|
|
2097
|
+
:param include_format: False to get the bare rows without the envelope.
|
|
2098
|
+
:return: dict with columns/pivot/data, or the rows alone when
|
|
2099
|
+
``include_format`` is False.
|
|
2100
|
+
"""
|
|
2101
|
+
request = self._build_request(**kwargs)
|
|
2102
|
+
response = self._process_request(
|
|
2103
|
+
method="POST",
|
|
2104
|
+
route="data/",
|
|
2105
|
+
params={"include-format": "true" if include_format else "false"},
|
|
2106
|
+
data=json.dumps(request.to_json(), cls=DSAPIEncoder)
|
|
2107
|
+
)
|
|
2108
|
+
return response.json()
|
|
2109
|
+
|
|
2110
|
+
# ------------------------------------------------------------------ git branches
|
|
2111
|
+
|
|
2112
|
+
def branches(self, pipeline) -> dict:
|
|
2113
|
+
"""
|
|
2114
|
+
list the branches relevant to a pipeline.
|
|
2115
|
+
|
|
2116
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2117
|
+
:return: dict with 'default', 'feature' and 'release' - feature branches are
|
|
2118
|
+
this pipeline's drafts, release branches are the frozen refs deployments
|
|
2119
|
+
run from.
|
|
2120
|
+
"""
|
|
2121
|
+
response = self._process_request(
|
|
2122
|
+
method="GET",
|
|
2123
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/branches/"
|
|
2124
|
+
)
|
|
2125
|
+
return response.json()
|
|
2126
|
+
|
|
2127
|
+
def create_branch(self, pipeline, name: str = None, source: str = None) -> Pipeline:
|
|
2128
|
+
"""
|
|
2129
|
+
create a branch for a pipeline and return the pipeline as it stands on it.
|
|
2130
|
+
|
|
2131
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2132
|
+
:param name: branch name. Leave None for a draft, which is named for you.
|
|
2133
|
+
A release is named ``release/<name>``.
|
|
2134
|
+
:param source: ref to branch from; the default branch when None.
|
|
2135
|
+
:return: the Pipeline read at the new branch, with 'branch' set.
|
|
2136
|
+
"""
|
|
2137
|
+
payload = {}
|
|
2138
|
+
if name is not None:
|
|
2139
|
+
payload["name"] = name
|
|
2140
|
+
if source is not None:
|
|
2141
|
+
payload["source"] = source
|
|
2142
|
+
response = self._process_request(
|
|
2143
|
+
method="POST",
|
|
2144
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/branches/",
|
|
2145
|
+
data=json.dumps(payload)
|
|
2146
|
+
)
|
|
2147
|
+
return Pipeline.from_dict(response.json())
|
|
2148
|
+
|
|
2149
|
+
def delete_branch(self, pipeline, branch: str) -> None:
|
|
2150
|
+
"""
|
|
2151
|
+
discard a branch.
|
|
2152
|
+
|
|
2153
|
+
A draft goes on demand. A release is refused with 409 while a deployment or a
|
|
2154
|
+
trigger still runs from it - pause or redeploy those first, rather than
|
|
2155
|
+
leaving a schedule pointing at a ref that no longer exists.
|
|
2156
|
+
|
|
2157
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2158
|
+
:param branch: branch ref.
|
|
2159
|
+
"""
|
|
2160
|
+
self._process_request(
|
|
2161
|
+
method="DELETE",
|
|
2162
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/branches/{branch}/"
|
|
2163
|
+
)
|
|
2164
|
+
|
|
2165
|
+
def merge_branch(self, pipeline, branch: str) -> dict:
|
|
2166
|
+
"""
|
|
2167
|
+
merge a draft into the default branch and delete it.
|
|
2168
|
+
|
|
2169
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2170
|
+
:param branch: the feature branch to publish.
|
|
2171
|
+
:return: dict with 'merged_sha', 'deleted_branch' and 'files_changed'.
|
|
2172
|
+
"""
|
|
2173
|
+
response = self._process_request(
|
|
2174
|
+
method="POST",
|
|
2175
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/branches/{branch}/merge"
|
|
2176
|
+
)
|
|
2177
|
+
return response.json()
|
|
2178
|
+
|
|
2179
|
+
def get_pipeline_at(self, pipeline, branch: str) -> Pipeline:
|
|
2180
|
+
"""
|
|
2181
|
+
read a pipeline as it stands on a branch, rather than on the default one.
|
|
2182
|
+
|
|
2183
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2184
|
+
:param branch: branch ref.
|
|
2185
|
+
:return: Pipeline.
|
|
2186
|
+
"""
|
|
2187
|
+
response = self._process_request(
|
|
2188
|
+
method="GET",
|
|
2189
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/branches/{branch}/"
|
|
2190
|
+
)
|
|
2191
|
+
return Pipeline.from_dict(response.json())
|
|
2192
|
+
|
|
2193
|
+
def get_script_at(self, name: str, branch: str) -> Script:
|
|
2194
|
+
"""
|
|
2195
|
+
read a RAW script's source as it stands on a branch.
|
|
2196
|
+
|
|
2197
|
+
A branch run executes the branch's script, so this is what actually runs
|
|
2198
|
+
there - the default-branch copy may differ.
|
|
2199
|
+
|
|
2200
|
+
:param name: script name.
|
|
2201
|
+
:param branch: branch ref.
|
|
2202
|
+
:return: Script.
|
|
2203
|
+
"""
|
|
2204
|
+
response = self._process_request(
|
|
2205
|
+
method="GET",
|
|
2206
|
+
route=f"{Script.route()}/{name}/branches/{branch}/"
|
|
2207
|
+
)
|
|
2208
|
+
return Script.from_dict(response.json())
|
|
2209
|
+
|
|
2210
|
+
def save_script_at(self, script: Script, branch: str) -> None:
|
|
2211
|
+
"""
|
|
2212
|
+
save a RAW script on a branch, leaving the default branch untouched until the
|
|
2213
|
+
branch is merged.
|
|
2214
|
+
|
|
2215
|
+
:param script: Script with its source set.
|
|
2216
|
+
:param branch: branch ref.
|
|
2217
|
+
"""
|
|
2218
|
+
self._process_request(
|
|
2219
|
+
method="PUT",
|
|
2220
|
+
route=f"{Script.route()}/{script.name}/branches/{branch}/",
|
|
2221
|
+
files={"payload": (None, json.dumps(script.to_dict(), cls=DSAPIEncoder))}
|
|
2222
|
+
)
|
|
2223
|
+
|
|
2224
|
+
# ------------------------------------------------------------------ deployments
|
|
2225
|
+
|
|
2226
|
+
def deploy(self,
|
|
2227
|
+
pipeline,
|
|
2228
|
+
twins: list = None,
|
|
2229
|
+
interval: int = None,
|
|
2230
|
+
delay: int = None,
|
|
2231
|
+
packaging: str = None,
|
|
2232
|
+
source: str = None,
|
|
2233
|
+
properties: dict = None,
|
|
2234
|
+
plot: bool = None,
|
|
2235
|
+
train: bool = None,
|
|
2236
|
+
write: bool = None) -> Deployment:
|
|
2237
|
+
"""
|
|
2238
|
+
deploy a pipeline: merge the draft, cut the release, build the image and create
|
|
2239
|
+
the schedule - the whole sequence, as one call.
|
|
2240
|
+
|
|
2241
|
+
Returns immediately with a Deployment to poll; an image build outlasts the
|
|
2242
|
+
gateway timeout, so the record carries the progress instead of the request.
|
|
2243
|
+
Poll it with :meth:`get` on the returned id, or :meth:`await_deployment`.
|
|
2244
|
+
|
|
2245
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2246
|
+
:param twins: hardware ids or twin UUIDs this schedule covers - both forms are
|
|
2247
|
+
accepted - or ``{twin, target, deviceId}`` entries where target is "cloud"
|
|
2248
|
+
(default) or "edge".
|
|
2249
|
+
:param interval: milliseconds between runs.
|
|
2250
|
+
:param delay: milliseconds to wait after each interval boundary.
|
|
2251
|
+
:param packaging: "image" (default) or "release".
|
|
2252
|
+
:param source: branch or ref to deploy from.
|
|
2253
|
+
:param properties: pipeline properties for every run.
|
|
2254
|
+
:param plot: produce plots on each run. Refused on edge.
|
|
2255
|
+
:param train: train models on each run. Refused on edge, and on an
|
|
2256
|
+
image-packaged deployment - the model would be trained and silently
|
|
2257
|
+
discarded, because the image's frozen model is what predict uses.
|
|
2258
|
+
:param write: write results back. Defaults on.
|
|
2259
|
+
:return: Deployment to poll.
|
|
2260
|
+
"""
|
|
2261
|
+
payload = {}
|
|
2262
|
+
if twins is not None:
|
|
2263
|
+
payload["twins"] = twins
|
|
2264
|
+
for name, value in (("interval", interval), ("delay", delay),
|
|
2265
|
+
("packaging", packaging), ("source", source),
|
|
2266
|
+
("properties", properties)):
|
|
2267
|
+
if value is not None:
|
|
2268
|
+
payload[name] = value
|
|
2269
|
+
for name, value in (("plot", plot), ("train", train), ("write", write)):
|
|
2270
|
+
if value is not None:
|
|
2271
|
+
payload[name] = value
|
|
2272
|
+
response = self._process_request(
|
|
2273
|
+
method="POST",
|
|
2274
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/deploy/",
|
|
2275
|
+
data=json.dumps(payload)
|
|
2276
|
+
)
|
|
2277
|
+
return Deployment.from_dict(response.json())
|
|
2278
|
+
|
|
2279
|
+
def deploy_preview(self, pipeline, **kwargs) -> dict:
|
|
2280
|
+
"""
|
|
2281
|
+
plan a deploy without performing it: what would be merged, cut, built and
|
|
2282
|
+
scheduled, and every reason it would be refused.
|
|
2283
|
+
|
|
2284
|
+
Writes nothing, and always answers 200 - read ``ok`` and ``problems`` rather
|
|
2285
|
+
than catching an exception. Takes the same arguments as :meth:`deploy`.
|
|
2286
|
+
|
|
2287
|
+
:param pipeline: pipeline key, UUID or Pipeline.
|
|
2288
|
+
:return: the plan, including 'ok' and 'problems'.
|
|
2289
|
+
"""
|
|
2290
|
+
payload = {k: v for k, v in kwargs.items() if v is not None}
|
|
2291
|
+
response = self._process_request(
|
|
2292
|
+
method="POST",
|
|
2293
|
+
route=f"{Pipeline.route()}/{self._pipeline_uuid(pipeline)}/deploy/preview/",
|
|
2294
|
+
data=json.dumps(payload)
|
|
2295
|
+
)
|
|
2296
|
+
return response.json()
|
|
2297
|
+
|
|
2298
|
+
def _deployment_action(self, deployment, action: str) -> Deployment:
|
|
2299
|
+
deployment_id = (deployment.deployment_id
|
|
2300
|
+
if isinstance(deployment, Deployment) else deployment)
|
|
2301
|
+
response = self._process_request(
|
|
2302
|
+
method="POST",
|
|
2303
|
+
route=f"{Deployment.route()}/{deployment_id}/{action}/"
|
|
2304
|
+
)
|
|
2305
|
+
return Deployment.from_dict(response.json())
|
|
2306
|
+
|
|
2307
|
+
def pause_deployment(self, deployment) -> Deployment:
|
|
2308
|
+
"""
|
|
2309
|
+
pause a deployment: delete its trigger, keep the record.
|
|
2310
|
+
|
|
2311
|
+
Synchronous. The manifest is kept, so :meth:`resume_deployment` rebuilds the
|
|
2312
|
+
same schedule rather than asking for it again.
|
|
2313
|
+
|
|
2314
|
+
:param deployment: Deployment or its id.
|
|
2315
|
+
:return: the updated Deployment.
|
|
2316
|
+
"""
|
|
2317
|
+
return self._deployment_action(deployment, "pause")
|
|
2318
|
+
|
|
2319
|
+
def resume_deployment(self, deployment) -> Deployment:
|
|
2320
|
+
"""
|
|
2321
|
+
resume a paused deployment, re-creating its trigger from the stored manifest.
|
|
2322
|
+
|
|
2323
|
+
:param deployment: Deployment or its id.
|
|
2324
|
+
:return: the updated Deployment.
|
|
2325
|
+
"""
|
|
2326
|
+
return self._deployment_action(deployment, "resume")
|
|
2327
|
+
|
|
2328
|
+
def retry_deployment(self, deployment) -> Deployment:
|
|
2329
|
+
"""
|
|
2330
|
+
continue a failed or interrupted deployment from where it stopped.
|
|
2331
|
+
|
|
2332
|
+
Safe to call repeatedly: a merge or a release cut cannot be undone, so
|
|
2333
|
+
completed steps are skipped rather than replayed.
|
|
2334
|
+
|
|
2335
|
+
:param deployment: Deployment or its id.
|
|
2336
|
+
:return: the updated Deployment.
|
|
2337
|
+
"""
|
|
2338
|
+
return self._deployment_action(deployment, "retry")
|
|
2339
|
+
|
|
2340
|
+
def await_deployment(self,
|
|
2341
|
+
deployment,
|
|
2342
|
+
timeout: int = 900,
|
|
2343
|
+
interval: int = 5) -> Deployment:
|
|
2344
|
+
"""
|
|
2345
|
+
poll a deployment until it stops moving.
|
|
2346
|
+
|
|
2347
|
+
:param deployment: Deployment or its id.
|
|
2348
|
+
:param timeout: seconds before giving up waiting.
|
|
2349
|
+
:param interval: seconds between polls.
|
|
2350
|
+
:return: the Deployment in its final state - check ``status``, which is
|
|
2351
|
+
'deployed' on success and 'failed' otherwise.
|
|
2352
|
+
"""
|
|
2353
|
+
import time
|
|
2354
|
+
deployment_id = (deployment.deployment_id
|
|
2355
|
+
if isinstance(deployment, Deployment) else deployment)
|
|
2356
|
+
deadline = time.time() + timeout
|
|
2357
|
+
current = self.get(deployment_id=deployment_id)
|
|
2358
|
+
while time.time() < deadline:
|
|
2359
|
+
if current.status in (DeploymentStatus.DEPLOYED, DeploymentStatus.FAILED,
|
|
2360
|
+
DeploymentStatus.PAUSED):
|
|
2361
|
+
return current
|
|
2362
|
+
time.sleep(interval)
|
|
2363
|
+
current = self.get(deployment_id=deployment_id)
|
|
2364
|
+
return current
|
|
2365
|
+
|
|
2016
2366
|
def build_image(self, key: str, branch: str = None) -> str:
|
|
2017
2367
|
"""
|
|
2018
2368
|
build an image of a pipeline, store it on the image repository and return its pipeline image id.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.1.0.dev18"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wizata_dsapi-2.1.0.dev18 → wizata_dsapi-2.1.0.dev20}/wizata_dsapi.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|