CmdTasks removed text tags added yes no

This commit is contained in:
davewiththenicehat 2021-06-14 18:43:18 -04:00
parent 03b0bc47a0
commit 93b68e3a31
2 changed files with 192 additions and 91 deletions

View file

@ -24,6 +24,7 @@ from evennia.utils import logger, utils, gametime, create, search
from evennia.utils.eveditor import EvEditor from evennia.utils.eveditor import EvEditor
from evennia.utils.evtable import EvTable from evennia.utils.evtable import EvTable
from evennia.utils.evmore import EvMore from evennia.utils.evmore import EvMore
from evennia.utils.evmenu import ask_yes_no
from evennia.utils.utils import crop, class_from_module from evennia.utils.utils import crop, class_from_module
from evennia.scripts.taskhandler import TaskHandlerTask from evennia.scripts.taskhandler import TaskHandlerTask
@ -1217,7 +1218,7 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
tasks[/switch] [function name] tasks[/switch] [function name]
Process the action in the switch to all tasks that are deferring a specific function name. Process the action in the switch to all tasks that are deferring a specific function name.
This would match the name of the callback you passed to a delay or the task handler. This would match the name of the callback you passed to a delay or the task handler.
tasks[/switch] [task id], [completion date], [function memory reference] tasks[/switch] [task id]
Process the action in the switch to a specific task. Process the action in the switch to a specific task.
Switches: Switches:
@ -1237,17 +1238,16 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
Only the action requested on the first switch will be processed. All other switches will Only the action requested on the first switch will be processed. All other switches will
be ignored. be ignored.
Manipulation of a single task is intended to be done via the clickable links or through
code directly. Due to generally short life of a task, the inclusion of completion date
and function's memory reference guarentees an incorrect task will not be manipulated.
By default, tasks that are canceled and never called are automatically removed after By default, tasks that are canceled and never called are automatically removed after
one minute. one minute.
Example: Example:
tasks/cancel move_callback tasks/cancel move_callback
Cancel all movement delays from the slow_exit contrib. Cancel all movement delays from the slow_exit contrib.
In this example slow exits creates it's tasks with: utils.delay(move_delay, move_callback) In this example slow exits creates it's tasks with:
utils.delay(move_delay, move_callback)
tasks/cancel 2
Cancel task id 2.
""" """
@ -1265,6 +1265,36 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None
return t_comp_date, t_func_mem_ref return t_comp_date, t_func_mem_ref
def do_task_action(self, *args, **kwargs):
"""
Process the action of a tasks command.
This exists to gain support with yes or no function from EvMenu.
"""
task_id = self.task_id
# get a reference of the global task handler
global _TASK_HANDLER
if _TASK_HANDLER is None:
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
# verify manipulating the correct task
task_args = _TASK_HANDLER.tasks.get(task_id, False)
if not task_args: # check if the task is still active
self.msg('Task completed while waiting for input.')
return
else:
# make certain a task with matching IDs has not been created
t_comp_date, t_func_mem_ref = self.coll_date_func(task_args)
if self.t_comp_date != t_comp_date or self.t_func_mem_ref != t_func_mem_ref:
self.msg('Task completed while waiting for input.')
return
# Do the action requested by command caller
action_return = self.task_action()
self.msg(f'{self.action_request} request completed.')
self.msg(f'The task function {self.action_request} returned: {action_return}')
def func(self): def func(self):
# get a reference of the global task handler # get a reference of the global task handler
global _TASK_HANDLER global _TASK_HANDLER
@ -1278,16 +1308,80 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
return return
# handle caller's request to manipulate a task(s) # handle caller's request to manipulate a task(s)
if self.switches or self.lhs: if self.switches and self.lhs:
# find if the argument is a task id or function name
action_request = self.switches[0] action_request = self.switches[0]
# handle caller requesting an action on specific deferred function try:
if len(self.lhslist) == 1: arg_is_id = int(self.lhslist[0])
except ValueError:
arg_is_id = False
# if the argument is a task id, proccess the action on a single task
if arg_is_id:
err_arg_msg = 'Switch and task ID are required when manipulating a task.'
task_comp_msg = 'Task completed while processing request.'
# handle missing arguments or switches
if not self.switches and self.lhs:
self.msg(err_arg_msg)
return
# create a handle for the task
task_id = arg_is_id
task = TaskHandlerTask(task_id)
# handle task no longer existing
if not task.exists():
self.msg(f'Task {task_id} does not exist.')
return
# get a reference of the function caller requested
switch_action = getattr(task, action_request, False)
if not switch_action:
self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \
f'{task_comp_msg.lower()}')
# verify manipulating the correct task
if task_id in _TASK_HANDLER.tasks:
task_args = _TASK_HANDLER.tasks.get(task_id, False)
if not task_args: # check if the task is still active
self.msg(task_comp_msg)
return
else:
t_comp_date, t_func_mem_ref = self.coll_date_func(task_args)
t_func_name = str(task_args[1]).split(' ')
t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None
if task.exists(): # make certain the task has not been called yet.
prompt = f'Yes or No, {action_request} task {task_id}? With completion date ' \
f'{t_comp_date}. Deferring function {t_func_name}.'
no_msg = f'No {action_request} processed.'
# record variables for use in do_task_action method
self.task_id = task_id
self.t_comp_date = t_comp_date
self.t_func_mem_ref = t_func_mem_ref
self.task_action = switch_action
self.action_request = action_request
ask_yes_no(self.caller, prompt, self.do_task_action, no_msg, no_msg, True)
return True
else:
self.msg(task_comp_msg)
return
# the argument is not a task id, process the action on all task deferring the function
# specified as an argument
else:
name_match_found = False name_match_found = False
arg_func_name = self.lhslist[0].lower() arg_func_name = self.lhslist[0].lower()
# repack tasks into a new dictionary # repack tasks into a new dictionary
current_tasks = {} current_tasks = {}
for task_id, task_args in _TASK_HANDLER.tasks.items(): for task_id, task_args in _TASK_HANDLER.tasks.items():
current_tasks.update({task_id: task_args}) current_tasks.update({task_id: task_args})
# call requested action on all tasks with the function name # call requested action on all tasks with the function name
for task_id, task_args in current_tasks.items(): for task_id, task_args in current_tasks.items():
t_func_name = str(task_args[1]).split(' ') t_func_name = str(task_args[1]).split(' ')
@ -1302,65 +1396,18 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
action_return = switch_action() action_return = switch_action()
self.msg(f'Task action {action_request} completed on task ID {task_id}.') self.msg(f'Task action {action_request} completed on task ID {task_id}.')
self.msg(f'The task function {action_request} returned: {action_return}') self.msg(f'The task function {action_request} returned: {action_return}')
# provide a message if not tasks of the function name was found # provide a message if not tasks of the function name was found
if not name_match_found: if not name_match_found:
self.msg(f'No tasks deferring function name {arg_func_name} found.') self.msg(f'No tasks deferring function name {arg_func_name} found.')
return return
return True return True
err_arg_msg = 'Task ID, completion date and memory reference are required when ' \
'manipulating a delay.' # check if an maleformed request was created
task_comp_msg = 'Task completed while processing request.' elif self.switches or self.lhs:
# handle missing arguments or switches self.msg('Task command misformed.')
if not self.switches and self.lhs: self.msg('Proper format tasks[/switch] [function name or task id]')
self.msg(err_arg_msg) return
return
# handle incorrect arguments
if len(self.lhslist) < 2:
self.msg(err_arg_msg)
return
# create a handle for the task
task_id = int(self.lhslist[0])
task = TaskHandlerTask(task_id)
# handle task no longer existing
if not task.exists():
self.msg(f'Task {task_id} does not exist.')
return
# get a reference of the function caller requested
switch_action = getattr(task, action_request, False)
if not switch_action:
self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \
f'{task_comp_msg.lower()}')
# verify manipulating the correct task
if task_id in _TASK_HANDLER.tasks:
task_args = _TASK_HANDLER.tasks.get(task_id, False)
if task_args: # check if the task is still active
sw_comp_date = self.lhslist[1]
sw_func_mem_ref = self.lhslist[2]
t_comp_date, t_func_mem_ref = self.coll_date_func(task_args)
# handle completion date mismatch
if not t_comp_date == sw_comp_date:
self.msg('Task completion time does not match time passed.')
self.msg(task_comp_msg)
self.msg('Likely a new task with the same ID was created')
return
# handle function memory reference mismatch
if not t_func_mem_ref == sw_func_mem_ref:
self.msg("Memory reference for the task's function does not match argument")
self.msg(task_comp_msg)
self.msg('Likely a new task with the same ID was created')
return
else: # task no longer exists
self.msg(task_comp_msg)
return
if task.exists(): # make certain the task has not been called yet.
# call the task's method
action_return = switch_action()
self.msg(f'Task action {action_request} completed.')
self.msg(f'The task function {action_request} returned: {action_return}')
return True
else:
self.msg(task_comp_msg)
return
# No task manupilation requested, build a table of tasks and display it # No task manupilation requested, build a table of tasks and display it
# get the width of screen in characters # get the width of screen in characters
@ -1382,14 +1429,6 @@ class CmdTasks(COMMAND_DEFAULT_CLASS):
task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers) task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers)
for i in range(len(tasks_header)): for i in range(len(tasks_header)):
tasks_list[i].append(task_data[i]) tasks_list[i].append(task_data[i])
# add task actions to the tasks list
actions = ('pause', 'unpause', 'do_task', 'remove', 'call', 'cancel')
for i in range(len(tasks_header)):
tasks_list[i].append(f"|lc{self.key}/{actions[i]} {task_id}, {t_comp_date}, " \
f"{t_func_mem_ref}|lt{actions[i]}|le")
# if the screen width is large enough, add directional arrows
if width >= 75:
tasks_list[i][-1] = f"^{tasks_list[i][-1]}^"
# create and display the table # create and display the table
tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells',
align='center') align='center')

