Commit 7735aaa722d935dca4af29ebd9a06e41365c3948

Authored by Etienne Pallier
1 parent cbbd0c65
Exists in dev

updated Agent specific commands format et new get_specific_cmds method avec list…

…e arguments auto-generée
@@ -626,8 +626,7 @@ def install_or_update(UPDATE: bool = False, with_packages: bool = True, with_dat @@ -626,8 +626,7 @@ def install_or_update(UPDATE: bool = False, with_packages: bool = True, with_dat
626 # self.addExecuted(self.current_command, command) 626 # self.addExecuted(self.current_command, command)
627 from git import Repo 627 from git import Repo
628 else: 628 else:
629 - log.error(  
630 - "GitPython package (required for obsconfig class) installation failed") 629 + log.error("GitPython package (required for obsconfig class) installation failed")
631 ''' 630 '''
632 print("Guitastro : Generating (updating) API documentation (using Sphinx)") 631 print("Guitastro : Generating (updating) API documentation (using Sphinx)")
633 # Make html doc from RST 632 # Make html doc from RST
src/core/pyros_django/agent/Agent.py
@@ -40,8 +40,10 @@ and execute them on reception at each iteration : @@ -40,8 +40,10 @@ and execute them on reception at each iteration :
40 40
41 41
42 # For cmd parsing 42 # For cmd parsing
43 -from typing import List, Tuple 43 +from array import array
  44 +from typing import List, Tuple, Union, Any
44 import ast 45 import ast
  46 +from inspect import signature
45 47
46 import os 48 import os
47 from pathlib import Path 49 from pathlib import Path
@@ -256,8 +258,11 @@ class StoppableThreadEvenWhenSleeping(threading.Thread): @@ -256,8 +258,11 @@ class StoppableThreadEvenWhenSleeping(threading.Thread):
256 class AgentCmdException(Exception): 258 class AgentCmdException(Exception):
257 ''' Base class for all Agent command exceptions ''' 259 ''' Base class for all Agent command exceptions '''
258 # pass 260 # pass
259 - def __init__(self, cmd:AgentCmd): 261 + def __init__( self, cmd: Union[AgentCmd,str] ):
260 self.cmd = cmd 262 self.cmd = cmd
  263 + print(type(cmd))
  264 + exit
  265 + self.cmd_name = cmd if isinstance(cmd,str) else cmd.name
261 ''' 266 '''
262 def __str__(self): 267 def __str__(self):
263 return f"The Agent command '{self.cmd.name}' is unknown to the agent" 268 return f"The Agent command '{self.cmd.name}' is unknown to the agent"
@@ -267,19 +272,19 @@ class AgentCmdException(Exception): @@ -267,19 +272,19 @@ class AgentCmdException(Exception):
267 class UnknownCmdException(AgentCmdException): 272 class UnknownCmdException(AgentCmdException):
268 ''' Raised when an Agent (specific) cmd is NOT known by the agent ''' 273 ''' Raised when an Agent (specific) cmd is NOT known by the agent '''
269 def __str__(self): 274 def __str__(self):
270 - return f"The Agent command '{self.cmd.name}' is unknown to the agent" 275 + return f"The Agent command '{self.cmd_name}' is unknown to the agent"
271 #return f"({type(self).__name__}): Device Generic command has no implementation in the controller" 276 #return f"({type(self).__name__}): Device Generic command has no implementation in the controller"
272 277
273 class AgentCmdUnimplementedException(AgentCmdException): 278 class AgentCmdUnimplementedException(AgentCmdException):
274 ''' Raised when an Agent Specific cmd is known by the agent but not implemented ''' 279 ''' Raised when an Agent Specific cmd is known by the agent but not implemented '''
275 def __str__(self): 280 def __str__(self):
276 - return f"The Agent command '{self.cmd.name}' is known by the agent but not implemented" 281 + return f"The Agent command '{self.cmd_name}' is known by the agent but not implemented"
277 #return f"({type(self).__name__}): Device Generic command has no implementation in the controller" 282 #return f"({type(self).__name__}): Device Generic command has no implementation in the controller"
278 283
279 class AgentCmdBadArgsException(AgentCmdException): 284 class AgentCmdBadArgsException(AgentCmdException):
280 ''' Raised when an Agent cmd has bad, missing, or too many argument(s) ''' 285 ''' Raised when an Agent cmd has bad, missing, or too many argument(s) '''
281 def __str__(self): 286 def __str__(self):
282 - return f"The Agent command '{self.cmd.name}' has bad, missing, or too many argument(s)" 287 + return f"The Agent command '{self.cmd_name}' has bad, missing, or too many argument(s)"
283 #return f"({type(self).__name__}): Device Generic command has no implementation in the controller" 288 #return f"({type(self).__name__}): Device Generic command has no implementation in the controller"
284 289
285 290
@@ -327,18 +332,19 @@ class Agent: @@ -327,18 +332,19 @@ class Agent:
327 # Default LOG level is INFO 332 # Default LOG level is INFO
328 #PYROS_DEFAULT_GLOBAL_LOG_LEVEL = LogPyros.LOG_LEVEL_INFO # INFO 333 #PYROS_DEFAULT_GLOBAL_LOG_LEVEL = LogPyros.LOG_LEVEL_INFO # INFO
329 334
330 - # This Agent Specific commands list, that he is able to execute  
331 - # To be overriden by subclasses (here are just a few examples of commands)  
332 - # Format : ("cmd",timeout) with :  
333 - # - cmd : the command name  
334 - # - timeout : the command timeout (in sec)  
335 - AGENT_SPECIFIC_COMMANDS = [  
336 - #"do_specific1",  
337 - #"set_specific2",  
338 - #"do_specific3",  
339 - ("do_specific1", 10),  
340 - ("set_specific2", 5),  
341 - ("do_specific3", 3), 335 + '''
  336 + This Agent Specific commands list, that he is able to execute
  337 + To be overriden by subclasses (here are just a few examples of commands)
  338 + Format : ("cmd", args, timeout) with :
  339 + - cmd (str) : the command name
  340 + - timeout (int) : the command timeout (in sec)
  341 + - exec_mode (int) : 0 (sequential), 1 (thread), or 2 (process)
  342 + '''
  343 + AGENT_SPECIFIC_COMMANDS: List[ Tuple[str, int, int] ] = [
  344 + # Format : (“cmd_name”, timeout, exec_mode)
  345 + ("do_specific1", 10, 0),
  346 + #("set_specific2", 5, 0),
  347 + ("do_specific3", 3, 0),
342 ] 348 ]
343 349
344 # 350 #
@@ -384,7 +390,11 @@ class Agent: @@ -384,7 +390,11 @@ class Agent:
384 # - "self set_state ATTENTIVE" => means to send the command "set_state ATTENTIVE" to MYSELF 390 # - "self set_state ATTENTIVE" => means to send the command "set_state ATTENTIVE" to MYSELF
385 # - "self do_restart_loop" => means to send the command "do_restart_loop" to MYSELF (no args) 391 # - "self do_restart_loop" => means to send the command "do_restart_loop" to MYSELF (no args)
386 # 392 #
387 - TEST_COMMANDS_LIST = [ 393 + TEST_COMMANDS_LIST: List[ Tuple[ str, int, str, Union[int,None] ] ] = [
  394 +
  395 + # Format : ("self cmd_name cmd_args", timeout, "expected_result", expected_status),
  396 + ("self do_specific1 1 2 3.5 titi (3,'titi',5) [1,3,5,7,9]", 200, '15.5', None),
  397 +
388 398
389 # 1) First, 3 EXCEPTION CASES (uncomment to activate exception) 399 # 1) First, 3 EXCEPTION CASES (uncomment to activate exception)
390 # Each of these lines will stop execution with an exception 400 # Each of these lines will stop execution with an exception
@@ -416,15 +426,16 @@ class Agent: @@ -416,15 +426,16 @@ class Agent:
416 ("self get_mode", 100, "MODE = ATTENTIVE", None), 426 ("self get_mode", 100, "MODE = ATTENTIVE", None),
417 427
418 # => should get "7" 428 # => should get "7"
419 - ("self do_eval 3+5-1", 200, 7, None), 429 + ("self do_eval 3+5-1", 200, '7', None),
420 430
421 # END, will not go further 431 # END, will not go further
422 #("self do_exit", 2, "STOPPING"), 432 #("self do_exit", 2, "STOPPING"),
423 433
424 # Agent specific commands => should be executed 434 # Agent specific commands => should be executed
425 - ("self do_specific3", 200, None, None), 435 + ("self do_specific3", 200, '', None),
426 ("self do_exit", 500, "STOPPING", None), 436 ("self do_exit", 500, "STOPPING", None),
427 - ("self do_specific1 1 2 3.5 titi (3,'titi',5) [1,3,5,7,9]", 200, 7, None), 437 + ("self do_specific1 1 2 3.5 titi (3,'titi',5) [1,3,5,7,9]", 200, '15.5', None),
  438 +
428 439
429 ("self set_mode ROUTINE", 200, "MODE = ROUTINE", None), 440 ("self set_mode ROUTINE", 200, "MODE = ROUTINE", None),
430 # => should get "ROUTINE" 441 # => should get "ROUTINE"
@@ -1042,15 +1053,15 @@ class Agent: @@ -1042,15 +1053,15 @@ class Agent:
1042 log.info("*"*10 + " NEXT COMMAND PROCESSING (START) " + "*"*10 + '\n') 1053 log.info("*"*10 + " NEXT COMMAND PROCESSING (START) " + "*"*10 + '\n')
1043 try : 1054 try :
1044 cmd = self._process_next_command_if_exists() 1055 cmd = self._process_next_command_if_exists()
1045 - print("after get")  
1046 print(cmd) 1056 print(cmd)
1047 except (AgentCmdUnimplementedException, AgentCmdBadArgsException, UnknownCmdException) as e : 1057 except (AgentCmdUnimplementedException, AgentCmdBadArgsException, UnknownCmdException) as e :
1048 print(e) 1058 print(e)
1049 - log.error(f"EXCEPTION on Agent command '{e.cmd.name}'")  
1050 - if type(e) is UnknownCmdException:  
1051 - e.cmd.set_as_skipped("EXCEPTION: unknown command")  
1052 - else :  
1053 - e.cmd.set_as_processed("EXCEPTION: command known but unimplemented or bad args") 1059 + log.error(f"EXCEPTION on Agent command '{e.cmd_name}'")
  1060 + if isinstance(e.cmd, AgentCmd) :
  1061 + if type(e) is AgentCmdUnimplementedException:
  1062 + e.cmd.set_as_unimplemented("EXCEPTION: command known but unimplemented")
  1063 + else:
  1064 + e.cmd.set_as_invalid("EXCEPTION: command unknown or bad args")
1054 self._cleanup_before_exit() 1065 self._cleanup_before_exit()
1055 raise 1066 raise
1056 log.info("*"*10 + " NEXT COMMAND PROCESSING (END) " + "*"*10 + "\n") 1067 log.info("*"*10 + " NEXT COMMAND PROCESSING (END) " + "*"*10 + "\n")
@@ -1421,6 +1432,22 @@ class Agent: @@ -1421,6 +1432,22 @@ class Agent:
1421 def show_mode_and_status(self): 1432 def show_mode_and_status(self):
1422 log.info(f"CURRENT MODE is {self.mode} (status is {self.status})") 1433 log.info(f"CURRENT MODE is {self.mode} (status is {self.status})")
1423 1434
  1435 + def get_specific_cmds(self)->str:
  1436 + specific_commands = ""
  1437 + for command_tuple in self.AGENT_SPECIFIC_COMMANDS:
  1438 + cmd_name = command_tuple[0]
  1439 + specific_commands += cmd_name
  1440 + # Exception if exists an unimplemented command
  1441 + try:
  1442 + f = getattr(self, cmd_name)
  1443 + except AttributeError:
  1444 + raise AgentCmdUnimplementedException(cmd_name) from None
  1445 + args = signature(f)
  1446 + specific_commands += str(args)
  1447 + specific_commands += ";"
  1448 + if specific_commands: specific_commands = specific_commands[0:-1]
  1449 + return specific_commands
  1450 + '''
1424 def get_specifics_cmd(self): 1451 def get_specifics_cmd(self):
1425 specific_commands = "" 1452 specific_commands = ""
1426 for index, command_tuple in enumerate(self.AGENT_SPECIFIC_COMMANDS): 1453 for index, command_tuple in enumerate(self.AGENT_SPECIFIC_COMMANDS):
@@ -1428,6 +1455,7 @@ class Agent: @@ -1428,6 +1455,7 @@ class Agent:
1428 if index != len(self.AGENT_SPECIFIC_COMMANDS)-1: 1455 if index != len(self.AGENT_SPECIFIC_COMMANDS)-1:
1429 specific_commands += ";" 1456 specific_commands += ";"
1430 return specific_commands 1457 return specific_commands
  1458 + '''
1431 1459
1432 def get_mode(self): 1460 def get_mode(self):
1433 return self.mode 1461 return self.mode
@@ -1982,7 +2010,7 @@ class Agent: @@ -1982,7 +2010,7 @@ class Agent:
1982 # Execute method self."cmd.name"() 2010 # Execute method self."cmd.name"()
1983 # This can raise an exception (caught by this method caller) 2011 # This can raise an exception (caught by this method caller)
1984 try: 2012 try:
1985 - res = self.exec_cmd_from_its_name(cmd) 2013 + res = self._exec_cmd_from_its_name(cmd)
1986 except (AgentCmdUnimplementedException, AgentCmdBadArgsException) as e: 2014 except (AgentCmdUnimplementedException, AgentCmdBadArgsException) as e:
1987 # These exceptions are managed at higher level : 2015 # These exceptions are managed at higher level :
1988 raise 2016 raise
@@ -2013,11 +2041,25 @@ class Agent: @@ -2013,11 +2041,25 @@ class Agent:
2013 self.printd("Logging data...") 2041 self.printd("Logging data...")
2014 ''' 2042 '''
2015 2043
2016 - def exec_cmd_from_its_name(self, cmd:AgentCmd): 2044 + def _exec_cmd_from_its_name(self, cmd:AgentCmd)->Any:
  2045 + #print(dir(self))
  2046 + '''
  2047 + for method in dir(self):
  2048 + if callable(getattr(self, method)):
  2049 + m = getattr(self, method)
  2050 + print(method, ' => ', signature(m))
  2051 + '''
  2052 + #print("***************")
  2053 + #print(self.get_specific_cmds())
  2054 + #print("***************")
  2055 +
2017 methods_list = [method for method in dir(self) if callable(getattr(self, method))] 2056 methods_list = [method for method in dir(self) if callable(getattr(self, method))]
2018 #print(methodsList) 2057 #print(methodsList)
2019 func = cmd.name 2058 func = cmd.name
2020 if func not in methods_list: raise AgentCmdUnimplementedException(cmd) 2059 if func not in methods_list: raise AgentCmdUnimplementedException(cmd)
  2060 + f = getattr(self, func)
  2061 + ###print(func, ' => ', signature(f))
  2062 +
2021 #for arg in cmd.args: print(arg) 2063 #for arg in cmd.args: print(arg)
2022 #print(cmd.args) 2064 #print(cmd.args)
2023 #print(*cmd.args) 2065 #print(*cmd.args)
@@ -2046,9 +2088,17 @@ class Agent: @@ -2046,9 +2088,17 @@ class Agent:
2046 for arg in cmd.args: 2088 for arg in cmd.args:
2047 #print(arg) 2089 #print(arg)
2048 #try: 2090 #try:
2049 - # Evaluate arg only if it is not a word (letters) 2091 + # Evaluate arg only if it is not a word (letters) :
  2092 + # - a word like "toto" is not evaluated => stays as is (=str)
  2093 + # Are evaluated :
  2094 + # - an int or float
  2095 + # - a (tuple)
  2096 + # - a [list]
  2097 + # - ...
  2098 + #print('********', arg, " :")
2050 if not arg[0].isalpha(): 2099 if not arg[0].isalpha():
2051 arg = ast.literal_eval(arg) 2100 arg = ast.literal_eval(arg)
  2101 + #print("evaluated to", type(arg), arg)
2052 #except ValueError as e: newarg = arg 2102 #except ValueError as e: newarg = arg
2053 args.append(arg) 2103 args.append(arg)
2054 try: 2104 try:
@@ -2063,6 +2113,7 @@ class Agent: @@ -2063,6 +2113,7 @@ class Agent:
2063 ##raise AgentCmdUnimplementedException(cmd).with_traceback(tb) 2113 ##raise AgentCmdUnimplementedException(cmd).with_traceback(tb)
2064 ##raise AgentCmdUnimplementedException(cmd).with_traceback(None) 2114 ##raise AgentCmdUnimplementedException(cmd).with_traceback(None)
2065 2115
  2116 +
2066 def _is_agent_level_cmd(self, cmd:AgentCmd): 2117 def _is_agent_level_cmd(self, cmd:AgentCmd):
2067 return self._is_agent_general_cmd(cmd) or self._is_agent_specific_cmd(cmd) 2118 return self._is_agent_general_cmd(cmd) or self._is_agent_specific_cmd(cmd)
2068 2119
@@ -2092,7 +2143,7 @@ class Agent: @@ -2092,7 +2143,7 @@ class Agent:
2092 def _is_agent_specific_cmd(self, cmd:AgentCmd): 2143 def _is_agent_specific_cmd(self, cmd:AgentCmd):
2093 #return cmd.name in self.AGENT_SPECIFIC_COMMANDS 2144 #return cmd.name in self.AGENT_SPECIFIC_COMMANDS
2094 #return (cmd.name,) in self.AGENT_SPECIFIC_COMMANDS 2145 #return (cmd.name,) in self.AGENT_SPECIFIC_COMMANDS
2095 - for (cmd_name,timeout) in self.AGENT_SPECIFIC_COMMANDS: 2146 + for (cmd_name,_,_) in self.AGENT_SPECIFIC_COMMANDS:
2096 if cmd.name == cmd_name : return True 2147 if cmd.name == cmd_name : return True
2097 2148
2098 ''' 2149 '''
@@ -2118,7 +2169,7 @@ class Agent: @@ -2118,7 +2169,7 @@ class Agent:
2118 def do_flush_commands(self): 2169 def do_flush_commands(self):
2119 AgentCmd.delete_pending_commands_for_agent(self.name) 2170 AgentCmd.delete_pending_commands_for_agent(self.name)
2120 2171
2121 - def do_exec_commands(self, what:str): 2172 + def do_exec_command(self, what:str):
2122 # - Temporaly stop execution of new commands (let them accumulate) 2173 # - Temporaly stop execution of new commands (let them accumulate)
2123 if what == "stop": pass 2174 if what == "stop": pass
2124 # - Resume execution of commands (accumulated since "do_stop_exec_cmd") 2175 # - Resume execution of commands (accumulated since "do_stop_exec_cmd")
@@ -2183,6 +2234,7 @@ class Agent: @@ -2183,6 +2234,7 @@ class Agent:
2183 2234
2184 #def do_specific1(self, arg1:int, arg2:int=2, arg3:int=3) -> int: 2235 #def do_specific1(self, arg1:int, arg2:int=2, arg3:int=3) -> int:
2185 #def do_specific1(self, arg1:int, arg2:int=2, arg3:float=3.1, arg4:list=[1,2,3]) -> float: 2236 #def do_specific1(self, arg1:int, arg2:int=2, arg3:float=3.1, arg4:list=[1,2,3]) -> float:
  2237 +
2186 def do_specific1(self, 2238 def do_specific1(self,
2187 arg1:int, 2239 arg1:int,
2188 arg2:int, 2240 arg2:int,
@@ -2200,11 +2252,12 @@ class Agent: @@ -2200,11 +2252,12 @@ class Agent:
2200 print(arg5[1]) 2252 print(arg5[1])
2201 arg6 = ast.literal_eval(arg6) 2253 arg6 = ast.literal_eval(arg6)
2202 ''' 2254 '''
2203 - print(arg4) 2255 + #print(arg4)
2204 res = arg1 + arg2 + arg3 + arg5[0] + arg5[2] 2256 res = arg1 + arg2 + arg3 + arg5[0] + arg5[2]
2205 if arg6: res += arg6[0] 2257 if arg6: res += arg6[0]
2206 return res 2258 return res
2207 2259
  2260 + # Undefined specific cmd
2208 #def set_specific2(self, arg1:str, arg2:int): pass 2261 #def set_specific2(self, arg1:str, arg2:int): pass
2209 2262
2210 def do_specific3(self): 2263 def do_specific3(self):
@@ -2303,7 +2356,7 @@ class Agent: @@ -2303,7 +2356,7 @@ class Agent:
2303 log.debug(cmd.result) 2356 log.debug(cmd.result)
2304 log.debug(self._cmdts.expected_res) 2357 log.debug(self._cmdts.expected_res)
2305 if cmd.is_executed() and self._cmdts.expected_res: 2358 if cmd.is_executed() and self._cmdts.expected_res:
2306 - assert(cmd.result == self._cmdts.expected_res) 2359 + assert(str(cmd.result) == self._cmdts.expected_res)
2307 2360
2308 log.debug(cmd.state) 2361 log.debug(cmd.state)
2309 log.debug(self._cmdts.expected_status) 2362 log.debug(self._cmdts.expected_status)
@@ -2374,7 +2427,6 @@ class Agent: @@ -2374,7 +2427,6 @@ class Agent:
2374 # Execution was completeted => get result 2427 # Execution was completeted => get result
2375 elif self._cmdts.is_executed(): 2428 elif self._cmdts.is_executed():
2376 cmdts_res = self._cmdts.get_result() 2429 cmdts_res = self._cmdts.get_result()
2377 - print("toto")  
2378 log.info(f"Cmd executed. Result is '{cmdts_res}'") 2430 log.info(f"Cmd executed. Result is '{cmdts_res}'")
2379 #cmdts_is_processed = True 2431 #cmdts_is_processed = True
2380 ''' Optimisation possible pour gagner une iteration: 2432 ''' Optimisation possible pour gagner une iteration:
src/core/pyros_django/common/models.py
1 ##from __future__ import unicode_literals 1 ##from __future__ import unicode_literals
2 2
  3 +# (EP 21/9/22) To allow autoreferencing (ex: AgentCmd.create() returns a AgentCmd)
  4 +from __future__ import annotations
  5 +
3 # Stdlib imports 6 # Stdlib imports
4 from numpy import False_ 7 from numpy import False_
5 from src.device_controller.abstract_component.device_controller import DeviceCmd 8 from src.device_controller.abstract_component.device_controller import DeviceCmd
@@ -626,10 +629,9 @@ class AgentCmd(models.Model): @@ -626,10 +629,9 @@ class AgentCmd(models.Model):
626 # -------------- Command CLASS (static) METHODS -------------- 629 # -------------- Command CLASS (static) METHODS --------------
627 630
628 # Avoid to override the Model __init__ method 631 # Avoid to override the Model __init__ method
  632 + # See https://docs.djangoproject.com/en/stable/ref/models/instances/#creating-objects
629 @classmethod 633 @classmethod
630 - # TODO: return type AgentCmd  
631 - #def create(cls, agent_from:str, agent_to:str, cmd_name:str, cmd_args:str=None, cmd_validity:int=None) -> AgentCmd :  
632 - def create(cls, agent_from:str, agent_to:str, cmd_name:str, cmd_args:str=None, cmd_validity:int=None) : 634 + def create(cls, agent_from:str, agent_to:str, cmd_name:str, cmd_args:str=None, cmd_validity:int=None) -> AgentCmd :
633 #print(agent_to) 635 #print(agent_to)
634 if '.' in agent_to: 636 if '.' in agent_to:
635 agent_to, component_name = agent_to.split('.') 637 agent_to, component_name = agent_to.split('.')
@@ -654,9 +656,8 @@ class AgentCmd(models.Model): @@ -654,9 +656,8 @@ class AgentCmd(models.Model):
654 """ 656 """
655 657
656 @classmethod 658 @classmethod
657 - # TODO: return type AgentCmd  
658 - #def send_cmd_from_to(cls, agent_from, agent_to, cmd_name, cmd_args=None, cmd_validity:int=None)->AgentCmd:  
659 - def send_cmd_from_to(cls, agent_from, agent_to, cmd_name, cmd_args=None, cmd_validity:int=None): 659 + def send_cmd_from_to(cls, agent_from, agent_to, cmd_name, cmd_args=None, cmd_validity:int=None)->AgentCmd:
  660 + """ Create and send a command, then return it """
660 # def send(cls, from_agent, to_agent, cmd_name, cmd_args=None): 661 # def send(cls, from_agent, to_agent, cmd_name, cmd_args=None):
661 """ 662 """
662 ex: send("AgentA",“AgentB”,"EVAL”,“3+4”) 663 ex: send("AgentA",“AgentB”,"EVAL”,“3+4”)
@@ -968,7 +969,47 @@ class AgentCmd(models.Model): @@ -968,7 +969,47 @@ class AgentCmd(models.Model):
968 # Optimization: update only 1 field 969 # Optimization: update only 1 field
969 if do_save: self.save(update_fields=["r_read_time"]) 970 if do_save: self.save(update_fields=["r_read_time"])
970 971
  972 + #
  973 + # Set cmd status
  974 + #
  975 +
  976 + def set_as_pending(self):
  977 + self.set_state_to(self.CMD_STATUS_CODES.CMD_PENDING)
  978 +
  979 + # from PENDING
  980 + def set_as_unimplemented(self, result:str=None):
  981 + assert self.is_pending()
  982 + self.set_state_to(self.CMD_STATUS_CODES.CMD_UNIMPLEMENTED)
  983 +
  984 + # from PENDING
  985 + def set_as_invalid(self, result:str=None):
  986 + assert self.is_pending()
  987 + self.set_state_to(self.CMD_STATUS_CODES.CMD_INVALID)
  988 +
  989 + # from PENDING
  990 + def set_as_skipped(self, result:str=None):
  991 + assert self.is_pending()
  992 + self.set_state_to(self.CMD_STATUS_CODES.CMD_SKIPPED, result=result)
  993 +
  994 + # from PENDING
  995 + def set_as_expired(self):
  996 + assert self.is_pending()
  997 + print(f"- Set this command as expired (older than its validity duration of {self.validity_duration}s): {self}")
  998 + self.set_state_to(self.CMD_STATUS_CODES.CMD_EXPIRED)
  999 +
  1000 + # from PENDING
  1001 + def set_as_running(self):
  1002 + assert self.is_pending()
  1003 + printd(f"- Set command {self.name} as running")
  1004 + self.set_state_to(self.CMD_STATUS_CODES.CMD_RUNNING)
  1005 +
  1006 + '''
  1007 + def set_as_executed(self):
  1008 + self.set_state_to(self.CMD_STATUS_CODES.CMD_EXECUTED)
  1009 + '''
  1010 + # from RUNNING
971 def set_as_processed(self, result:str=None): 1011 def set_as_processed(self, result:str=None):
  1012 + assert self.is_running()
972 printd(f"- Set command {self.name} as processed") 1013 printd(f"- Set command {self.name} as processed")
973 self.set_state_to(self.CMD_STATUS_CODES.CMD_EXECUTED, result=result) 1014 self.set_state_to(self.CMD_STATUS_CODES.CMD_EXECUTED, result=result)
974 # print(self) 1015 # print(self)
@@ -979,32 +1020,30 @@ class AgentCmd(models.Model): @@ -979,32 +1020,30 @@ class AgentCmd(models.Model):
979 """ 1020 """
980 # Optimization: update the related fields, but does not work, why ? 1021 # Optimization: update the related fields, but does not work, why ?
981 ##self.save(update_fields=["state", "r_processed_time"]) 1022 ##self.save(update_fields=["state", "r_processed_time"])
982 -  
983 #def set_as_outofdate(self): 1023 #def set_as_outofdate(self):
984 - def set_as_expired(self):  
985 - print(  
986 - f"- Set this command as expired (older than its validity duration of {self.validity_duration}s): {self}")  
987 - self.set_state_to(self.CMD_STATUS_CODES.CMD_EXPIRED)  
988 1024
989 - def set_as_pending(self):  
990 - self.set_state_to(self.CMD_STATUS_CODES.CMD_PENDING) 1025 + # from RUNNING
  1026 + def set_as_exec_error(self, result:str=None):
  1027 + assert self.is_running()
  1028 + self.set_state_to(self.CMD_STATUS_CODES.CMD_EXEC_ERROR, result=result)
991 1029
992 - def set_as_skipped(self, result:str=None):  
993 - self.set_state_to(self.CMD_STATUS_CODES.CMD_SKIPPED, result=result) 1030 + # from RUNNING
  1031 + def set_as_exec_timeout(self, result:str=None):
  1032 + assert self.is_running()
  1033 + self.set_state_to(self.CMD_STATUS_CODES.CMD_EXEC_TIMEOUT, result=result)
994 1034
  1035 + # from RUNNING
  1036 + def set_as_exec_timeout(self, result:str=None):
  1037 + assert self.is_running()
  1038 + self.set_state_to(self.CMD_STATUS_CODES.CMD_EXEC_TIMEOUT, result=result)
  1039 +
  1040 + # from RUNNING
995 def set_as_killed_by(self, author_agent: str): 1041 def set_as_killed_by(self, author_agent: str):
  1042 + assert self.is_running()
996 printd(f"- Set command {self.name} as killed") 1043 printd(f"- Set command {self.name} as killed")
997 #print(f"- Set this command as killed: {self}") 1044 #print(f"- Set this command as killed: {self}")
998 self.set_state_to(self.CMD_STATUS_CODES.CMD_EXEC_KILLED, author_agent) 1045 self.set_state_to(self.CMD_STATUS_CODES.CMD_EXEC_KILLED, author_agent)
999 1046
1000 - def set_as_running(self):  
1001 - printd(f"- Set command {self.name} as running")  
1002 - self.set_state_to(self.CMD_STATUS_CODES.CMD_RUNNING)  
1003 - '''  
1004 - def set_as_executed(self):  
1005 - self.set_state_to(self.CMD_STATUS_CODES.CMD_EXECUTED)  
1006 - '''  
1007 -  
1008 def set_state_to(self, status: str, author_agent_name: str = None, result:str=None): 1047 def set_state_to(self, status: str, author_agent_name: str = None, result:str=None):
1009 ''' 1048 '''
1010 If comment is present it will be set in the "result" field 1049 If comment is present it will be set in the "result" field