Made sure tickerhandler cleans itself of alrady-deleted objects. Some more bug fixes to reworked tutorialworld.
This commit is contained in:
parent
ca69c5aaec
commit
56104d9a1d
6 changed files with 79 additions and 54 deletions
|
|
@ -342,6 +342,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
|
||||||
caller.ndb.last_cmd = None
|
caller.ndb.last_cmd = None
|
||||||
# return result to the deferred
|
# return result to the deferred
|
||||||
returnValue(ret)
|
returnValue(ret)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
string = "%s\nAbove traceback is from an untrapped error."
|
string = "%s\nAbove traceback is from an untrapped error."
|
||||||
string += " Please file a bug report."
|
string += " Please file a bug report."
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ start
|
||||||
tickerhandler to regularly 'tick and randomly display various
|
tickerhandler to regularly 'tick and randomly display various
|
||||||
weather-related messages.
|
weather-related messages.
|
||||||
|
|
||||||
The room also has 'details' set on it (such as the old well), those
|
The room also has 'details' set on it (such as the ruin in the distance), those
|
||||||
are snippets of text stored on the room that the custom look command
|
are snippets of text stored on the room that the custom look command
|
||||||
used for all tutorial rooms can display.
|
used for all tutorial rooms can display.
|
||||||
#
|
#
|
||||||
|
|
@ -620,8 +620,9 @@ hole
|
||||||
#
|
#
|
||||||
@detail hole;above =
|
@detail hole;above =
|
||||||
Whereas the lower edges of the hole seem jagged and natural you can
|
Whereas the lower edges of the hole seem jagged and natural you can
|
||||||
faintly make out that it turns into a man-made circular shaft higher
|
faintly make out it turning into a man-made circular shaft higher up.
|
||||||
up. It looks like an old well.
|
It looks like an old well. There must have been much more water
|
||||||
|
here once.
|
||||||
#
|
#
|
||||||
@detail passages;dark =
|
@detail passages;dark =
|
||||||
Those dark passages seem to criss-cross the cliff. No need to
|
Those dark passages seem to criss-cross the cliff. No need to
|
||||||
|
|
@ -1062,7 +1063,9 @@ stairs down
|
||||||
the tomb of some sort of ancient heroine - it must be the goal you
|
the tomb of some sort of ancient heroine - it must be the goal you
|
||||||
have been looking for!
|
have been looking for!
|
||||||
#
|
#
|
||||||
@dig Tomb of woman on horse
|
@tel tut#14
|
||||||
|
#
|
||||||
|
@dig/teleport Tomb of woman on horse
|
||||||
: tutorial_world.rooms.TeleportRoom
|
: tutorial_world.rooms.TeleportRoom
|
||||||
= Tomb with statue of riding woman;horse;riding;
|
= Tomb with statue of riding woman;horse;riding;
|
||||||
#
|
#
|
||||||
|
|
@ -1099,7 +1102,9 @@ stairs down
|
||||||
the tomb of some sort of ancient heroine - it must be the goal you
|
the tomb of some sort of ancient heroine - it must be the goal you
|
||||||
have been looking for!
|
have been looking for!
|
||||||
#
|
#
|
||||||
@dig Tomb of the crowned queen
|
@tel tut#14
|
||||||
|
#
|
||||||
|
@dig/teleport Tomb of the crowned queen
|
||||||
: tutorial_world.rooms.TeleportRoom
|
: tutorial_world.rooms.TeleportRoom
|
||||||
= Tomb with statue of a crowned queen;crown;queen
|
= Tomb with statue of a crowned queen;crown;queen
|
||||||
#
|
#
|
||||||
|
|
@ -1136,7 +1141,9 @@ stairs down
|
||||||
the tomb of some sort of ancient heroine - it must be the goal you
|
the tomb of some sort of ancient heroine - it must be the goal you
|
||||||
have been looking for!
|
have been looking for!
|
||||||
#
|
#
|
||||||
@dig Tomb of the shield
|
@tel tut#14
|
||||||
|
#
|
||||||
|
@dig/teleport Tomb of the shield
|
||||||
: tutorial_world.rooms.TeleportRoom
|
: tutorial_world.rooms.TeleportRoom
|
||||||
= Tomb with shield of arms;shield
|
= Tomb with shield of arms;shield
|
||||||
#
|
#
|
||||||
|
|
@ -1173,7 +1180,9 @@ stairs down
|
||||||
the tomb of some sort of ancient heroine - it must be the goal you
|
the tomb of some sort of ancient heroine - it must be the goal you
|
||||||
have been looking for!
|
have been looking for!
|
||||||
#
|
#
|
||||||
@dig Tomb of the hero
|
@tel tut#14
|
||||||
|
#
|
||||||
|
@dig/teleport Tomb of the hero
|
||||||
: tutorial_world.rooms.TeleportRoom
|
: tutorial_world.rooms.TeleportRoom
|
||||||
= Tomb depicting a heroine fighting a monster;knight;hero;monster;beast
|
= Tomb depicting a heroine fighting a monster;knight;hero;monster;beast
|
||||||
#
|
#
|
||||||
|
|
@ -1217,10 +1226,11 @@ stairs down
|
||||||
#
|
#
|
||||||
# The ancient tomb
|
# The ancient tomb
|
||||||
#
|
#
|
||||||
# This is the real tomb, the goal of the adventure.
|
# This is the real tomb, the goal of the adventure. It is not
|
||||||
|
# directly accessible from the Antechamber but you are
|
||||||
|
# teleported here only if you solve the puzzle of the Obelisk.
|
||||||
#
|
#
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
# Create the real tomb
|
|
||||||
#
|
#
|
||||||
@dig/teleport Ancient tomb;tut#16
|
@dig/teleport Ancient tomb;tut#16
|
||||||
: tutorial_world.rooms.TutorialRoom
|
: tutorial_world.rooms.TutorialRoom
|
||||||
|
|
|
||||||
|
|
@ -113,11 +113,11 @@ class Mob(tut_objects.TutorialObject):
|
||||||
# chase the mob around when building.
|
# chase the mob around when building.
|
||||||
self.db.patrolling = True
|
self.db.patrolling = True
|
||||||
self.db.aggressive = True
|
self.db.aggressive = True
|
||||||
self.db.immortal = True
|
self.db.immortal = False
|
||||||
# db-store if it is dead or not
|
# db-store if it is dead or not
|
||||||
self.db.is_dead = True
|
self.db.is_dead = True
|
||||||
# specifies how much damage we remove from non-magic weapons
|
# specifies how much damage we divide away from non-magic weapons
|
||||||
self.db.magic_resistance = 0.01
|
self.db.damage_resistance = 100.0
|
||||||
# pace (number of seconds between ticks) for
|
# pace (number of seconds between ticks) for
|
||||||
# the respective modes.
|
# the respective modes.
|
||||||
self.db.patrolling_pace = 6
|
self.db.patrolling_pace = 6
|
||||||
|
|
@ -388,12 +388,13 @@ class Mob(tut_objects.TutorialObject):
|
||||||
Someone landed a hit on us. Check our status
|
Someone landed a hit on us. Check our status
|
||||||
and start attacking if not already doing so.
|
and start attacking if not already doing so.
|
||||||
"""
|
"""
|
||||||
if not self.db.immortal:
|
if not self.ndb.is_immortal:
|
||||||
if not weapon.db.magic:
|
if not weapon.db.magic:
|
||||||
# not a magic weapon - scale damage with magical
|
# not a magic weapon - divide away magic resistance
|
||||||
# resistance
|
damage /= self.db.damage_resistance
|
||||||
damage = self.db.damage_resistance * damage
|
|
||||||
attacker.msg(self.db.weapon_ineffective_msg)
|
attacker.msg(self.db.weapon_ineffective_msg)
|
||||||
|
else:
|
||||||
|
self.location.msg_contents(self.db.hit_msg)
|
||||||
self.db.health -= damage
|
self.db.health -= damage
|
||||||
|
|
||||||
# analyze the result
|
# analyze the result
|
||||||
|
|
@ -403,7 +404,6 @@ class Mob(tut_objects.TutorialObject):
|
||||||
self.set_dead()
|
self.set_dead()
|
||||||
else:
|
else:
|
||||||
# still alive, start attack if not already attacking
|
# still alive, start attack if not already attacking
|
||||||
attacker.msg(self.db.hit_msg)
|
|
||||||
if self.db.aggressive and not self.ndb.is_attacking:
|
if self.db.aggressive and not self.ndb.is_attacking:
|
||||||
self.start_attacking()
|
self.start_attacking()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import random
|
||||||
|
|
||||||
from evennia import DefaultObject, DefaultExit, Command, CmdSet
|
from evennia import DefaultObject, DefaultExit, Command, CmdSet
|
||||||
from evennia import utils
|
from evennia import utils
|
||||||
|
from evennia.utils import search
|
||||||
from evennia.utils.spawner import spawn
|
from evennia.utils.spawner import spawn
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
@ -276,7 +277,7 @@ class CmdLight(Command):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.obj.light():
|
if self.obj.light():
|
||||||
self.caller("You light %s." % self.obj.key)
|
self.caller.msg("You light %s." % self.obj.key)
|
||||||
self.caller.location.msg_contents("%s lights %s!" % (self.caller, self.obj.key), exclude=[self.caller])
|
self.caller.location.msg_contents("%s lights %s!" % (self.caller, self.obj.key), exclude=[self.caller])
|
||||||
else:
|
else:
|
||||||
self.caller.msg("%s is already burning." % self.obj.key)
|
self.caller.msg("%s is already burning." % self.obj.key)
|
||||||
|
|
@ -285,6 +286,8 @@ class CmdLight(Command):
|
||||||
class CmdSetLight(CmdSet):
|
class CmdSetLight(CmdSet):
|
||||||
"CmdSet for the lightsource commands"
|
"CmdSet for the lightsource commands"
|
||||||
key = "lightsource_cmdset"
|
key = "lightsource_cmdset"
|
||||||
|
# this is higher than the dark cmdset - important!
|
||||||
|
priority = 3
|
||||||
|
|
||||||
def at_cmdset_creation(self):
|
def at_cmdset_creation(self):
|
||||||
"called at cmdset creation"
|
"called at cmdset creation"
|
||||||
|
|
@ -320,24 +323,27 @@ class LightSource(TutorialObject):
|
||||||
# add the Light command
|
# add the Light command
|
||||||
self.cmdset.add_default(CmdSetLight, permanent=True)
|
self.cmdset.add_default(CmdSetLight, permanent=True)
|
||||||
|
|
||||||
def _burnout(self, ret):
|
def _burnout(self):
|
||||||
"""
|
"""
|
||||||
This is called when this light source burns out. We make no
|
This is called when this light source burns out. We make no
|
||||||
use of the return value.
|
use of the return value.
|
||||||
"""
|
"""
|
||||||
|
# delete ourselves from the database
|
||||||
|
self.db.is_giving_light = False
|
||||||
try:
|
try:
|
||||||
# our location is usually a Character (their inventory), we try
|
|
||||||
# to send to -their- location so everyone else also notices the
|
|
||||||
# light goes out.
|
|
||||||
self.location.location.msg_contents("%s's %s flickers and dies." %
|
self.location.location.msg_contents("%s's %s flickers and dies." %
|
||||||
(self.location, self.key), exclude=self.location)
|
(self.location, self.key), exclude=self.location)
|
||||||
self.location.msg("Your %s flickers and dies." % self.key)
|
self.location.msg("Your %s flickers and dies." % self.key)
|
||||||
|
self.location.location.check_light_state()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# we are not in someone's inventory (maybe we were dropped.)
|
try:
|
||||||
self.location.msg_contents("A %s on the floor flickers and dies." % self.key)
|
self.location.msg_contents("A %s on the floor flickers and dies." % self.key)
|
||||||
# delete ourselves.
|
self.location.location.check_light_state()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
self.delete()
|
self.delete()
|
||||||
|
|
||||||
|
|
||||||
def light(self):
|
def light(self):
|
||||||
"""
|
"""
|
||||||
Light this object - this is called by Light command.
|
Light this object - this is called by Light command.
|
||||||
|
|
@ -348,10 +354,13 @@ class LightSource(TutorialObject):
|
||||||
self.db.is_giving_light = True
|
self.db.is_giving_light = True
|
||||||
# if we are in a dark room, trigger its light check
|
# if we are in a dark room, trigger its light check
|
||||||
try:
|
try:
|
||||||
self.location.check_light_state()
|
self.location.location.check_light_state()
|
||||||
except Exception:
|
except AttributeError:
|
||||||
# if we are not in a dark room, never mind
|
try:
|
||||||
pass
|
# maybe we are directly in the room
|
||||||
|
self.location.check_light_state()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
finally:
|
finally:
|
||||||
# start the burn timer. When it runs out, self._burnout
|
# start the burn timer. When it runs out, self._burnout
|
||||||
# will be called.
|
# will be called.
|
||||||
|
|
@ -549,12 +558,11 @@ class CmdPressButton(Command):
|
||||||
self.caller.location.msg_contents(string % self.caller.key, exclude=self.caller)
|
self.caller.location.msg_contents(string % self.caller.key, exclude=self.caller)
|
||||||
self.obj.open_wall()
|
self.obj.open_wall()
|
||||||
|
|
||||||
self.caller.msg(string)
|
|
||||||
|
|
||||||
|
|
||||||
class CmdSetCrumblingWall(CmdSet):
|
class CmdSetCrumblingWall(CmdSet):
|
||||||
"Group the commands for crumblingWall"
|
"Group the commands for crumblingWall"
|
||||||
key = "crumblingwall_cmdset"
|
key = "crumblingwall_cmdset"
|
||||||
|
priority = 2
|
||||||
|
|
||||||
def at_cmdset_creation(self):
|
def at_cmdset_creation(self):
|
||||||
"called when object is first created."
|
"called when object is first created."
|
||||||
|
|
@ -612,18 +620,18 @@ class CrumblingWall(TutorialObject, DefaultExit):
|
||||||
# set cmdset
|
# set cmdset
|
||||||
self.cmdset.add(CmdSetCrumblingWall, permanent=True)
|
self.cmdset.add(CmdSetCrumblingWall, permanent=True)
|
||||||
|
|
||||||
def open(self):
|
def open_wall(self):
|
||||||
"""
|
"""
|
||||||
This method is called by the push button command once the puzzle
|
This method is called by the push button command once the puzzle
|
||||||
is solved. It opens the wall and sets a timer for it to reset
|
is solved. It opens the wall and sets a timer for it to reset
|
||||||
itself.
|
itself.
|
||||||
"""
|
"""
|
||||||
# this will make it into a proper exit
|
# this will make it into a proper exit (this returns a list)
|
||||||
eloc = self.caller.search(self.obj.db.destination, global_search=True)
|
eloc = search.search_object(self.db.destination)
|
||||||
if not eloc:
|
if not eloc:
|
||||||
self.caller.msg("The exit leads nowhere, there's just more stone behind it ...")
|
self.caller.msg("The exit leads nowhere, there's just more stone behind it ...")
|
||||||
else:
|
else:
|
||||||
self.obj.destination = eloc
|
self.destination = eloc[0]
|
||||||
self.exit_open = True
|
self.exit_open = True
|
||||||
# start a 45 second timer before closing again
|
# start a 45 second timer before closing again
|
||||||
utils.delay(45, self.reset)
|
utils.delay(45, self.reset)
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ class CmdTutorialSetDetail(default_cmds.MuxCommand):
|
||||||
if not hasattr(self.obj, "set_detail"):
|
if not hasattr(self.obj, "set_detail"):
|
||||||
self.caller.msg("Details cannot be set on %s." % self.obj)
|
self.caller.msg("Details cannot be set on %s." % self.obj)
|
||||||
return
|
return
|
||||||
for key in self.args.split(";"):
|
for key in self.lhs.split(";"):
|
||||||
# loop over all aliases, if any (if not, this will just be
|
# loop over all aliases, if any (if not, this will just be
|
||||||
# the one key to loop over)
|
# the one key to loop over)
|
||||||
self.obj.set_detail(key, self.rhs)
|
self.obj.set_detail(key, self.rhs)
|
||||||
|
|
@ -341,7 +341,7 @@ class WeatherRoom(TutorialRoom):
|
||||||
#
|
#
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
DARK_MESSAGES = ("It is pitch black. You are likely to be eaten by a grue."
|
DARK_MESSAGES = ("It is pitch black. You are likely to be eaten by a grue.",
|
||||||
"It's pitch black. You fumble around but cannot find anything.",
|
"It's pitch black. You fumble around but cannot find anything.",
|
||||||
"You don't see a thing. You feel around, managing to bump your fingers hard against something. Ouch!",
|
"You don't see a thing. You feel around, managing to bump your fingers hard against something. Ouch!",
|
||||||
"You don't see a thing! Blindly grasping the air around you, you find nothing.",
|
"You don't see a thing! Blindly grasping the air around you, you find nothing.",
|
||||||
|
|
@ -475,6 +475,12 @@ class DarkRoom(TutorialRoom):
|
||||||
self.db.is_lit = False
|
self.db.is_lit = False
|
||||||
self.cmdsets.add(DarkCmdSet, permanent=True)
|
self.cmdsets.add(DarkCmdSet, permanent=True)
|
||||||
|
|
||||||
|
def at_init(self):
|
||||||
|
"""
|
||||||
|
Called when room is first recached (such as after a reload)
|
||||||
|
"""
|
||||||
|
self.check_light_state()
|
||||||
|
|
||||||
def _carries_light(self, obj):
|
def _carries_light(self, obj):
|
||||||
"""
|
"""
|
||||||
Checks if the given object carries anything that gives light.
|
Checks if the given object carries anything that gives light.
|
||||||
|
|
@ -483,9 +489,9 @@ class DarkRoom(TutorialRoom):
|
||||||
but for the Attribute is_giving_light - this makes it easy to
|
but for the Attribute is_giving_light - this makes it easy to
|
||||||
later add other types of light-giving items. We also accept
|
later add other types of light-giving items. We also accept
|
||||||
if there is a light-giving object in the room overall (like if
|
if there is a light-giving object in the room overall (like if
|
||||||
a lantern was dropped in the room)
|
a splinter was dropped in the room)
|
||||||
"""
|
"""
|
||||||
return obj.db.is_giving_light or any(obj for obj in obj.contents if obj.db.is_giving_light)
|
return obj.is_superuser or obj.db.is_giving_light or obj.is_superuser or any(o for o in obj.contents if o.db.is_giving_light)
|
||||||
|
|
||||||
def _heal(self, character):
|
def _heal(self, character):
|
||||||
"""
|
"""
|
||||||
|
|
@ -502,18 +508,15 @@ class DarkRoom(TutorialRoom):
|
||||||
the room and also by the Light sources when they turn on.
|
the room and also by the Light sources when they turn on.
|
||||||
"""
|
"""
|
||||||
if any(self._carries_light(obj) for obj in self.contents):
|
if any(self._carries_light(obj) for obj in self.contents):
|
||||||
# people are carrying lights
|
self.cmdset.remove(DarkCmdSet)
|
||||||
if not self.db.is_lit:
|
self.db.is_lit = True
|
||||||
self.cmdset.remove(DarkCmdSet)
|
for char in (obj for obj in self.contents if obj.has_player):
|
||||||
self.db.is_lit = True
|
# this won't do anything if it is already removed
|
||||||
for char in (obj for obj in self.contents if obj.has_player):
|
char.msg("The room is lit up.")
|
||||||
# this won't do anything if it is already removed
|
|
||||||
char.msg("The room is lit up.")
|
|
||||||
else:
|
else:
|
||||||
# noone is carrying light - darken the room
|
# noone is carrying light - darken the room
|
||||||
if self.db.is_lit:
|
self.db.is_lit = False
|
||||||
self.db.is_lit = False
|
self.cmdset.add(DarkCmdSet, permanent=True)
|
||||||
self.cmdset.add(DarkCmdSet, permanent=True)
|
|
||||||
for char in (obj for obj in self.contents if obj.has_player):
|
for char in (obj for obj in self.contents if obj.has_player):
|
||||||
if char.is_superuser:
|
if char.is_superuser:
|
||||||
char.msg("You are Superuser, so you are not affected by the dark state.")
|
char.msg("You are Superuser, so you are not affected by the dark state.")
|
||||||
|
|
@ -529,7 +532,7 @@ class DarkRoom(TutorialRoom):
|
||||||
# a puppeted object, that is, a Character
|
# a puppeted object, that is, a Character
|
||||||
self._heal(obj)
|
self._heal(obj)
|
||||||
# in case the new guy carries light with them
|
# in case the new guy carries light with them
|
||||||
self.check_light_state()
|
self.check_light_state()
|
||||||
|
|
||||||
def at_object_leave(self, obj, target_location):
|
def at_object_leave(self, obj, target_location):
|
||||||
"""
|
"""
|
||||||
|
|
@ -538,7 +541,6 @@ class DarkRoom(TutorialRoom):
|
||||||
teleported away.
|
teleported away.
|
||||||
"""
|
"""
|
||||||
self.check_light_state()
|
self.check_light_state()
|
||||||
obj.cmdset.delete(DarkCmdSet)
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
#
|
#
|
||||||
|
|
@ -773,7 +775,7 @@ class CmdLookBridge(Command):
|
||||||
fall_exit = search_object(self.obj.db.fall_exit)
|
fall_exit = search_object(self.obj.db.fall_exit)
|
||||||
if fall_exit:
|
if fall_exit:
|
||||||
self.caller.msg("{r%s{n" % FALL_MESSAGE)
|
self.caller.msg("{r%s{n" % FALL_MESSAGE)
|
||||||
self.caller.move_to(fall_exit, quiet=True)
|
self.caller.move_to(fall_exit[0], quiet=True)
|
||||||
# inform others on the bridge
|
# inform others on the bridge
|
||||||
self.obj.msg_contents("A plank gives way under %s's feet and " \
|
self.obj.msg_contents("A plank gives way under %s's feet and " \
|
||||||
"they fall from the bridge!" % self.caller.key)
|
"they fall from the bridge!" % self.caller.key)
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ call the handler's save() and restore() methods when the server reboots.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from twisted.internet.defer import inlineCallbacks
|
from twisted.internet.defer import inlineCallbacks
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from evennia.scripts.scripts import ExtendedLoopingCall
|
from evennia.scripts.scripts import ExtendedLoopingCall
|
||||||
from evennia.server.models import ServerConfig
|
from evennia.server.models import ServerConfig
|
||||||
from evennia.utils.logger import log_trace, log_err
|
from evennia.utils.logger import log_trace, log_err
|
||||||
|
|
@ -84,14 +85,17 @@ class Ticker(object):
|
||||||
The callback should ideally work under @inlineCallbacks so it can yield
|
The callback should ideally work under @inlineCallbacks so it can yield
|
||||||
appropriately.
|
appropriately.
|
||||||
"""
|
"""
|
||||||
for key, (obj, args, kwargs) in self.subscriptions.items():
|
for store_key, (obj, args, kwargs) in self.subscriptions.items():
|
||||||
hook_key = yield kwargs.get("_hook_key", "at_tick")
|
hook_key = yield kwargs.get("_hook_key", "at_tick")
|
||||||
if not obj:
|
if not obj:
|
||||||
# object was deleted between calls
|
# object was deleted between calls
|
||||||
self.validate()
|
self.remove(store_key)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
yield _GA(obj, hook_key)(*args, **kwargs)
|
yield _GA(obj, hook_key)(*args, **kwargs)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
log_trace()
|
||||||
|
self.remove(store_key)
|
||||||
except Exception:
|
except Exception:
|
||||||
log_trace()
|
log_trace()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue