Commit 7735aaa722d935dca4af29ebd9a06e41365c3948
1 parent
cbbd0c65
Exists in
dev
updated Agent specific commands format et new get_specific_cmds method avec list…
…e arguments auto-generée
Showing
3 changed files
with
150 additions
and
60 deletions
Show diff stats
pyros.py
@@ -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 |