naeural-client 2.4.6__py3-none-any.whl → 2.5.1__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.
@@ -11,5 +11,5 @@ from .base_decentra_object import BaseDecentrAIObject
11
11
  from .plugins_manager_mixin import _PluginsManagerMixin
12
12
  from .logging import Logger
13
13
  from .code_cheker import BaseCodeChecker
14
- from .const import PLUGIN_SIGNATURES
14
+ from .const import PLUGIN_SIGNATURES, PAYLOAD_DATA
15
15
  from .default.instance import PLUGIN_TYPES
naeural_client/_ver.py CHANGED
@@ -1,4 +1,4 @@
1
- __VER__ = "2.4.6"
1
+ __VER__ = "2.5.1"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  with open("pyproject.toml", "rt") as fd:
@@ -1,7 +1,9 @@
1
1
  import json
2
2
  import os
3
3
  import traceback
4
- from collections import deque
4
+ import pandas as pd
5
+
6
+ from collections import deque, OrderedDict
5
7
  from datetime import datetime as dt
6
8
  from threading import Lock, Thread
7
9
  from time import sleep
@@ -9,15 +11,22 @@ from time import time as tm
9
11
 
10
12
  from ..base_decentra_object import BaseDecentrAIObject
11
13
  from ..bc import DefaultBlockEngine
12
- from ..const import COMMANDS, ENVIRONMENT, HB, PAYLOAD_DATA, STATUS_TYPE, PLUGIN_SIGNATURES, BLOCKCHAIN_CONFIG
14
+ from ..const import (
15
+ COMMANDS, ENVIRONMENT, HB, PAYLOAD_DATA, STATUS_TYPE,
16
+ PLUGIN_SIGNATURES, DEFAULT_PIPELINES,
17
+ BLOCKCHAIN_CONFIG
18
+ )
13
19
  from ..const import comms as comm_ct
14
20
  from ..io_formatter import IOFormatterWrapper
15
21
  from ..logging import Logger
16
22
  from ..utils import load_dotenv
17
23
  from .payload import Payload
18
24
  from .pipeline import Pipeline
25
+ from .webapp_pipeline import WebappPipeline
19
26
  from .transaction import Transaction
20
- from ..utils.config import load_user_defined_config, get_user_config_file
27
+ from ..utils.config import load_user_defined_config, get_user_config_file, get_user_folder
28
+
29
+ # from ..default.instance import PLUGIN_TYPES # circular import
21
30
 
22
31
  # TODO: add support for remaining commands from EE
23
32
 
@@ -48,30 +57,35 @@ class GenericSession(BaseDecentrAIObject):
48
57
  }
49
58
 
50
59
 
51
- def __init__(self, *,
52
- host=None,
53
- port=None,
54
- user=None,
55
- pwd=None,
56
- secured=None,
57
- name='pySDK',
58
- encrypt_comms=True,
59
- config={},
60
- filter_workers=None,
61
- log: Logger = None,
62
- on_payload=None,
63
- on_notification=None,
64
- on_heartbeat=None,
65
- debug_silent=True,
66
- silent=False,
67
- verbosity=1,
68
- dotenv_path=None,
69
- show_commands=False,
70
- blockchain_config=BLOCKCHAIN_CONFIG,
71
- bc_engine=None,
72
- formatter_plugins_locations=['plugins.io_formatters'],
73
- root_topic="naeural",
74
- **kwargs) -> None:
60
+ def __init__(
61
+ self, *,
62
+ host=None,
63
+ port=None,
64
+ user=None,
65
+ pwd=None,
66
+ secured=None,
67
+ name='pySDK',
68
+ encrypt_comms=True,
69
+ config={},
70
+ filter_workers=None,
71
+ log: Logger = None,
72
+ on_payload=None,
73
+ on_notification=None,
74
+ on_heartbeat=None,
75
+ debug_silent=True,
76
+ silent=False,
77
+ verbosity=1,
78
+ dotenv_path=None,
79
+ show_commands=False,
80
+ blockchain_config=BLOCKCHAIN_CONFIG,
81
+ bc_engine=None,
82
+ formatter_plugins_locations=['plugins.io_formatters'],
83
+ root_topic="naeural",
84
+ local_cache_base_folder=None,
85
+ local_cache_app_folder='_local_cache',
86
+ use_home_folder=False,
87
+ **kwargs
88
+ ) -> None:
75
89
  """
76
90
  A Session is a connection to a communication server which provides the channel to interact with nodes from the Naeural Edge Protocol network.
77
91
  A Session manages `Pipelines` and handles all messages received from the communication server.
@@ -165,6 +179,9 @@ class GenericSession(BaseDecentrAIObject):
165
179
  self.online_timeout = 60
166
180
  self.filter_workers = filter_workers
167
181
  self.__show_commands = show_commands
182
+
183
+ # this is used to store data received from net-mon instances
184
+ self.__current_network_statuses = {}
168
185
 
169
186
  pwd = pwd or kwargs.get('password', kwargs.get('pass', None))
170
187
  user = user or kwargs.get('username', None)
@@ -194,11 +211,28 @@ class GenericSession(BaseDecentrAIObject):
194
211
  self.__open_transactions_lock = Lock()
195
212
 
196
213
  self.__create_user_callback_threads()
214
+
215
+ if local_cache_app_folder is None:
216
+ local_cache_app_folder = '_local_cache'
217
+ #
218
+
219
+ if os.path.exists(os.path.join(".", local_cache_app_folder)) and local_cache_base_folder is None:
220
+ local_cache_base_folder = '.'
221
+ # end if
222
+
223
+ if local_cache_base_folder is None or use_home_folder:
224
+ # use_home_folder allows us to use the home folder as the base folder
225
+ local_cache_base_folder = get_user_folder()
226
+ # end if
227
+
228
+
197
229
  super(GenericSession, self).__init__(
198
230
  log=log,
199
231
  DEBUG=not debug_silent,
200
232
  create_logger=True,
201
233
  silent=self.silent,
234
+ local_cache_base_folder=local_cache_base_folder,
235
+ local_cache_app_folder=local_cache_app_folder,
202
236
  )
203
237
  return
204
238
 
@@ -425,6 +459,8 @@ class GenericSession(BaseDecentrAIObject):
425
459
  self._dct_online_nodes_last_heartbeat[msg_node_addr] = dict_msg
426
460
 
427
461
  msg_node_id = dict_msg[PAYLOAD_DATA.EE_ID]
462
+ # track the node based on heartbeat - a normal heartbeat means the node is online
463
+ # however this can lead to long wait times for the first heartbeat for all nodes
428
464
  self.__track_online_node(msg_node_addr, msg_node_id)
429
465
 
430
466
  msg_active_configs = dict_msg.get(HB.CONFIG_STREAMS)
@@ -520,11 +556,48 @@ class GenericSession(BaseDecentrAIObject):
520
556
  self.custom_on_notification(self, msg_node_addr, Payload(dict_msg))
521
557
 
522
558
  return
559
+
560
+
561
+ def __maybe_process_net_mon(
562
+ self,
563
+ dict_msg: dict,
564
+ msg_pipeline : str,
565
+ msg_signature : str
566
+ ):
567
+ REQUIRED_PIPELINE = DEFAULT_PIPELINES.ADMIN_PIPELINE
568
+ REQUIRED_SIGNATURE = PLUGIN_SIGNATURES.NET_MON_01
569
+ if msg_pipeline.lower() == REQUIRED_PIPELINE.lower() and msg_signature.upper() == REQUIRED_SIGNATURE.upper():
570
+ # handle net mon message
571
+ sender_addr = dict_msg.get(PAYLOAD_DATA.EE_SENDER, None)
572
+ path = dict_msg.get(PAYLOAD_DATA.EE_PAYLOAD_PATH, [None, None, None, None])
573
+ ee_id = dict_msg.get(PAYLOAD_DATA.EE_ID, None)
574
+ current_network = dict_msg.get(PAYLOAD_DATA.NETMON_CURRENT_NETWORK, {})
575
+ if current_network:
576
+ all_addresses = [
577
+ x[PAYLOAD_DATA.NETMON_ADDRESS] for x in current_network.values()
578
+ ]
579
+ online_addresses = [
580
+ x[PAYLOAD_DATA.NETMON_ADDRESS] for x in current_network.values()
581
+ if x[PAYLOAD_DATA.NETMON_STATUS_KEY] == PAYLOAD_DATA.NETMON_STATUS_ONLINE
582
+ ]
583
+ self.P(f"Net config from <{sender_addr}> `{ee_id}`: {len(online_addresses)}/{len(all_addresses)}", color='y')
584
+ self.__current_network_statuses[sender_addr] = current_network
585
+ # end if current_network is valid
586
+ # end if NET_MON_01
587
+ return
588
+
523
589
 
524
590
  # TODO: maybe convert dict_msg to Payload object
525
591
  # also maybe strip the dict from useless info for the user of the sdk
526
592
  # Add try-except + sleep
527
- def __on_payload(self, dict_msg: dict, msg_node_addr, msg_pipeline, msg_signature, msg_instance) -> None:
593
+ def __on_payload(
594
+ self,
595
+ dict_msg: dict,
596
+ msg_node_addr,
597
+ msg_pipeline,
598
+ msg_signature,
599
+ msg_instance
600
+ ) -> None:
528
601
  """
