From 039eb8c824e0cd43c2064074ee3d9308cda9c67d Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 17 Apr 2016 10:33:19 +0200 Subject: [PATCH] Added proper error handling to evmenu when trying to use persistent mode with callables that cannot be pickled, such as methods and functions defined inside other functions. --- evennia/utils/eveditor.py | 11 ++++++---- evennia/utils/evmenu.py | 44 +++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/evennia/utils/eveditor.py b/evennia/utils/eveditor.py index 75ed40f9cd..b6c2b3b0cd 100644 --- a/evennia/utils/eveditor.py +++ b/evennia/utils/eveditor.py @@ -36,7 +36,7 @@ and initialize it: from builtins import object import re -import inspect + from django.conf import settings from evennia import Command, CmdSet from evennia.utils import is_iter, fill, dedent, logger @@ -135,6 +135,11 @@ to non-persistent mode (which means the editor session won't survive an eventual server reload - so save often!)|n """ +_TRACE_PERSISTENT_SAVING = \ +"EvEditor persistent-mode error. Commonly, this is because one or " \ +"more of the EvEditor callbacks could not be pickled, for example " \ +"because it's a class method or is defined inside another function." + _MSG_NO_UNDO = "Nothing to undo." _MSG_NO_REDO = "Nothing to redo." @@ -662,9 +667,7 @@ class EvEditor(object): caller.attributes.add("_eveditor_buffer_temp", (self._buffer, self._undo_buffer)) except Exception, err: caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err)) - logger.log_trace("EvEditor persistent-mode error. Commonly, this is because one or "\ - "more of the EvEditor callbacks could not be pickled, for example because it's "\ - "a class method or is defined inside another function.") + logger.log_trace(_TRACE_PERSISTENT_SAVING) persistent = False # Create the commands we need diff --git a/evennia/utils/evmenu.py b/evennia/utils/evmenu.py index e3b3b75076..47ccb33385 100644 --- a/evennia/utils/evmenu.py +++ b/evennia/utils/evmenu.py @@ -140,6 +140,7 @@ from textwrap import dedent from inspect import isfunction, getargspec from django.conf import settings from evennia import Command, CmdSet +from evennia.utils import logger from evennia.utils.evtable import EvTable from evennia.utils.ansi import ANSIString, strip_ansi from evennia.utils.utils import mod_import, make_iter, pad, m_len @@ -166,6 +167,20 @@ _HELP_NO_OPTIONS = _("Commands: help, quit") _HELP_NO_OPTIONS_NO_QUIT = _("Commands: help") _HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.") +_ERROR_PERSISTENT_SAVING = \ +""" +{error} + +|rThe menu state could not be saved for persistent mode. Switching +to non-persistent mode (which means the menu session won't survive +an eventual server reload).|n +""" + +_TRACE_PERSISTENT_SAVING = \ +"EvMenu persistent-mode error. Commonly, this is because one or " \ +"more of the EvEditor callbacks could not be pickled, for example " \ +"because it's a class method or is defined inside another function." + class EvMenuError(RuntimeError): """ @@ -496,22 +511,29 @@ class EvMenu(object): # store ourself on the object self.caller.ndb._menutree = self + if persistent: + # save the menu to the database + try: + caller.attributes.add("_menutree_saved", + ((menudata, ), + {"startnode": startnode, + "cmdset_mergetype": cmdset_mergetype, + "cmdset_priority": cmdset_priority, + "auto_quit": auto_quit, "auto_look": auto_look, "auto_help": auto_help, + "cmd_on_exit": cmd_on_exit, "persistent": persistent, + "nodetext_formatter": nodetext_formatter, "options_formatter": options_formatter, + "node_formatter": node_formatter, "input_parser": input_parser})) + caller.attributes.add("_menutree_saved_startnode", startnode) + except Exception as err: + caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err)) + logger.log_trace(_TRACE_PERSISTENT_SAVING) + persistent = False + # set up the menu command on the caller menu_cmdset = EvMenuCmdSet() menu_cmdset.mergetype = str(cmdset_mergetype).lower().capitalize() or "Replace" menu_cmdset.priority = int(cmdset_priority) self.caller.cmdset.add(menu_cmdset, permanent=persistent) - if persistent: - caller.attributes.add("_menutree_saved", - ((menudata, ), - {"startnode": startnode, - "cmdset_mergetype": cmdset_mergetype, - "cmdset_priority": cmdset_priority, - "auto_quit": auto_quit, "auto_look": auto_look, "auto_help": auto_help, - "cmd_on_exit": cmd_on_exit, "persistent": persistent, - "nodetext_formatter": nodetext_formatter, "options_formatter": options_formatter, - "node_formatter": node_formatter, "input_parser": input_parser})) - caller.attributes.add("_menutree_saved_startnode", startnode) # start the menu self.goto(self._startnode, "")