wizata-dsapi 1.3.19__py3-none-any.whl → 1.3.21__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.
wizata_dsapi/mlmodel.py CHANGED
@@ -1,10 +1,5 @@
1
- import json
2
- import uuid
3
-
4
1
  from typing import List, Iterator
5
-
6
2
  from .api_dto import ApiDto
7
- from enum import Enum
8
3
 
9
4
 
10
5
  def get_bool(obj, name: str):
@@ -14,6 +9,118 @@ def get_bool(obj, name: str):
14
9
  return bool(obj[name])
15
10
 
16
11
 
12
+ class ModelInfo:
13
+ """
14
+ define a pointer to a machine learning model.
15
+
16
+ :ivar model_type str: mlflow model flavour
17
+ """
18
+
19
+ def __init__(self,
20
+ key: str,
21
+ twin_hardware_id: str = None,
22
+ property_name: str = None,
23
+ alias: str = None,
24
+ model_type: str = None,
25
+ file_format: str = 'pkl',
26
+ source: str = 'wizata'
27
+ ):
28
+ self.key = key
29
+ self.twin_hardware_id = twin_hardware_id
30
+ self.property_name = property_name
31
+ self.alias = alias
32
+ self.file_format = file_format
33
+ self.source = source
34
+ self.model_type = model_type
35
+ self.trained_model = None
36
+ self.scaler = None
37
+
38
+ def identifier(self, include_alias: bool = False) -> str:
39
+ """
40
+ returns the complete string identifier for this model.
41
+ :param include_alias: include the alias pointer or leave it to target the default version.
42
+ :return: complete identifier of a model.
43
+ """
44
+ if self.key is None:
45
+ raise KeyError('please specific a model key')
46
+ identifier = self.key
47
+
48
+ if self.twin_hardware_id is not None:
49
+ identifier += f".{self.twin_hardware_id}"
50
+
51
+ if self.property_name is not None:
52
+ identifier += f".{self.property_name}"
53
+
54
+ if include_alias and self.alias is not None:
55
+ identifier += f"@{self.alias}"
56
+
57
+ return identifier
58
+
59
+ def to_json(self):
60
+ """
61
+ convert this entity in a dict that can be json serializable
62
+ :return: dict
63
+ """
64
+ obj = {
65
+ "key": self.key,
66
+ "file_format": self.file_format,
67
+ "source": self.source
68
+ }
69
+ if self.twin_hardware_id is not None:
70
+ obj["twin_hardware_id"] = str(self.twin_hardware_id)
71
+ if self.property_name is not None:
72
+ obj["property_name"] = self.property_name
73
+ if self.alias is not None:
74
+ obj["alias"] = self.alias
75
+ if self.model_type is not None:
76
+ obj["model_type"] = self.model_type
77
+ if self.file_format is not None:
78
+ obj["file_format"] = self.file_format
79
+ if self.source is not None:
80
+ obj["source"] = self.source
81
+ return obj
82
+
83
+ def from_json(self, obj):
84
+ """
85
+ load this entity from a dict
86
+ """
87
+ if "key" in obj.keys():
88
+ self.key = obj["key"]
89
+ if "twin_hardware_id" in obj.keys():
90
+ self.twin_hardware_id = obj["twin_hardware_id"]
91
+ if "property_name" in obj.keys():
92
+ self.property_name = obj["property_name"]
93
+ if "alias" in obj.keys():
94
+ self.alias = obj["alias"]
95
+ if "model_type" in obj.keys():
96
+ self.model_type = obj["model_type"]
97
+ if "file_format" in obj.keys():
98
+ self.key = obj["file_format"]
99
+ if "source" in obj.keys():
100
+ self.source = obj["source"]
101
+
102
+
103
+ class ModelList:
104
+ """
105
+ used to conveniently manipulate a list of models.
106
+ """
107
+
108
+ def __init__(self):
109
+ self.models: List[ModelInfo] = []
110
+
111
+ def __iter__(self) -> Iterator[ModelInfo]:
112
+ return iter(self.models)
113
+
114
+ def __len__(self) -> int:
115
+ return len(self.models)
116
+
117
+ def __getitem__(self, index: int) -> ModelInfo:
118
+ return self.models[index]
119
+
120
+ def append(self, model: ModelInfo):
121
+ self.models.append(model)
122
+
123
+
17
124
  class MLModelConfig(ApiDto):