529
602
  Handle a payload message received from the communication server.
530
603
 
@@ -546,6 +619,8 @@ class GenericSession(BaseDecentrAIObject):
546
619
 
547
620
  if self.__maybe_ignore_message(msg_node_addr):
548
621
  return
622
+
623
+ self.__maybe_process_net_mon(dict_msg, msg_pipeline, msg_signature)
549
624
 
550
625
  # call the pipeline and instance defined callbacks
551
626
  for pipeline in self.own_pipelines:
@@ -1182,6 +1257,7 @@ class GenericSession(BaseDecentrAIObject):
1182
1257
  on_data=None,
1183
1258
  on_notification=None,
1184
1259
  max_wait_time=0,
1260
+ pipeline_type=None,
1185
1261
  **kwargs) -> Pipeline:
1186
1262
  """
1187
1263
  Create a new pipeline on a node. A pipeline is the equivalent of the "config file" used by the Naeural Edge Protocol edge node team internally.
@@ -1249,7 +1325,8 @@ class GenericSession(BaseDecentrAIObject):
1249
1325
  raise Exception("Unable to attach to pipeline. Node does not exist")
1250
1326
 
1251
1327
  node_addr = self.__get_node_address(node)
1252
- pipeline = Pipeline(
1328
+ pipeline_type = pipeline_type or Pipeline
1329
+ pipeline = pipeline_type(
1253
1330
  self,
1254
1331
  self.log,
1255
1332
  node_addr=node_addr,
@@ -1699,9 +1776,11 @@ class GenericSession(BaseDecentrAIObject):
1699
1776
  *,
1700
1777
  node,
1701
1778
  name,
1702
- signature=PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01,
1779
+ signature,
1780
+ ngrok_edge_label=None,
1703
1781
  endpoints=None,
1704
1782
  use_ngrok=True,
1783
+ extra_debug=False,
1705
1784
  **kwargs
1706
1785
  ):
1707
1786
  """
@@ -1717,7 +1796,7 @@ class GenericSession(BaseDecentrAIObject):
1717
1796
  Name of the web app.
1718
1797
 
1719
1798
  signature : str, optional
1720
- The signature of the plugin that will be used. Defaults to PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01.
1799
+ The signature of the plugin that will be used. Defaults to PLUGIN_SIGNATURES.CUSTOM_WEBAPI_01.
1721
1800
 
1722
1801
  endpoints : list[dict], optional
1723
1802
  A list of dictionaries defining the endpoint configuration. Defaults to None.
@@ -1728,9 +1807,16 @@ class GenericSession(BaseDecentrAIObject):
1728
1807
 
