xaal.lib 0.7.7__py3-none-any.whl → 0.7.8__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.
xaal/lib/bindings.py CHANGED
@@ -2,86 +2,86 @@ import uuid
2
2
 
3
3
  from .exceptions import UUIDError
4
4
 
5
+
5
6
  class UUID:
6
- def __init__(self,*args,**kwargs):
7
- self.__uuid = uuid.UUID(*args,**kwargs)
7
+ def __init__(self, *args, **kwargs):
8
+ self.__uuid = uuid.UUID(*args, **kwargs)
8
9
 
9
10
  @staticmethod
10
- def random_base(digit=2):
11
+ def random_base(digit=2) -> 'UUID':
11
12
  """zeros the last digits of a random uuid, usefull w/ you want to forge some addresses
12
- two digit is great.
13
+ two digit is great.
13
14
  """
14
- if (digit > 0) and (digit < 13):
15
+ if (digit > 0) and (digit < 13):
15
16
  tmp = str(uuid.uuid1())
16
- st = "%s%s" % (tmp[:-digit],'0'*digit)
17
+ st = "%s%s" % (tmp[:-digit], '0' * digit)
17
18
  return UUID(st)
18
19
  else:
19
20
  raise UUIDError
20
21
 
21
22
  @staticmethod
22
- def random():
23
+ def random() -> 'UUID':
23
24
  tmp = uuid.uuid1().int
24
25
  return UUID(int=tmp)
25
26
 
26
- def __add__(self,value):
27
+ def __add__(self, value: int) -> 'UUID':
27
28
  tmp = self.__uuid.int + value
28
29
  return UUID(int=tmp)
29
30
 
30
- def __sub__(self,value):
31
+ def __sub__(self, value: int) -> 'UUID':
31
32
  tmp = self.__uuid.int - value
32
33
  return UUID(int=tmp)
33
34
 
34
- def __eq__(self,value):
35
+ def __eq__(self, value) -> bool:
35
36
  return self.__uuid == value
36
37
 
37
- def __lt__(self, value ):
38
+ def __lt__(self, value) -> bool:
38
39
  return self.__uuid.int < value
39
40
 
40
- def __gt__(self, value ):
41
+ def __gt__(self, value) -> bool:
41
42
  return self.__uuid.int > value
42
43
 
43
- def __str__(self):
44
+ def __str__(self) -> str:
44
45
  return str(self.__uuid)
45
-
46
- def __repr__(self): # pragma: no cover
46
+
47
+ def __repr__(self) -> str: # pragma: no cover
47
48
  return f"UUID('{self.__uuid}')"
48
49
 
49
- def __hash__(self):
50
+ def __hash__(self) -> int:
50
51
  return self.__uuid.__hash__()
51
52
 
52
- def get(self):
53
+ def get(self) -> uuid.UUID:
53
54
  return self.__uuid
54
-
55
- def set(self,value):
55
+
56
+ def set(self, value: uuid.UUID):
56
57
  self.__uuid = value
57
58
 
58
59
  @property
59
- def str(self):
60
+ def str(self) -> str:
60
61
  return str(self)
61
62
 
62
63
  @property
63
- def bytes(self):
64
+ def bytes(self) -> bytes:
64
65
  return self.__uuid.bytes
65
66
 
66
67
 
67
-
68
68
  class URL:
69
- def __init__(self,value):
69
+ def __init__(self, value):
70
70
  self.__url = value
71
71
 
72
- def __eq__(self,value):
72
+ def __eq__(self, value):
73
73
  return self.__url == value
74
74
 
75
75
  def __str__(self):
76
76
  return str(self.__url)
77
-
78
- def __repr__(self): # pragma: no cover
79
- return f"URL('{self.__url}')"
80
77
 
81
- def set(self,value):
78
+ def __repr__(self) -> str: # pragma: no cover
79
+ return f"URL('{self.__url}')"
80
+
81
+ def set(self, value: str):
82
82
  self.__url = value
83
83
 
84
- def get(self):
84
+ def get(self) -> str:
85
85
  return self.__url
86
86
 
87
87
  @property
@@ -93,6 +93,4 @@ class URL:
93
93
  return self.__url
94
94
 
95
95
 
96
-
97
- classes = [UUID,URL]
98
-
96
+ classes = [UUID, URL]
xaal/lib/cbor.py CHANGED
@@ -16,25 +16,30 @@ def tag_hook(decoder, tag, shareable_index=None):
16
16
  return bindings.URL(tag.value)