18
125
  """
19
126
  a model config defines execution properties within a pipeline.
@@ -87,6 +194,25 @@ class MLModelConfig(ApiDto):
87
194
  self.model_type = model_type
88
195
  self.model_alias = model_alias
89
196
 
197
+ def create_model_info(self, hardware_id: str = None) -> ModelInfo:
198
+ """
199
+ create model info corresponding to the configuration.
200
+ :param hardware_id: provide a hardware id for this model if by_twin.
201
+ :return:
202
+ """
203
+ if self.by_twin and hardware_id is None:
204
+ raise ValueError('hardware_id is required if by_twin to create a model info')
205
+ model_info = ModelInfo(
206
+ key=self.model_key,
207
+ twin_hardware_id=hardware_id,
208
+ property_name=self.property_name,
209
+ source=self.source,
210
+ alias=self.model_alias,
211
+ file_format=self.model_format,
212
+ model_type=self.model_type
213
+ )
214
+ return model_info
215
+
90
216
  def from_json(self, obj):
91
217
 
92
218
  # Managed deprecated fields
@@ -230,228 +356,3 @@ class MLModelConfig(ApiDto):
230
356
  else:
231
357
  raise TypeError(f'unsupported target_feat type {self.target_feat.__class__.__name__}')
232
358
 
233
-
234
- class ModelInfo:
235
- """
236
- define a pointer to a machine learning model.
237
- """
238
-
239
- def __init__(self,
240
- key: str,
241
- twin_hardware_id: str = None,
242
- property_name: str = None,
243
- alias: str = None,
244
- file_format: str = 'pkl',
245
- source: str = 'wizata'
246
- ):
247
- self.key = key
248
- self.twin_hardware_id = twin_hardware_id
249
- self.property_name = property_name
250
- self.alias = alias
251
- self.file_format = file_format
252
- self.source = source
253
- self.trained_model = None
254
- self.scaler = None
255
-
256
- def identifier(self, include_alias: bool = False) -> str:
257
- """
258
- returns the complete string identifier for this model.
259
- :param include_alias: include the alias pointer or leave it to target the default version.
260
- :return: complete identifier of a model.
261
- """
262
- if self.key is None:
263
- raise KeyError('please specific a model key')
264
- identifier = self.key
265
-
266
- if self.twin_hardware_id is not None:
267
- identifier += f".{self.twin_hardware_id}"
268
-
269
- if self.property_name is not None:
270
- identifier += f".{self.property_name}"
271
-
272
- if include_alias and self.alias is not None:
273
- identifier += f"@{self.alias}"
274
-
275
- return identifier
276
-
277
- def to_json(self):
278
- """
279
- convert this entity in a dict that can be json serializable
280
- :return: dict
281
- """
282
- obj = {
283
- "key": self.key,
284
- "file_format": self.file_format,
285
- "source": self.source
286
- }
287
- if self.twin_hardware_id is not None:
288
- obj["twin_hardware_id"] = str(self.twin_hardware_id)
289
- if self.property_name is not None:
290
- obj["property_name"] = self.property_name
291
- if self.alias is not None:
292
- obj["alias"] = self.alias
293
- if self.file_format is not None:
294
- obj["file_format"] = self.file_format
295
- if self.source is not None:
296
- obj["source"] = self.source
297
- return obj
298
-
299
- def from_json(self, obj):
300
- """
301
- load this entity from a dict
302
- """
303
- if "key" in obj.keys():
304
- self.key = obj["key"]
305
- if "twin_hardware_id" in obj.keys():
306
- self.twin_hardware_id = obj["twin_hardware_id"]
307
- if "property_name" in obj.keys():
308
- self.property_name = obj["property_name"]
309
- if "alias" in obj.keys():
310
- self.alias = obj["alias"]
311
- if "file_format" in obj.keys():
312
- self.key = obj["file_format"]
313
- if "source" in obj.keys():
314
- self.source = obj["source"]
315
-
316
-
317
- class ModelList:
318
- """
319
- used to conveniently manipulate a list of models.
320
- """
321
-
322
- def __init__(self):
323
- self.models: List[ModelInfo] = []
324
-
325
- def __iter__(self) -> Iterator[ModelInfo]:
326
- return iter(self.models)
327
-
328
- def __len__(self) -> int:
329
- return len(self.models)
330
-
331
- def __getitem__(self, index: int) -> ModelInfo:
332
- return self.models[index]
333
-
334
- def append(self, model: ModelInfo):
335
- self.models.append(model)
336
-
337
-
338
- class MLModel(ApiDto):
339
- """
340
- used to define a stored machine learning model within Wizata.
341
- - deprecated -
342
- """
343
-
344
- @classmethod
345
- def route(cls):
346
- return "mlmodels"
347
-
348
- @classmethod
349
- def from_dict(cls, data):
350
- obj = MLModel()
351
- obj.from_json(data)
352
- return obj
353
-
354
- @classmethod
355
- def get_type(cls):
356
- return "pickle"
357
-
358
- def __init__(self,
359
- model_id: str = None,
360
- generated_by_id=None,
361
- exact_names=True,
362
- exact_numbers=True,
363
- key=None):
364
- self.model_id = model_id
365
- self.key = key
366
-
367
- self.generatedById = generated_by_id
368
-
369
- self.status = 'draft'
370
- self.input_columns = []
371
- self.output_columns = []
372
-
373
- self.needExactColumnNumbers = exact_numbers
374
- self.needExactColumnNames = exact_names
375
- self.has_anomalies = False
376
- self.label_counts = 0
377
- self.has_target_feat = False
378
-
379
- self.trained_model = None
380
- self.scaler = None
381
-
382
- self.experimentId = None
383
-
384
- def api_id(self) -> str:
385
- return str(self.model_id).upper()
386
-
387
- def endpoint(self) -> str:
388
- return "MLModels"
389
-
390
- def to_json(self, target: str = None):
391
- obj = {"id": str(self.model_id),
392
- "status": str(self.status),
393
- "needExactColumnNames": str(self.needExactColumnNames),
394
- "needExactColumnNumbers": str(self.needExactColumnNumbers),
395
- "hasAnomalies": str(self.has_anomalies),
396
- "hasTargetFeat": str(self.has_target_feat),
397
- "labelCount": str(self.label_counts)
398
- }
399
- if self.key is not None:
400
- obj["key"] = str(self.key)
401
- if self.generatedById is not None:
402
- obj["generatedById"] = self.generatedById
403
- if self.input_columns is not None:
404
- obj["inputColumns"] = json.dumps(list(self.input_columns))
405
- if self.output_columns is not None:
406
- obj["outputColumns"] = json.dumps(list(self.output_columns))
407
- if self.experimentId is not None:
408
- obj["experimentId"] = str(self.experimentId)
409
- return obj
410
-
411
- def from_json(self, obj):
412
- if "id" in obj.keys():
413
- self.model_id = obj["id"]
414
- if "key" in obj.keys() and obj["key"] is not None:
415
- self.key = obj["key"]
416
- if "generatedById" in obj.keys() and obj["generatedById"] is not None:
417
- self.generatedById = int(obj["generatedById"])
418
- if "experimentId" in obj.keys() and obj["experimentId"] is not None:
419
- self.experimentId = uuid.UUID(obj["experimentId"])
420
- if "status" in obj.keys():
421
- self.status = str(obj["status"]).lower()
422
- if "inputColumns" in obj.keys():
423
- self.input_columns = json.loads(obj["inputColumns"])
424
- if "outputColumns" in obj.keys():
425
- self.output_columns = json.loads(obj["outputColumns"])
426
- if "labelCount" in obj.keys():
427
- self.label_counts = int(obj["labelCount"])
428
- if "hasAnomalies" in obj.keys():
429
- if isinstance(obj["hasAnomalies"], str) and obj["hasAnomalies"].lower() == "false":
430
- self.has_anomalies = False
431
- else:
432
- self.has_anomalies = bool(obj["hasAnomalies"])
433
- if "hasTargetFeat" in obj.keys():
434
- if isinstance(obj["hasTargetFeat"], str) and obj["hasTargetFeat"].lower() == "false":
435
- self.has_target_feat = False
436
- else:
437
- self.has_target_feat = bool(obj["hasTargetFeat"])
438
- if "needExactColumnNumbers" in obj.keys():
439
- if isinstance(obj["needExactColumnNumbers"], str) and obj["needExactColumnNumbers"].lower() == "false":
440
- self.needExactColumnNumbers = False
441
- else:
442
- self.needExactColumnNumbers = bool(obj["needExactColumnNumbers"])
443
- if "needExactColumnNames" in obj.keys():
444
- if isinstance(obj["needExactColumnNames"], str) and obj["needExactColumnNames"].lower() == "false":
445
- self.needExactColumnNames = False
446
- else:
447
- self.needExactColumnNames = bool(obj["needExactColumnNames"])
448
-
449
- def get_sample_payload(self):
450
- pl_columns = {"timestamp": "[timestamp]"}
451
- for hardwareId in self.input_columns:
452
- pl_columns[hardwareId] = "[" + hardwareId + "]"
453
- pl_json = {
454
- "id": str(self.model_id),
455
- "dataset": pl_columns
456
- }
457
- return pl_json
wizata_dsapi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.3.19"
1
+ __version__ = "1.3.21"
@@ -23,7 +23,7 @@ from .api_dto import ApiDto, VarType
23
23
  from .business_label import BusinessLabel
24
24
  from .plot import Plot
25
25
  from .request import Request
26
- from .mlmodel import MLModel
26
+ from .mlmodel import ModelInfo, ModelList
27
27
  from .experiment import Experiment
28
28
  from .script import Script
29
29
  from .execution import Execution, ExecutionStatus
@@ -590,15 +590,6 @@ class WizataDSAPIClient(ApiInterface):
590
590
  return obj.script_id
591
591
  else:
592
592
  raise self.__raise_error(response)
593
- if isinstance(obj, MLModel):
594
- response = requests.put(self.__url() + "mlmodels/",
595
- headers=self.__header(),
596
- data=pickle.dumps(obj))
597
- if response.status_code == 200:
598
- obj.model_id = uuid.UUID(response.json()['id'])
599
- return obj.model_id
600
- else:
601
- raise self.__raise_error(response)
602
593
  if isinstance(obj, Template):
603
594
  return self.upsert_template(obj.key, obj.name)
604
595
  if isinstance(obj, Pipeline):
@@ -847,13 +838,6 @@ class WizataDSAPIClient(ApiInterface):
847
838
  execution.script = self.get(script_name=script)
848
839
  elif isinstance(script, Script):
849
840
  execution.script = script
850
- if ml_model is not None:
851
- if isinstance(ml_model, uuid.UUID) or (isinstance(ml_model, str) and is_valid_uuid(ml_model)):
852
- execution.ml_model = MLModel(ml_model)
853
- elif isinstance(ml_model, str):
854
- execution.ml_model = self.get(model_key=ml_model)
855
- elif isinstance(ml_model, MLModel):
856
- execution.ml_model = ml_model
857
841
  if image is not None:
858
842
  execution.pipeline_image_id = image
859
843
  if isAnomalyDetection:
@@ -899,9 +883,6 @@ class WizataDSAPIClient(ApiInterface):
899
883
  if "plots" in obj.keys():
900
884
  for plot in obj["plots"]:
901
885
  result_execution.plots.append(self.get(Plot(plot_id=plot["id"])))
902
- if "models" in obj.keys():
903
- for mlmodel in obj["models"]:
904
- result_execution.models.append(self.get(MLModel(model_id=mlmodel["id"])))
905
886
  if "resultDataframe" in obj.keys() and obj["resultDataframe"]["id"] is not None:
906
887
  result_execution.output_ds_dataframe = self.get(DSDataFrame(df_id=obj["resultDataframe"]["id"]))
907
888
 
@@ -1104,7 +1085,7 @@ class WizataDSAPIClient(ApiInterface):
1104
1085
  scaler=None,
1105
1086
  has_anomalies: bool = False,
1106
1087
  has_target_feat: bool = False,
1107
- experiment_key = None) -> tuple[MLModel, pandas.DataFrame]:
1088
+ experiment_key = None) -> tuple[ModelInfo, pandas.DataFrame]:
1108
1089
  """