1729
1808
  """
1730
1809
 
1731
- pipeline: Pipeline = self.create_pipeline(
1810
+ ngrok_use_api = True
1811
+
1812
+ # if isinstance(signature, str):
1813
+
1814
+
1815
+ pipeline: WebappPipeline = self.create_pipeline(
1732
1816
  node=node,
1733
1817
  name=name,
1818
+ pipeline_type=WebappPipeline,
1819
+ extra_debug=extra_debug,
1734
1820
  # default TYPE is "Void"
1735
1821
  )
1736
1822
 
@@ -1738,6 +1824,8 @@ class GenericSession(BaseDecentrAIObject):
1738
1824
  signature=signature,
1739
1825
  instance_id=self.log.get_unique_id(),
1740
1826
  use_ngrok=use_ngrok,
1827
+ ngrok_edge_label=ngrok_edge_label,
1828
+ ngrok_use_api=ngrok_use_api,
1741
1829
  **kwargs
1742
1830
  )
1743
1831
 
@@ -2058,4 +2146,55 @@ class GenericSession(BaseDecentrAIObject):
2058
2146
 
2059
2147
  @property
2060
2148
  def client_address(self):
2061
- return self.get_client_address()
2149
+ return self.get_client_address()
2150
+
2151
+ def get_network_known_nodes(self, timeout=10, online_only=False, supervisors_only=False):
2152
+ """
2153
+ This function will return a Pandas dataframe known nodes in the network based on
2154
+ all the net-mon messages received so far.
2155
+ """
2156
+ mapping = OrderedDict({
2157
+ 'Address': PAYLOAD_DATA.NETMON_ADDRESS,
2158
+ 'Alias' : PAYLOAD_DATA.NETMON_EEID,
2159
+ 'Last state': PAYLOAD_DATA.NETMON_STATUS_KEY,
2160
+ 'Ago (s)' : PAYLOAD_DATA.NETMON_LAST_SEEN,
2161
+ 'Last probe' : PAYLOAD_DATA.NETMON_LAST_REMOTE_TIME,
2162
+ 'Node zone' : PAYLOAD_DATA.NETMON_NODE_UTC,
2163
+ 'Supervisor' : PAYLOAD_DATA.NETMON_IS_SUPERVISOR,
2164
+ })
2165
+ reverse_mapping = {v: k for k, v in mapping.items()}
2166
+ res = OrderedDict()
2167
+ for k in mapping:
2168
+ res[k] = []
2169
+ start = tm()
2170
+ while (tm() - start) < timeout:
2171
+ if len(self.__current_network_statuses) > 0:
2172
+ break
2173
+ sleep(0.1)
2174
+ # end while
2175
+ if len(self.__current_network_statuses) > 0:
2176
+ best_info = {}
2177
+ best_super = None
2178
+ for supervisor, net_info in self.__current_network_statuses.items():
2179
+ if len(net_info) > len(best_info):
2180
+ best_info = net_info
2181
+ best_super = supervisor
2182
+ # done found best supervisor
2183
+ for _, node_info in best_info.items():
2184
+ is_online = node_info.get(PAYLOAD_DATA.NETMON_STATUS_KEY, None) == PAYLOAD_DATA.NETMON_STATUS_ONLINE
2185
+ is_supervisor = node_info.get(PAYLOAD_DATA.NETMON_IS_SUPERVISOR, False)
2186
+ if online_only and not is_online:
2187
+ continue
2188
+ if supervisors_only and not is_supervisor:
2189
+ continue
2190
+ for key, column in reverse_mapping.items():
2191
+ val = node_info.get(key, None)
2192
+ if key == PAYLOAD_DATA.NETMON_LAST_REMOTE_TIME:
2193
+ # val hols a string '2024-12-23 23:50:16.462155' and must be converted to a datetime
2194
+ val = dt.strptime(val, '%Y-%m-%d %H:%M:%S.%f')
2195
+ # strip the microseconds
2196
+ val = val.replace(microsecond=0)
2197
+ res[column].append(val)
2198
+ # end for
2199
+ # end if
2200
+ return pd.DataFrame(res), best_super
@@ -64,6 +64,19 @@ class Payload(UserDict):
64
64
  except ModuleNotFoundError:
65
65
  raise "This functionality requires the PIL library. To use this feature, please install it using 'pip install pillow'"
66
66
  return image
67
+
68
+ def __getattr__(self, key):
69
+ try:
70
+ return self.data[key]
71
+ except KeyError as e:
72
+ raise AttributeError(f"{self.__class__.__name__} object has no attribute '{key}'") from e
73
+
74
+ def __setattr__(self, key, value):
75
+ # If we're setting 'data' itself, just call super()
76
+ if key == 'data':
77
+ super().__setattr__(key, value)
78
+ else:
79
+ self.data[key] = value
67
80
 
68
81
 
69
82
  if __name__ == "__main__":
@@ -71,9 +84,10 @@ if __name__ == "__main__":
71
84
  payload = Payload()
72
85
  payload.data = {
73
86
  "IMG": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42mNkAAwOyKg",
74
- "TEST" : "TEST"
87
+ "TEST" : "TEST VALUE"
75
88
  }
76
89
 
77
90
  print(type(payload), payload)
78
91
  print(type(payload.data), payload.data)
79
- print(json.dumps(payload.data, indent=2))
92
+ print(json.dumps(payload.data, indent=2))
93
+ print(payload.TEST)
@@ -28,7 +28,21 @@ class Pipeline(BaseCodeChecker):
28
28
  `Plugin` == `Signature`
29
29
  """
30
30
 
31
- def __init__(self, session, log, *, node_addr, name, config={}, plugins=[], on_data=None, on_notification=None, is_attached=False, existing_config=None, **kwargs) -> None:
31
+ def __init__(
32
+ self,
33
+ session,
34
+ log,
35
+ *,
36
+ node_addr,
37
+ name,
38
+ config={},
39
+ plugins=[],
40
+ on_data=None,
41
+ on_notification=None,
42
+ is_attached=False,
43
+ existing_config=None,
44
+ **kwargs
45
+ ) -> None:
32
46
  """
33
47
  A `Pipeline` is a an object that encapsulates a one-to-many, data acquisition to data processing, flow of data.
34
48
 
@@ -112,9 +126,24 @@ class Pipeline(BaseCodeChecker):
112
126
  self.on_notification_callbacks = []
113
127
 
114
128
  if on_data is not None:
115
- self.on_data_callbacks.append(on_data)
129
+ if isinstance(on_data, list):
130
+ for cb in on_data:
131
+ if cb is not None:
132
+ self.on_data_callbacks.append(cb)
133
+ elif callable(on_data):
134
+ self.on_data_callbacks.append(on_data)
135
+ else:
136
+ raise ValueError("on_data should be a callable or a list of callables")
137
+
116
138
  if on_notification is not None:
117
- self.on_notification_callbacks.append(on_notification)
139
+ if isinstance(on_notification, list):
140
+ for cb in on_data:
141
+ if cb is not None:
142
+ self.on_notification_callbacks.append(cb)
143
+ elif callable(on_notification):
144
+ self.on_notification_callbacks.append(on_notification)
145
+ else:
146
+ raise ValueError("on_notification should be a callable or a list of callables")
118
147
 
119
148
  self.lst_plugin_instances: list[Instance] = []
120
149
 
@@ -798,7 +827,16 @@ class Pipeline(BaseCodeChecker):
798
827
  """
799
828
  return self.__was_last_operation_successful
800
829
 
801
- def create_plugin_instance(self, *, signature, instance_id, config={}, on_data=None, on_notification=None, **kwargs) -> Instance:
830
+ def create_plugin_instance(
831
+ self,
832
+ *,
833
+ signature,
834
+ instance_id,
835
+ config={},
836
+ on_data=None,
837
+ on_notification=None,
838
+ **kwargs
839
+ ) -> Instance:
802
840
  """
803
841
  Create a new instance of a desired plugin, with a given configuration. This instance is attached to this pipeline,
804
842
  meaning it processes data from this pipelines data source. Parameters can be passed either in the `config` dict, or as `kwargs`.
@@ -988,7 +1026,13 @@ class Pipeline(BaseCodeChecker):
988
1026
  **kwargs
989
1027
  )
990
1028
 
991
- def deploy(self, with_confirmation=True, wait_confirmation=True, timeout=10, verbose=False):
1029
+ def deploy(
1030
+ self,
1031
+ with_confirmation=True,
1032
+ wait_confirmation=True,
1033
+ timeout=10,
1034
+ verbose=False
1035
+ ):
992
1036
  """