View file

@ -594,7 +594,6 @@ class TestCmdTasks(CommandTest):
self.task_handler.clear() self.task_handler.clear()
self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks)
task_args = self.task_handler.tasks.get(self.task.get_id(), False) task_args = self.task_handler.tasks.get(self.task.get_id(), False)
self.t_comp_date, self.t_func_mem_ref = system.CmdTasks.coll_date_func(task_args)
def tearDown(self): def tearDown(self):
@ -620,36 +619,46 @@ class TestCmdTasks(CommandTest):
def test_pause_unpause(self): def test_pause_unpause(self):
# test pause # test pause
args = f'/pause {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' args = f'/pause {self.task.get_id()}'
wanted_msg = 'Task action pause completed.|The task function pause returned:' wanted_msg = 'Yes or No, pause task 1? With completion date'
self.call(system.CmdTasks(), args, wanted_msg) cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.')
self.char1.execute_cmd('y')
self.assertTrue(self.task.paused) self.assertTrue(self.task.paused)
self.task_handler.clock.advance(self.timedelay + 1) self.task_handler.clock.advance(self.timedelay + 1)
# test unpause # test unpause
args = f'/unpause {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' args = f'/unpause {self.task.get_id()}'
self.assertTrue(self.task.exists()) self.assertTrue(self.task.exists())
wanted_msg = 'Task action unpause completed.|The task function unpause returned: None' wanted_msg = 'Yes or No, unpause task 1? With completion date'
self.call(system.CmdTasks(), args, wanted_msg) cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.')
self.char1.execute_cmd('y')
# verify task continues after unpause # verify task continues after unpause
self.task_handler.clock.advance(1) self.task_handler.clock.advance(1)
self.assertFalse(self.task.exists()) self.assertFalse(self.task.exists())
def test_do_task(self): def test_do_task(self):
args = f'/do_task {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' args = f'/do_task {self.task.get_id()}'
wanted_msg = 'Task action do_task completed.|The task function do_task returned: success' wanted_msg = 'Yes or No, do_task task 1? With completion date'
self.call(system.CmdTasks(), args, wanted_msg) cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.')
self.char1.execute_cmd('y')
self.assertFalse(self.task.exists()) self.assertFalse(self.task.exists())
def test_remove(self): def test_remove(self):
args = f'/remove {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' args = f'/remove {self.task.get_id()}'
wanted_msg = 'Task action remove completed.|The task function remove returned: True' wanted_msg = 'Yes or No, remove task 1? With completion date'
self.call(system.CmdTasks(), args, wanted_msg) cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.')
self.char1.execute_cmd('y')
self.assertFalse(self.task.exists()) self.assertFalse(self.task.exists())
def test_call(self): def test_call(self):
args = f'/call {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' args = f'/call {self.task.get_id()}'
wanted_msg = 'Task action call completed.|The task function call returned: success' wanted_msg = 'Yes or No, call task 1? With completion date'
self.call(system.CmdTasks(), args, wanted_msg) cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.')
self.char1.execute_cmd('y')
# make certain the task is still active # make certain the task is still active
self.assertTrue(self.task.active()) self.assertTrue(self.task.active())
# go past delay time, the task should call do_task and remove itself after calling. # go past delay time, the task should call do_task and remove itself after calling.
@ -657,9 +666,11 @@ class TestCmdTasks(CommandTest):
self.assertFalse(self.task.exists()) self.assertFalse(self.task.exists())
def test_cancel(self): def test_cancel(self):
args = f'/cancel {self.task.get_id()}, {self.t_comp_date}, {self.t_func_mem_ref}' args = f'/cancel {self.task.get_id()}'
wanted_msg = 'Task action cancel completed.|The task function cancel returned: True' wanted_msg = 'Yes or No, cancel task 1? With completion date'
self.call(system.CmdTasks(), args, wanted_msg) cmd_result = self.call(system.CmdTasks(), args, wanted_msg)
self.assertRegex(cmd_result, '\. Deferring function func_test_cmd_tasks\.')
self.char1.execute_cmd('y')
self.assertTrue(self.task.exists()) self.assertTrue(self.task.exists())
self.assertFalse(self.task.active()) self.assertFalse(self.task.active())
@ -677,6 +688,57 @@ class TestCmdTasks(CommandTest):
self.call(system.CmdTasks(), args, wanted_msg) self.call(system.CmdTasks(), args, wanted_msg)
self.assertTrue(self.task.active()) self.assertTrue(self.task.active())
def test_no_input(self):
args = f'/cancel {self.task.get_id()}'
self.call(system.CmdTasks(), args)
# task should complete since no input was received
self.task_handler.clock.advance(self.timedelay + 1)
self.assertFalse(self.task.exists())
def test_responce_of_yes(self):
self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}')
self.char1.msg = Mock()
self.char1.execute_cmd('y')
text = ''
for _, _, kwargs in self.char1.msg.mock_calls:
text += kwargs.get('text', '')
self.assertEqual(text, 'cancel request completed.The task function cancel returned: True')
self.assertTrue(self.task.exists())
def test_task_complete_waiting_input(self):
"""Test for task completing while waiting for input."""
self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}')
self.task_handler.clock.advance(self.timedelay + 1)
self.char1.msg = Mock()
self.char1.execute_cmd('y')
text = ''
for _, _, kwargs in self.char1.msg.mock_calls:
text += kwargs.get('text', '')
self.assertEqual(text, 'Task completed while waiting for input.')
self.assertFalse(self.task.exists())
def test_new_task_waiting_input(self):
"""
Test task completing than a new task with the same ID being made while waitinf for input.
"""
self.assertTrue(self.task.get_id(), 1)
self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}')
self.task_handler.clock.advance(self.timedelay + 1)
self.assertFalse(self.task.exists())
self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks)
self.assertTrue(self.task.get_id(), 1)
self.char1.msg = Mock()
self.char1.execute_cmd('y')
text = ''
for _, _, kwargs in self.char1.msg.mock_calls:
text += kwargs.get('text', '')
self.assertEqual(text, 'Task completed while waiting for input.')
def test_misformed_command(self):
wanted_msg = 'Task command misformed.|Proper format tasks[/switch] ' \
'[function name or task id]'
self.call(system.CmdTasks(), f'/cancel', wanted_msg)
class TestAdmin(CommandTest): class TestAdmin(CommandTest):
def test_emit(self): def test_emit(self):