Some optimizations, cleanup and a few bugfixes. Just changing a spurious property retrieval in the typeclass removed an extra, pointless database query.

This commit is contained in:
Griatch 2012-09-18 01:03:35 +02:00
parent 160d4a2807
commit 0dae03156c
5 changed files with 57 additions and 38 deletions

View file

@ -632,16 +632,13 @@ class ObjectDB(TypedObject):
data (object): an optional data object that may or may not data (object): an optional data object that may or may not
be used by the protocol. be used by the protocol.
""" """
# This is an important function that must always work. if _GA(self, 'player'):
# we use a different __getattribute__ to avoid recursive loops. _GA(_GA(self, 'player'), "msg")(message, from_obj=from_obj, data=data)
if object.__getattribute__(self, 'player'):
object.__getattribute__(self, 'player').msg(message, from_obj=from_obj, data=data)
def emit_to(self, message, from_obj=None, data=None): def emit_to(self, message, from_obj=None, data=None):
"Deprecated. Alias for msg" "Deprecated. Alias for msg"
logger.log_depmsg("emit_to() is deprecated. Use msg() instead.") logger.log_depmsg("emit_to() is deprecated. Use msg() instead.")
self.msg(message, from_obj, data) _GA(self, "msg")(message, from_obj, data)
def msg_contents(self, message, exclude=None, from_obj=None, data=None): def msg_contents(self, message, exclude=None, from_obj=None, data=None):
""" """

View file

@ -44,7 +44,6 @@ from django.conf import settings
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.contrib.contenttypes.models import ContentType
from src.typeclasses.models import _get_cache, _set_cache, _del_cache from src.typeclasses.models import _get_cache, _set_cache, _del_cache
from src.server.sessionhandler import SESSIONS from src.server.sessionhandler import SESSIONS
@ -64,6 +63,8 @@ _GA = object.__getattribute__
_SA = object.__setattr__ _SA = object.__setattr__
_DA = object.__delattr__ _DA = object.__delattr__
_TYPECLASS = None
#------------------------------------------------------------ #------------------------------------------------------------
# #
# PlayerAttribute # PlayerAttribute
@ -199,8 +200,11 @@ class PlayerDB(TypedObject):
#@obj.setter #@obj.setter
def obj_set(self, value): def obj_set(self, value):
"Setter. Allows for self.obj = value" "Setter. Allows for self.obj = value"
from src.typeclasses.typeclass import TypeClass global _TYPECLASS
if isinstance(value, TypeClass): if not _TYPECLASS:
from src.typeclasses.typeclass import TypeClass as _TYPECLASS
if isinstance(value, _TYPECLASS):
value = value.dbobj value = value.dbobj
try: try:
_set_cache(self, "obj", value) _set_cache(self, "obj", value)
@ -260,7 +264,6 @@ class PlayerDB(TypedObject):
#@is_connected.setter #@is_connected.setter
def is_connected_set(self, value): def is_connected_set(self, value):
"Setter. Allows for self.is_connected = value" "Setter. Allows for self.is_connected = value"
print "set_is_connected:", self, value
_set_cache(self, "is_connected", value) _set_cache(self, "is_connected", value)
#@is_connected.deleter #@is_connected.deleter
def is_connected_del(self): def is_connected_del(self):
@ -356,21 +359,19 @@ class PlayerDB(TypedObject):
Evennia -> User Evennia -> User
This is the main route for sending data back to the user from the server. This is the main route for sending data back to the user from the server.
""" """
if from_obj: if from_obj:
try: try:
from_obj.at_msg_send(outgoing_string, to_obj=self, data=data) _GA(from_obj, "at_msg_send")(outgoing_string, to_obj=self, data=data)
except Exception: except Exception:
pass pass
if (_GA(self, "character") and not
if (object.__getattribute__(self, "character") _GA(self, "character").at_msg_receive(outgoing_string, from_obj=from_obj, data=data)):
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 # the at_msg_receive() hook may block receiving of certain messages
return return
outgoing_string = utils.to_str(outgoing_string, force_string=True) outgoing_string = utils.to_str(outgoing_string, force_string=True)
for session in object.__getattribute__(self, 'sessions'): for session in _GA(self, 'sessions'):
session.msg(outgoing_string, data) session.msg(outgoing_string, data)
@ -383,8 +384,8 @@ class PlayerDB(TypedObject):
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
"Make sure to delete user also when deleting player - the two may never exist separately." "Make sure to delete user also when deleting player - the two may never exist separately."
try: try:
if self.user: if _GA(self, "user"):
self.user.delete() _GA(_GA(self, "user"), "delete")()
except AssertionError: except AssertionError:
pass pass
try: try:
@ -398,7 +399,7 @@ class PlayerDB(TypedObject):
def execute_cmd(self, raw_string): def execute_cmd(self, raw_string):
""" """
Do something as this playe. This command transparently Do something as this player. This command transparently
lets its typeclass execute the command. lets its typeclass execute the command.
raw_string - raw command input coming from the command line. raw_string - raw command input coming from the command line.
""" """
@ -423,8 +424,11 @@ class PlayerDB(TypedObject):
the Player object itself. If no Character exists (since Player is the Player object itself. If no Character exists (since Player is
OOC), None will be returned. OOC), None will be returned.
""" """
matches = self.__class__.objects.player_search(ostring) matches = _GA(_GA(_GA(self, "_class__"), "objects"), "player_search")(ostring)
matches = _AT_SEARCH_RESULT(self, ostring, matches, global_search=True) matches = _AT_SEARCH_RESULT(self, ostring, matches, global_search=True)
if matches and return_character and hasattr(matches, "character"): if matches and return_character:
return matches.character try:
return _GA(matches, "character")
except:
pass
return matches return matches

View file

@ -56,6 +56,7 @@ _DA = object.__delattr__
_PLOADS = pickle.loads _PLOADS = pickle.loads
_PDUMPS = pickle.dumps _PDUMPS = pickle.dumps
# Property Cache mechanism. # Property Cache mechanism.
def _get_cache(obj, name): def _get_cache(obj, name):
@ -889,6 +890,17 @@ class TypedObject(SharedMemoryModel):
# try to look back to this very database object.) # try to look back to this very database object.)
return _GA(_GA(self, 'typeclass'), propname) return _GA(_GA(self, 'typeclass'), propname)
def _hasattr(self, obj, attrname):
"""
Loop-safe version of hasattr, to avoid running a lookup that
will be rerouted up the typeclass. Returns True/False.
"""
try:
_GA(obj, attrname)
return True
except AttributeError:
return False
#@property #@property
_dbid_cache = None _dbid_cache = None
def __dbid_get(self): def __dbid_get(self):
@ -1504,7 +1516,7 @@ class TypedObject(SharedMemoryModel):
def nattr(self, attribute_name=None, value=None, delete=False): def nattr(self, attribute_name=None, value=None, delete=False):
""" """
This is the equivalence of self.attr but for non-persistent This is the equivalence of self.attr but for non-persistent
stores. stores. Will not raise error but return None.
""" """
if attribute_name == None: if attribute_name == None:
# act as a list method # act as a list method
@ -1515,11 +1527,11 @@ class TypedObject(SharedMemoryModel):
if not val.startswith['_']] if not val.startswith['_']]
elif delete == True: elif delete == True:
if hasattr(self.ndb, attribute_name): if hasattr(self.ndb, attribute_name):
_DA(self.db, attribute_name) _DA(_GA(self, "db"), attribute_name)
elif value == None: elif value == None:
# act as a getter. # act as a getter.
if hasattr(self.ndb, attribute_name): if hasattr(self.ndb, attribute_name):
_GA(self.ndb, attribute_name) _GA(_GA(self, "ndb"), attribute_name)
else: else:
return None return None
else: else:

