Fix edge case in TaskHandler when un-pickleable callable supplied
This commit is contained in:
parent
cec566be79
commit
bf4af8b208
2 changed files with 27 additions and 26 deletions
|
|
@ -5,6 +5,7 @@ Module containing the task handler for Evennia deferred tasks, persistent or not
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
|
from pickle import PickleError
|
||||||
from twisted.internet.task import deferLater
|
from twisted.internet.task import deferLater
|
||||||
from twisted.internet.defer import CancelledError as DefCancelledError
|
from twisted.internet.defer import CancelledError as DefCancelledError
|
||||||
from evennia.server.models import ServerConfig
|
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
|
# Check if callback can be pickled. args and kwargs have been checked
|
||||||
safe_callback = None
|
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)
|
ServerConfig.objects.conf("delayed_tasks", self.to_save)
|
||||||
|
|
||||||
def add(self, timedelay, callback, *args, **kwargs):
|
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
|
any (any): any additional positional arguments to send to the callback
|
||||||
*args: positional arguments to pass to callback.
|
*args: positional arguments to pass to callback.
|
||||||
**kwargs: keyword arguments to pass to callback.
|
**kwargs: keyword arguments to pass to callback.
|
||||||
persistent (bool, optional): persist the task (stores it).
|
- persistent (bool, optional): persist the task (stores it).
|
||||||
persistent key and value is removed from kwargs it will
|
Persistent key and value is removed from kwargs it will
|
||||||
not be passed to callback.
|
not be passed to callback.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -346,11 +337,22 @@ class TaskHandler(object):
|
||||||
safe_args = []
|
safe_args = []
|
||||||
safe_kwargs = {}
|
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
|
# Check that args and kwargs contain picklable information
|
||||||
for arg in args:
|
for arg in args:
|
||||||
try:
|
try:
|
||||||
dbserialize(arg)
|
dbserialize(arg)
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError, PickleError):
|
||||||
log_err(
|
log_err(
|
||||||
"The positional argument {} cannot be "
|
"The positional argument {} cannot be "
|
||||||
"pickled and will not be present in the arguments "
|
"pickled and will not be present in the arguments "
|
||||||
|
|
@ -362,7 +364,7 @@ class TaskHandler(object):
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
try:
|
try:
|
||||||
dbserialize(value)
|
dbserialize(value)
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError, PickleError):
|
||||||
log_err(
|
log_err(
|
||||||
"The {} keyword argument {} cannot be "
|
"The {} keyword argument {} cannot be "
|
||||||
"pickled and will not be present in the arguments "
|
"pickled and will not be present in the arguments "
|
||||||
|
|
|
||||||
|
|
@ -1030,20 +1030,19 @@ def delay(timedelay, callback, *args, **kwargs):
|
||||||
after `timedelay` seconds.
|
after `timedelay` seconds.
|
||||||
args (any, optional): Will be used as arguments to callback
|
args (any, optional): Will be used as arguments to callback
|
||||||
Keyword Args:
|
Keyword Args:
|
||||||
persistent (bool, optional): should make the delay persistent
|
persistent (bool, optional): Should make the delay persistent
|
||||||
over a reboot or reload
|
over a reboot or reload. Defaults to False.
|
||||||
any (any): Will be used as keyword arguments to callback.
|
any (any): Will be used as keyword arguments to callback.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
deferred (deferred): Will fire with callback after
|
deferred or int: If ``persistent`` kwarg is `False`, return deferred
|
||||||
`timedelay` seconds. Note that if `timedelay()` is used in the
|
that will fire with callback after `timedelay` seconds. Note that
|
||||||
commandhandler callback chain, the callback chain can be
|
if `timedelay()` is used in the commandhandler callback chain, the
|
||||||
defined directly in the command body and don't need to be
|
callback chain can be defined directly in the command body and
|
||||||
specified here.
|
don't need to be specified here. Reference twisted.internet.defer.Deferred.
|
||||||
Reference twisted.internet.defer.Deferred
|
If persistent kwarg is set, return the task's ID as an integer. This is
|
||||||
if persistent kwarg is truthy:
|
intended for use with ``evennia.scripts.taskhandler.TASK_HANDLER``
|
||||||
task_id (int): the task's id intended for use with
|
`.do_task` and `.remove` methods.
|
||||||
evennia.scripts.taskhandler.TASK_HANDLER's do_task and remove methods.
|
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will
|
The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue