mirror of
https://github.com/evennia/evennia.git
synced 2026-03-25 01:06:32 +01:00
Continuing work on API, making local-use class properties _private to make things easier to explore.
This commit is contained in:
parent
1ce5c6b84a
commit
fc156b5a54
5 changed files with 308 additions and 328 deletions
|
|
@ -21,7 +21,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||
|
||||
from src.utils.idmapper.models import SharedMemoryModel
|
||||
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||
from src.typeclasses.models import get_cache, set_cache, del_cache
|
||||
from src.typeclasses.models import _get_cache, _set_cache, _del_cache
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
from src.objects.manager import ObjectManager
|
||||
from src.players.models import PlayerDB
|
||||
|
|
@ -34,11 +34,11 @@ from src.utils.utils import make_iter, to_unicode, to_str, mod_import
|
|||
|
||||
#PlayerDB = ContentType.objects.get(app_label="players", model="playerdb").model_class()
|
||||
|
||||
AT_SEARCH_RESULT = mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
_AT_SEARCH_RESULT = mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
|
||||
GA = object.__getattribute__
|
||||
SA = object.__setattr__
|
||||
DA = object.__delattr__
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_DA = object.__delattr__
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -214,10 +214,10 @@ class ObjectDB(TypedObject):
|
|||
def aliases_get(self):
|
||||
"Getter. Allows for value = self.aliases"
|
||||
try:
|
||||
return GA(self, "_cached_aliases")
|
||||
return _GA(self, "_cached_aliases")
|
||||
except AttributeError:
|
||||
aliases = list(Alias.objects.filter(db_obj=self).values_list("db_key", flat=True))
|
||||
SA(self, "_cached_aliases", aliases)
|
||||
_SA(self, "_cached_aliases", aliases)
|
||||
return aliases
|
||||
#@aliases.setter
|
||||
def aliases_set(self, aliases):
|
||||
|
|
@ -225,13 +225,13 @@ class ObjectDB(TypedObject):
|
|||
for alias in make_iter(aliases):
|
||||
new_alias = Alias(db_key=alias, db_obj=self)
|
||||
new_alias.save()
|
||||
SA(self, "_cached_aliases", aliases)
|
||||
_SA(self, "_cached_aliases", aliases)
|
||||
#@aliases.deleter
|
||||
def aliases_del(self):
|
||||
"Deleter. Allows for del self.aliases"
|
||||
for alias in Alias.objects.filter(db_obj=self):
|
||||
alias.delete()
|
||||
DA(self, "_cached_aliases")
|
||||
_DA(self, "_cached_aliases")
|
||||
aliases = property(aliases_get, aliases_set, aliases_del)
|
||||
|
||||
# player property (wraps db_player)
|
||||
|
|
@ -242,26 +242,26 @@ class ObjectDB(TypedObject):
|
|||
We have to be careful here since Player is also
|
||||
a TypedObject, so as to not create a loop.
|
||||
"""
|
||||
return get_cache(self, "player")
|
||||
return _get_cache(self, "player")
|
||||
#@player.setter
|
||||
def player_set(self, player):
|
||||
"Setter. Allows for self.player = value"
|
||||
if isinstance(player, TypeClass):
|
||||
player = player.dbobj
|
||||
set_cache(self, "player", player)
|
||||
_set_cache(self, "player", player)
|
||||
#@player.deleter
|
||||
def player_del(self):
|
||||
"Deleter. Allows for del self.player"
|
||||
self.db_player = None
|
||||
self.save()
|
||||
del_cache(self, "player")
|
||||
_del_cache(self, "player")
|
||||
player = property(player_get, player_set, player_del)
|
||||
|
||||
# location property (wraps db_location)
|
||||
#@property
|
||||
def location_get(self):
|
||||
"Getter. Allows for value = self.location."
|
||||
loc = get_cache(self, "location")
|
||||
loc = _get_cache(self, "location")
|
||||
if loc:
|
||||
return loc.typeclass
|
||||
return None
|
||||
|
|
@ -281,7 +281,7 @@ class ObjectDB(TypedObject):
|
|||
loc = location.dbobj
|
||||
else:
|
||||
loc = location.dbobj
|
||||
set_cache(self, "location", loc)
|
||||
_set_cache(self, "location", loc)
|
||||
except Exception:
|
||||
string = "Cannot set location: "
|
||||
string += "%s is not a valid location."
|
||||
|
|
@ -293,14 +293,14 @@ class ObjectDB(TypedObject):
|
|||
"Deleter. Allows for del self.location"
|
||||
self.db_location = None
|
||||
self.save()
|
||||
del_cache()
|
||||
_del_cache(self, "location")
|
||||
location = property(location_get, location_set, location_del)
|
||||
|
||||
# home property (wraps db_home)
|
||||
#@property
|
||||
def home_get(self):
|
||||
"Getter. Allows for value = self.home"
|
||||
home = get_cache(self, "home")
|
||||
home = _get_cache(self, "home")
|
||||
if home:
|
||||
return home.typeclass
|
||||
return None
|
||||
|
|
@ -318,7 +318,7 @@ class ObjectDB(TypedObject):
|
|||
hom = home.dbobj
|
||||
else:
|
||||
hom = home.dbobj
|
||||
set_cache(self, "home", hom)
|
||||
_set_cache(self, "home", hom)
|
||||
except Exception:
|
||||
string = "Cannot set home: "
|
||||
string += "%s is not a valid home."
|
||||
|
|
@ -330,14 +330,14 @@ class ObjectDB(TypedObject):
|
|||
"Deleter. Allows for del self.home."
|
||||
self.db_home = None
|
||||
self.save()
|
||||
del_cache(self, "home")
|
||||
_del_cache(self, "home")
|
||||
home = property(home_get, home_set, home_del)
|
||||
|
||||
# destination property (wraps db_destination)
|
||||
#@property
|
||||
def destination_get(self):
|
||||
"Getter. Allows for value = self.destination."
|
||||
dest = get_cache(self, "destination")
|
||||
dest = _get_cache(self, "destination")
|
||||
if dest:
|
||||
return dest.typeclass
|
||||
return None
|
||||
|
|
@ -357,7 +357,7 @@ class ObjectDB(TypedObject):
|
|||
dest = destination.dbobj
|
||||
else:
|
||||
dest = destination.dbobj
|
||||
set_cache(self, "destination", dest)
|
||||
_set_cache(self, "destination", dest)
|
||||
except Exception:
|
||||
string = "Cannot set destination: "
|
||||
string += "%s is not a valid destination."
|
||||
|
|
@ -369,7 +369,7 @@ class ObjectDB(TypedObject):
|
|||
"Deleter. Allows for del self.destination"
|
||||
self.db_destination = None
|
||||
self.save()
|
||||
del_cache(self, "destination")
|
||||
_del_cache(self, "destination")
|
||||
destination = property(destination_get, destination_set, destination_del)
|
||||
|
||||
# cmdset_storage property.
|
||||
|
|
@ -403,17 +403,10 @@ class ObjectDB(TypedObject):
|
|||
#
|
||||
|
||||
# this is required to properly handle attributes and typeclass loading.
|
||||
#attribute_model_path = "src.objects.models"
|
||||
#attribute_model_name = "ObjAttribute"
|
||||
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
|
||||
attribute_class = ObjAttribute
|
||||
db_model_name = "objectdb" # used by attributes to safely store objects
|
||||
|
||||
# this is used by all typedobjects as a fallback
|
||||
try:
|
||||
default_typeclass_path = settings.BASE_OBJECT_TYPECLASS
|
||||
except Exception:
|
||||
default_typeclass_path = "src.objects.objects.Object"
|
||||
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
|
||||
_attribute_class = ObjAttribute
|
||||
_db_model_name = "objectdb" # used by attributes to safely store objects
|
||||
_default_typeclass_path = settings.BASE_OBJECT_TYPECLASS or "src.objects.objects.Object"
|
||||
|
||||
#@property
|
||||
def sessions_get(self):
|
||||
|
|
@ -533,7 +526,7 @@ class ObjectDB(TypedObject):
|
|||
if ignore_errors:
|
||||
return results
|
||||
# this import is cache after the first call.
|
||||
return AT_SEARCH_RESULT(self, ostring, results, global_search)
|
||||
return _AT_SEARCH_RESULT(self, ostring, results, global_search)
|
||||
|
||||
#
|
||||
# Execution/action methods
|
||||
|
|
|
|||
|
|
@ -47,13 +47,13 @@ from django.utils.encoding import smart_str
|
|||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
from src.players import manager
|
||||
from src.players import manager
|
||||
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
|
||||
from src.utils import logger, utils
|
||||
from src.commands.cmdsethandler import CmdSetHandler
|
||||
from src.commands import cmdhandler
|
||||
|
||||
AT_SEARCH_RESULT = utils.mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
_AT_SEARCH_RESULT = utils.mod_import(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
|
|
@ -67,7 +67,7 @@ class PlayerAttribute(Attribute):
|
|||
but are intended to store OOC information specific to each user
|
||||
and game (example would be configurations etc).
|
||||
"""
|
||||
db_obj = models.ForeignKey("PlayerDB")
|
||||
db_obj = models.ForeignKey("PlayerDB")
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
|
|
@ -81,11 +81,11 @@ class PlayerAttribute(Attribute):
|
|||
|
||||
class PlayerNick(TypeNick):
|
||||
"""
|
||||
|
||||
The default nick types used by Evennia are:
|
||||
|
||||
The default nick types used by Evennia are:
|
||||
inputline (default) - match against all input
|
||||
player - match against player searches
|
||||
obj - match against object searches
|
||||
obj - match against object searches
|
||||
channel - used to store own names for channels
|
||||
"""
|
||||
db_obj = models.ForeignKey("PlayerDB", verbose_name="player")
|
||||
|
|
@ -99,7 +99,7 @@ class PlayerNick(TypeNick):
|
|||
class PlayerNickHandler(TypeNickHandler):
|
||||
"""
|
||||
Handles nick access and setting. Accessed through ObjectDB.nicks
|
||||
"""
|
||||
"""
|
||||
NickClass = PlayerNick
|
||||
|
||||
|
||||
|
|
@ -112,52 +112,52 @@ class PlayerNickHandler(TypeNickHandler):
|
|||
class PlayerDB(TypedObject):
|
||||
"""
|
||||
This is a special model using Django's 'profile' functionality
|
||||
and extends the default Django User model. It is defined as such
|
||||
by use of the variable AUTH_PROFILE_MODULE in the settings.
|
||||
One accesses the fields/methods. We try use this model as much
|
||||
and extends the default Django User model. It is defined as such
|
||||
by use of the variable AUTH_PROFILE_MODULE in the settings.
|
||||
One accesses the fields/methods. We try use this model as much
|
||||
as possible rather than User, since we can customize this to
|
||||
our liking.
|
||||
our liking.
|
||||
|
||||
The TypedObject supplies the following (inherited) properties:
|
||||
key - main name
|
||||
typeclass_path - the path to the decorating typeclass
|
||||
typeclass - auto-linked typeclass
|
||||
date_created - time stamp of object creation
|
||||
permissions - perm strings
|
||||
dbref - #id of object
|
||||
permissions - perm strings
|
||||
dbref - #id of object
|
||||
db - persistent attribute storage
|
||||
ndb - non-persistent attribute storage
|
||||
ndb - non-persistent attribute storage
|
||||
|
||||
The PlayerDB adds the following properties:
|
||||
user - Connected User object. django field, needs to be save():d.
|
||||
The PlayerDB adds the following properties:
|
||||
user - Connected User object. django field, needs to be save():d.
|
||||
obj - game object controlled by player
|
||||
character - alias for obj
|
||||
character - alias for obj
|
||||
name - alias for user.username
|
||||
sessions - sessions connected to this player
|
||||
is_superuser - bool if this player is a superuser
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
#
|
||||
# PlayerDB Database model setup
|
||||
#
|
||||
# inherited fields (from TypedObject):
|
||||
# PlayerDB Database model setup
|
||||
#
|
||||
# inherited fields (from TypedObject):
|
||||
# db_key, db_typeclass_path, db_date_created, db_permissions
|
||||
|
||||
# this is the one-to-one link between the customized Player object and
|
||||
# this profile model. It is required by django.
|
||||
# this profile model. It is required by django.
|
||||
user = models.ForeignKey(User, unique=True, db_index=True,
|
||||
help_text="The <I>User</I> object holds django-specific authentication for each Player. A unique User should be created and tied to each Player, the two should never be switched or changed around. The User will be deleted automatically when the Player is.")
|
||||
# the in-game object connected to this player (if any).
|
||||
# Use the property 'obj' to access.
|
||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True,
|
||||
# the in-game object connected to this player (if any).
|
||||
# Use the property 'obj' to access.
|
||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True,
|
||||
verbose_name="character", help_text='In-game object.')
|
||||
|
||||
|
||||
# database storage of persistant cmdsets.
|
||||
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
|
||||
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
|
||||
help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_DEFAULT.")
|
||||
|
||||
# Database manager
|
||||
# Database manager
|
||||
objects = manager.PlayerManager()
|
||||
|
||||
class Meta:
|
||||
|
|
@ -166,18 +166,18 @@ class PlayerDB(TypedObject):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"Parent must be initiated first"
|
||||
TypedObject.__init__(self, *args, **kwargs)
|
||||
TypedObject.__init__(self, *args, **kwargs)
|
||||
# handlers
|
||||
self.cmdset = CmdSetHandler(self)
|
||||
self.cmdset.update(init_mode=True)
|
||||
self.nicks = PlayerNickHandler(self)
|
||||
self.nicks = PlayerNickHandler(self)
|
||||
|
||||
# Wrapper properties to easily set database fields. These are
|
||||
# @property decorators that allows to access these fields using
|
||||
# normal python operations (without having to remember to save()
|
||||
# etc). So e.g. a property 'attr' has a get/set/del decorator
|
||||
# defined that allows the user to do self.attr = value,
|
||||
# value = self.attr and del self.attr respectively (where self
|
||||
# defined that allows the user to do self.attr = value,
|
||||
# value = self.attr and del self.attr respectively (where self
|
||||
# is the object in question).
|
||||
|
||||
# obj property (wraps db_obj)
|
||||
|
|
@ -190,13 +190,13 @@ class PlayerDB(TypedObject):
|
|||
"Setter. Allows for self.obj = value"
|
||||
from src.typeclasses.typeclass import TypeClass
|
||||
if isinstance(value, TypeClass):
|
||||
value = value.dbobj
|
||||
value = value.dbobj
|
||||
try:
|
||||
self.db_obj = value
|
||||
self.save()
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
raise Exception("Cannot assign %s as a player object!" % value)
|
||||
raise Exception("Cannot assign %s as a player object!" % value)
|
||||
#@obj.deleter
|
||||
def obj_del(self):
|
||||
"Deleter. Allows for del self.obj"
|
||||
|
|
@ -204,8 +204,8 @@ class PlayerDB(TypedObject):
|
|||
self.save()
|
||||
obj = property(obj_get, obj_set, obj_del)
|
||||
|
||||
# whereas the name 'obj' is consistent with the rest of the code,
|
||||
# 'character' is a more intuitive property name, so we
|
||||
# whereas the name 'obj' is consistent with the rest of the code,
|
||||
# 'character' is a more intuitive property name, so we
|
||||
# define this too, as an alias to player.obj.
|
||||
#@property
|
||||
def character_get(self):
|
||||
|
|
@ -234,7 +234,7 @@ class PlayerDB(TypedObject):
|
|||
if utils.is_iter(value):
|
||||
value = ",".join([str(val).strip() for val in value])
|
||||
self.db_cmdset_storage = value
|
||||
self.save()
|
||||
self.save()
|
||||
#@cmdset_storage.deleter
|
||||
def cmdset_storage_del(self):
|
||||
"Deleter. Allows for del self.name"
|
||||
|
|
@ -249,26 +249,19 @@ class PlayerDB(TypedObject):
|
|||
|
||||
#
|
||||
# PlayerDB main class properties and methods
|
||||
#
|
||||
#
|
||||
|
||||
def __str__(self):
|
||||
return smart_str("%s(player %i)" % (self.name, self.id))
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s(player#%i)" % (self.name, self.id)
|
||||
|
||||
# this is used by all typedobjects as a fallback
|
||||
try:
|
||||
default_typeclass_path = settings.BASE_PLAYER_TYPECLASS
|
||||
except Exception:
|
||||
default_typeclass_path = "src.players.player.Player"
|
||||
|
||||
# this is required to properly handle attributes and typeclass loading
|
||||
#attribute_model_path = "src.players.models"
|
||||
#attribute_model_name = "PlayerAttribute"
|
||||
typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
|
||||
attribute_class = PlayerAttribute
|
||||
db_model_name = "playerdb" # used by attributes to safely store objects
|
||||
_typeclass_paths = settings.PLAYER_TYPECLASS_PATHS
|
||||
_attribute_class = PlayerAttribute
|
||||
_db_model_name = "playerdb" # used by attributes to safely store objects
|
||||
_default_typeclass_path = settings.BASE_PLAYER_TYPECLASS or "src.players.player.Player"
|
||||
|
||||
# name property (wraps self.user.username)
|
||||
#@property
|
||||
|
|
@ -299,7 +292,7 @@ class PlayerDB(TypedObject):
|
|||
#@sessions.deleter
|
||||
def sessions_del(self):
|
||||
"Deleter. Protects the sessions property from deletion"
|
||||
raise Exception("Cannot delete sessions manually!")
|
||||
raise Exception("Cannot delete sessions manually!")
|
||||
sessions = property(sessions_get, sessions_set, sessions_del)
|
||||
|
||||
#@property
|
||||
|
|
@ -309,12 +302,12 @@ class PlayerDB(TypedObject):
|
|||
is_superuser = property(is_superuser_get)
|
||||
|
||||
#
|
||||
# PlayerDB class access methods
|
||||
#
|
||||
|
||||
# PlayerDB class access methods
|
||||
#
|
||||
|
||||
def msg(self, outgoing_string, from_obj=None, data=None):
|
||||
"""
|
||||
Evennia -> User
|
||||
Evennia -> User
|
||||
This is the main route for sending data back to the user from the server.
|
||||
"""
|
||||
|
||||
|
|
@ -324,10 +317,10 @@ class PlayerDB(TypedObject):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
if (object.__getattribute__(self, "character")
|
||||
if (object.__getattribute__(self, "character")
|
||||
and not self.character.at_msg_receive(outgoing_string, from_obj=from_obj, data=data)):
|
||||
# the at_msg_receive() hook may block receiving of certain messages
|
||||
return
|
||||
return
|
||||
|
||||
outgoing_string = utils.to_str(outgoing_string, force_string=True)
|
||||
|
||||
|
|
@ -340,31 +333,31 @@ class PlayerDB(TypedObject):
|
|||
Swaps character, if possible
|
||||
"""
|
||||
return self.__class__.objects.swap_character(self, new_character, delete_old_character=delete_old_character)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Execution/action methods
|
||||
#
|
||||
|
||||
|
||||
def execute_cmd(self, raw_string):
|
||||
"""
|
||||
Do something as this playe. This command transparently
|
||||
lets its typeclass execute the command.
|
||||
raw_string - raw command input coming from the command line.
|
||||
"""
|
||||
lets its typeclass execute the command.
|
||||
raw_string - raw command input coming from the command line.
|
||||
"""
|
||||
# nick replacement - we require full-word matching.
|
||||
|
||||
|
||||
raw_string = utils.to_unicode(raw_string)
|
||||
|
||||
raw_list = raw_string.split(None)
|
||||
raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]]
|
||||
for nick in PlayerNick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
|
||||
for nick in PlayerNick.objects.filter(db_obj=self, db_type__in=("inputline","channel")):
|
||||
if nick.db_nick in raw_list:
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1)
|
||||
break
|
||||
return cmdhandler.cmdhandler(self.typeclass, raw_string)
|
||||
|
||||
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
|
||||
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
|
||||
location=None, ignore_errors=False, player=False):
|
||||
"""
|
||||
A shell method mimicking the ObjectDB equivalent, for easy inclusion from
|
||||
|
|
@ -373,8 +366,8 @@ class PlayerDB(TypedObject):
|
|||
|
||||
if self.character:
|
||||
# run the normal search
|
||||
return self.character.search(ostring, global_search=global_search, attribute_name=attribute_name,
|
||||
use_nicks=use_nicks, location=location,
|
||||
return self.character.search(ostring, global_search=global_search, attribute_name=attribute_name,
|
||||
use_nicks=use_nicks, location=location,
|
||||
ignore_errors=ignore_errors, player=player)
|
||||
if player:
|
||||
# seach for players
|
||||
|
|
@ -383,7 +376,6 @@ class PlayerDB(TypedObject):
|
|||
# more limited player-only search. Still returns an Object.
|
||||
ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
|
||||
matches = ObjectDB.objects.object_search(ostring, caller=self, global_search=global_search)
|
||||
# deal with results
|
||||
matches = AT_SEARCH_RESULT(self, ostring, matches, global_search=global_search)
|
||||
return matches
|
||||
|
||||
# deal with results
|
||||
matches = _AT_SEARCH_RESULT(self, ostring, matches, global_search=global_search)
|
||||
return matches
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ handled by Scripts.
|
|||
Scripts have to check for themselves that they should be applied at a
|
||||
particular moment of time; this is handled by the is_valid() hook.
|
||||
Scripts can also implement at_start and at_end hooks for preparing and
|
||||
cleaning whatever effect they have had on the game object.
|
||||
cleaning whatever effect they have had on the game object.
|
||||
|
||||
Common examples of uses of Scripts:
|
||||
- load the default cmdset to the player object's cmdhandler
|
||||
|
|
@ -20,8 +20,8 @@ Common examples of uses of Scripts:
|
|||
start combat or enter a dark room.
|
||||
- Weather patterns in-game
|
||||
- merge a new cmdset with the default one for changing which
|
||||
commands are available at a particular time
|
||||
- give the player/object a time-limited bonus/effect
|
||||
commands are available at a particular time
|
||||
- give the player/object a time-limited bonus/effect
|
||||
|
||||
"""
|
||||
from django.conf import settings
|
||||
|
|
@ -45,7 +45,7 @@ class ScriptAttribute(Attribute):
|
|||
verbose_name = "Script Attribute"
|
||||
verbose_name_plural = "Script Attributes"
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# ScriptDB
|
||||
|
|
@ -54,7 +54,7 @@ class ScriptAttribute(Attribute):
|
|||
|
||||
class ScriptDB(TypedObject):
|
||||
"""
|
||||
The Script database representation.
|
||||
The Script database representation.
|
||||
|
||||
The TypedObject supplies the following (inherited) properties:
|
||||
key - main name
|
||||
|
|
@ -62,10 +62,10 @@ class ScriptDB(TypedObject):
|
|||
typeclass_path - the path to the decorating typeclass
|
||||
typeclass - auto-linked typeclass
|
||||
date_created - time stamp of object creation
|
||||
permissions - perm strings
|
||||
dbref - #id of object
|
||||
permissions - perm strings
|
||||
dbref - #id of object
|
||||
db - persistent attribute storage
|
||||
ndb - non-persistent attribute storage
|
||||
ndb - non-persistent attribute storage
|
||||
|
||||
The ScriptDB adds the following properties:
|
||||
desc - optional description of script
|
||||
|
|
@ -74,21 +74,21 @@ class ScriptDB(TypedObject):
|
|||
start_delay - if the script should start repeating right away
|
||||
repeats - how many times the script should repeat
|
||||
persistent - if script should survive a server reboot
|
||||
is_active - bool if script is currently running
|
||||
is_active - bool if script is currently running
|
||||
|
||||
"""
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# ScriptDB Database Model setup
|
||||
#
|
||||
# These databse fields are all set using their corresponding properties,
|
||||
# named same as the field, but withtou the db_* prefix.
|
||||
|
||||
# inherited fields (from TypedObject):
|
||||
# inherited fields (from TypedObject):
|
||||
# db_key, db_typeclass_path, db_date_created, db_permissions
|
||||
|
||||
# optional description.
|
||||
|
||||
# optional description.
|
||||
db_desc = models.CharField('desc', max_length=255, blank=True)
|
||||
# A reference to the database object affected by this Script, if any.
|
||||
db_obj = models.ForeignKey("objects.ObjectDB", null=True, blank=True, verbose_name='scripted object',
|
||||
|
|
@ -106,7 +106,7 @@ class ScriptDB(TypedObject):
|
|||
|
||||
# Database manager
|
||||
objects = ScriptManager()
|
||||
|
||||
|
||||
class Meta:
|
||||
"Define Django meta options"
|
||||
verbose_name = "Script"
|
||||
|
|
@ -115,8 +115,8 @@ class ScriptDB(TypedObject):
|
|||
# @property decorators that allows to access these fields using
|
||||
# normal python operations (without having to remember to save()
|
||||
# etc). So e.g. a property 'attr' has a get/set/del decorator
|
||||
# defined that allows the user to do self.attr = value,
|
||||
# value = self.attr and del self.attr respectively (where self
|
||||
# defined that allows the user to do self.attr = value,
|
||||
# value = self.attr and del self.attr respectively (where self
|
||||
# is the script in question).
|
||||
|
||||
# desc property (wraps db_desc)
|
||||
|
|
@ -186,7 +186,7 @@ class ScriptDB(TypedObject):
|
|||
self.db_start_delay = False
|
||||
self.save()
|
||||
start_delay = property(start_delay_get, start_delay_set, start_delay_del)
|
||||
|
||||
|
||||
# repeats property (wraps db_repeats)
|
||||
#@property
|
||||
def repeats_get(self):
|
||||
|
|
@ -221,7 +221,7 @@ class ScriptDB(TypedObject):
|
|||
self.save()
|
||||
persistent = property(persistent_get, persistent_set, persistent_del)
|
||||
|
||||
# is_active property (wraps db_is_active)
|
||||
# is_active property (wraps db_is_active)
|
||||
#@property
|
||||
def is_active_get(self):
|
||||
"Getter. Allows for value = self.is_active"
|
||||
|
|
@ -245,33 +245,26 @@ class ScriptDB(TypedObject):
|
|||
#
|
||||
|
||||
# this is required to properly handle attributes and typeclass loading
|
||||
#attribute_model_path = "src.scripts.models"
|
||||
#attribute_model_name = "ScriptAttribute"
|
||||
typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
|
||||
attribute_class = ScriptAttribute
|
||||
db_model_name = "scriptdb" # used by attributes to safely store objects
|
||||
|
||||
# this is used by all typedobjects as a fallback
|
||||
try:
|
||||
default_typeclass_path = settings.BASE_SCRIPT_TYPECLASS
|
||||
except:
|
||||
default_typeclass_path = "src.scripts.scripts.DoNothing"
|
||||
_typeclass_paths = settings.SCRIPT_TYPECLASS_PATHS
|
||||
_attribute_class = ScriptAttribute
|
||||
_db_model_name = "scriptdb" # used by attributes to safely store objects
|
||||
_default_typeclass_path = settings.BASE_SCRIPT_TYPECLASS or "src.scripts.scripts.DoNothing"
|
||||
|
||||
def at_typeclass_error(self):
|
||||
"""
|
||||
If this is called, it means the typeclass has a critical
|
||||
If this is called, it means the typeclass has a critical
|
||||
error and cannot even be loaded. We don't allow a script
|
||||
to be created under those circumstances. Already created,
|
||||
permanent scripts are set to already be active so they
|
||||
won't get activated now (next reboot the bug might be fixed)
|
||||
"""
|
||||
# By setting is_active=True, we trick the script not to run "again".
|
||||
self.is_active = True
|
||||
self.is_active = True
|
||||
return super(ScriptDB, self).at_typeclass_error()
|
||||
|
||||
delete_iter = 0
|
||||
def delete(self):
|
||||
if self.delete_iter > 0:
|
||||
return
|
||||
return
|
||||
self.delete_iter += 1
|
||||
super(ScriptDB, self).delete()
|
||||
|
|
|
|||
|
|
@ -43,35 +43,35 @@ from src.locks.lockhandler import LockHandler
|
|||
from src.utils import logger, utils
|
||||
from src.utils.utils import make_iter, is_iter, has_parent, to_unicode, to_str
|
||||
|
||||
PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
|
||||
_PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
|
||||
|
||||
CTYPEGET = ContentType.objects.get
|
||||
GA = object.__getattribute__
|
||||
SA = object.__setattr__
|
||||
DA = object.__delattr__
|
||||
PLOADS = pickle.loads
|
||||
PDUMPS = pickle.dumps
|
||||
_CTYPEGET = ContentType.objects.get
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_DA = object.__delattr__
|
||||
_PLOADS = pickle.loads
|
||||
_PDUMPS = pickle.dumps
|
||||
|
||||
# Property Cache mechanism.
|
||||
|
||||
def get_cache(obj, name):
|
||||
def _get_cache(obj, name):
|
||||
"On-model Cache handler."
|
||||
try:
|
||||
return GA(obj, "_cached_db_%s" % name)
|
||||
return _GA(obj, "_cached_db_%s" % name)
|
||||
except AttributeError:
|
||||
val = GA(obj, "db_%s" % name)
|
||||
if val: SA(obj, "_cached_db_%s" % name, val)
|
||||
val = _GA(obj, "db_%s" % name)
|
||||
if val: _SA(obj, "_cached_db_%s" % name, val)
|
||||
return val
|
||||
def set_cache(obj, name, val):
|
||||
def _set_cache(obj, name, val):
|
||||
"On-model Cache setter"
|
||||
SA(obj, "db_%s" % name, val)
|
||||
GA(obj, "save")()
|
||||
SA(obj, "_cached_db_%s" % name, val)
|
||||
_SA(obj, "db_%s" % name, val)
|
||||
_GA(obj, "save")()
|
||||
_SA(obj, "_cached_db_%s" % name, val)
|
||||
|
||||
def del_cache(obj, name):
|
||||
def _del_cache(obj, name):
|
||||
"On-model cache deleter"
|
||||
try:
|
||||
DA(obj, "_cached_db_%s" % name)
|
||||
_DA(obj, "_cached_db_%s" % name)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
|
@ -290,61 +290,61 @@ class Attribute(SharedMemoryModel):
|
|||
|
||||
# key property (wraps db_key)
|
||||
#@property
|
||||
def key_get(self):
|
||||
def __key_get(self):
|
||||
"Getter. Allows for value = self.key"
|
||||
return get_cache(self, "key")
|
||||
return _get_cache(self, "key")
|
||||
#@key.setter
|
||||
def key_set(self, value):
|
||||
def __key_set(self, value):
|
||||
"Setter. Allows for self.key = value"
|
||||
set_cache(self, "key", value)
|
||||
_set_cache(self, "key", value)
|
||||
#@key.deleter
|
||||
def key_del(self):
|
||||
def __key_del(self):
|
||||
"Deleter. Allows for del self.key"
|
||||
raise Exception("Cannot delete attribute key!")
|
||||
key = property(key_get, key_set, key_del)
|
||||
key = property(__key_get, __key_set, __key_del)
|
||||
|
||||
# obj property (wraps db_obj)
|
||||
#@property
|
||||
def obj_get(self):
|
||||
def __obj_get(self):
|
||||
"Getter. Allows for value = self.obj"
|
||||
return get_cache(self, "obj")
|
||||
return _get_cache(self, "obj")
|
||||
#@obj.setter
|
||||
def obj_set(self, value):
|
||||
def __obj_set(self, value):
|
||||
"Setter. Allows for self.obj = value"
|
||||
set_cache(self, "obj", value)
|
||||
_set_cache(self, "obj", value)
|
||||
#@obj.deleter
|
||||
def obj_del(self):
|
||||
def __obj_del(self):
|
||||
"Deleter. Allows for del self.obj"
|
||||
self.db_obj = None
|
||||
self.save()
|
||||
del_cache(self, "obj")
|
||||
obj = property(obj_get, obj_set, obj_del)
|
||||
_del_cache(self, "obj")
|
||||
obj = property(__obj_get, __obj_set, __obj_del)
|
||||
|
||||
# date_created property (wraps db_date_created)
|
||||
#@property
|
||||
def date_created_get(self):
|
||||
def __date_created_get(self):
|
||||
"Getter. Allows for value = self.date_created"
|
||||
return get_cache(self, "date_created")
|
||||
return _get_cache(self, "date_created")
|
||||
#@date_created.setter
|
||||
def date_created_set(self, value):
|
||||
def __date_created_set(self, value):
|
||||
"Setter. Allows for self.date_created = value"
|
||||
raise Exception("Cannot edit date_created!")
|
||||
#@date_created.deleter
|
||||
def date_created_del(self):
|
||||
def __date_created_del(self):
|
||||
"Deleter. Allows for del self.date_created"
|
||||
raise Exception("Cannot delete date_created!")
|
||||
date_created = property(date_created_get, date_created_set, date_created_del)
|
||||
date_created = property(__date_created_get, __date_created_set, __date_created_del)
|
||||
|
||||
# value property (wraps db_value)
|
||||
#@property
|
||||
def value_get(self):
|
||||
def __value_get(self):
|
||||
"""
|
||||
Getter. Allows for value = self.value. Reads from cache if possible.
|
||||
"""
|
||||
if self.no_cache:
|
||||
# re-create data from database and cache it
|
||||
try:
|
||||
value = self.from_attr(PLOADS(to_str(self.db_value)))
|
||||
value = self.__from_attr(_PLOADS(to_str(self.db_value)))
|
||||
except pickle.UnpicklingError:
|
||||
value = self.db_value
|
||||
self.cached_value = value
|
||||
|
|
@ -355,36 +355,36 @@ class Attribute(SharedMemoryModel):
|
|||
return self.cached_value
|
||||
|
||||
#@value.setter
|
||||
def value_set(self, new_value):
|
||||
def __value_set(self, new_value):
|
||||
"""
|
||||
Setter. Allows for self.value = value. We make sure to cache everything.
|
||||
"""
|
||||
new_value = self.to_attr(new_value)
|
||||
self.cached_value = self.from_attr(new_value)
|
||||
new_value = self.__to_attr(new_value)
|
||||
self.cached_value = self.__from_attr(new_value)
|
||||
self.no_cache = False
|
||||
self.db_value = to_unicode(PDUMPS(to_str(new_value)))
|
||||
self.db_value = to_unicode(_PDUMPS(to_str(new_value)))
|
||||
self.save()
|
||||
#@value.deleter
|
||||
def value_del(self):
|
||||
def __value_del(self):
|
||||
"Deleter. Allows for del attr.value. This removes the entire attribute."
|
||||
self.delete()
|
||||
value = property(value_get, value_set, value_del)
|
||||
value = property(__value_get, __value_set, __value_del)
|
||||
|
||||
# lock_storage property (wraps db_lock_storage)
|
||||
#@property
|
||||
def lock_storage_get(self):
|
||||
def __lock_storage_get(self):
|
||||
"Getter. Allows for value = self.lock_storage"
|
||||
return get_cache(self, "lock_storage")
|
||||
return _get_cache(self, "lock_storage")
|
||||
#@lock_storage.setter
|
||||
def lock_storage_set(self, value):
|
||||
def __lock_storage_set(self, value):
|
||||
"""Saves the lock_storage. This is usually not called directly, but through self.lock()"""
|
||||
self.db_lock_storage = value
|
||||
self.save()
|
||||
#@lock_storage.deleter
|
||||
def lock_storage_del(self):
|
||||
def __lock_storage_del(self):
|
||||
"Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
|
||||
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
|
||||
lock_storage = property(lock_storage_get, lock_storage_set, lock_storage_del)
|
||||
lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
|
||||
|
||||
|
||||
#
|
||||
|
|
@ -401,7 +401,7 @@ class Attribute(SharedMemoryModel):
|
|||
|
||||
# operators on various data
|
||||
|
||||
def to_attr(self, data):
|
||||
def __to_attr(self, data):
|
||||
"""
|
||||
Convert data to proper attr data format before saving
|
||||
|
||||
|
|
@ -434,10 +434,10 @@ class Attribute(SharedMemoryModel):
|
|||
dtype = type(item)
|
||||
if dtype in (basestring, int, float): # check the most common types first, for speed
|
||||
return item
|
||||
elif hasattr(item, "id") and hasattr(item, "db_model_name") and hasattr(item, "db_key"):
|
||||
db_model_name = item.db_model_name
|
||||
elif hasattr(item, "id") and hasattr(item, "_db_model_name") and hasattr(item, "db_key"):
|
||||
db_model_name = item._db_model_name # don't use _GA here, could be typeclass
|
||||
if db_model_name == "typeclass":
|
||||
db_model_name = GA(item.dbobj, "db_model_name")
|
||||
db_model_name = _GA(item.dbobj, "_db_model_name")
|
||||
return PackedDBobject(item.id, db_model_name, item.db_key)
|
||||
elif dtype == tuple:
|
||||
return tuple(iter_db2id(val) for val in item)
|
||||
|
|
@ -452,13 +452,13 @@ class Attribute(SharedMemoryModel):
|
|||
|
||||
if dtype in (basestring, int, float):
|
||||
return ("simple",data)
|
||||
elif hasattr(data, "id") and hasattr(data, "db_model_name") and hasattr(data, 'db_key'):
|
||||
elif hasattr(data, "id") and hasattr(data, "_db_model_name") and hasattr(data, 'db_key'):
|
||||
# all django models (objectdb,scriptdb,playerdb,channel,msg,typeclass)
|
||||
# have the protected property db_model_name hardcoded on themselves for speed.
|
||||
db_model_name = data.db_model_name
|
||||
# have the protected property _db_model_name hardcoded on themselves for speed.
|
||||
db_model_name = data._db_model_name # don't use _GA here, could be typeclass
|
||||
if db_model_name == "typeclass":
|
||||
# typeclass cannot help us, we want the actual child object model name
|
||||
db_model_name = GA(data.dbobj, "db_model_name")
|
||||
db_model_name = _GA(data.dbobj,"_db_model_name")
|
||||
return ("dbobj", PackedDBobject(data.id, db_model_name, data.db_key))
|
||||
elif hasattr(data, "__iter__"):
|
||||
return ("iter", iter_db2id(data))
|
||||
|
|
@ -466,7 +466,7 @@ class Attribute(SharedMemoryModel):
|
|||
return ("simple", data)
|
||||
|
||||
|
||||
def from_attr(self, datatuple):
|
||||
def __from_attr(self, datatuple):
|
||||
"""
|
||||
Retrieve data from a previously stored attribute. This
|
||||
is always a dict with keys type and data.
|
||||
|
|
@ -488,7 +488,7 @@ class Attribute(SharedMemoryModel):
|
|||
"""
|
||||
Convert db-stored dbref back to object
|
||||
"""
|
||||
mclass = CTYPEGET(model=data.db_model).model_class()
|
||||
mclass = _CTYPEGET(model=data.db_model).model_class()
|
||||
try:
|
||||
return mclass.objects.dbref_search(data.id)
|
||||
|
||||
|
|
@ -636,9 +636,11 @@ class TypeNickHandler(object):
|
|||
# remove the found nick(s)
|
||||
query.delete()
|
||||
def get(self, nick=None, nick_type="inputline", obj=None):
|
||||
"""Retrieves a given nick (with a specified nick_type) on an object. If no nick is given, returns a list
|
||||
"""
|
||||
Retrieves a given nick (with a specified nick_type) on an object. If no nick is given, returns a list
|
||||
of all nicks on the object, or the empty list.
|
||||
Defaults to searching the current object."""
|
||||
Defaults to searching the current object.
|
||||
"""
|
||||
if not obj:
|
||||
# defaults to the current object
|
||||
obj = self.obj
|
||||
|
|
@ -739,101 +741,101 @@ class TypedObject(SharedMemoryModel):
|
|||
|
||||
# key property (wraps db_key)
|
||||
#@property
|
||||
def key_get(self):
|
||||
def __key_get(self):
|
||||
"Getter. Allows for value = self.key"
|
||||
return get_cache(self, "key")
|
||||
return _get_cache(self, "key")
|
||||
#@key.setter
|
||||
def key_set(self, value):
|
||||
def __key_set(self, value):
|
||||
"Setter. Allows for self.key = value"
|
||||
set_cache(self, "key", value)
|
||||
_set_cache(self, "key", value)
|
||||
#@key.deleter
|
||||
def key_del(self):
|
||||
def __key_del(self):
|
||||
"Deleter. Allows for del self.key"
|
||||
raise Exception("Cannot delete objectdb key!")
|
||||
key = property(key_get, key_set, key_del)
|
||||
key = property(__key_get, __key_set, __key_del)
|
||||
|
||||
# name property (wraps db_key too - alias to self.key)
|
||||
#@property
|
||||
def name_get(self):
|
||||
def __name_get(self):
|
||||
"Getter. Allows for value = self.name"
|
||||
return get_cache(self, "key")
|
||||
return _get_cache(self, "key")
|
||||
#@name.setter
|
||||
def name_set(self, value):
|
||||
def __name_set(self, value):
|
||||
"Setter. Allows for self.name = value"
|
||||
set_cache(self, "key", value)
|
||||
_set_cache(self, "key", value)
|
||||
#@name.deleter
|
||||
def name_del(self):
|
||||
def __name_del(self):
|
||||
"Deleter. Allows for del self.name"
|
||||
raise Exception("Cannot delete name!")
|
||||
name = property(name_get, name_set, name_del)
|
||||
name = property(__name_get, __name_set, __name_del)
|
||||
|
||||
# typeclass_path property
|
||||
#@property
|
||||
def typeclass_path_get(self):
|
||||
def __typeclass_path_get(self):
|
||||
"Getter. Allows for value = self.typeclass_path"
|
||||
return get_cache(self, "typeclass_path")
|
||||
return _get_cache(self, "typeclass_path")
|
||||
#@typeclass_path.setter
|
||||
def typeclass_path_set(self, value):
|
||||
def __typeclass_path_set(self, value):
|
||||
"Setter. Allows for self.typeclass_path = value"
|
||||
set_cache(self, "typeclass_path", value)
|
||||
_set_cache(self, "typeclass_path", value)
|
||||
#@typeclass_path.deleter
|
||||
def typeclass_path_del(self):
|
||||
def __typeclass_path_del(self):
|
||||
"Deleter. Allows for del self.typeclass_path"
|
||||
self.db_typeclass_path = ""
|
||||
self.save()
|
||||
del_cache(self, "typeclass_path")
|
||||
typeclass_path = property(typeclass_path_get, typeclass_path_set, typeclass_path_del)
|
||||
_del_cache(self, "typeclass_path")
|
||||
typeclass_path = property(__typeclass_path_get, __typeclass_path_set, __typeclass_path_del)
|
||||
|
||||
# date_created property
|
||||
#@property
|
||||
def date_created_get(self):
|
||||
def __date_created_get(self):
|
||||
"Getter. Allows for value = self.date_created"
|
||||
return get_cache(self, "date_created")
|
||||
return _get_cache(self, "date_created")
|
||||
#@date_created.setter
|
||||
def date_created_set(self, value):
|
||||
def __date_created_set(self, value):
|
||||
"Setter. Allows for self.date_created = value"
|
||||
raise Exception("Cannot change date_created!")
|
||||
#@date_created.deleter
|
||||
def date_created_del(self):
|
||||
def __date_created_del(self):
|
||||
"Deleter. Allows for del self.date_created"
|
||||
raise Exception("Cannot delete date_created!")
|
||||
date_created = property(date_created_get, date_created_set, date_created_del)
|
||||
date_created = property(__date_created_get, __date_created_set, __date_created_del)
|
||||
|
||||
# permissions property
|
||||
#@property
|
||||
def permissions_get(self):
|
||||
def __permissions_get(self):
|
||||
"Getter. Allows for value = self.name. Returns a list of permissions."
|
||||
perms = get_cache(self, "permissions")
|
||||
perms = _get_cache(self, "permissions")
|
||||
if perms:
|
||||
return [perm.strip() for perm in perms.split(',')]
|
||||
return []
|
||||
#@permissions.setter
|
||||
def permissions_set(self, value):
|
||||
def __permissions_set(self, value):
|
||||
"Setter. Allows for self.name = value. Stores as a comma-separated string."
|
||||
value = ",".join([utils.to_unicode(val).strip() for val in make_iter(value)])
|
||||
set_cache(self, "permissions", value)
|
||||
_set_cache(self, "permissions", value)
|
||||
#@permissions.deleter
|
||||
def permissions_del(self):
|
||||
def __permissions_del(self):
|
||||
"Deleter. Allows for del self.name"
|
||||
self.db_permissions = ""
|
||||
self.save()
|
||||
del_cache(self, "permissions")
|
||||
permissions = property(permissions_get, permissions_set, permissions_del)
|
||||
_del_cache(self, "permissions")
|
||||
permissions = property(__permissions_get, __permissions_set, __permissions_del)
|
||||
|
||||
# lock_storage property (wraps db_lock_storage)
|
||||
#@property
|
||||
def lock_storage_get(self):
|
||||
def __lock_storage_get(self):
|
||||
"Getter. Allows for value = self.lock_storage"
|
||||
return get_cache(self, "lock_storage")
|
||||
return _get_cache(self, "lock_storage")
|
||||
#@lock_storage.setter
|
||||
def lock_storage_set(self, value):
|
||||
def __lock_storage_set(self, value):
|
||||
"""Saves the lock_storagetodate. This is usually not called directly, but through self.lock()"""
|
||||
set_cache(self, "lock_storage", value)
|
||||
_set_cache(self, "lock_storage", value)
|
||||
#@lock_storage.deleter
|
||||
def lock_storage_del(self):
|
||||
def __lock_storage_del(self):
|
||||
"Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
|
||||
logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
|
||||
lock_storage = property(lock_storage_get, lock_storage_set, lock_storage_del)
|
||||
lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
|
||||
|
||||
|
||||
|
||||
|
|
@ -844,9 +846,9 @@ class TypedObject(SharedMemoryModel):
|
|||
#
|
||||
|
||||
# these are identifiers for fast Attribute access and caching
|
||||
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
|
||||
attribute_class = Attribute # replaced by relevant attribute class for child
|
||||
db_model_name = "typeclass" # used by attributes to safely store objects
|
||||
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
|
||||
_attribute_class = Attribute # replaced by relevant attribute class for child
|
||||
_db_model_name = "typeclass" # used by attributes to safely store objects
|
||||
|
||||
def __eq__(self, other):
|
||||
return other and hasattr(other, 'id') and self.id == other.id
|
||||
|
|
@ -866,31 +868,31 @@ class TypedObject(SharedMemoryModel):
|
|||
have to be very careful to avoid loops.
|
||||
"""
|
||||
try:
|
||||
return GA(self, propname)
|
||||
return _GA(self, propname)
|
||||
except AttributeError:
|
||||
# check if the attribute exists on the typeclass instead
|
||||
# (we make sure to not incur a loop by not triggering the
|
||||
# typeclass' __getattribute__, since that one would
|
||||
# try to look back to this very database object.)
|
||||
typeclass = GA(self, 'typeclass')
|
||||
typeclass = _GA(self, 'typeclass')
|
||||
if typeclass:
|
||||
return GA(typeclass, propname)
|
||||
return _GA(typeclass, propname)
|
||||
else:
|
||||
raise AttributeError
|
||||
|
||||
#@property
|
||||
def dbref_get(self):
|
||||
def __dbref_get(self):
|
||||
"""
|
||||
Returns the object's dbref id on the form #NN.
|
||||
Alternetively, use obj.id directly to get dbref
|
||||
without any #.
|
||||
"""
|
||||
return "#%s" % str(GA(self, "id"))
|
||||
dbref = property(dbref_get)
|
||||
return "#%s" % str(_GA(self, "id"))
|
||||
dbref = property(__dbref_get)
|
||||
|
||||
# typeclass property
|
||||
#@property
|
||||
def typeclass_get(self):
|
||||
def __typeclass_get(self):
|
||||
"""
|
||||
Getter. Allows for value = self.typeclass.
|
||||
The typeclass is a class object found at self.typeclass_path;
|
||||
|
|
@ -898,15 +900,15 @@ class TypedObject(SharedMemoryModel):
|
|||
types of objects that the game needs. This property
|
||||
handles loading and initialization of the typeclass on the fly.
|
||||
|
||||
Note: The liberal use of GA and __setattr__ (instead
|
||||
Note: The liberal use of _GA and __setattr__ (instead
|
||||
of normal dot notation) is due to optimization: it avoids calling
|
||||
the custom self.__getattribute__ more than necessary.
|
||||
"""
|
||||
|
||||
path = GA(self, "typeclass_path")
|
||||
typeclass = GA(self, "_cached_typeclass")
|
||||
path = _GA(self, "typeclass_path")
|
||||
typeclass = _GA(self, "_cached_typeclass")
|
||||
try:
|
||||
if typeclass and GA(typeclass, "path") == path:
|
||||
if typeclass and _GA(typeclass, "path") == path:
|
||||
# don't call at_init() when returning from cache
|
||||
return typeclass
|
||||
except AttributeError:
|
||||
|
|
@ -915,25 +917,25 @@ class TypedObject(SharedMemoryModel):
|
|||
errstring = ""
|
||||
if not path:
|
||||
# this means we should get the default obj without giving errors.
|
||||
return GA(self, "get_default_typeclass")(cache=True, silent=True, save=True)
|
||||
return _GA(self, "_get_default_typeclass")(cache=True, silent=True, save=True)
|
||||
else:
|
||||
# handle loading/importing of typeclasses, searching all paths.
|
||||
# (self.typeclass_paths is a shortcut to settings.TYPECLASS_*_PATHS
|
||||
# (self._typeclass_paths is a shortcut to settings.TYPECLASS_*_PATHS
|
||||
# where '*' is either OBJECT, SCRIPT or PLAYER depending on the typed
|
||||
# entities).
|
||||
typeclass_paths = [path] + ["%s.%s" % (prefix, path) for prefix in GA(self, 'typeclass_paths')]
|
||||
typeclass_paths = [path] + ["%s.%s" % (prefix, path) for prefix in _GA(self, '_typeclass_paths')]
|
||||
|
||||
for tpath in typeclass_paths:
|
||||
|
||||
# try to import and analyze the result
|
||||
typeclass = GA(self, "_path_import")(tpath)
|
||||
typeclass = _GA(self, "_path_import")(tpath)
|
||||
if callable(typeclass):
|
||||
# we succeeded to import. Cache and return.
|
||||
SA(self, 'db_typeclass_path', tpath)
|
||||
GA(self, 'save')()
|
||||
SA(self, "_cached_db_typeclass_path", tpath)
|
||||
_SA(self, 'db_typeclass_path', tpath)
|
||||
_GA(self, 'save')()
|
||||
_SA(self, "_cached_db_typeclass_path", tpath)
|
||||
typeclass = typeclass(self)
|
||||
SA(self, "_cached_typeclass", typeclass)
|
||||
_SA(self, "_cached_typeclass", typeclass)
|
||||
try:
|
||||
typeclass.at_init()
|
||||
except Exception:
|
||||
|
|
@ -946,16 +948,16 @@ class TypedObject(SharedMemoryModel):
|
|||
errstring += "\n%s" % typeclass # this will hold a growing error message.
|
||||
# If we reach this point we couldn't import any typeclasses. Return default. It's up to the calling
|
||||
# method to use e.g. self.is_typeclass() to detect that the result is not the one asked for.
|
||||
GA(self, "_display_errmsg")(errstring)
|
||||
return GA(self, "get_default_typeclass")(cache=False, silent=False, save=False)
|
||||
_GA(self, "_display_errmsg")(errstring)
|
||||
return _GA(self, "_get_default_typeclass")(cache=False, silent=False, save=False)
|
||||
|
||||
#@typeclass.deleter
|
||||
def typeclass_del(self):
|
||||
def __typeclass_del(self):
|
||||
"Deleter. Disallow 'del self.typeclass'"
|
||||
raise Exception("The typeclass property should never be deleted, only changed in-place!")
|
||||
|
||||
# typeclass property
|
||||
typeclass = property(typeclass_get, fdel=typeclass_del)
|
||||
typeclass = property(__typeclass_get, fdel=__typeclass_del)
|
||||
|
||||
def _path_import(self, path):
|
||||
"""
|
||||
|
|
@ -1014,7 +1016,7 @@ class TypedObject(SharedMemoryModel):
|
|||
else:
|
||||
logger.log_trace(cmessage)
|
||||
|
||||
def get_default_typeclass(self, cache=False, silent=False, save=False):
|
||||
def _get_default_typeclass(self, cache=False, silent=False, save=False):
|
||||
"""
|
||||
This is called when a typeclass fails to
|
||||
load for whatever reason.
|
||||
|
|
@ -1022,34 +1024,34 @@ class TypedObject(SharedMemoryModel):
|
|||
|
||||
Default operation is to load a default typeclass.
|
||||
"""
|
||||
defpath = GA(self, "default_typeclass_path")
|
||||
typeclass = GA(self, "_path_import")(defpath)
|
||||
defpath = _GA(self, "_default_typeclass_path")
|
||||
typeclass = _GA(self, "_path_import")(defpath)
|
||||
# if not silent:
|
||||
# #errstring = "\n\nUsing Default class '%s'." % defpath
|
||||
# GA(self, "_display_errmsg")(errstring)
|
||||
# _GA(self, "_display_errmsg")(errstring)
|
||||
|
||||
if not callable(typeclass):
|
||||
# if typeclass still doesn't exist at this point, we're in trouble.
|
||||
# fall back to hardcoded core class which is wrong for e.g. scripts/players etc.
|
||||
failpath = defpath
|
||||
defpath = "src.objects.objects.Object"
|
||||
typeclass = GA(self, "_path_import")(defpath)
|
||||
typeclass = _GA(self, "_path_import")(defpath)
|
||||
if not silent:
|
||||
#errstring = " %s\n%s" % (typeclass, errstring)
|
||||
errstring = " Default class '%s' failed to load." % failpath
|
||||
errstring += "\n Using Evennia's default class '%s'." % defpath
|
||||
GA(self, "_display_errmsg")(errstring)
|
||||
_GA(self, "_display_errmsg")(errstring)
|
||||
if not callable(typeclass):
|
||||
# if this is still giving an error, Evennia is wrongly configured or buggy
|
||||
raise Exception("CRITICAL ERROR: The final fallback typeclass %s cannot load!!" % defpath)
|
||||
typeclass = typeclass(self)
|
||||
if save:
|
||||
SA(self, 'db_typeclass_path', defpath)
|
||||
GA(self, 'save')()
|
||||
_SA(self, 'db_typeclass_path', defpath)
|
||||
_GA(self, 'save')()
|
||||
if cache:
|
||||
SA(self, "_cached_db_typeclass_path", defpath)
|
||||
_SA(self, "_cached_db_typeclass_path", defpath)
|
||||
|
||||
SA(self, "_cached_typeclass", typeclass)
|
||||
_SA(self, "_cached_typeclass", typeclass)
|
||||
try:
|
||||
typeclass.at_init()
|
||||
except Exception:
|
||||
|
|
@ -1070,17 +1072,17 @@ class TypedObject(SharedMemoryModel):
|
|||
parents.
|
||||
"""
|
||||
try:
|
||||
typeclass = GA(typeclass, "path")
|
||||
typeclass = _GA(typeclass, "path")
|
||||
except AttributeError:
|
||||
pass
|
||||
typeclasses = [typeclass] + ["%s.%s" % (path, typeclass) for path in GA(self, "typeclass_paths")]
|
||||
typeclasses = [typeclass] + ["%s.%s" % (path, typeclass) for path in _GA(self, "_typeclass_paths")]
|
||||
if exact:
|
||||
current_path = GA(self, "_cached_db_typeclass_path")
|
||||
current_path = _GA(self, "_cached_db_typeclass_path")
|
||||
return typeclass and any((current_path == typec for typec in typeclasses))
|
||||
else:
|
||||
# check parent chain
|
||||
return any((cls for cls in self.typeclass.__class__.mro()
|
||||
if any(("%s.%s" % (GA(cls,"__module__"), GA(cls,"__name__")) == typec for typec in typeclasses))))
|
||||
if any(("%s.%s" % (_GA(cls,"__module__"), _GA(cls,"__name__")) == typec for typec in typeclasses))))
|
||||
|
||||
#
|
||||
# Object manipulation methods
|
||||
|
|
@ -1135,13 +1137,13 @@ class TypedObject(SharedMemoryModel):
|
|||
new_typeclass = self.typeclass
|
||||
if self.typeclass_path == new_typeclass.path:
|
||||
# the typeclass loading worked as expected
|
||||
DA(self, "_cached_db_typeclass_path")
|
||||
SA(self, "_cached_typeclass", None)
|
||||
_DA(self, "_cached_db_typeclass_path")
|
||||
_SA(self, "_cached_typeclass", None)
|
||||
elif no_default:
|
||||
# something went wrong; the default was loaded instead,
|
||||
# and we don't allow that; instead we return to previous.
|
||||
SA(self, "typeclass_path", old_typeclass_path)
|
||||
SA(self, "_cached_typeclass", None)
|
||||
_SA(self, "typeclass_path", old_typeclass_path)
|
||||
_SA(self, "_cached_typeclass", None)
|
||||
return False
|
||||
|
||||
if clean_attributes:
|
||||
|
|
@ -1181,7 +1183,7 @@ class TypedObject(SharedMemoryModel):
|
|||
|
||||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
return GA(self, "attribute_class").objects.filter(db_obj=self).filter(
|
||||
return _GA(self, "_attribute_class").objects.filter(db_obj=self).filter(
|
||||
db_key__iexact=attribute_name).count()
|
||||
|
||||
def set_attribute(self, attribute_name, new_value=None):
|
||||
|
|
@ -1194,7 +1196,7 @@ class TypedObject(SharedMemoryModel):
|
|||
a str, the object will be stored as a pickle.
|
||||
"""
|
||||
attrib_obj = None
|
||||
attrclass = GA(self, "attribute_class")
|
||||
attrclass = _GA(self, "_attribute_class")
|
||||
try:
|
||||
# use old attribute
|
||||
attrib_obj = attrclass.objects.filter(
|
||||
|
|
@ -1216,7 +1218,7 @@ class TypedObject(SharedMemoryModel):
|
|||
"""
|
||||
attrib_obj = default
|
||||
try:
|
||||
attrib_obj = self.attribute_class.objects.filter(
|
||||
attrib_obj = _GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self).filter(db_key__iexact=attribute_name)[0]
|
||||
except IndexError:
|
||||
return default
|
||||
|
|
@ -1230,7 +1232,7 @@ class TypedObject(SharedMemoryModel):
|
|||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
try:
|
||||
return self.attribute_class.objects.filter(
|
||||
return _GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self).filter(db_key__iexact=attribute_name)[0].value
|
||||
except IndexError:
|
||||
raise AttributeError
|
||||
|
|
@ -1242,7 +1244,7 @@ class TypedObject(SharedMemoryModel):
|
|||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
try:
|
||||
self.attribute_class.objects.filter(
|
||||
_GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self).filter(db_key__iexact=attribute_name)[0].delete()
|
||||
except IndexError:
|
||||
pass
|
||||
|
|
@ -1255,7 +1257,7 @@ class TypedObject(SharedMemoryModel):
|
|||
attribute_name: (str) The attribute's name.
|
||||
"""
|
||||
try:
|
||||
self.attribute_class.objects.filter(
|
||||
_GA(self, "_attribute_class").objects.filter(
|
||||
db_obj=self).filter(db_key__iexact=attribute_name)[0].delete()
|
||||
except IndexError:
|
||||
raise AttributeError
|
||||
|
|
@ -1264,7 +1266,7 @@ class TypedObject(SharedMemoryModel):
|
|||
"""
|
||||
Returns all attributes defined on the object.
|
||||
"""
|
||||
return list(self.attribute_class.objects.filter(db_obj=self))
|
||||
return list(_GA(self,"_attribute_class").objects.filter(db_obj=self))
|
||||
|
||||
def attr(self, attribute_name=None, value=None, delete=False):
|
||||
"""
|
||||
|
|
@ -1291,7 +1293,7 @@ class TypedObject(SharedMemoryModel):
|
|||
self.set_attribute(attribute_name, value)
|
||||
|
||||
#@property
|
||||
def db_get(self):
|
||||
def __db_get(self):
|
||||
"""
|
||||
A second convenience wrapper for the the attribute methods. It
|
||||
allows for the syntax
|
||||
|
|
@ -1310,35 +1312,35 @@ class TypedObject(SharedMemoryModel):
|
|||
class DbHolder(object):
|
||||
"Holder for allowing property access of attributes"
|
||||
def __init__(self, obj):
|
||||
SA(self, 'obj', obj)
|
||||
_SA(self, 'obj', obj)
|
||||
def __getattribute__(self, attrname):
|
||||
if attrname == 'all':
|
||||
# we allow for overwriting the all() method
|
||||
# with an attribute named 'all'.
|
||||
attr = GA(self, 'obj').get_attribute("all")
|
||||
attr = _GA(self, 'obj').get_attribute("all")
|
||||
if attr:
|
||||
return attr
|
||||
return GA(self, 'all')
|
||||
return GA(self, 'obj').get_attribute(attrname)
|
||||
return _GA(self, 'all')
|
||||
return _GA(self, 'obj').get_attribute(attrname)
|
||||
def __setattr__(self, attrname, value):
|
||||
GA(self, 'obj').set_attribute(attrname, value)
|
||||
_GA(self, 'obj').set_attribute(attrname, value)
|
||||
def __delattr__(self, attrname):
|
||||
GA(self, 'obj').del_attribute(attrname)
|
||||
_GA(self, 'obj').del_attribute(attrname)
|
||||
def all(self):
|
||||
return GA(self, 'obj').get_all_attributes()
|
||||
return _GA(self, 'obj').get_all_attributes()
|
||||
self._db_holder = DbHolder(self)
|
||||
return self._db_holder
|
||||
#@db.setter
|
||||
def db_set(self, value):
|
||||
def __db_set(self, value):
|
||||
"Stop accidentally replacing the db object"
|
||||
string = "Cannot assign directly to db object! "
|
||||
string += "Use db.attr=value instead."
|
||||
raise Exception(string)
|
||||
#@db.deleter
|
||||
def db_del(self):
|
||||
def __db_del(self):
|
||||
"Stop accidental deletion."
|
||||
raise Exception("Cannot delete the db object!")
|
||||
db = property(db_get, db_set, db_del)
|
||||
db = property(__db_get, __db_set, __db_del)
|
||||
|
||||
#
|
||||
# NON-PERSISTENT storage methods
|
||||
|
|
@ -1358,19 +1360,19 @@ class TypedObject(SharedMemoryModel):
|
|||
if not val.startswith['_']]
|
||||
elif delete == True:
|
||||
if hasattr(self.ndb, attribute_name):
|
||||
DA(self.db, attribute_name)
|
||||
_DA(self.db, attribute_name)
|
||||
elif value == None:
|
||||
# act as a getter.
|
||||
if hasattr(self.ndb, attribute_name):
|
||||
GA(self.ndb, attribute_name)
|
||||
_GA(self.ndb, attribute_name)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
# act as a setter
|
||||
SA(self.db, attribute_name, value)
|
||||
_SA(self.db, attribute_name, value)
|
||||
|
||||
#@property
|
||||
def ndb_get(self):
|
||||
def __ndb_get(self):
|
||||
"""
|
||||
A non-persistent store (ndb: NonDataBase). Everything stored
|
||||
to this is guaranteed to be cleared when a server is shutdown.
|
||||
|
|
@ -1388,22 +1390,22 @@ class TypedObject(SharedMemoryModel):
|
|||
def __getattribute__(self, key):
|
||||
# return None if no matching attribute was found.
|
||||
try:
|
||||
return GA(self, key)
|
||||
return _GA(self, key)
|
||||
except AttributeError:
|
||||
return None
|
||||
self._ndb_holder = NdbHolder()
|
||||
return self._ndb_holder
|
||||
#@ndb.setter
|
||||
def ndb_set(self, value):
|
||||
def __ndb_set(self, value):
|
||||
"Stop accidentally replacing the db object"
|
||||
string = "Cannot assign directly to ndb object! "
|
||||
string = "Use ndb.attr=value instead."
|
||||
raise Exception(string)
|
||||
#@ndb.deleter
|
||||
def ndb_del(self):
|
||||
def __ndb_del(self):
|
||||
"Stop accidental deletion."
|
||||
raise Exception("Cannot delete the ndb object!")
|
||||
ndb = property(ndb_get, ndb_set, ndb_del)
|
||||
ndb = property(__ndb_get, __ndb_set, __ndb_del)
|
||||
|
||||
#
|
||||
# Lock / permission methods
|
||||
|
|
@ -1437,9 +1439,9 @@ class TypedObject(SharedMemoryModel):
|
|||
if perm in [p.lower() for p in self.permissions]:
|
||||
# simplest case - we have a direct match
|
||||
return True
|
||||
if perm in PERMISSION_HIERARCHY:
|
||||
if perm in _PERMISSION_HIERARCHY:
|
||||
# check if we have a higher hierarchy position
|
||||
ppos = PERMISSION_HIERARCHY.index(perm)
|
||||
return any(True for hpos, hperm in enumerate(PERMISSION_HIERARCHY)
|
||||
ppos = _PERMISSION_HIERARCHY.index(perm)
|
||||
return any(True for hpos, hperm in enumerate(_PERMISSION_HIERARCHY)
|
||||
if hperm in [p.lower() for p in self.permissions] and hpos > ppos)
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ from src.utils.logger import log_trace, log_errmsg
|
|||
from django.conf import settings
|
||||
|
||||
# these are called so many times it's worth to avoid lookup calls
|
||||
GA = object.__getattribute__
|
||||
SA = object.__setattr__
|
||||
DA = object.__delattr__
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_DA = object.__delattr__
|
||||
|
||||
# To ensure the sanity of the model, there are a
|
||||
# few property names we won't allow the admin to
|
||||
|
|
@ -75,13 +75,13 @@ class TypeClass(object):
|
|||
"""
|
||||
# typecheck of dbobj - we can't allow it to be added here
|
||||
# unless it's really a TypedObject.
|
||||
dbobj_cls = GA(dbobj, '__class__')
|
||||
dbobj_mro = GA(dbobj_cls, '__mro__')
|
||||
dbobj_cls = _GA(dbobj, '__class__')
|
||||
dbobj_mro = _GA(dbobj_cls, '__mro__')
|
||||
if not any('src.typeclasses.models.TypedObject' in str(mro) for mro in dbobj_mro):
|
||||
raise Exception("dbobj is not a TypedObject: %s: %s" % (dbobj_cls, dbobj_mro))
|
||||
|
||||
# store the reference to the database model instance
|
||||
SA(self, 'dbobj', dbobj)
|
||||
_SA(self, 'dbobj', dbobj)
|
||||
|
||||
def __getattribute__(self, propname):
|
||||
"""
|
||||
|
|
@ -93,25 +93,25 @@ class TypeClass(object):
|
|||
accessible through getattr.
|
||||
"""
|
||||
if propname == 'dbobj':
|
||||
return GA(self, 'dbobj')
|
||||
return _GA(self, 'dbobj')
|
||||
if propname.startswith('__') and propname.endswith('__'):
|
||||
# python specials are parsed as-is (otherwise things like
|
||||
# isinstance() fail to identify the typeclass)
|
||||
return GA(self, propname)
|
||||
return _GA(self, propname)
|
||||
#print "get %s (dbobj:%s)" % (propname, type(dbobj))
|
||||
try:
|
||||
return GA(self, propname)
|
||||
return _GA(self, propname)
|
||||
except AttributeError:
|
||||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
dbobj = _GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
log_trace("Typeclass CRITICAL ERROR! dbobj not found for Typeclass %s!" % self)
|
||||
raise
|
||||
try:
|
||||
return GA(dbobj, propname)
|
||||
return _GA(dbobj, propname)
|
||||
except AttributeError:
|
||||
try:
|
||||
return GA(dbobj,"get_attribute_raise")(propname)
|
||||
return _GA(dbobj,"get_attribute_raise")(propname)
|
||||
except AttributeError:
|
||||
string = "Object: '%s' not found on %s(%s), nor on its typeclass %s."
|
||||
raise AttributeError(string % (propname, dbobj, dbobj.dbref, dbobj.typeclass_path))
|
||||
|
|
@ -132,7 +132,7 @@ class TypeClass(object):
|
|||
return
|
||||
|
||||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
dbobj = _GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
dbobj = None
|
||||
log_trace("This is probably due to an unsafe reload.")
|
||||
|
|
@ -141,19 +141,19 @@ class TypeClass(object):
|
|||
try:
|
||||
# only set value on propname if propname already exists
|
||||
# on dbobj. __getattribute__ will raise attribute error otherwise.
|
||||
GA(dbobj, propname)
|
||||
SA(dbobj, propname, value)
|
||||
_GA(dbobj, propname)
|
||||
_SA(dbobj, propname, value)
|
||||
except AttributeError:
|
||||
dbobj.set_attribute(propname, value)
|
||||
else:
|
||||
SA(self, propname, value)
|
||||
_SA(self, propname, value)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
dbobj-recognized comparison
|
||||
"""
|
||||
try:
|
||||
return other == self or other == GA(self, dbobj) or other == GA(self, dbobj).user
|
||||
return other == self or other == _GA(self, dbobj) or other == _GA(self, dbobj).user
|
||||
except AttributeError:
|
||||
# if self.dbobj.user fails it means the two previous comparisons failed already
|
||||
return False
|
||||
|
|
@ -172,11 +172,11 @@ class TypeClass(object):
|
|||
return
|
||||
|
||||
try:
|
||||
DA(self, propname)
|
||||
_DA(self, propname)
|
||||
except AttributeError:
|
||||
# not on typeclass, try to delete on db/ndb
|
||||
try:
|
||||
dbobj = GA(self, 'dbobj')
|
||||
dbobj = _GA(self, 'dbobj')
|
||||
except AttributeError:
|
||||
log_trace("This is probably due to an unsafe reload.")
|
||||
return # ignore delete
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue