taskhandler.Task created
Created an object to represent a task. This allows for the return of TASK_HANDLER.add or utils.delay to be an object that has callable methods. It has been created to mock the most common methods and attributes of a twisted deferred object. Changed test_utils.test_delay for new usage. Returned previously changed modules slow_exit, tutorial_world.objects and portal.telnet to their previous states. As the return of utils.delay can be used as if it were a deferred. All evennia unit tests pass
This commit is contained in:
parent
16f6edb18d
commit
f57fb645c8
6 changed files with 206 additions and 42 deletions
|
|
@ -36,7 +36,6 @@ TickerHandler might be better.
|
|||
"""
|
||||
|
||||
from evennia import DefaultExit, utils, Command
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
|
||||
MOVE_DELAY = {"stroll": 6, "walk": 4, "run": 2, "sprint": 1}
|
||||
|
||||
|
|
@ -71,11 +70,11 @@ class SlowExit(DefaultExit):
|
|||
|
||||
traversing_object.msg("You start moving %s at a %s." % (self.key, move_speed))
|
||||
# create a delayed movement
|
||||
task_id = utils.delay(move_delay, move_callback)
|
||||
t = utils.delay(move_delay, move_callback)
|
||||
# we store the deferred on the character, this will allow us
|
||||
# to abort the movement. We must use an ndb here since
|
||||
# deferreds cannot be pickled.
|
||||
traversing_object.ndb.currently_moving = _TASK_HANDLER.get_deferred(task_id)
|
||||
traversing_object.ndb.currently_moving = t
|
||||
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,13 @@ from evennia.contrib import slow_exit
|
|||
slow_exit.MOVE_DELAY = {"stroll": 0, "walk": 0, "run": 0, "sprint": 0}
|
||||
|
||||
|
||||
def _cancellable_mockdelay(time, callback, *args, **kwargs):
|
||||
callback(*args, **kwargs)
|
||||
return Mock()
|
||||
|
||||
|
||||
class TestSlowExit(CommandTest):
|
||||
@patch("evennia.utils.delay", _cancellable_mockdelay)
|
||||
def test_exit(self):
|
||||
exi = create_object(
|
||||
slow_exit.SlowExit, key="slowexit", location=self.room1, destination=self.room2
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import random
|
|||
from evennia import DefaultObject, DefaultExit, Command, CmdSet
|
||||
from evennia.utils import search, delay, dedent
|
||||
from evennia.prototypes.spawner import spawn
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
|
||||
# -------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -390,8 +389,7 @@ class LightSource(TutorialObject):
|
|||
# start the burn timer. When it runs out, self._burnout
|
||||
# will be called. We store the deferred so it can be
|
||||
# killed in unittesting.
|
||||
task_id = delay(60 * 3, self._burnout)
|
||||
self.deferred = _TASK_HANDLER.get_deferred(task_id)
|
||||
self.deferred = delay(60 * 3, self._burnout)
|
||||
return True
|
||||
|
||||
|
||||
|
|
@ -689,8 +687,7 @@ class CrumblingWall(TutorialObject, DefaultExit):
|
|||
self.db.exit_open = True
|
||||
# start a 45 second timer before closing again. We store the deferred so it can be
|
||||
# killed in unittesting.
|
||||
task_id = delay(45, self.reset)
|
||||
self.deferred = _TASK_HANDLER.get_deferred(task_id)
|
||||
self.deferred = delay(45, self.reset)
|
||||
return True
|
||||
|
||||
def _translate_position(self, root, ipos):
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ class TaskHandler(object):
|
|||
self.tasks[task_id] = task
|
||||
else: # the task already completed
|
||||
return False
|
||||
return task_id
|
||||
return Task(task_id)
|
||||
|
||||
def exists(self, task_id):
|
||||
"""
|
||||
|
|
@ -388,3 +388,150 @@ class TaskHandler(object):
|
|||
|
||||
# Create the soft singleton
|
||||
TASK_HANDLER = TaskHandler()
|
||||
|
||||
|
||||
class Task:
|
||||
"""
|
||||
A light
|
||||
"""
|
||||
def __init__(self, task_id):
|
||||
self.task_id = task_id
|
||||
|
||||
def get_deferred(self):
|
||||
"""
|
||||
Return the instance of the deferred the task id is using.
|
||||
|
||||
Returns:
|
||||
An instance of a deferral or False if there is no task with the id.
|
||||
None is returned if there is no deferral affiliated with this id.
|
||||
"""
|
||||
return TASK_HANDLER.get_deferred(self.task_id)
|
||||
|
||||
def pause(self):
|
||||
"""
|
||||
Pause the callback of a task.
|
||||
To resume use Task.unpause
|
||||
"""
|
||||
d = TASK_HANDLER.get_deferred(self.task_id)
|
||||
if d:
|
||||
d.pause()
|
||||
|
||||
def unpause(self):
|
||||
"""
|
||||
Process all callbacks made since pause() was called.
|
||||
"""
|
||||
d = TASK_HANDLER.get_deferred(self.task_id)
|
||||
if d:
|
||||
d.unpause()
|
||||
|
||||
@property
|
||||
def paused(self):
|
||||
"""
|
||||
A task attribute to check if the deferral of a task has been paused.
|
||||
|
||||
This exists to mock usage of a twisted deferred object.
|
||||
|
||||
This will return None if the deferred object for the task does not
|
||||
exist or if the task no longer exists.
|
||||
"""
|
||||
d = TASK_HANDLER.get_deferred(self.task_id)
|
||||
if d:
|
||||
return d.paused
|
||||
else:
|
||||
return None
|
||||
|
||||
def do_task(self):
|
||||
"""
|
||||
Execute the task (call its callback).
|
||||
If calling before timedelay cancel the deferral affliated to this task.
|
||||
Remove the task from the dictionary of current tasks on a successful
|
||||
callback.
|
||||
|
||||
Returns:
|
||||
False (bool): if the:
|
||||
task no longer exists,
|
||||
has no affliated instance of deferral
|
||||
The return of the callback passed on task creation.
|
||||
This makes it possible for the callback to also return False
|
||||
None: if there was a raised exception
|
||||
|
||||
Note:
|
||||
On a successful call the task will be removed from the dictionary
|
||||
of current tasks.
|
||||
|
||||
"""
|
||||
return TASK_HANDLER.do_task(self.task_id)
|
||||
|
||||
def remove(self):
|
||||
"""
|
||||
Remove a task without executing it.
|
||||
Deletes the instance of the task's deferral.
|
||||
|
||||
Returns:
|
||||
True (bool): if the removal completed successfully or if the a
|
||||
task with the id does not exist.
|
||||
None: if there was a raised exception
|
||||
|
||||
"""
|
||||
return TASK_HANDLER.remove(self.task_id)
|
||||
|
||||
def cancel(self):
|
||||
"""
|
||||
Stop a task from automatically executing.
|
||||
This will not remove the task.
|
||||
|
||||
Returns:
|
||||
True (bool): if the removal completed successfully.
|
||||
False (bool): if the task:
|
||||
does not exist,
|
||||
has already run,
|
||||
does not have a deferral instance created for the task.
|
||||
None, if there was a raised exception
|
||||
"""
|
||||
return TASK_HANDLER.cancel(self.task_id)
|
||||
|
||||
def active(self):
|
||||
"""
|
||||
Check if a task is active (has not been called yet).
|
||||
|
||||
Returns:
|
||||
True (bool): If a task is active (has not been called yet).
|
||||
False (bool): if the task
|
||||
is not active (has already been called),
|
||||
does not exist
|
||||
"""
|
||||
return TASK_HANDLER.active(self.task_id)
|
||||
|
||||
@property
|
||||
def called(self):
|
||||
"""
|
||||
A task attribute to check if the deferral of a task has been called.
|
||||
|
||||
This exists to mock usage of a twisted deferred object.
|
||||
It will not set to false if Task.call has been called.
|
||||
|
||||
"""
|
||||
return not TASK_HANDLER.active(self.task_id)
|
||||
|
||||
def exists(self):
|
||||
"""
|
||||
Test if a task exists.
|
||||
|
||||
Returns:
|
||||
True (bool): if the task exists.
|
||||
False (bool): if the task does not exist.
|
||||
|
||||
Note:
|
||||
Most task handler methods check for existence for you.
|
||||
"""
|
||||
return TASK_HANDLER.exists(self.task_id)
|
||||
|
||||
def get_id(self):
|
||||
"""
|
||||
Returns the global id for this task. For use with
|
||||
`evennia.scripts.taskhandler.TASK_HANDLER`.
|
||||
|
||||
Returns:
|
||||
task_id (int): global task id for this task.
|
||||
"""
|
||||
return self.task_id
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP
|
|||
from evennia.server.portal.mxp import Mxp, mxp_parse
|
||||
from evennia.utils import ansi
|
||||
from evennia.utils.utils import to_bytes
|
||||
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||
|
||||
_RE_N = re.compile(r"\|n$")
|
||||
_RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
|
||||
|
|
@ -128,8 +127,8 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
|
|||
|
||||
from evennia.utils.utils import delay
|
||||
|
||||
task_id = delay(2, callback=self.handshake_done, timeout=True)
|
||||
self._handshake_delay = _TASK_HANDLER.get_deferred(task_id)
|
||||
# timeout the handshakes in case the client doesn't reply at all
|
||||
self._handshake_delay = delay(2, callback=self.handshake_done, timeout=True)
|
||||
|
||||
# TCP/IP keepalive watches for dead links
|
||||
self.transport.setTcpKeepAlive(1)
|
||||
|
|
|
|||
|
|
@ -331,71 +331,87 @@ class TestDelay(EvenniaTest):
|
|||
_TASK_HANDLER.clock = task.Clock()
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a persistent deferral, that completes after delay time
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref, persistent=True)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref, persistent=True)
|
||||
self.assertTrue(_TASK_HANDLER.active(t.get_id())) # test Task.get_id
|
||||
self.assertTrue(t.active())
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertTrue(t.called) # test Task.called property
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a persistent deferral, that completes on a manual call
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref, persistent=True)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
result = _TASK_HANDLER.do_task(task_id)
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref, persistent=True)
|
||||
self.assertTrue(t.active())
|
||||
result = t.do_task()
|
||||
self.assertTrue(result)
|
||||
self.assertFalse(_TASK_HANDLER.exists(task_id))
|
||||
self.assertFalse(t.exists())
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass, important keep
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a non persisten deferral, that completes after delay time.
|
||||
utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a non-persistent deferral, that completes on a manual call
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
result = _TASK_HANDLER.do_task(task_id)
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
result = t.do_task()
|
||||
self.assertTrue(result)
|
||||
self.assertFalse(_TASK_HANDLER.exists(task_id))
|
||||
self.assertFalse(t.exists())
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass, important keep
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test a non persisten deferral, with a short timedelay
|
||||
utils.delay(.1, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
t = utils.delay(.1, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
_TASK_HANDLER.clock.advance(.1) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test canceling a deferral.
|
||||
# after this the task_id 1 remains used by this canceled but unused task
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
success = _TASK_HANDLER.cancel(task_id)
|
||||
self.assertFalse(_TASK_HANDLER.active(task_id))
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
success = t.cancel()
|
||||
self.assertFalse(t.active())
|
||||
self.assertTrue(success)
|
||||
self.assertTrue(_TASK_HANDLER.exists(task_id))
|
||||
self.assertTrue(t.exists())
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, False)
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test removing an active task
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
success = _TASK_HANDLER.remove(task_id)
|
||||
self.assertFalse(_TASK_HANDLER.active(task_id))
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
success = t.remove()
|
||||
self.assertFalse(t.active())
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, False)
|
||||
self.assertFalse(_TASK_HANDLER.exists(task_id))
|
||||
self.assertFalse(t.exists())
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test removing a canceled task
|
||||
task_id = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(_TASK_HANDLER.active(task_id))
|
||||
deferal_inst = _TASK_HANDLER.get_deferred(task_id)
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
deferal_inst = t.get_deferred()
|
||||
deferal_inst.cancel()
|
||||
self.assertFalse(_TASK_HANDLER.active(task_id))
|
||||
success = _TASK_HANDLER.remove(task_id)
|
||||
self.assertFalse(t.active())
|
||||
success = t.remove()
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, False)
|
||||
self.assertFalse(_TASK_HANDLER.exists(task_id))
|
||||
self.assertFalse(t.exists())
|
||||
self.char1.ndb.dummy_var = False
|
||||
# test pause, paused and unpause
|
||||
t = utils.delay(timedelay, dummy_func, self.char1.dbref)
|
||||
self.assertTrue(t.active())
|
||||
t.pause()
|
||||
self.assertTrue(t.paused)
|
||||
t.unpause()
|
||||
self.assertFalse(t.paused)
|
||||
self.assertEqual(self.char1.ndb.dummy_var, False)
|
||||
t.pause()
|
||||
_TASK_HANDLER.clock.advance(timedelay) # make time pass
|
||||
self.assertEqual(self.char1.ndb.dummy_var, False)
|
||||
t.unpause()
|
||||
self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran')
|
||||
self.char1.ndb.dummy_var = False
|
||||
# restart condictions
|
||||
# cancel a diferall directly, without calling task handler's cancel
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue