diff --git a/CHANGELOG.md b/CHANGELOG.md index 789f750322..a865a4569b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ without arguments starts a full interactive Python console. - Make code auto-formatted with Black. - Make default `set` command able to edit nested structures (PR by Aaron McMillan) - Allow running Evennia test suite from core repo with `make test`. +- Return `store_key` from `TickerHandler.add` and add `store_key` as a kwarg to + the `TickerHandler.remove` method. This makes it easier to manage tickers. ## Evennia 0.9 (2018-2019) diff --git a/evennia/scripts/scripts.py b/evennia/scripts/scripts.py index 4b1f33f105..b4bede818a 100644 --- a/evennia/scripts/scripts.py +++ b/evennia/scripts/scripts.py @@ -168,9 +168,8 @@ class ScriptBase(ScriptDB, metaclass=TypeclassBase): Start task runner. """ - if self.ndb._task: - return - self.ndb._task = ExtendedLoopingCall(self._step_task) + if not self.ndb._task: + self.ndb._task = ExtendedLoopingCall(self._step_task) if self.db._paused_time: # the script was paused; restarting diff --git a/evennia/scripts/tickerhandler.py b/evennia/scripts/tickerhandler.py index 49a450e41e..78e6166786 100644 --- a/evennia/scripts/tickerhandler.py +++ b/evennia/scripts/tickerhandler.py @@ -499,6 +499,11 @@ class TickerHandler(object): callback every time it is called. This must be data possible to pickle! + Returns: + store_key (tuple): The immutable store-key for this ticker. This can + be stored and passed into `.remove(store_key=store_key)` later to + easily stop this ticker later. + Notes: The callback will be identified by type and stored either as as combination of serialized database object + methodname or @@ -521,17 +526,29 @@ class TickerHandler(object): self.ticker_storage[store_key] = (args, kwargs) self.ticker_pool.add(store_key, *args, **kwargs) self.save() + return store_key - def remove(self, interval=60, callback=None, idstring="", persistent=True): + def remove( + self, interval=60, callback=None, idstring="", persistent=True, store_key=None + ): """ - Remove object from ticker or only remove it from tickers with - a given interval. + Remove ticker subscription from handler. Args: interval (int, optional): Interval of ticker to remove. callback (callable function or method): Either a function or the method of a typeclassed object. idstring (str, optional): Identifier id of ticker to remove. + persistent (bool, optional): Whether this ticker is persistent or not. + store_key (str, optional): If given, all other kwargs are ignored and only + this is used to identify the ticker. + + Raises: + KeyError: If no matching ticker was found to remove. + + Notes: + The store-key is normally built from the interval/callback/idstring/persistent values; + but if the `store_key` is explicitly given, this is used instead. """ if isinstance(callback, int): @@ -539,13 +556,17 @@ class TickerHandler(object): "TICKER_HANDLER.remove has changed: " "the interval is now the first argument, callback the second." ) - - obj, path, callfunc = self._get_callback(callback) - store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent) + if not store_key: + obj, path, callfunc = self._get_callback(callback) + store_key = self._store_key( + obj, path, interval, callfunc, idstring, persistent + ) to_remove = self.ticker_storage.pop(store_key, None) if to_remove: self.ticker_pool.remove(store_key) self.save() + else: + raise KeyError(f"No Ticker was found matching the store-key {store_key}.") def clear(self, interval=None): """ diff --git a/evennia/utils/dbserialize.py b/evennia/utils/dbserialize.py index 5e6fd5c8e1..864e053a1c 100644 --- a/evennia/utils/dbserialize.py +++ b/evennia/utils/dbserialize.py @@ -587,7 +587,15 @@ def to_pickle(data): return [process_item(val) for val in item] elif hasattr(item, "sessid") and hasattr(item, "conn_time"): return pack_session(item) - return pack_dbobj(item) + try: + return pack_dbobj(item) + except TypeError: + return item + except Exception: + logger.log_error( + f"The object {item} of type {type(item)} could not be stored." + ) + raise return process_item(data) @@ -726,12 +734,20 @@ def from_pickle(data, db_obj=None): def do_pickle(data): """Perform pickle to string""" - return dumps(data, protocol=PICKLE_PROTOCOL) + try: + return dumps(data, protocol=PICKLE_PROTOCOL) + except Exception: + logger.log_error(f"Could not pickle data for storage: {data}") + raise def do_unpickle(data): """Retrieve pickle from pickled string""" - return loads(to_bytes(data)) + try: + return loads(to_bytes(data)) + except Exception: + logger.log_error(f"Could not unpickle data from storage: {data}") + raise def dbserialize(data): diff --git a/evennia/utils/text2html.py b/evennia/utils/text2html.py index 3474b5612b..8e42db1a46 100644 --- a/evennia/utils/text2html.py +++ b/evennia/utils/text2html.py @@ -9,7 +9,7 @@ snippet #577349 on http://code.activestate.com. """ import re -import cgi +from html import escape as html_escape from .ansi import * @@ -326,7 +326,7 @@ class TextToHTMLparser(object): """ cdict = match.groupdict() if cdict["htmlchars"]: - return cgi.escape(cdict["htmlchars"]) + return html_escape(cdict["htmlchars"]) elif cdict["lineend"]: return "
" elif cdict["firstspace"]: