diff --git a/evennia/scripts/taskhandler.py b/evennia/scripts/taskhandler.py index bd979a9fde..ab1b29666d 100644 --- a/evennia/scripts/taskhandler.py +++ b/evennia/scripts/taskhandler.py @@ -5,6 +5,7 @@ Module containing the task handler for Evennia deferred tasks, persistent or not from datetime import datetime, timedelta from twisted.internet import reactor +from pickle import PickleError from twisted.internet.task import deferLater from twisted.internet.defer import CancelledError as DefCancelledError from evennia.server.models import ServerConfig @@ -287,18 +288,8 @@ class TaskHandler(object): # Check if callback can be pickled. args and kwargs have been checked safe_callback = None - try: - dbserialize(callback) - except (TypeError, AttributeError): - raise ValueError( - "the specified callback {} cannot be pickled. " - "It must be a top-level function in a module or an " - "instance method.".format(callback) - ) - else: - safe_callback = callback - self.to_save[task_id] = dbserialize((date, safe_callback, args, kwargs)) + self.to_save[task_id] = dbserialize((date, callback, args, kwargs)) ServerConfig.objects.conf("delayed_tasks", self.to_save) def add(self, timedelay, callback, *args, **kwargs): @@ -318,8 +309,8 @@ class TaskHandler(object): any (any): any additional positional arguments to send to the callback *args: positional arguments to pass to callback. **kwargs: keyword arguments to pass to callback. - persistent (bool, optional): persist the task (stores it). - persistent key and value is removed from kwargs it will + - persistent (bool, optional): persist the task (stores it). + Persistent key and value is removed from kwargs it will not be passed to callback. Returns: @@ -346,11 +337,22 @@ class TaskHandler(object): safe_args = [] safe_kwargs = {} + # an unsaveable callback should immediately abort + try: + dbserialize(callback) + except (TypeError, AttributeError, PickleError): + raise ValueError( + "the specified callback {} cannot be pickled. " + "It must be a top-level function in a module or an " + "instance method.".format(callback) + ) + return + # Check that args and kwargs contain picklable information for arg in args: try: dbserialize(arg) - except (TypeError, AttributeError): + except (TypeError, AttributeError, PickleError): log_err( "The positional argument {} cannot be " "pickled and will not be present in the arguments " @@ -362,7 +364,7 @@ class TaskHandler(object): for key, value in kwargs.items(): try: dbserialize(value) - except (TypeError, AttributeError): + except (TypeError, AttributeError, PickleError): log_err( "The {} keyword argument {} cannot be " "pickled and will not be present in the arguments " diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 105f9474a6..4d0d3a6c42 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -1030,20 +1030,19 @@ def delay(timedelay, callback, *args, **kwargs): after `timedelay` seconds. args (any, optional): Will be used as arguments to callback Keyword Args: - persistent (bool, optional): should make the delay persistent - over a reboot or reload + persistent (bool, optional): Should make the delay persistent + over a reboot or reload. Defaults to False. any (any): Will be used as keyword arguments to callback. Returns: - deferred (deferred): Will fire with callback after - `timedelay` seconds. Note that if `timedelay()` is used in the - commandhandler callback chain, the callback chain can be - defined directly in the command body and don't need to be - specified here. - Reference twisted.internet.defer.Deferred - if persistent kwarg is truthy: - task_id (int): the task's id intended for use with - evennia.scripts.taskhandler.TASK_HANDLER's do_task and remove methods. + deferred or int: If ``persistent`` kwarg is `False`, return deferred + that will fire with callback after `timedelay` seconds. Note that + if `timedelay()` is used in the commandhandler callback chain, the + callback chain can be defined directly in the command body and + don't need to be specified here. Reference twisted.internet.defer.Deferred. + If persistent kwarg is set, return the task's ID as an integer. This is + intended for use with ``evennia.scripts.taskhandler.TASK_HANDLER`` + `.do_task` and `.remove` methods. Note: The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will