17
17
  return tag
18
18
 
19
+
19
20
  def default_encoder(encoder, value):
20
- if isinstance(value,bindings.UUID):
21
+ if isinstance(value, bindings.UUID):
21
22
  encoder.encode(CBORTag(37, value.bytes))
22
23
 
23
- if isinstance(value,bindings.URL):
24
+ if isinstance(value, bindings.URL):
24
25
  encoder.encode(CBORTag(32, value.bytes))
25
26
 
27
+
26
28
  def dumps(obj, **kwargs):
27
- return cbor2.dumps(obj,default=default_encoder,**kwargs)
29
+ return cbor2.dumps(obj, default=default_encoder, **kwargs)
30
+
28
31
 
29
32
  def loads(payload, **kwargs):
30
- #return cbor2.loads(payload,tag_hook=tag_hook,**kwargs)
31
- return _loads(payload,tag_hook=tag_hook,**kwargs)
33
+ # return cbor2.loads(payload,tag_hook=tag_hook,**kwargs)
34
+ return _loads(payload, tag_hook=tag_hook, **kwargs)
35
+
32
36
 
33
37
  def _loads(s, **kwargs):
34
38
  with BytesIO(s) as fp:
35
39
  return CBORDecoder(fp, **kwargs).decode()
36
40
 
37
- #class CustomDecoder(CBORDecoder):pass
41
+
42
+ # class CustomDecoder(CBORDecoder):pass
38
43
 
39
44
 
40
45
  def cleanup(obj):
@@ -45,14 +50,14 @@ def cleanup(obj):
45
50
  Warning: This operate in-place changes.
46
51
  Warning: This won't work for tags in dict keys.
47
52
  """
48
- if isinstance(obj,list):
49
- for i in range(0,len(obj)):
53
+ if isinstance(obj, list):
54
+ for i in range(0, len(obj)):
50
55
  obj[i] = cleanup(obj[i])
51
56
  return obj
52
57
 
53
- if isinstance(obj,dict):
58
+ if isinstance(obj, dict):
54
59
  for k in obj.keys():
55
- obj.update({k:cleanup(obj[k])})
60
+ obj.update({k: cleanup(obj[k])})
56
61
  return obj
57
62
 
58
63
  if type(obj) in bindings.classes:
xaal/lib/config.py CHANGED
@@ -1,53 +1,82 @@
1
1
 
2
2
  # Default configuration
3
+
3
4
  import os
4
5
  import sys
5
6
  import binascii
6
7
  from configobj import ConfigObj
7
8
 
8
- self = sys.modules[__name__]
9
-
10
9
  # Default settings
11
- DEF_ADDR = '224.0.29.200' # mcast address
12
- DEF_PORT = 1236 # mcast port
13
- DEF_HOPS = 10 # mcast hop
14
- DEF_ALIVE_TIMER = 100 # Time between two alive msg
15
- DEF_CIPHER_WINDOW = 60 * 2 # Time Window in seconds to avoid replay attacks
16
- DEF_QUEUE_SIZE = 10 # How many packet we can send in one loop
17
- DEF_LOG_LEVEL = 'DEBUG' # should be INFO|DEBUG|None
18
- DEF_LOG_PATH = '/var/log/xaal' # where log are
19
-
20
- # TBD : Move this stuff
10
+ DEF_ADDR = '224.0.29.200'
11
+ DEF_PORT = 1236
12
+ DEF_HOPS = 10
13
+ DEF_ALIVE_TIMER = 100
14
+ DEF_CIPHER_WINDOW = 60 * 2
15
+ DEF_QUEUE_SIZE = 10
16
+ DEF_LOG_LEVEL = 'DEBUG'
17
+ DEF_LOG_PATH = '/var/log/xaal'
18
+
21
19
  STACK_VERSION = 7
22
20
 
21
+ class Config:
22
+ def __init__(self):
23
+ self.conf_dir = os.environ.get('XAAL_CONF_DIR', os.path.expanduser("~/.xaal"))
24
+ self.address = DEF_ADDR
25
+ self.port = DEF_PORT
26
+ self.hops = DEF_HOPS
27
+ self.alive_timer = DEF_ALIVE_TIMER
28
+ self.cipher_window = DEF_CIPHER_WINDOW
29
+ self.queue_size = DEF_QUEUE_SIZE
30
+ self.log_level = DEF_LOG_LEVEL
31
+ self.log_path = DEF_LOG_PATH
32
+ self.key = b''
33
+ self.STACK_VERSION = STACK_VERSION
34
+
35
+ def load(self, name='xaal.ini'):
36
+ filename = os.path.join(self.conf_dir, name)
37
+ if not os.path.isfile(filename):
38
+ raise FileNotFoundError(f"Unable to load xAAL config file [{filename}]")
39
+
40
+ cfg = ConfigObj(filename)
41
+ self.address = self.safe_string(cfg.get('address'), DEF_ADDR)
42
+ self.port = self.safe_int(cfg.get('port'), DEF_PORT)
43
+ self.hops = self.safe_int(cfg.get('hops'), DEF_HOPS)
44
+ self.alive_timer = self.safe_int(cfg.get('alive_timer'), DEF_ALIVE_TIMER)
45
+ self.cipher_window = self.safe_int(cfg.get('cipher_window'), DEF_CIPHER_WINDOW)
46
+ self.queue_size = self.safe_int(cfg.get('queue_size'), DEF_QUEUE_SIZE)
47
+ self.log_level = self.safe_string(cfg.get('log_level'), DEF_LOG_LEVEL)
48
+ self.log_path = self.safe_string(cfg.get('log_path'), DEF_LOG_PATH)
49
+ key = cfg.get('key', None)
50
+ if key and type(key) is str:
51
+ self.key = binascii.unhexlify(key.encode('utf-8'))
52
+ else:
53
+ raise ValueError(f"Key not set in config file [{filename}]")
54
+
55
+ ## Helper functions
56
+ # Pylint enforce to sanity check the input. In fact, ConfigObj can do the job without issue
57
+ # but Pytlint assume cfg.get can return None (even w/ default set), so it warm about wrong
58
+ # type in all config setting. By doing this I insure that the value is of the right type.
59
+
60
+ @staticmethod
61
+ def safe_int(value, default):
62
+ try:
63
+ return int(value)
64
+ except (ValueError, TypeError):
65
+ return default
66
+
67
+ @staticmethod
68
+ def safe_string(value, default):
69
+ if value is None:
70
+ return default
71
+ try:
72
+ return str(value)
73
+ except (ValueError, TypeError):
74
+ return default
75
+
23
76
 
24
- if 'XAAL_CONF_DIR' in os.environ:
25
- self.conf_dir = os.environ['XAAL_CONF_DIR']
26
- else:
27
- self.conf_dir = os.path.expanduser("~") + '/.xaal'
28
-
29
-
30
- def load_config(name='xaal.ini'):
31
- filename = os.path.join(self.conf_dir, name)
32
- if not os.path.isfile(filename):
33
- print("Unable to load xAAL config file [%s]" % filename)
34
- sys.exit(-1)
35
-
36
- cfg = ConfigObj(filename)
37
- self.address = cfg.get('address',DEF_ADDR)
38
- self.port = int(cfg.get('port',DEF_PORT))
39
- self.hops = int(cfg.get('hops',DEF_HOPS))
40
- self.alive_timer = int(cfg.get('alive_timer',DEF_ALIVE_TIMER))
41
- self.cipher_window = int(cfg.get('ciper_window',DEF_CIPHER_WINDOW))
42
- self.queue_size = int(cfg.get('queue_size',DEF_QUEUE_SIZE))
43
- self.log_level = cfg.get('log_level',DEF_LOG_LEVEL)
44
- self.log_path = cfg.get('log_path',DEF_LOG_PATH)
45
- key = cfg.get('key',None)
46
-
47
- if key:
48
- self.key = binascii.unhexlify(key.encode('utf-8'))
49
- else:
50
- print("Please set key in config file [%s]" % filename)
51
- self.key = None
52
-
53
- load_config()
77
+ config = Config()
78
+ try:
79
+ config.load()
80
+ except Exception as e:
81
+ print(e)
82
+ sys.exit(-1)
xaal/lib/core.py CHANGED
@@ -18,26 +18,50 @@
18
18
  # along with xAAL. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
- from .messages import MessageType, MessageAction, MessageFactory, ALIVE_ADDR
22
- from .exceptions import *
23
-
24
- import time
25
21
  import inspect
26
-
27
22
  import logging
23
+ import time
24
+ import typing
25
+ from typing import Any, Awaitable, Optional, List, Callable, Union
26
+
27
+ from .exceptions import EngineError, XAALError
28
+ from .messages import ALIVE_ADDR, MessageAction, MessageFactory, MessageType
29
+
30
+ if typing.TYPE_CHECKING:
31
+ from .devices import Device, Attribute
32
+ from .messages import Message
33
+
34
+ # Function type w/ no argument, and no return (Timer, Hooks)
35
+ FuncT = Union[Callable[[], None], Callable[[], Awaitable[None]]]
36
+
37
+ # Function type w/ message as argument (subscribers), no return
38
+ SubFuncT = Union[Callable[['Message'], None], Callable[['Message'], Awaitable[None]]]
39
+
28
40
  logger = logging.getLogger(__name__)
29
41
 
30
- class EngineMixin(object):
31
42
 
32
- __slots__ = ['devices','timers','subscribers','msg_filter','_attributesChange','network','msg_factory']
43
+ #####################################################
44
+ # Timer class
45
+ #####################################################
46
+ class Timer(object):
47
+ def __init__(self, func: FuncT, period: int, counter: int):
48
+ # Timer function should a Callable[[],None], but it can be a coroutine too
49
+ self.func = func
50
+ self.period = period
51
+ self.counter = counter
52
+ self.deadline = time.time() + period
53
+
54
+
55
+ class EngineMixin(object):
56
+ __slots__ = ['devices', 'timers', 'subscribers', 'msg_filter', '_attributesChange', 'network', 'msg_factory']
33
57
 
34
- def __init__(self,address,port,hops,key):
35
- self.devices = [] # list of devices / use (un)register_devices()
36
- self.timers = [] # functions to call periodic
37
- self.subscribers = [] # message receive workflow
38
- self.msg_filter = None # message filter
58
+ def __init__(self, address: str, port: int, hops: int, key: bytes):
59
+ self.devices:list[Device] = [] # list of devices / use (un)register_devices()
60
+ self.timers: list[Timer] = [] # functions to call periodic
61
+ self.subscribers: list[SubFuncT] = [] # message receive workflow
62
+ self.msg_filter = None # message filter
39
63
 
40
- self._attributesChange = [] # list of XAALAttributes instances
64
+ self._attributesChange = [] # list of XAALAttributes instances
41
65
 
42
66
  # network connector
43
67
  self.network = None
@@ -49,21 +73,21 @@ class EngineMixin(object):
49
73
  #####################################################
50
74
  # Devices management
51
75
  #####################################################
52
- def add_device(self, dev):
53
- """register a new device """
76
+ def add_device(self, dev: 'Device'):
77
+ """register a new device"""
54
78
  if dev not in self.devices:
55
79
  self.devices.append(dev)
56
80
  dev.engine = self
57
81
  if self.is_running():
58
82
  self.send_alive(dev)
59
83
 
60
- def add_devices(self, devs):
84
+ def add_devices(self, devs: List['Device']):
61
85
  """register new devices"""
62
86
  for dev in devs:
63
87
  self.add_device(dev)
64
88
 
65
- def remove_device(self, dev):
66
- """unregister a device """
89
+ def remove_device(self, dev: 'Device'):
90
+ """unregister a device"""
67
91
  dev.engine = None
68
92
  # Remove dev from devices list
69
93
  self.devices.remove(dev)
@@ -72,54 +96,53 @@ class EngineMixin(object):
72
96
  # xAAL messages Tx handling
73
97
  #####################################################
74
98
  # Fifo for msg to send
75
- def queue_msg(self, msg):
99
+ def queue_msg(self, msg: bytes):
76
100
  logger.critical("To be implemented queue_msg: %s", msg)
77
101
 
78
- def send_request(self,dev,targets,action,body = None):
102
+ def send_request(self, dev: 'Device', targets: list, action: str, body: Optional[dict] = None):
79
103
  """queue a new request"""
80
104
  msg = self.msg_factory.build_msg(dev, targets, MessageType.REQUEST, action, body)
81
105
  self.queue_msg(msg)
82
106
 
83
- def send_reply(self, dev, targets, action, body=None):
107
+ def send_reply(self, dev: 'Device', targets: list, action: str, body: Optional[dict] = None):
84
108
  """queue a new reply"""
85
109
  msg = self.msg_factory.build_msg(dev, targets, MessageType.REPLY, action, body)
86
110
  self.queue_msg(msg)
87
111
 
88
- def send_error(self, dev, errcode, description=None):
112
+ def send_error(self, dev: 'Device', errcode: int, description: Optional[str] = None):
89
113
  """queue a error message"""
90
114
  msg = self.msg_factory.build_error_msg(dev, errcode, description)
91
115
  self.queue_msg(msg)
92
116
 
93
- def send_get_description(self, dev, targets):
117
+ def send_get_description(self, dev: 'Device', targets: list):
94
118
  """queue a get_description request"""
95
119
  self.send_request(dev, targets, MessageAction.GET_DESCRIPTION.value)
96
120
 
97
- def send_get_attributes(self, dev, targets):
121
+ def send_get_attributes(self, dev: 'Device', targets: list):
98
122
  """queue a get_attributes request"""
99
123
  self.send_request(dev, targets, MessageAction.GET_ATTRIBUTES.value)
100
124
 
101
- def send_notification(self, dev, action, body=None):
125
+ def send_notification(self, dev: 'Device', action: str, body: Optional[dict] = None):
102
126
  """queue a notificaton"""
103
- msg = self.msg_factory.build_msg(dev, [], MessageType.NOTIFY, action,body)
127
+ msg = self.msg_factory.build_msg(dev, [], MessageType.NOTIFY, action, body)
104
128
  self.queue_msg(msg)
105
129
 
106
- def send_alive(self, dev):
130
+ def send_alive(self, dev: 'Device'):
107
131
  """Send a Alive message for a given device"""
108
132
  timeout = dev.get_timeout()
109
133
  msg = self.msg_factory.build_alive_for(dev, timeout)
110
134
  self.queue_msg(msg)
111
135
  dev.update_alive()
112
136
 
113
- def send_is_alive(self, dev, targets=[ALIVE_ADDR,], dev_types=["any.any",]):
137
+ def send_is_alive(self, dev: 'Device', targets: list = [ALIVE_ADDR,], dev_types: list = ["any.any", ] ):
114
138
  """Send a is_alive message, w/ dev_types filtering"""
115
139
  body = {'dev_types': dev_types}
116
- self.send_request(dev,targets, MessageAction.IS_ALIVE.value, body)
117
-
140
+ self.send_request(dev, targets, MessageAction.IS_ALIVE.value, body)
118
141
 
119
142
  #####################################################
120
143
  # Messages filtering
121
144
  #####################################################
122
- def enable_msg_filter(self, func=None):
145
+ def enable_msg_filter(self, func: Optional[Callable[['Message'], bool]] = None):
123
146
  """enable message filter"""
124
147
  self.msg_filter = func or self.default_msg_filter
125
148
 
@@ -127,7 +150,7 @@ class EngineMixin(object):
127
150
  """disable message filter"""
128
151
  self.msg_filter = None
129
152
 
130
- def default_msg_filter(self, msg):
153
+ def default_msg_filter(self, msg: 'Message'):
131
154
  """