View file

@ -11,7 +11,6 @@ used by the typesystem or django itself.
""" """
from src.utils.logger import log_trace, log_errmsg from src.utils.logger import log_trace, log_errmsg
from django.conf import settings
__all__ = ("TypeClass",) __all__ = ("TypeClass",)
@ -115,10 +114,11 @@ class TypeClass(object):
return _GA(dbobj, propname) return _GA(dbobj, propname)
except AttributeError: except AttributeError:
try: try:
#XXX deprecated
return _GA(dbobj,"get_attribute_raise")(propname) return _GA(dbobj,"get_attribute_raise")(propname)
except AttributeError: except AttributeError:
string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s." string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s."
raise AttributeError(string % (propname, dbobj, dbobj.dbid, dbobj.typeclass_path)) raise AttributeError(string % (propname, dbobj, _GA(dbobj, "dbid"), _GA(dbobj, "typeclass_path")))
def __setattr__(self, propname, value): def __setattr__(self, propname, value):
""" """
@ -134,7 +134,6 @@ class TypeClass(object):
string += " (protected: [%s])" % (", ".join(PROTECTED)) string += " (protected: [%s])" % (", ".join(PROTECTED))
log_errmsg(string % (self.name, propname)) log_errmsg(string % (self.name, propname))
return return
try: try:
dbobj = _GA(self, 'dbobj') dbobj = _GA(self, 'dbobj')
except AttributeError: except AttributeError:
@ -148,19 +147,20 @@ class TypeClass(object):
_GA(dbobj, propname) _GA(dbobj, propname)
_SA(dbobj, propname, value) _SA(dbobj, propname, value)
except AttributeError: except AttributeError:
#XXX deprecated
dbobj.set_attribute(propname, value) dbobj.set_attribute(propname, value)
else: else:
_SA(self, propname, value) _SA(self, propname, value)
def __eq__(self, other): def __eq__(self, other):
""" """
dbobj-recognized comparison dbobj-recognized comparison
""" """
try: 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: except AttributeError:
# if self.dbobj.user fails it means the two previous comparisons failed already # if self.dbobj.user fails it means the two previous comparisons failed already
return False return False
def __delattr__(self, propname): def __delattr__(self, propname):

View file

@ -34,7 +34,13 @@ def is_iter(iterable):
they are actually iterable), since string iterations they are actually iterable), since string iterations
are usually not what we want to do with a string. are usually not what we want to do with a string.
""" """
return hasattr(iterable, '__iter__') # use a try..except here to avoid a property
# lookup when using this from a typeclassed entity
try:
_GA(iterable, '__iter__')
return True
except AttributeError:
return False
def make_iter(obj): def make_iter(obj):
"Makes sure that the object is always iterable." "Makes sure that the object is always iterable."