993
1037
  This method is used to deploy the pipeline on the Naeural Edge Protocol edge node.
994
1038
  Here we collect all the proposed configurations and send them to the Naeural Edge Protocol edge node.
@@ -0,0 +1,114 @@
1
+ import time
2
+ from .pipeline import Pipeline
3
+
4
+
5
+
6
+ class WebappPipeline(Pipeline):
7
+
8
+ def __init__(
9
+ self,
10
+ session,
11
+ log,
12
+ *,
13
+ node_addr,
14
+ name,
15
+ config={},
16
+ plugins=[],
17
+ is_attached=False,
18
+ on_data=None,
19
+ on_notification=None,
20
+ existing_config=None,
21
+ extra_debug=False,
22
+ **kwargs
23
+ ) -> None:
24
+ """
25
+ This is a special type of pipeline that is used to deploy webapps.
26
+ It will override the deploy method to return the ngrok URL as well as the on_data method to extract the ngrok URL.
27
+ """
28
+ self.ngrok_url = None
29
+ self.__extra_debug = extra_debug
30
+ _on_data = [self.__check_payloads, on_data]
31
+ super().__init__(
32
+ session,
33
+ log,
34
+ node_addr=node_addr,
35
+ name=name,
36
+ config=config,
37
+ plugins=plugins,
38
+ is_attached=is_attached,
39
+ on_data=_on_data,
40
+ on_notification=on_notification,
41
+ existing_config=existing_config,
42
+
43
+ **kwargs
44
+ )
45
+ return
46
+
47
+
48
+ def __check_payloads(self, session, plugin_signature, plugin_instance, data):
49
+ """
50
+ Check if the payload if from ngrok and extract the ngrok URL.
51
+
52
+ Parameters
53
+ ----------
54
+
55
+
56
+ session : Session
57
+ The session object that received the payload.
58
+
59
+ plugin_signature : str
60
+ The signature of the plugin that sent the payload.
61
+
62
+ plugin_instance : str
63
+ The instance of the plugin that sent the payload.
64
+
65
+ data : Payload
66
+ The payload received from the edge node.
67
+
68
+
69
+ """
70
+ if self.__extra_debug:
71
+ self.P(f"Received payload from {plugin_signature} ({plugin_instance})")
72
+ if "NGROK_URL" in data:
73
+ self.ngrok_url = data["NGROK_URL"]
74
+ return
75
+
76
+ def create_plugin_instance(
77
+ self,
78
+ *,
79
+ signature,
80
+ instance_id,
81
+ config={},
82
+ ngrok_edge_label=None,
83
+ **kwargs
84
+ ):
85
+
86
+ if ngrok_edge_label is not None:
87
+ self.ngrok_url = "URL_DEFINED_IN_EDGE_LABEL"
88
+
89
+ return super().create_plugin_instance(
90
+ signature=signature,
91
+ instance_id=instance_id,
92
+ config=config,
93
+ ngrok_edge_label=ngrok_edge_label,
94
+ **kwargs
95
+ )
96
+
97
+ def deploy(self, verbose=False, timeout=15, **kwargs):
98
+ """
99
+ Deploy the pipeline and return the URL of the webapp.
100
+
101
+ Returns
102
+ -------
103
+ str
104
+ The URL of the webapp.
105
+ """
106
+ res = super().deploy(verbose=verbose, timeout=timeout, **kwargs)
107
+ # now we wait for the ngrok url to be available
108
+ start = time.time()
109
+ while self.ngrok_url is None:
110
+ elapsed = time.time() - start
111
+ if elapsed > timeout:
112
+ raise Exception("Timeout waiting for ngrok url")
113
+ # return the ngrok url
114
+ return self.ngrok_url
@@ -25,6 +25,8 @@ class BaseDecentrAIObject(object):
25
25
  prefix_log=None,
26
26
  log_at_startup=False,
27
27
  silent=False,
28
+ local_cache_base_folder='.',
29
+ local_cache_app_folder='_local_cache',
28
30
  **kwargs):
29
31
 
30
32
  super(BaseDecentrAIObject, self).__init__()
@@ -34,10 +36,10 @@ class BaseDecentrAIObject(object):
34
36
  raise ValueError("Logger object is invalid: {}".format(log))
35
37
  else:
36
38
  log = Logger(
37
- "DEF",
39
+ "R1",
38
40
  DEBUG=DEBUG,
39
- base_folder='.',
40
- app_folder='_local_cache',
41
+ base_folder=local_cache_base_folder,
42
+ app_folder=local_cache_app_folder,
41
43
  silent=silent,
42
44
  )
43
45
  # endif
naeural_client/bc/base.py CHANGED
@@ -280,12 +280,23 @@ class BaseBlockEngine:
280
280
 
281
281
  ensure_ascii_payloads: bool
282
282
  flag that controls if the payloads are encoded as ascii or not. Default `False` for JS compatibility.
283
+
284
+ user_config: bool
285
+ flag that controls if the keys are stored in the user private folder or in the data folder of the _local_cache
283
286
 
284
287
  """
285
288
  _lock: Lock = Lock()
286
289
  __instances = {}
287
290
 
288
- def __new__(cls, name, log, config, ensure_ascii_payloads=False, verbosity=1, user_config=False):
291
+ def __new__(
292
+ cls,
293
+ name,
294
+ log,
295
+ config,
296
+ ensure_ascii_payloads=False,
297
+ verbosity=1,
298
+ user_config=False
299
+ ):
289
300
  with cls._lock:
290
301
  if name not in cls.__instances:
291
302
  instance = super(BaseBlockEngine, cls).__new__(cls)
@@ -328,7 +339,7 @@ class BaseBlockEngine:
328
339
  pem_name = config.get(BCct.K_PEM_FILE, '_pk.pem')
329
340
  pem_folder = config.get(BCct.K_PEM_LOCATION, 'data')
330
341
  pem_fn = os.path.join(log.get_target_folder(pem_folder), pem_name)
331
- #endif pem is defined in ~/.naeural/config
342
+ #endif pem is defined in ~/.naeural/ or in the data folder of the _local_cache
332
343
  self.__pem_file = pem_fn
333
344
  self._init()
334
345
  return
naeural_client/cli/cli.py CHANGED
@@ -4,6 +4,7 @@ from naeural_client.utils.config import maybe_init_config, log_with_color
4
4
  from naeural_client.cli.cli_commands import CLI_COMMANDS
5
5
 
6
6
  from naeural_client import version
7
+ import traceback
7
8
 
8
9
  def build_parser():
9
10
  """
@@ -14,8 +15,8 @@ def build_parser():
14
15
  argparse.ArgumentParser
15
16
  Configured argument parser.