132
155
  Filter messages:
133
156
  - check if message has alive request address
@@ -150,17 +173,17 @@ class EngineMixin(object):
150
173
  """Periodic sending alive messages"""
151
174
  now = time.time()
152
175
  for dev in self.devices:
153
- if dev.next_alive < now :
176
+ if dev.next_alive < now:
154
177
  self.send_alive(dev)
155
178
 
156
179
  #####################################################
157
180
  # xAAL attributes changes
158
181
  #####################################################
159
- def add_attributes_change(self, attr):
182
+ def add_attributes_change(self, attr: 'Attribute'):
160
183
  """add a new attribute change to the list"""
161
184
  self._attributesChange.append(attr)
162
185
 
163
- def get_attributes_change(self):
186
+ def get_attributes_change(self) -> List['Attribute']:
164
187
  """return the pending attributes changes list"""
165
188
  return self._attributesChange
166
189
 
@@ -180,17 +203,18 @@ class EngineMixin(object):
180
203
  #####################################################
181
204
  # xAAL messages subscribers
182
205
  #####################################################
183
- def subscribe(self,func):
206
+ def subscribe(self, func: SubFuncT):
207
+ # func should be a Callable[[Message],None], but it can be a coroutine too
184
208
  self.subscribers.append(func)
185
209
 
