wizata-dsapi 1.2.8__py3-none-any.whl → 1.2.11__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/__init__.py CHANGED
@@ -4,7 +4,7 @@ from .api_dto import ApiDto, VarType
4
4
  from .paged_query_result import PagedQueryResult
5
5
  from .plot import Plot
6
6
  from .mlmodel import MLModel, MLModelConfig
7
- from .request import Request, filter_map, RequestGroup, RequestGroupMap
7
+ from .request import Request, filter_map, RequestGroup, RequestGroupMap, DynamicSelector
8
8
  from .execution import Execution, ExecutionStatus, ExecutionStepLog, AbortedException
9
9
  from .experiment import Experiment
10
10
  from .ds_dataframe import DSDataFrame
wizata_dsapi/request.py CHANGED
@@ -15,6 +15,35 @@ filter_map = {
15
15
  '!=': 'neq'
16
16
  }
17
17
 
18
+ class DynamicSelector:
19
+ """
20
+ A dynamic selector defines how datapoint(s) are fetched within a query.
21
+ - it corresponds to a request to fetch datapoints
22
+ - it must be used on a twin base query
23
+ :ivar category: filter datapoints on uuid of a category or str name.
24
+ """
25
+
26
+ def __init__(self, category = None):
27
+ self.category = category
28
+
29
+ @classmethod
30
+ def from_dict(cls, obj):
31
+ dynamic_selector = cls()
32
+ dynamic_selector.from_json(obj)
33
+ return dynamic_selector
34
+
35
+ def from_json(self, obj):
36
+ if not isinstance(obj, dict):
37
+ raise TypeError('dynamic selector to parse is not a dict.')
38
+ if "category" in obj:
39
+ self.category = obj["category"]
40
+
41
+ def to_json(self) -> dict:
42
+ obj = {}
43
+ if self.category:
44
+ obj["category"] = self.category
45
+ return obj
46
+
18
47
  class RequestGroup:
19
48
  """
20
49
  Define a group statement within a structured query.
@@ -140,10 +169,9 @@ class Request(ApiDto):
140
169
  self.request_id = request_id
141
170
  self.function = None
142
171
 
143
- # Equipments & Data Points
144
- self.equipments = []
145
- if datapoints is not None:
146
- self.add_datapoints(datapoints)
172
+ # Datapoints
173
+ self._datapoints = []
174
+ self.datapoints = datapoints
147
175
 
148
176
  # Template & Registration
149
177
  self.template = None
@@ -293,63 +321,6 @@ class Request(ApiDto):
293
321
  else:
294
322
  return
295
323
 
296
- def prepare(self):
297
- """
298
- prepare analyse the query and produce a dict with query information.
299
- :return: dict
300
- """
301
- query = {}
302
- if self.request_id is not None:
303
- query["id"] = str(self.request_id)
304
- if self.equipments is not None:
305
- query["equipments_list"] = self.equipments
306
- else:
307
- raise KeyError("Missing data points inside the query - add_datapoints")
308
- if self.start is not None and self.end is not None:
309
-
310
- if isinstance(self.start, str):
311
- start = self.start
312
- else:
313
- start = self.__format_date(self.start)
314
-
315
- if isinstance(self.end, str):
316
- end = self.end
317
- else:
318
- end = self.__format_date(self.end)
319
-
320
- query["timeframe"] = {
321
- "start": start,
322
- "end": end
323
- }
324
- else:
325
- if self.group is None:
326
- raise KeyError("missing in query start and end date, "
327
- "please use datatime format or try with a group system")
328
- query["aggregations"] = {
329
- "agg_method": self.aggregation
330
- }
331
- if self.interval:
332
- query["aggregations"]["interval"] = self.interval * 1000
333
- if self.null is not None and self.null != 'drop':
334
- query['null'] = self.null
335
- if self.template is not None:
336
- query['template'] = self.template
337
- if isinstance(self.template, dict) and 'template_id' in query['template']:
338
- query['template']['template_id'] = str(query['template']['template_id'])
339
- if self.filters is not None:
340
- query['filters'] = self.filters
341
- if self.group is not None:
342
- query['group'] = self.group
343
- if self.options is not None:
344
- query['options'] = self.options
345
- if self.field is not None:
346
- query['field'] = self.field
347
- if self.bucket is not None:
348
- query['bucket'] = self.bucket
349
- if self.tags is not None:
350
- query['tags'] = self.tags
351
- return query
352
-
353
324
  def __format_date(self, dt_to_format):
354
325
  if isinstance(dt_to_format, datetime):
355
326
  millisec = dt_to_format.timestamp() * 1000
@@ -387,79 +358,42 @@ class Request(ApiDto):
387
358
  else:
388
359
  raise TypeError(f'unsupported end datetime type {self.end.__class__.__name__}')
389
360
 
390
- def add_datapoints(self, datapoints, shift: int = 0):
391
- """
392
- add datapoints to existing list of datapoints in the query.
393
- :param datapoints: datapoints to fetch identified by hardware id or template property name.
394
- :param shift: shift to apply in seconds on timestamp, by default 0.
395
- """
396
- self.equipments.append({
397
- "id": None,
398
- "datapoints": list(datapoints),
399
- "shift": str(shift) + "s"
400
- })
361
+ @property
362
+ def datapoints(self):
363
+ return self._datapoints
364
+
365
+ @datapoints.setter
366
+ def datapoints(self, values):
367
+ self._datapoints = []
368
+ if values:
369
+ if not isinstance(values, list):
370
+ raise ValueError(f'datapoints on a query must be a list of str, dict or DynamicSelector')
371
+ for value in values:
372
+ if isinstance(value, str):
373
+ self._datapoints.append(value)
374
+ elif isinstance(value, dict):
375
+ self._datapoints.append(DynamicSelector.from_dict(value))
376
+ elif isinstance(value, DynamicSelector):
377
+ self._datapoints.append(value)
378
+ else:
379
+ raise TypeError(f'datapoints on a query must be a list of str, dict or DynamicSelector '
380
+ f'but encountered {type(value)} as {value}')
401
381
 
402
- def get_datapoints(self) -> list:
403
- """
404
- get datapoints
405
- :return: list of declared datapoints.
406
- """
382
+ @property
383
+ def datapoints_without_selectors(self):
407
384
  datapoints = []
408
-
409
- if self.equipments is not None:
410
- for equipment in self.equipments:
411
- if "datapoints" not in equipment.keys():
412
- raise KeyError("No 'data points' have been provided for equipment with id '" +
413
- str(equipment["id"]) + "'")
414
- for datapoint in equipment["datapoints"]:
415
- if isinstance(datapoint, str):
416
- datapoints.append(datapoint)
417
- elif "id" in datapoint.keys():
418
- datapoints.append(datapoint["id"])
419
- else:
420
- raise KeyError("Incorrect datapoint declaration : '" + str(datapoint) + "'")
421
-
385
+ for datapoint in self._datapoints:
386
+ if not isinstance(datapoint, DynamicSelector):
387
+ datapoints.append(datapoint)
422
388
  return datapoints
423
389
 
424
- def set_datapoints(self, datapoints: list):
425
- """
426
- replace current datapoints by provided list
427
- """
428
- self.equipments = []
429
- if datapoints is not None:
430
- self.add_datapoints(datapoints)
431
-
432
- def add_equipment(self, equipment_id: uuid.UUID, datapoints, shift=0):
433
- """
434
- add datapoints to fetch with a digital twin id identification.
435
- :param equipment_id: UUID of the Digital Twin ID to which the datapoints are linked.
436
- :param datapoints: List(str) of datapoints to fetch identified by Hardware ID.
437
- :param shift: Shift to apply in seconds on timestamp, by default 0.
438
- """
439
- if not isinstance(equipment_id, uuid.UUID):
440
- raise TypeError("equipment_id must be of type uuid.UUID")
441
- for equipment in self.equipments:
442
- if "id" in equipment.keys() and equipment["id"] == str(equipment_id):
443
- raise ValueError("equipment_id is already in the request please remove it before adding datapoints.")
444
- self.equipments.append({
445
- "id": str(equipment_id),
446
- "datapoints": list(datapoints),
447
- "shift": str(shift) + "s"
448
- })
449
-
450
- def remove_equipment(self, equipment_id: uuid.UUID):
451
- """
452
- remove equipment from the list including all its listed datapoints.
453
- :param equipment_id: UUID of the Digital Twin item.
454
- """
455
- if equipment_id is not None and not isinstance(equipment_id, uuid.UUID):
456
- raise TypeError("equipment_id must be None or of type uuid.UUID")
457
- found = None
458
- for equipment in self.equipments:
459
- if "id" in equipment.keys() and equipment["id"] == str(equipment_id):
460
- found = equipment
461
- if found is not None:
462
- self.equipments.remove(equipment)
390
+ @property
391
+ def datapoints_only_selectors(self):
392
+ datapoints = []
393
+ for datapoint in self._datapoints:
394
+ if isinstance(datapoint, DynamicSelector):
395
+ datapoints.append(datapoint)
396
+ return datapoints
463
397
 
464
398
  def set_aggregation(self, method, interval=None):
465
399
  """