1109
1090
  Register a Machine Learning model to Wizata.
1110
1091
  Model is tested by the API against a sample dataframe.
@@ -1124,15 +1105,13 @@ class WizataDSAPIClient(ApiInterface):
1124
1105
  elif df is None:
1125
1106
  raise ValueError('A sample dataframe must be provided')
1126
1107
 
1127
- # Create a ML Model object
1128
- ml_model = MLModel()
1108
+ ml_model = ModelInfo(key=model_key)
1129
1109
  ml_model.trained_model = train_model
1130
1110
  if scaler is not None:
1131
1111
  ml_model.scaler = scaler
1132
1112
  ml_model.has_anomalies = has_anomalies
1133
1113
  ml_model.has_target_feat = has_target_feat
1134
1114
  ml_model.input_columns = df.columns
1135
- ml_model.key = model_key
1136
1115
 
1137
1116
  if experiment_key is not None:
1138
1117
  ml_model.experimentId = self.get(experiment_key=experiment_key).experiment_id
@@ -1141,7 +1120,8 @@ class WizataDSAPIClient(ApiInterface):
1141
1120
  result_df = predict(df, ml_model)
1142
1121
  if result_df is not None:
1143
1122
  ml_model.status = "valid"
1144
- self.upsert(ml_model)
1123
+ #TODO: proper method to upload and download from registry to modify this one
1124
+ ## self.upsert(ml_model)
1145
1125
  return ml_model, result_df