186
- def unsubscribe(self,func):
210
+ def unsubscribe(self, func: SubFuncT):
187
211
  self.subscribers.remove(func)
188
212
 
189
213
  #####################################################
190
214
  # timers
191
215
  #####################################################
192
- def add_timer(self, func, period,counter=-1):
193
- """
216
+ def add_timer(self, func: FuncT, period: int, counter: int = -1):
217
+ """
194
218
  func: function to call
195
219
  period: period in second
196
220
  counter: number of repeat, -1 => always
@@ -201,7 +225,7 @@ class EngineMixin(object):
201
225
  self.timers.append(t)
202
226
  return t
203
227
 
204
- def remove_timer(self, timer):
228
+ def remove_timer(self, timer: Timer):
205
229
  """remove a given timer from the list"""
206
230
  self.timers.remove(timer)
207
231
 
@@ -220,23 +244,15 @@ class EngineMixin(object):
220
244
  def run(self):
221
245
  logger.critical("To be implemented run")
222
246
 
223
- def is_running(self):
247
+ def is_running(self) -> bool:
224
248
  logger.critical("To be implemented is_running")
249
+ return False
225
250
 
226
- #####################################################
227
- # Timer class
228
- #####################################################
229
- class Timer(object):
230
- def __init__(self, func, period, counter):
231
- self.func = func
232
- self.period = period
233
- self.counter = counter
234
- self.deadline = time.time() + period
235
251
 