@@ -555,9 +489,87 @@ class Request(ApiDto):
555
489
  raise KeyError(f'parameter {name} not found in request.')
556
490
 
557
491
  def to_json(self, target: str = None):
558
- obj = self.prepare()
559
- self.set_extra_data(obj)
560
- return obj
492
+ query = {}
493
+
494
+ if self.request_id is not None:
495
+ query["id"] = str(self.request_id)
496
+
497
+ datapoints = []
498
+ for datapoint in self.datapoints:
499
+ if isinstance(datapoint, str):
500
+ datapoints.append(datapoint)
501
+ elif isinstance(datapoint, dict):
502
+ datapoints.append(datapoint)
503
+ elif isinstance(datapoint, DynamicSelector):
504
+ datapoints.append(datapoint.to_json())
505
+ else:
506
+ raise TypeError(f'datapoints on a query must be a list of str, dict or DynamicSelector '
507
+ f'but encountered {type(datapoint)} as {datapoint}')
508
+ query["datapoints"] = datapoints
509
+
510
+ if self.start is not None and self.end is not None:
511
+
512
+ if isinstance(self.start, str):
513
+ start = self.start
514
+ else:
515
+ start = self.__format_date(self.start)
516
+
517
+ if isinstance(self.end, str):
518
+ end = self.end
519
+ else:
520
+ end = self.__format_date(self.end)
521
+
522
+ query["timeframe"] = {
523
+ "start": start,
524
+ "end": end
525
+ }
526
+ else:
527
+ if self.group is None:
528
+ raise KeyError("missing in query start and end date, "
529
+ "please use datatime format or try with a group system")
530
+ query["aggregations"] = {
531
+ "agg_method": self.aggregation
532
+ }
533
+ if self.interval:
534
+ query["aggregations"]["interval"] = self.interval * 1000
535
+ if self.null is not None and self.null != 'drop':
536
+ query['null'] = self.null
537
+ if self.template is not None:
538
+ query['template'] = self.template
539
+ if isinstance(self.template, dict) and 'template_id' in query['template']:
540
+ query['template']['template_id'] = str(query['template']['template_id'])
541
+ if self.filters is not None:
542
+ query['filters'] = self.filters
543
+ if self.group is not None:
544
+ query['group'] = self.group
545
+ if self.options is not None:
546
+ query['options'] = self.options
547
+ if self.field is not None:
548
+ query['field'] = self.field
549
+ if self.bucket is not None:
550
+ query['bucket'] = self.bucket
551
+ if self.tags is not None:
552
+ query['tags'] = self.tags
553
+
554
+ if self.target_feat is not None:
555
+ query["target_feat"] = {
556
+ "sensor": self.target_feat["sensor"],
557
+ "operator": self.target_feat["operator"],
558
+ "threshold": self.target_feat["threshold"]
559
+ }
560
+ if self.on_off_sensor is not None and self.restart_time is not None:
561
+ query["restart_filter"] = {
562
+ "on_off_sensor": self.on_off_sensor,
563
+ "stop_restart_time": self.restart_time
564
+ }
565
+
566
+ if self.sensitivity is not None:
567
+ query["sensitivity"] = self.sensitivity
568
+
569
+ if self.extra_data is not None:
570
+ query["extra_data"] = self.extra_data
571
+
572
+ return query
561
573
 
562
574
  def from_json(self, json_data):
563
575
  if "id" in json_data.keys():