1146
1126
  else:
1147
1127
  raise RuntimeError('no dataframe was generated by your model while testing predict capabilities')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wizata_dsapi
3
- Version: 1.3.19
3
+ Version: 1.3.21
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -16,7 +16,7 @@ wizata_dsapi/experiment.py,sha256=QYQ1CJ-MTWsXq08xYbm5sAp95dRxbPOmGDgaAOoBMDQ,46
16
16
  wizata_dsapi/group_system.py,sha256=6rUKe0_J3YWACysyBlzuw_TEpKNXgLOMxhpWsNxOzwY,1708
17
17
  wizata_dsapi/ilogger.py,sha256=iYnID-Z-qrYhie26C43404aIuU4_tHSKXbDeQIdo82Q,807
18
18
  wizata_dsapi/insight.py,sha256=ABFZ04DqYxxzqAEfU1tzlTZqqrigM-zN-8Lbetko3g0,6468
19
- wizata_dsapi/mlmodel.py,sha256=UWMMEM7HraaWDcAvhNWprDmp51slfQCRZ9rJz8gSkXE,18308
19
+ wizata_dsapi/mlmodel.py,sha256=oMPJ84Lj3kiV3nrvyUsohgmDQTCylEkJYoKadbOPdDo,14769
20
20
  wizata_dsapi/model_toolkit.py,sha256=a76ckSuetSKDjEkOl7o49g9oaItdw9iOaPt0JcstmhU,1551