236
252
  #####################################################
237
253
  # Usefull functions to Engine developpers
238
254
  #####################################################
239
- def filter_msg_for_devices(msg, devices):
255
+ def filter_msg_for_devices(msg: 'Message', devices: List['Device']) -> List['Device']:
240
256
  """
241
257
  loop throught the devices, to find which are expected w/ the msg
242
258
  - Filter on dev_types for is_alive broadcast request.
@@ -245,28 +261,29 @@ def filter_msg_for_devices(msg, devices):
245
261
  results = []
246
262
  if msg.is_request_isalive() and (ALIVE_ADDR in msg.targets):
247
263
  # if we receive a broadcast is_alive request, we reply
248
- # with filtering on dev_tyes.
264
+ # with filtering on dev_tyes.
249
265
  if 'dev_types' in msg.body.keys():
250
266
  dev_types = msg.body['dev_types']
251
- if 'any.any' in dev_types:
267
+ if "any.any" in dev_types:
252
268
  results = devices
253
269
  else:
254
270
  for dev in devices:
255
- any_subtype = dev.dev_type.split('.')[0] + '.any'
271
+ any_subtype = dev.dev_type.split(".")[0] + ".any"
256
272
  if dev.dev_type in dev_types:
257
273
  results.append(dev)
258
274
  elif any_subtype in dev_types:
259
275
  results.append(dev)
260
276
  else:
261
277
  # this is a normal request, only filter on device address
262
- # note: direct is_alive are treated like normal request
278
+ # note: direct is_alive are treated like normal request
263
279
  # so dev_types filtering is discarded
264
280
  for dev in devices:
265
281
  if dev.address in msg.targets:
266
282
  results.append(dev)
267
283
  return results
268
284
 
269
- def search_action(msg, device):
285
+
286
+ def search_action(msg: 'Message', device: 'Device'):
270
287
  """
271
288
  Extract an action (match with methods) from a msg on the device.
272
289
  Return:
@@ -279,6 +296,7 @@ def search_action(msg, device):
279
296
  params = {}
280
297
  result = None
281
298
  if msg.action in methods.keys():
299
+ assert msg.action
282
300
  method = methods[msg.action]
283
301
  body_params = None
284
302
  if msg.body:
@@ -286,23 +304,22 @@ def search_action(msg, device):
286
304
  body_params = msg.body
287
305
 
288
306
  for k in body_params:
289
- temp = '_%s' %k
307
+ temp = "_%s" % k
290
308
  if temp in method_params:
291
- params.update({temp:body_params[k]})
309
+ params.update({temp: body_params[k]})
292
310
  else:
293
- logger.warning("Wrong method parameter [%s] for action %s" %(k, msg.action))
294
- result = (method,params)
311
+ logger.warning("Wrong method parameter [%s] for action %s" % (k, msg.action))
312
+ result = (method, params)
295
313
  else:
296
- raise XAALError("Method %s not found on device %s" % (msg.action,device))
314
+ raise XAALError("Method %s not found on device %s" % (msg.action, device))
297
315
  return result
298
316
 
299
- def get_args_method(method):
300
- """ return the list on arguments for a given python method """
317
+
318
+ def get_args_method(method: Any) -> List[str]:
319
+ """return the list on arguments for a given python method"""
301
320
  spec = inspect.getfullargspec(method)
302
321
  try:
303
322
  spec.args.remove('self')
304
323
  except Exception:
305
324
  pass
306
325
  return spec.args
307
-
308
-