16
17
  """
17
- descr = f"nepctl v{version} - CLI for Naeural Edge Protocol SDK package"
18
- parser = argparse.ArgumentParser(description=descr)
18
+ title = f"nepctl v{version} - CLI for Naeural Edge Protocol SDK package"
19
+ parser = argparse.ArgumentParser(description=title)
19
20
  subparsers = parser.add_subparsers(dest="command", help="Available commands")
20
21
 
21
22
  for command, subcommands in CLI_COMMANDS.items():
@@ -25,8 +26,9 @@ def build_parser():
25
26
  # Nested subcommands
26
27
  command_subparsers = command_parser.add_subparsers(dest="subcommand")
27
28
  for subcommand, subcmd_info in subcommands.items():
29
+ description = subcmd_info.get("description", f"{subcommand} command")
28
30
  subcommand_parser = command_subparsers.add_parser(
29
- subcommand, help=f"{subcommand} command"
31
+ subcommand, help=description
30
32
  )
31
33
  if isinstance(subcmd_info, dict) and "params" in subcmd_info:
32
34
  for param, description in subcmd_info["params"].items():
@@ -83,7 +85,7 @@ def main():
83
85
 
84
86
  except Exception as e:
85
87
  # Handle unexpected errors gracefully
86
- print(f"Error: {e}")
88
+ log_with_color(f"Error: {e}:\n{traceback.format_exc()}", color='r')
87
89
 
88
90
 
89
91
  if __name__ == "__main__":
@@ -2,7 +2,7 @@ from naeural_client.cli.nodes import (
2
2
  get_nodes, get_supervisors,
3
3
  restart_node, shutdown_node
4
4
  )
5
- from naeural_client.utils.config import show_config, reset_config
5
+ from naeural_client.utils.config import show_config, reset_config, show_address
6
6
 
7
7
 
8
8
  # Define the available commands
@@ -11,30 +11,37 @@ CLI_COMMANDS = {
11
11
  "nodes": {
12
12
  "func": get_nodes,
13
13
  "params": {
14
- "--all": "Get all nodes",
15
- "--peered": "Get only peered nodes"
14
+ "--all": "Get all known nodes", # DONE
15
+ "--online" : "Get only online nodes", # DONE
16
+ # "--peered": "Get only peered nodes"
16
17
  }
17
18
  },
18
19
  "supervisors": {
19
- "func": get_supervisors,
20
+ "func": get_supervisors, # DONE
20
21
  },
21
22
  },
22
23
  "config": {
23
24
  "show": {
24
- "func": show_config,
25
+ "func": show_config, # DONE
26
+ "description": "Show the current configuration including the location",
25
27
  },
26
28
  "reset": {
27
29
  "func": reset_config,
30
+ "description": "Reset the configuration to default",
28
31
  },
32
+ "addr": {
33
+ "func": show_address, # DONE
34
+ "description": "Show the current client address",
35
+ }
29
36
  },
30
37
  "restart": {
31
- "func": restart_node,
38
+ "func": restart_node, # TODO
32
39
  "params": {
33
40
  "node": "The node to restart"
34
41
  }
35
42
  },
36
43
  "shutdown": {
37
- "func": shutdown_node,
44
+ "func": shutdown_node, # TODO
38
45
  "params": {
39
46
  "node": "The node to shutdown"
40
47
  }
@@ -10,12 +10,20 @@ def get_nodes(args):
10
10
  3. Wait for the second net mon message via Session and show progress.
11
11
  4. Get the active nodes union via Session and display the nodes marking those peered vs non-peered.
12
12
  """
13
+ from naeural_client import Session
14
+ sess = Session(silent=True)
13
15
  if args.all:
14
- log_with_color("Getting all nodes information", color="b")
15
- elif args.peered:
16
- log_with_color("Getting peered nodes information", color="b")
16
+ df, supervisor = sess.get_network_known_nodes()
17
+ log_with_color(f"Network historical map as seen by <{supervisor}>:", color='b')
18
+ log_with_color(f"{df}")
19
+ elif args.online:
20
+ df, supervisor = sess.get_network_known_nodes(online_only=True)
21
+ log_with_color(f"Online nodes as seen by <{supervisor}>:", color='b')
22
+ log_with_color(f"{df}")
17
23
  else:
18
- log_with_color("Getting default nodes information", color="b")
24
+ df, supervisor = sess.get_network_known_nodes(online_only=True)
25
+ log_with_color(f"Online nodes as seen by <{supervisor}>:", color='b')
26
+ log_with_color(f"{df}")
19
27
  return
20
28
 
21
29
 
@@ -23,7 +31,10 @@ def get_supervisors(args):
23
31
  """
24
32
  This function is used to get the information about the supervisors.
25
33
  """
26
- log_with_color("Getting supervisors information", color='b')
34
+ from naeural_client import Session
35
+ sess = Session(silent=True)
36
+ df, supervisor = sess.get_network_known_nodes(online_only=True, supervisors_only=True)
37
+ log_with_color(f"Supervisors reported by <{supervisor}>:\n{df}")
27
38
  return
28
39
 
29
40
 
@@ -7,4 +7,4 @@ from .payload import STATUS_TYPE, PAYLOAD_DATA, COMMANDS, NOTIFICATION_CODES, NE
7
7
  from .base import CONFIG_STREAM, BIZ_PLUGIN_DATA, PLUGIN_INFO, BLOCKCHAIN_CONFIG
8
8
  from . import heartbeat as HB
9
9
  from .environment import ENVIRONMENT
10
- from .apps import PLUGIN_SIGNATURES
10
+ from .apps import PLUGIN_SIGNATURES, DEFAULT_PIPELINES
@@ -5,8 +5,12 @@ class PLUGIN_SIGNATURES:
5
5
  """
6
6
  NET_MON_01 = 'NET_MON_01'
7
7
  VIEW_SCENE_01 = 'VIEW_SCENE_01'
8
- CUSTOM_WEB_APP_01 = 'CUSTOM_CODE_FASTAPI_01'
8
+ CUSTOM_WEBAPI_01 = 'CUSTOM_CODE_FASTAPI_01'
9
9
  CHAIN_DIST_CUSTOM_JOB_01 = 'PROCESS_REAL_TIME_COLLECTED_DATA_CUSTOM_EXEC_CHAIN_DIST'
10
10
  TELEGRAM_BASIC_BOT_01 = 'TELEGRAM_BASIC_BOT_01'
11
11
  TELEGRAM_CONVERSATIONAL_BOT_01 = 'TELEGRAM_CONVERSATIONAL_BOT_01'
12
- # INSERT_NEW_PLUGIN_HERE
12
+ # INSERT_NEW_PLUGIN_HERE
13
+
14
+
15
+ class DEFAULT_PIPELINES:
16
+ ADMIN_PIPELINE = 'admin_pipeline'
@@ -195,6 +195,16 @@ class PAYLOAD_DATA:
195
195
 
196
196
  ID_TAGS = 'ID_TAGS'
197
197
 
198
+ NETMON_CURRENT_NETWORK = 'CURRENT_NETWORK'
199
+ NETMON_STATUS_KEY = "working"
200
+ NETMON_STATUS_ONLINE = "ONLINE"
201
+ NETMON_ADDRESS = "address"
202
+ NETMON_EEID = "eeid"
203
+ NETMON_LAST_REMOTE_TIME = 'last_remote_time'
204
+ NETMON_NODE_UTC = 'node_utc'
205
+ NETMON_LAST_SEEN = 'last_seen_sec'
206
+ NETMON_IS_SUPERVISOR = 'is_supervisor'
207
+
198
208
 
199
209
  class NET_CONFIG:
200
210
  STORE_COMMAND = "SET_CONFIG"
@@ -1,6 +1,6 @@
1
1
  from .net_mon_01_plugin import NetMon01
2
2
  from .view_scene_01_plugin import ViewScene01
3
- from .custom_web_app_01_plugin import CustomWebApp01
3
+ from .custom_webapi_01_plugin import CustomWebapi01
4
4
  from .chain_dist_custom_job_01_plugin import ChainDistCustomJob01
5
5
  from .telegram_basic_bot_01_plugin import BasicTelegramBot01
6
6
 
@@ -11,6 +11,6 @@ class PLUGIN_TYPES:
11
11
  """