21
21
  wizata_dsapi/paged_query_result.py,sha256=0Iyt2Kd4tvrfthhT-tk9EmSERsbJTaPNON2euHcBn6k,1150
22
22
  wizata_dsapi/pipeline.py,sha256=WDJeOxPZJiYW1qwTNZUm3jom2epIxqrSoiUwcrTF9EE,31300
@@ -31,10 +31,10 @@ wizata_dsapi/template.py,sha256=wtCRKKk3PchH4RrNgNYlEF_9C6bzZwKIeLyEvgv6Fdo,1370
31
31
  wizata_dsapi/trigger.py,sha256=w3BZYP-L3SUwvaT0oCTanh_Ewn57peZvlt7vxzHv9J8,5129
32
32
  wizata_dsapi/twin.py,sha256=S0DUzQf1smZXZTdXpXZPtkZYCfKIhw53EecCnsl9i4Q,11017
33
33
  wizata_dsapi/twinregistration.py,sha256=Mi6-YuwroiEXc0c1hgrOaphh4hNVoHupxOnXedVtJtE,13377
34
- wizata_dsapi/version.py,sha256=jaVXz6TyVY_Nag7MZC9dCEvvdZi4YdmlKEq9xG4gRts,23
34
+ wizata_dsapi/version.py,sha256=L7ePzmJS2DCpRZIO6IeXNVJp_LWlECnzA-aOTxRmcCE,23
35
35
  wizata_dsapi/wizard_function.py,sha256=RbM7W7Gf-6Rhp_1dU9DBYkHaciknGAGvuAndhAS_vyo,942