@@ -566,28 +578,27 @@ class Request(ApiDto):
566
578
  if "name" in json_data.keys():
567
579
  self.name = json_data["name"]
568
580
 
569
- found_dps = False
581
+ datapoints = []
570
582
  if "equipments_list" in json_data.keys():
571
- self.equipments = json_data["equipments_list"]
572
- for equipment in self.equipments:
583
+ for equipment in json_data["equipments_list"]:
573
584
  if "datapoints" not in equipment.keys():
574
- raise KeyError("No 'data points' have been provided for equipment with id '" +
585
+ raise KeyError("no 'datapoints' have been provided for equipment with id '" +
575
586
  str(equipment["id"]) + "'")
576
- else:
577
- found_dps = True
578
- elif "datapoints" in json_data.keys():
579
- equipment = {"datapoints": []}
580
- for datapoint in json_data["datapoints"]:
581
- equipment["datapoints"].append(datapoint)
582
- self.equipments.append(equipment)
583
- found_dps = True
587
+ datapoints.extend(equipment["datapoints"])
588
+
589
+ if "datapoints" in json_data.keys():
590
+ datapoints.extend(["datapoints"])
584
591
 
585
592
  if "template" in json_data.keys():
586
593
  self.template = json_data["template"]
587
- found_dps = True
588
594
 
589
- if not found_dps:
590
- raise KeyError('no equipments_list datapoints, nor template specified inside the request.')
595
+ if len(datapoints) == 0 and self.template is None:
596
+ raise KeyError('at least one datapoint or template is required within a request')
597
+
598
+ if len(datapoints) >= 0:
599
+ self.datapoints = datapoints
600
+ else:
601
+ self._datapoints = []
591
602
 
592
603
  if "timeframe" in json_data.keys():
593
604
  if "start" not in json_data["timeframe"].keys():
@@ -682,28 +693,4 @@ class Request(ApiDto):
682
693
  if "extra_data" in json_data.keys():
683
694
  self.extra_data = json_data["extra_data"]
684
695
 
685
- def set_extra_data(self, obj) -> dict:
686
- """
687
- deprecated - set additional data to query used as post-processing
688
- """
689
- if obj is None:
690
- obj = {}
691
- if self.target_feat is not None:
692
- obj["target_feat"] = {
693
- "sensor": self.target_feat["sensor"],
694
- "operator": self.target_feat["operator"],
695
- "threshold": self.target_feat["threshold"]
696
- }
697
- if self.on_off_sensor is not None and self.restart_time is not None:
698
- obj["restart_filter"] = {
699
- "on_off_sensor": self.on_off_sensor,
700
- "stop_restart_time": self.restart_time
701
- }
702
-
703
- if self.sensitivity is not None:
704
- obj["sensitivity"] = self.sensitivity
705
-
706
- if self.extra_data is not None:
707
- obj["extra_data"] = self.extra_data
708
- return obj
709
696
 
wizata_dsapi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.2.8"
1
+ __version__ = "1.2.11"
@@ -645,7 +645,7 @@ class WizataDSAPIClient(ApiInterface):
645
645
  request = Request()
646
646
 
647
647
  if datapoints is not None:
648
- request.add_datapoints(datapoints)
648
+ request.datapoints = datapoints
649
649
 
650
650
  if start is not None:
651
651
  request.start = start
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wizata-dsapi
3
- Version: 1.2.8
3
+ Version: 1.2.11
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -1,4 +1,4 @@
1
- wizata_dsapi/__init__.py,sha256=4J-4ssj9oyI_5vv2_vMOR5ZFYQxrcHrmv900KOQEFYY,2010
1
+ wizata_dsapi/__init__.py,sha256=_oC-utWDXSGjPyhoD6SK-6pWI-MeCTtwsipuzYTqu_Y,2027
2
2
  wizata_dsapi/api_config.py,sha256=pyGPyoCrfOFl-C6DlDRdQbQWDG2Y_oB4gvzjh2wYb8w,5300
3
3
  wizata_dsapi/api_dto.py,sha256=-NdaTRvw5jW5xFGpIhY8U0-SdvzW2t6QD26y0UPApU0,2238
4
4
  wizata_dsapi/api_interface.py,sha256=DURk-0ey16T8sV5e2Y2G_YybPEusJvZuY0oD5L7AnXo,10903
@@ -23,7 +23,7 @@ wizata_dsapi/pipeline.py,sha256=WDJeOxPZJiYW1qwTNZUm3jom2epIxqrSoiUwcrTF9EE,3130
23
23
  wizata_dsapi/pipeline_deployment.py,sha256=grekBaxUK0EhL9w7lDB8vNuW_wzLnHVm9Mq8Lkbkguk,1722
24
24
  wizata_dsapi/pipeline_image.py,sha256=M3FOr45dJIAEvsmXPpMD8JZ09k5-YpW9PRYEWJqptcI,5272
25
25
  wizata_dsapi/plot.py,sha256=SPGKFWWYNcRvHcqvvnPIIIBKsd5UwhdsxLW7b2dG2rs,2360
26
- wizata_dsapi/request.py,sha256=WTwctIzHLLtSSixcXBsNyoyLqdZk8dZdaCTVbejSvIQ,26287
26
+ wizata_dsapi/request.py,sha256=A9Z1h2x0DDDOkE95R5IZD9gJk6rUGail604b_whvNjY,25204
27
27
  wizata_dsapi/script.py,sha256=DeEciwVpuCYZetgJCoivw_bYe8ma52WuTaTQ_VkLEcg,12930
28
28
  wizata_dsapi/solution_component.py,sha256=8gbZWx2h_xUqI_pAXa3goqAnR5Y-GDMii8MeGlaK1IE,9531
29
29
  wizata_dsapi/streamlit_utils.py,sha256=sXBdygktbixV828Zg01Nl27_a4F8zGFc4RY0C8g-1bc,1942
@@ -31,10 +31,10 @@ wizata_dsapi/template.py,sha256=h2f3dLduJ4WhreVxJXuFIB3pinnI3c39WxBms0bCgos,1300
31
31
  wizata_dsapi/trigger.py,sha256=w3BZYP-L3SUwvaT0oCTanh_Ewn57peZvlt7vxzHv9J8,5129
32
32
  wizata_dsapi/twin.py,sha256=_iYbbKw_m8flEzdnwGbA-NvSUiyQQDgCTa9vJeEggRg,10556
33
33
  wizata_dsapi/twinregistration.py,sha256=Mi6-YuwroiEXc0c1hgrOaphh4hNVoHupxOnXedVtJtE,13377
34
- wizata_dsapi/version.py,sha256=CfVXm0wwlKPW0khOcwhWw61TpgtZiLijCePsAIOK3aU,22
34
+ wizata_dsapi/version.py,sha256=aBWZsCYiXXcSUsUJr3tOTQWsH7ZDqJzyMYdQbOd5Qtc,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=Qz54vYoxRLBUa21Q55K5Oo1qtZpW9ucuXi4BX1N85oE,78716
37
+ wizata_dsapi/wizata_dsapi_client.py,sha256=VSSe2WPRmKsbOBV3CqeHP7hftGolbx2zZ7xMJgZdteQ,78713
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.2.8.dist-info/LICENSE.txt,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
46
- wizata_dsapi-1.2.8.dist-info/METADATA,sha256=WRikpYQRfPcBEkfk239lutdBmdl7ApxLsglLGMdmySk,2187
47
- wizata_dsapi-1.2.8.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
48
- wizata_dsapi-1.2.8.dist-info/top_level.txt,sha256=-OeTJbEnh5DuWyTOHtvw0Dw3LRg3G27TNS6W4ZtfwPs,13
49
- wizata_dsapi-1.2.8.dist-info/RECORD,,
45
+ wizata_dsapi-1.2.11.dist-info/LICENSE.txt,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
46
+ wizata_dsapi-1.2.11.dist-info/METADATA,sha256=WmNWFk9m22cJ0LT90dx-SdauE5CoaucERvdcYZXv-6o,2188
47
+ wizata_dsapi-1.2.11.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
48
+ wizata_dsapi-1.2.11.dist-info/top_level.txt,sha256=-OeTJbEnh5DuWyTOHtvw0Dw3LRg3G27TNS6W4ZtfwPs,13
49
+ wizata_dsapi-1.2.11.dist-info/RECORD,,