naeural-client 3.2.2__py3-none-any.whl → 3.2.3__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.
naeural_client/_ver.py CHANGED
@@ -1,4 +1,4 @@
1
- __VER__ = "3.2.2"
1
+ __VER__ = "3.2.3"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  with open("pyproject.toml", "rt") as fd:
@@ -45,7 +45,7 @@ from ..utils.config import (
45
45
 
46
46
  DEBUG_MQTT_SERVER = "r9092118.ala.eu-central-1.emqxsl.com"
47
47
  SDK_NETCONFIG_REQUEST_DELAY = 300
48
-
48
+ SHOW_PENDING_THRESHOLD = 3600
49
49
 
50
50
 
51
51
 
@@ -3319,6 +3319,50 @@ class GenericSession(BaseDecentrAIObject):
3319
3319
  return dct_result
3320
3320
 
3321
3321
 
3322
+ def date_to_readable(self, date, check_none=False, start_time=None, pending_threshold=SHOW_PENDING_THRESHOLD):
3323
+ """
3324
+ Convert a date to a human-readable format.
3325
+
3326
+ Parameters
3327
+ ----------
3328
+
3329
+ date : str
3330
+ The date to convert.
3331
+ check_none : bool, optional
3332
+ If True, and the date is None it will check if too much time passed from the start time.
3333
+ If too much time passed, it will return 'Error!', otherwise, it will return 'Pending'.
3334
+ If False, it will return 'Never' if the date is None.
3335
+ Defaults to False.
3336
+ start_time : str, optional
3337
+ The start time to compare with the date in case it is None. Defaults to None.
3338
+ pending_threshold : int, optional
3339
+ The threshold in seconds to consider a date as pending. Defaults to SHOW_PENDING_THRESHOLD.
3340
+ If the time passed since start_time is greater than pending_threshold and
3341
+ check_none is set to True, it will return 'Error!'.
3342
+
3343
+ Returns
3344
+ -------
3345
+
3346
+ str
3347
+ The human-readable date.
3348
+ """
3349
+ if date is None:
3350
+ if not check_none or start_time is None:
3351
+ return 'Never'
3352
+ # endif not check_none
3353
+ start_dt = self.log.str_to_date(start_time, fmt='%Y-%m-%d %H:%M:%S.%f')
3354
+ since_start = (dt.now() - start_dt).total_seconds()
3355
+ if since_start > pending_threshold:
3356
+ return 'Error!'
3357
+ return 'Pending'
3358
+ # endif date is None
3359
+ if date.startswith('1970'):
3360
+ return 'Never'
3361
+ if '.' in date:
3362
+ date = date.split('.')[0]
3363
+ return date
3364
+
3365
+
3322
3366
  def get_nodes_apps(
3323
3367
  self,
3324
3368
  node=None,
@@ -3409,16 +3453,18 @@ class GenericSession(BaseDecentrAIObject):
3409
3453
  if len(instance_status) == 0:
3410
3454
  # this instance is only present in config but is NOT loaded so ignore it
3411
3455
  continue
3412
- start_time = instance_status.get('INIT_TIMESTAMP')
3413
- last_probe = instance_status.get('EXEC_TIMESTAMP')
3414
- last_data = instance_status.get('LAST_PAYLOAD_TIME')
3415
- dates = [start_time, last_probe, last_data]
3416
- for i in range(len(dates)):
3417
- if isinstance(dates[i], str):
3418
- if dates[i].startswith('1970'):
3419
- dates[i] = 'Never'
3420
- elif '.' in dates[i]:
3421
- dates[i] = dates[i].split('.')[0]
3456
+ start_time = instance_status.get(HB.ACTIVE_PLUGINS_INFO.INIT_TIMESTAMP)
3457
+ last_probe = instance_status.get(HB.ACTIVE_PLUGINS_INFO.EXEC_TIMESTAMP)
3458
+ last_data = instance_status.get(HB.ACTIVE_PLUGINS_INFO.LAST_PAYLOAD_TIME)
3459
+ dates = [start_time, last_data]
3460
+ error_dates = [
3461
+ instance_status.get(HB.ACTIVE_PLUGINS_INFO.FIRST_ERROR_TIME),
3462
+ instance_status.get(HB.ACTIVE_PLUGINS_INFO.LAST_ERROR_TIME),
3463
+ ]
3464
+ dates = [self.date_to_readable(x, check_none=False) for x in dates]
3465
+ error_dates = [self.date_to_readable(x, check_none=False) for x in error_dates]
3466
+ last_probe = self.date_to_readable(last_probe, check_none=True, start_time=start_time)
3467
+
3422
3468
  lst_plugin_instance_data.append({
3423
3469
  'Node' : node,
3424
3470
  'Owner' : pipeline_owner,
@@ -3427,8 +3473,9 @@ class GenericSession(BaseDecentrAIObject):
3427
3473
  'Plugin': instance.signature,
3428
3474
  'Id': instance.instance_id,
3429
3475
  'Start' : dates[0],
3430
- 'Probe' : dates[1],
3431
- 'Data' : dates[2],
3476
+ 'Probe' : last_probe,
3477
+ 'Data' : dates[1],
3478
+ 'LastError': error_dates[1],
3432
3479
  })
3433
3480
  # endfor instances in app
3434
3481
  # endfor apps
@@ -3438,7 +3485,8 @@ class GenericSession(BaseDecentrAIObject):
3438
3485
  log_with_color(f'Node(s) {nodes} not found. Please check the configuration.', color='r')
3439
3486
  return
3440
3487
  if as_df:
3441
- df = pd.DataFrame(lst_plugin_instance_data)
3488
+ color_condition = lambda x: (x['LastError'] != 'Never' or x['Probe'] == 'Error!')
3489
+ df = self.log.colored_dataframe(lst_plugin_instance_data, color_condition=color_condition)
3442
3490
  if not (df.empty or df.shape[0] == 0):
3443
3491
  df['Node'] = df['Node'].apply(lambda x: self._shorten_addr(x))
3444
3492
  df['Owner'] = df['Owner'].apply(lambda x: self._shorten_addr(x))
@@ -7,12 +7,82 @@ import hashlib
7
7
  import numpy as np
8
8
  import traceback
9
9
  import random
10
+ import pandas as pd
10
11
  from queue import Queue
11
12
 
12
13
  from collections import OrderedDict, deque, defaultdict
13
14
 
14
15
  from io import BytesIO, TextIOWrapper
15
16
 
17
+ class ColorDataFrame(pd.DataFrame):
18
+ """
19
+ A DataFrame subclass that colors specific rows red when printed in a console.
20
+
21
+ Parameters
22
+ ----------
23
+ *args : tuple
24
+ Positional arguments passed to the pd.DataFrame constructor.
25
+ color_condition : callable, optional
26
+ A function that takes a row (pd.Series) and returns True if the row should be
27
+ highlighted in red, or False otherwise.
28
+ **kwargs : dict
29
+ Keyword arguments passed to the pd.DataFrame constructor.
30
+
31
+ Returns
32
+ -------
33
+ ColorDataFrame
34
+ A subclass of DataFrame that overrides the to_string method for coloring.
35
+
36
+ Examples
37
+ --------
38
+
39
+ df = ColorDataFrame(
40
+ df,
41
+ color_condition=lambda row: row['value'] > 9
42
+ )
43
+ print(df)
44
+ """
45
+
46
+ _metadata = ['_color_condition']
47
+
48
+ def __init__(self, *args, color_condition=lambda row: False, **kwargs):
49
+ super().__init__(*args, **kwargs)
50
+ # Store the condition function as an attribute
51
+ self._color_condition = color_condition
52
+ return
53
+
54
+ def to_string(self, *args, **kwargs):
55
+ """
56
+ Overridden version of to_string that applies ANSI colors to rows
57
+ matching the condition.
58
+ """
59
+ original_string = super().to_string(*args, **kwargs)
60
+ # Split the original string into lines
61
+ lines = original_string.split('\n')
62
+
63
+ header_lines = lines[:1]
64
+ data_lines = lines[1:]
65
+
66
+ colored_data_lines = []
67
+ for row_index, row_line in enumerate(data_lines):
68
+ # Attempt to parse the index from the leftmost part of each row line
69
+ try:
70
+ # The row's index in the actual DataFrame
71
+ df_index = self.index[row_index]
72
+ except IndexError:
73
+ colored_data_lines.append(row_line)
74
+ continue
75
+
76
+ # Check if row meets the color condition
77
+ if self._color_condition(self.loc[df_index]):
78
+ # Red color ANSI: \033[91m ... \033[0m
79
+ row_line = f"\033[91m{row_line}\033[0m"
80
+
81
+ colored_data_lines.append(row_line)
82
+
83
+ return "\n".join(header_lines + colored_data_lines)
84
+
85
+
16
86
 
17
87
  adjectives = [
18
88
  'able', 'arco', 'arty', 'awed', 'awny', 'bald', 'base', 'bass', 'bent', 'best', 'boxy',
@@ -64,6 +134,14 @@ class _UtilsMixin(object):
64
134
 
65
135
  def __init__(self):
66
136
  super(_UtilsMixin, self).__init__()
137
+
138
+
139
+ @staticmethod
140
+ def colored_dataframe(df, color_condition=lambda row: False):
141
+ """
142
+ A DataFrame subclass that colors specific rows red when printed in a console.
143
+ """
144
+ return ColorDataFrame(df, color_condition=color_condition)
67
145
 
68
146
  @staticmethod
69
147
  def get_function_parameters(function):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: naeural_client
3
- Version: 3.2.2
3
+ Version: 3.2.3
4
4
  Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
5
5
  Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
6
6
  Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
@@ -1,10 +1,10 @@
1
1
  naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
2
- naeural_client/_ver.py,sha256=NOz7aEJ1WJsh43U4LtIYy2q2MqQlpRN564G-nIQDATM,330
2
+ naeural_client/_ver.py,sha256=NqGZgRNQnimSeJA03BGa0lVm-mFJ6vDk6i-aLlC7aQA,330
3
3
  naeural_client/base_decentra_object.py,sha256=iXvAAf6wPnGWzeeiRfwLojVoan-m1e_VsyPzjUQuENo,4492
4
4
  naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
5
5
  naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
6
6
  naeural_client/base/distributed_custom_code_presets.py,sha256=cvz5R88P6Z5V61Ce1vHVVh8bOkgXd6gve_vdESDNAsg,2544
7
- naeural_client/base/generic_session.py,sha256=ATB1k_mQ_efvek_ZgsYYex3G4ouhXds3CHRz1_lOKZM,127702
7
+ naeural_client/base/generic_session.py,sha256=c0UV6Gkz5QF7hSBIckf_DHS0EN3S9V2ekrwILgKRYVk,129690
8
8
  naeural_client/base/instance.py,sha256=annR9qt6zqzIyf_AVzAIfxWHF8Y_zEjviels2MNfcPM,21916
9
9
  naeural_client/base/pipeline.py,sha256=5IJnb8SRiCDJ3IRl02gEMXxjugGedyhu6xESP33GMpo,62521
10
10
  naeural_client/base/plugin_template.py,sha256=7YAFaND2iXoZLgtunjYkFf_TBGieFr3VdNLO3vCqzmM,138795
@@ -86,7 +86,7 @@ naeural_client/logging/logger_mixins/process_mixin.py,sha256=ZO7S1mvKWwH_UIqv7JG
86
86
  naeural_client/logging/logger_mixins/resource_size_mixin.py,sha256=EdCeFM8Ol8q_OTOmsj5Q2uKPvkqkoNdcXSZjw4FgAh4,2297
87
87
  naeural_client/logging/logger_mixins/timers_mixin.py,sha256=6D1HlLB97TpIwJEqj4UPBf1Md2HVORlSWtwXqnKyab4,17315
88
88
  naeural_client/logging/logger_mixins/upload_mixin.py,sha256=mvooNlNDNa_9D906d5qkfzTcvvsAuBOResoGCZ5IFnE,7697
89
- naeural_client/logging/logger_mixins/utils_mixin.py,sha256=G07keY2KhMQB094MIuw4ao6-_NCvoKyomp0j-tASOk0,22658
89
+ naeural_client/logging/logger_mixins/utils_mixin.py,sha256=bD__K6CdSt99UTHdJkvb58cTlOWBouvPgUeifBHfrH4,24897
90
90
  naeural_client/logging/tzlocal/__init__.py,sha256=PBLaZSFatmJp2fX4Bwalwc5LgWX9Vcw-FWHnBvW1k8E,384
91
91
  naeural_client/logging/tzlocal/unix.py,sha256=Cgpzg1jxrcSivyT5xFRX69W5XkF5ollvXPr976RIbmA,7268
92
92
  naeural_client/logging/tzlocal/utils.py,sha256=6F2QE3b8xiKwBriQaT0jrgBeyrKhCj6b-eSCEywLSMg,3094
@@ -97,8 +97,8 @@ naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_L
97
97
  naeural_client/utils/config.py,sha256=ohZFdIaRLwcWK0sh0loDD7JS9bsC9mqsFYairWZSVNg,9814
98
98
  naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
99
99
  naeural_client/utils/oracle_sync/oracle_tester.py,sha256=QwfBqXxPIOTVT6WVySkkxPnU3eJVvoyOEbq1ZQRuPRw,27245
100
- naeural_client-3.2.2.dist-info/METADATA,sha256=uj-o5GbwAvg3Uxx9MKKVUiLYkfCNX2WV8vnkn9aPWTk,12363
101
- naeural_client-3.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
102
- naeural_client-3.2.2.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
103
- naeural_client-3.2.2.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
104
- naeural_client-3.2.2.dist-info/RECORD,,
100
+ naeural_client-3.2.3.dist-info/METADATA,sha256=r1vZWhhIFRBPhcEL-Jedn3lipOZZiDqKaPeytiviyBo,12363
101
+ naeural_client-3.2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
102
+ naeural_client-3.2.3.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
103
+ naeural_client-3.2.3.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
104
+ naeural_client-3.2.3.dist-info/RECORD,,