36
36
  wizata_dsapi/wizard_request.py,sha256=v6BaqKLKvTWmUSo0_gda9FabAQz5x_-GOH1Av50GzFo,3762
37
- wizata_dsapi/wizata_dsapi_client.py,sha256=kos_8j47CBXiy6y6b_H2yDUe3aWh76diEmWjCisYKkY,78662
37
+ wizata_dsapi/wizata_dsapi_client.py,sha256=h8iSz7IGbP-Zq9rbqMdq-hTrt16laD1JeaRWPzaLaoo,77695
38
38
  wizata_dsapi/words.py,sha256=tV8CqzCqODZCV7PgBxBF5exBxeF_ya9t5DiUy-cg6Sg,1535
39
39
  wizata_dsapi/models/__init__.py,sha256=O5PHqw8lKILw4apO-MfDxPz73wK0vADD9y3xjuzX7Tw,104
40
40
  wizata_dsapi/models/common.py,sha256=1dTqE80-mFJnUwEdNlJdhJzfZ2N5Kp8Nb3LQ8uwPtLc,3808
@@ -42,8 +42,8 @@ wizata_dsapi/plots/__init__.py,sha256=qgnSFqrjOPur-807M8uh5awIfjM1ZHXUXcAqHc-r2l
42
42
  wizata_dsapi/plots/common.py,sha256=jdPsJqLHBwSKc6dX83BSGPqSRxzIVNHSYO5yI_8sjGk,6568
43
43
  wizata_dsapi/scripts/__init__.py,sha256=hAxiETSQf0qOHde1si1tEAJU48seqEgHrchCzS2-LvQ,80
44
44
  wizata_dsapi/scripts/common.py,sha256=efwq-Rd0lvYljIs3gSFz9izogBD7asOU2cTK-IvHTkM,4244
45
- wizata_dsapi-1.3.19.dist-info/licenses/LICENSE.txt,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
46
- wizata_dsapi-1.3.19.dist-info/METADATA,sha256=KHpmyA9BrTDOH2UV0yQsj2lChqlElNny7O3Aft4E3iQ,5651
47
- wizata_dsapi-1.3.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
48
- wizata_dsapi-1.3.19.dist-info/top_level.txt,sha256=-OeTJbEnh5DuWyTOHtvw0Dw3LRg3G27TNS6W4ZtfwPs,13
49
- wizata_dsapi-1.3.19.dist-info/RECORD,,
45
+ wizata_dsapi-1.3.21.dist-info/licenses/LICENSE.txt,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
46
+ wizata_dsapi-1.3.21.dist-info/METADATA,sha256=GRqmZGZy0kyqq6l9txGH7CRX-K5mr5rgMBEDzaNr5lM,5651
47
+ wizata_dsapi-1.3.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
48
+ wizata_dsapi-1.3.21.dist-info/top_level.txt,sha256=-OeTJbEnh5DuWyTOHtvw0Dw3LRg3G27TNS6W4ZtfwPs,13
49
+ wizata_dsapi-1.3.21.dist-info/RECORD,,