12
12
  NET_MON_01 = NetMon01
13
13
  VIEW_SCENE_01 = ViewScene01
14
- CUSTOM_WEB_APP_01 = CustomWebApp01
14
+ CUSTOM_WEBAPI_01 = CustomWebapi01
15
15
  CHAIN_DIST_CUSTOM_JOB_01 = ChainDistCustomJob01
16
16
  TELEGRAM_BASIC_BOT_01 = BasicTelegramBot01
@@ -1,8 +1,8 @@
1
1
  from ...base import Instance, Pipeline
2
2
  from ...const import PLUGIN_SIGNATURES
3
3
 
4
- class CustomWebApp01(Instance):
5
- signature = PLUGIN_SIGNATURES.CUSTOM_WEB_APP_01
4
+ class CustomWebapi01(Instance):
5
+ signature = PLUGIN_SIGNATURES.CUSTOM_WEBAPI_01
6
6
 
7
7
  def get_proposed_endpoints(self):
8
8
  from copy import deepcopy
@@ -29,11 +29,13 @@ _HTML_END = "</pre></BODY>"
29
29
 
30
30
  COLORS = {
31
31
  'n': "\x1b[1;37m", # normal white
32
- 'd': "\x1b[0;37m", # grey white
32
+ 'd': "\033[90m", # dark gray
33
+ # 'd': "\x1b[0;37m", # grey white
33
34
  'r': "\x1b[1;31m",
34
35
  'g': "\x1b[1;32m",
35
36
  'y': "\x1b[1;33m",
36
- 'b': "\x1b[1;34m",
37
+ # 'b': "\x1b[1;34m",
38
+ 'b': "\x1b[1;36m", # changed to bright cyan
37
39
  'm': "\x1b[1;35m",
38
40
  'c': "\x1b[1;36m", # bright cyan
39
41
  'v': "\x1b[0;36m", # dim cyan
@@ -31,7 +31,8 @@ def log_with_color(s, color='n'):
31
31
  'r': '\033[31m', # Red
32
32
  'g': '\033[32m', # Green
33
33
  'y': '\033[33m', # Yellow
34
- 'b': "\x1b[1;34m", # bright blue
34
+ # 'b': "\x1b[1;34m", # bright blue
35
+ 'b': "\x1b[1;36m", # bright cyan
35
36
  'w': '\033[97m', # Light white
36
37
  'c': "\x1b[1;36m", # bright cyan
37
38
  'n': '\033[37m', # Dark white (default)
@@ -54,7 +55,7 @@ def get_user_config_file():
54
55
  """
55
56
  return get_user_folder() / "config"
56
57
 
57
- def reset_config(args):
58
+ def reset_config(*args, **kwargs):
58
59
  """
59
60
  Resets the configuration by creating a ~/.naeural folder and populating
60
61
  ~/.naeural/config with values from a local .env file, if it exists.
@@ -71,22 +72,49 @@ def reset_config(args):
71
72
  if current_env_file.exists():
72
73
  # Copy .env content to ~/.naeural/config
73
74
  shutil.copy(current_env_file, config_file)
74
- log_with_color(f"Configuration has been reset using {current_env_file} into {config_file}", color='y')
75
+ log_with_color(
76
+ f"Configuration has been reset using {current_env_file} into {config_file}",
77
+ color='y'
78
+ )
79
+ log_with_color(f"Please REVIEW the configuration in the file {config_file}", color='b')
75
80
  else:
76
81
  # Create an empty config file
77
82
  with config_file.open("wt") as file:
78
83
  file.write(ENV_TEMPLATE)
79
- log_with_color(f"Configuration has been reset to default in {config_file}:\n{ENV_TEMPLATE}", color='y')
84
+ log_with_color(
85
+ f"Configuration has been reset to default in {config_file}:\n{ENV_TEMPLATE}",
86
+ color='y'
87
+ )
88
+ log_with_color(f"Please UPDATE the configuration in the file {config_file}", color='b')
89
+ return
80
90
 
91
+ def show_address(*args):
92
+ """
93
+ Displays the current client address.
94
+ """
95
+ from naeural_client import Session
96
+ sess = Session(
97
+ silent=True
98
+ )
99
+ log_with_color(f"{sess.get_client_address()}", color='b')
100
+ return
81
101
 
82
- def show_config(args):
102
+ def show_config(*args):
83
103
  """
84
104
  Displays the current configuration from ~/.naeural/config.
85
105
  """
106
+ from naeural_client import Session
107
+ sess = Session(
108
+ silent=True
109
+ )
110
+
111
+ user_folder = get_user_folder()
86
112
  config_file = get_user_config_file()
87
113
 
114
+ log_with_color(f"NEP SDK folder: {user_folder}", color='b')
115
+ log_with_color(f"SDK Client address: {sess.get_client_address()}", color='b')
88
116
  if config_file.exists():
89
- log_with_color(f"Current configuration ({config_file}):")
117
+ log_with_color(f"Current configuration ({config_file}):", color='y')
90
118
  with config_file.open("r") as file:
91
119
  log_with_color(file.read())
92
120
  else:
@@ -127,5 +155,6 @@ def maybe_init_config():
127
155
  config_file = get_user_config_file()
128
156
 
129
157
  if not config_file.exists():
158
+ log_with_color(f"No configuration file found at {config_file}. Initializing configuration...", color="y")
130
159
  reset_config()
131
160
  load_user_defined_config()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: naeural_client
3
- Version: 2.4.6
3
+ Version: 2.5.1
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
@@ -13,6 +13,7 @@ Requires-Python: >=3.8
13
13
  Requires-Dist: cryptography>=39.0.0
14
14
  Requires-Dist: numpy
15
15
  Requires-Dist: paho-mqtt
16
+ Requires-Dist: pandas
16
17
  Requires-Dist: pika
17
18
  Requires-Dist: pyaml
18
19
  Requires-Dist: pyopenssl>=23.0.0
@@ -1,27 +1,28 @@
1
- naeural_client/__init__.py,sha256=UKEDGS0wFYyxwmhEAKJGecO2vYbIfRYUP4SQgnK10IE,578
2
- naeural_client/_ver.py,sha256=zKcAm4e0QSrkiLJJYIfGbBHsr-rZsc6iF7H58VmkETk,330
3
- naeural_client/base_decentra_object.py,sha256=wXjl65gWxxkhV6Tq48wFfNGITvdYdkKPT-wLurGB5vc,4287
1
+ naeural_client/__init__.py,sha256=GP8WSrn87sjTPO-QRNL2PG8JK5Mixbiea_HrtbG8RAQ,592
2
+ naeural_client/_ver.py,sha256=h7_TcvTF6Uh4pwHhVPbFlbsXRsmLWHYtIth7wH7eNy0,330
3
+ naeural_client/base_decentra_object.py,sha256=C4iwZTkhKNBS4VHlJs5DfElRYLo4Q9l1V1DNVSk1fyQ,4412
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=I1M2dxFMWe6FVxOs_n54DjYpWDIRGn9UJOqWo0YdBjA,77367
7
+ naeural_client/base/generic_session.py,sha256=0DQsq3-4i61-7flElK5lx-AzK3uwrDvJGbHzbUmH3gU,82553
8
8
  naeural_client/base/instance.py,sha256=kcZJmjLBtx8Bjj_ysIOx1JmLA-qSpG7E28j5rq6IYus,20444
9
- naeural_client/base/pipeline.py,sha256=KwcPWD2XMvHotWFMpcnIycFhqiNnZuyUTUWiLU0PM5Y,57519
9
+ naeural_client/base/pipeline.py,sha256=b4uNHrEIOlAtw4PGUx20dxwBhDck5__SrVXaHcSi8ZA,58251
10
10
  naeural_client/base/plugin_template.py,sha256=qGaXByd_JZFpjvH9GXNbT7KaitRxIJB6-1IhbKrZjq4,138123
11
11
  naeural_client/base/responses.py,sha256=ZKBZmRhYDv8M8mQ5C_ahGsQvtWH4b9ImRcuerQdZmNw,6937
12
12
  naeural_client/base/transaction.py,sha256=bfs6td5M0fINgPQNxhrl_AUjb1YiilLDQ-Cd_o3OR_E,5146
13
+ naeural_client/base/webapp_pipeline.py,sha256=QmPLVmhP0CPdi0YuvbZEH4APYz2Amtw3gyOu4bVodYA,2740
13
14
  naeural_client/base/payload/__init__.py,sha256=y8fBI8tG2ObNfaXFWjyWZXwu878FRYj_I8GIbHT4GKE,29
14
- naeural_client/base/payload/payload.py,sha256=v50D7mBBD2WwWzvpbRGMSr-X6vv5ie21IY1aDxTqe1c,2275
15
+ naeural_client/base/payload/payload.py,sha256=x-au7l67Z_vfn_4R2C_pjZCaFuUVXHngJiGOfIAYVdE,2690
15
16
  naeural_client/bc/__init__.py,sha256=FQj23D1PrY06NUOARiKQi4cdj0-VxnoYgYDEht8lpr8,158
16
- naeural_client/bc/base.py,sha256=VRIM7SWLqHf1vEOFoxdkQpv1P3zEPeEWsfQBW3N86_w,31497
17
+ naeural_client/bc/base.py,sha256=R-bz2pIe-rSdfp5cracN68kH68MwqvWcA-ATLw9qL6s,31707
17
18
  naeural_client/bc/chain.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
19
  naeural_client/bc/ec.py,sha256=mWjodWCRgC3omVXOA9jtNdtPVNn2kMKV3Dcjt9oFUCQ,22974
19
20
  naeural_client/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
21
  naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
21
22
  naeural_client/cli/README.md,sha256=WPdI_EjzAbUW1aPyj1sSR8rLydcJKZtoiaEtklQrjHo,74
22
- naeural_client/cli/cli.py,sha256=puxQ_5acL6tD2YOt8PdO5idiuKT2VUt7YzMigO3IY50,2752
23
- naeural_client/cli/cli_commands.py,sha256=Sm7_Ig3jxs0P7S9X_vsTrv4jthWfzo9Meb05ufI4pxQ,911
24
- naeural_client/cli/nodes.py,sha256=0aS9d26DtzEJHcNHiprBxlPPOdEX7B1DXDFyzL9mXVU,1406
23
+ naeural_client/cli/cli.py,sha256=cq3upG-uc_uxEgX1O5qm2z-g3PQAp65E4KgTgAHAYZQ,2882
24
+ naeural_client/cli/cli_commands.py,sha256=VK7jGCl-C5Bel6RUz5Qcf5mAT7at7bEUn52OV1xdff8,1309
25
+ naeural_client/cli/nodes.py,sha256=MkDFfw02iW_qNP9mPolJbGHPByL__ZHSpGODunbz80M,1953
25
26
  naeural_client/code_cheker/__init__.py,sha256=pwkdeZGVL16ZA4Qf2mRahEhoOvKhL7FyuQbMFLr1E5M,33
26
27
  naeural_client/code_cheker/base.py,sha256=lT5DRIFO5rqzsMNCmdMRfkAeevmezozehyfgmhnKpuI,19074
27
28
  naeural_client/code_cheker/checker.py,sha256=QWupeM7ToancVIq1tRUxRNUrI8B5l5eoY0kDU4-O5aE,7365
@@ -29,19 +30,19 @@ naeural_client/comm/__init__.py,sha256=za3B2HUKNXzYtjElMgGM9xbxNsdQfFY4JB_YzdyFk
29
30
  naeural_client/comm/amqp_wrapper.py,sha256=hzj6ih07DnLQy2VSfA88giDIFHaCp9uSdGLTA-IFE4s,8535
30
31
  naeural_client/comm/mqtt_wrapper.py,sha256=Ig3bFZkCbWd4y_Whn2PPa91Z3aLgNbNPau6Tn5yLPZ8,16167
31
32
  naeural_client/const/README.md,sha256=6OHesr-f5NBuuJGryEoi_TCu2XdlhfQYlDKx_IJoXeg,177
32
- naeural_client/const/__init__.py,sha256=z0xI8Siw7t3_VGphreAUHUumbCsFarNnqPI5G4_Eteg,447
33
- naeural_client/const/apps.py,sha256=TJpbD7-1tIKxMdpVgZMHOka1k7a6vtW45rQL87K-jvE,507
33
+ naeural_client/const/__init__.py,sha256=OtrSiHyTzrie5dyC1gWrYXYmg5cVMdwe0gxAlrHXCLg,466
34
+ naeural_client/const/apps.py,sha256=aZ9oiBT8MC1Vm7e0TyerRvQ7z4m0-GHR67BXdLnv5lE,573
34
35
  naeural_client/const/base.py,sha256=-NeZPwE0JrbTHmlI9BOmgzaGu5jUZHl9vOZ4hhh_QQo,3100
35
36
  naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
36
37
  naeural_client/const/environment.py,sha256=iytmTDgbOjvORPwHQmc0K0r-xJx7dnnzNnqAJJiFCDA,870
37
38
  naeural_client/const/formatter.py,sha256=AW3bWlqf39uaqV4BBUuW95qKYfF2OkkU4f9hy3kSVhM,200
38
39
  naeural_client/const/heartbeat.py,sha256=jGHmKfeHTFOXJaKUT3o_ocnQyF-EpcLeunW-ifkYKfU,2534
39
40
  naeural_client/const/misc.py,sha256=Y6x00YDtY1_nAk4OvikCLlfp8ggn11WQYTBGYzFlJPk,211
40
- naeural_client/const/payload.py,sha256=oCaGpmkGypPxfSVmMZiigbJBhMuKMfF549sjACG3P-c,6124
41
+ naeural_client/const/payload.py,sha256=fHhhdSv1o_5Ldy72jO7m3YZtMmJOpOHaVhfjbNCuuzo,6446
41
42
  naeural_client/default/__init__.py,sha256=ozU6CMMuWl0LhG8Ae3LrZ65a6tLrptfscVYGf83zjxM,46
42
- naeural_client/default/instance/__init__.py,sha256=Itb4l6_DR6CCw8KAxyQKlCmALyzDasNHIfM9VB-Umak,548
43
+ naeural_client/default/instance/__init__.py,sha256=w1de6OMj9a5GPGF-Wl1b_I_YAy9fWBEss2QnyPPyaB0,546
43
44
  naeural_client/default/instance/chain_dist_custom_job_01_plugin.py,sha256=QtHi3uXKsVs9eyMgbnvBVbMylErhV1Du4X2-7zDL7Y0,1915
44
- naeural_client/default/instance/custom_web_app_01_plugin.py,sha256=ZDe-QXmr6KLyUx5wzA3xVrMPg8yHnWLUbGjZtB0PFgg,4785
45
+ naeural_client/default/instance/custom_webapi_01_plugin.py,sha256=EEjW9c2EQatMktOjO5picyDYDSrppc6_TmMNI8lgFeA,4784
45
46
  naeural_client/default/instance/net_mon_01_plugin.py,sha256=u85i2AiYHkLJnam0wOx-m71hlp0EYyNtk3JwbkOrvHg,1208
46
47
  naeural_client/default/instance/telegram_basic_bot_01_plugin.py,sha256=P_W2K_ng7svbhoIoYGvkGxa4v9UUoxuOAAgtoM36wDo,161
47
48
  naeural_client/default/instance/telegram_conversational_bot_01_plugin.py,sha256=XkyE-uNbtFnTSGA1nOf-XNmUipAUjhg0xXV1glRb7gc,179
@@ -56,7 +57,7 @@ naeural_client/io_formatter/default/a_dummy.py,sha256=qr9eUizQ-NN5jdXVzkaZKMaf9K
56
57
  naeural_client/io_formatter/default/aixp1.py,sha256=MX0TeUR4APA-qN3vUC6uzcz8Pssz5lgrQWo7td5Ri1A,3052
57
58
  naeural_client/io_formatter/default/default.py,sha256=gEy78cP2D5s0y8vQh4aHuxqz7D10gGfuiKF311QhrpE,494
58
59
  naeural_client/logging/__init__.py,sha256=b79X45VC6c37u32flKB2GAK9f-RR0ocwP0JDCy0t7QQ,33
59
- naeural_client/logging/base_logger.py,sha256=uyR4rxXQGd9UrdIdRRhS6T7UmnzyEfFooVXikxOsfw4,65951
60
+ naeural_client/logging/base_logger.py,sha256=himUkM_48-YXS4u0zJ_5jSd564PeXNpa8uttpgKkljA,66032
60
61
  naeural_client/logging/small_logger.py,sha256=m12hCb_H4XifJYYfgCAOUDkcXm-h4pSODnFf277OFVI,2937
61
62
  naeural_client/logging/logger_mixins/__init__.py,sha256=yQO7umlRvz63FeWpi-F9GRmC_MOHcNW6R6pwvZZBy3A,600
62
63
  naeural_client/logging/logger_mixins/class_instance_mixin.py,sha256=xUXE2VZgmrlrSrvw0f6GF1jlTnVLeVkIiG0bhlBfq3o,2741
@@ -78,10 +79,10 @@ naeural_client/logging/tzlocal/win32.py,sha256=zBoj0vFVrGhnCm_f7xmYzGym4-fV-4Ij2
78
79
  naeural_client/logging/tzlocal/windows_tz.py,sha256=Sv9okktjZJfRGGUOOppsvQuX_eXyXUxkSKCAFmWT9Hw,34203
79
80
  naeural_client/utils/__init__.py,sha256=mAnke3-MeRzz3nhQvhuHqLnpaaCSmDxicd7Ck9uwpmI,77
80
81
  naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_LtMyCY,1072
81
- naeural_client/utils/config.py,sha256=t_VzyBnRHJa-Kt71HUu9gXxeDOri1Aqf_-gjO04gAYs,3681
82
+ naeural_client/utils/config.py,sha256=PORcwfYdy-z9hwYzBag1RR6Lv5lWUtWVxZAyN9cjWxA,4562
82
83
  naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
83
- naeural_client-2.4.6.dist-info/METADATA,sha256=a-crxanJN9BcwuAJykuT4g3hhamt2mBD_youSZqmq5w,14471
84
- naeural_client-2.4.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
85
- naeural_client-2.4.6.dist-info/entry_points.txt,sha256=PNdyotDaQBAslZREx5luVyj0kqpQnwNACwkFNTPIHU4,55
86
- naeural_client-2.4.6.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
87
- naeural_client-2.4.6.dist-info/RECORD,,
84
+ naeural_client-2.5.1.dist-info/METADATA,sha256=4CIHpXMmxsJ-MNeh52yI6y4le4uguhhiDX-z8yHkheg,14493
85
+ naeural_client-2.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
86
+ naeural_client-2.5.1.dist-info/entry_points.txt,sha256=PNdyotDaQBAslZREx5luVyj0kqpQnwNACwkFNTPIHU4,55
87
+ naeural_client-2.5.1.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
88
+ naeural_client-2.5.1.dist-info/RECORD,,