Changed how lazy-loading of handlers work, using a werkzeug recipe. Much more efficient now.

This commit is contained in:
Griatch 2014-07-06 13:10:03 +02:00
parent 680e603c4d
commit e6950aadf2
10 changed files with 125 additions and 144 deletions

View file

@ -141,7 +141,6 @@ class CmdClimb(Command):
obj = self.caller.search(self.args.strip())
if not obj:
return
print "obj", "self.obj", obj, self
if obj != self.obj:
self.caller.msg("Try as you might, you cannot climb that.")
return

View file

@ -7,7 +7,7 @@ All commands in Evennia inherit from the 'Command' class in this module.
import re
from src.locks.lockhandler import LockHandler
from src.utils.utils import is_iter, fill, LazyLoadHandler
from src.utils.utils import is_iter, fill, lazy_property
def _init_command(mcs, **kwargs):
@ -155,7 +155,10 @@ class Command(object):
overloading evential same-named class properties."""
if kwargs:
_init_command(self, **kwargs)
self.lockhandler = LazyLoadHandler(self, "lockhandler", LockHandler)
@lazy_property
def lockhandler(self):
return LockHandler(self)
def __str__(self):
"Print the command"

View file

@ -27,7 +27,7 @@ from src.utils.idmapper.models import SharedMemoryModel
from src.comms import managers
from src.comms.managers import identify_object
from src.locks.lockhandler import LockHandler
from src.utils.utils import crop, make_iter, LazyLoadHandler
from src.utils.utils import crop, make_iter, lazy_property
__all__ = ("Msg", "TempMsg", "ChannelDB")
@ -103,7 +103,6 @@ class Msg(SharedMemoryModel):
def __init__(self, *args, **kwargs):
SharedMemoryModel.__init__(self, *args, **kwargs)
#_SA(self, "locks", LazyLoadHandler(self, "locks", LockHandler))
self.extra_senders = []
class Meta:
@ -299,10 +298,13 @@ class TempMsg(object):
self.header = header
self.message = message
self.lock_storage = lockstring
self.locks = LazyLoadHandler(self, "locks", LockHandler)
self.hide_from = hide_from and make_iter(hide_from) or []
self.date_sent = datetime.now()
@lazy_property
def locks(self):
return LockHandler(self)
def __str__(self):
"This handles what is shown when e.g. printing the message"
senders = ",".join(obj.key for obj in self.senders)
@ -359,12 +361,6 @@ class ChannelDB(TypedObject):
_typeclass_paths = settings.CHANNEL_TYPECLASS_PATHS
_default_typeclass_path = settings.BASE_CHANNEL_TYPECLASS or "src.comms.comms.Channel"
def __init__(self, *args, **kwargs):
TypedObject.__init__(self, *args, **kwargs)
_SA(self, "tags", LazyLoadHandler(self, "tags", TagHandler))
_SA(self, "attributes", LazyLoadHandler(self, "attributes", AttributeHandler))
_SA(self, "aliases", LazyLoadHandler(self, "aliases", AliasHandler))
class Meta:
"Define Django meta options"
verbose_name = "Channel"

View file

@ -14,7 +14,7 @@ from src.utils.idmapper.models import SharedMemoryModel
from src.help.manager import HelpEntryManager
from src.typeclasses.models import Tag, TagHandler
from src.locks.lockhandler import LockHandler
from src.utils.utils import LazyLoadHandler
from src.utils.utils import lazy_property
__all__ = ("HelpEntry",)
@ -66,10 +66,16 @@ class HelpEntry(SharedMemoryModel):
objects = HelpEntryManager()
_is_deleted = False
def __init__(self, *args, **kwargs):
SharedMemoryModel.__init__(self, *args, **kwargs)
self.locks = LazyLoadHandler(self, "locks", LockHandler)
self.tags = LazyLoadHandler(self, "tags", TagHandler)
# lazy-loaded handlers
@lazy_property
def locks(self):
return LockHandler(self)
@lazy_property
def tags(self):
return TagHandler(self)
class Meta:
"Define Django meta options"

View file

@ -19,16 +19,15 @@ from django.db import models
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from src.typeclasses.models import (TypedObject, TagHandler, NickHandler,
AliasHandler, AttributeHandler)
from src.typeclasses.models import TypedObject, NickHandler
from src.objects.manager import ObjectManager
from src.players.models import PlayerDB
from src.commands.cmdsethandler import CmdSetHandler
from src.commands import cmdhandler
from src.scripts.scripthandler import ScriptHandler
from src.utils import logger
from src.utils.utils import (make_iter, to_str, to_unicode,
variable_from_module, dbref, LazyLoadHandler)
from src.utils.utils import (make_iter, to_str, to_unicode, lazy_property,
variable_from_module, dbref)
from django.utils.translation import ugettext as _
@ -130,19 +129,18 @@ class ObjectDB(TypedObject):
_typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
_default_typeclass_path = settings.BASE_OBJECT_TYPECLASS or "src.objects.objects.Object"
# Add the object-specific handlers
def __init__(self, *args, **kwargs):
"Parent must be initialized first."
TypedObject.__init__(self, *args, **kwargs)
# handlers
_SA(self, "cmdset", LazyLoadHandler(self, "cmdset", CmdSetHandler, True))
_SA(self, "scripts", LazyLoadHandler(self, "scripts", ScriptHandler))
_SA(self, "nicks", LazyLoadHandler(self, "nicks", NickHandler))
#_SA(self, "attributes", LazyLoadHandler(self, "attributes", AttributeHandler))
#_SA(self, "tags", LazyLoadHandler(self, "tags", TagHandler))
#_SA(self, "aliases", LazyLoadHandler(self, "aliases", AliasHandler))
# make sure to sync the contents cache when initializing
#_GA(self, "contents_update")()
# lazy-load handlers
@lazy_property
def cmdset(self):
return CmdSetHandler(self, True)
@lazy_property
def scripts(self):
return ScriptHandler(self)
@lazy_property
def nicks(self):
return NickHandler(self)
def _at_db_player_postsave(self):
"""

View file

@ -23,13 +23,12 @@ from django.utils.encoding import smart_str
from src.players import manager
from src.scripts.models import ScriptDB
from src.typeclasses.models import (TypedObject, TagHandler, NickHandler,
AliasHandler, AttributeHandler)
from src.typeclasses.models import (TypedObject, NickHandler)
from src.scripts.scripthandler import ScriptHandler
from src.commands.cmdsethandler import CmdSetHandler
from src.commands import cmdhandler
from src.utils import utils, logger
from src.utils.utils import to_str, make_iter, LazyLoadHandler
from src.utils.utils import to_str, make_iter, lazy_property
from django.utils.translation import ugettext as _
@ -111,15 +110,19 @@ class PlayerDB(TypedObject, AbstractUser):
app_label = 'players'
verbose_name = 'Player'
def __init__(self, *args, **kwargs):
"Parent must be initiated first"
TypedObject.__init__(self, *args, **kwargs)
# handlers
_SA(self, "cmdset", LazyLoadHandler(self, "cmdset", CmdSetHandler, True))
_SA(self, "scripts", LazyLoadHandler(self, "scripts", ScriptHandler))
_SA(self, "nicks", LazyLoadHandler(self, "nicks", NickHandler))
#_SA(self, "tags", LazyLoadHandler(self, "tags", TagHandler))
#_SA(self, "aliases", LazyLoadHandler(self, "aliases", AliasHandler))
# lazy-loading of handlers
@lazy_property
def cmdset(self):
return CmdSetHandler(self, True)
@lazy_property
def scripts(self):
return ScriptHandler(self)
@lazy_property
def nicks(self):
return NickHandler(self)
# alias to the objs property
def __characters_get(self):

View file

@ -27,9 +27,9 @@ Common examples of uses of Scripts:
from django.conf import settings
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
from src.typeclasses.models import TypedObject, TagHandler, AttributeHandler
from src.typeclasses.models import TypedObject
from src.scripts.manager import ScriptManager
from src.utils.utils import dbref, to_str, LazyLoadHandler
from src.utils.utils import dbref, to_str
__all__ = ("ScriptDB",)
_GA = object.__getattribute__
@ -108,13 +108,6 @@ class ScriptDB(TypedObject):
"Define Django meta options"
verbose_name = "Script"
def __init__(self, *args, **kwargs):
super(ScriptDB, self).__init__(*args, **kwargs)
_SA(self, "attributes", LazyLoadHandler(self, "attributes", AttributeHandler))
_SA(self, "tags", LazyLoadHandler(self, "tags", TagHandler))
#_SA(self, "aliases", AliasHandler(self))
#
#
# ScriptDB class properties

View file

@ -13,8 +13,9 @@ from django.conf import settings
#from src.scripts.models import ScriptDB
from src.comms.models import ChannelDB
from src.utils import logger, utils
from src.utils.utils import make_iter, to_unicode, LazyLoadHandler
from src.commands import cmdhandler, cmdsethandler
from src.utils.utils import make_iter, to_unicode
from src.commands.cmdhandler import cmdhandler
from src.commands.cmdsethandler import CmdSetHandler
from src.server.session import Session
IDLE_COMMAND = settings.IDLE_COMMAND
@ -49,7 +50,7 @@ class ServerSession(Session):
self.puppet = None
self.player = None
self.cmdset_storage_string = ""
self.cmdset = LazyLoadHandler(self, "cmdset", cmdsethandler.CmdSetHandler, True)
self.cmdset = CmdSetHandler(self, True)
def __cmdset_storage_get(self):
return [path.strip() for path in self.cmdset_storage_string.split(',')]
@ -103,7 +104,7 @@ class ServerSession(Session):
self.player.save()
# add the session-level cmdset
self.cmdset = LazyLoadHandler(self, "cmdset", cmdsethandler.CmdSetHandler, True)
self.cmdset = CmdSetHandler(self, True)
def at_disconnect(self):
"""
@ -198,7 +199,7 @@ class ServerSession(Session):
else:
text = self.player.nicks.nickreplace(text,
categories=("inputline", "channels"), include_player=False)
cmdhandler.cmdhandler(self, text, callertype="session", sessid=self.sessid)
cmdhandler(self, text, callertype="session", sessid=self.sessid)
self.update_session_counters()
if "oob" in kwargs:
# handle oob instructions

View file

@ -34,7 +34,6 @@ import weakref
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.db.models import Q
from django.utils.encoding import smart_str
from django.contrib.contenttypes.models import ContentType
@ -48,7 +47,7 @@ from src.typeclasses import managers
from src.locks.lockhandler import LockHandler
from src.utils import logger
from src.utils.utils import (
make_iter, is_iter, to_str, inherits_from, LazyLoadHandler)
make_iter, is_iter, to_str, inherits_from, lazy_property)
from src.utils.dbserialize import to_pickle, from_pickle
from src.utils.picklefield import PickledObjectField
@ -132,12 +131,9 @@ class Attribute(SharedMemoryModel):
# Database manager
objects = managers.AttributeManager()
# Lock handler self.locks
def __init__(self, *args, **kwargs):
"Initializes the parent first -important!"
#SharedMemoryModel.__init__(self, *args, **kwargs)
super(Attribute, self).__init__(*args, **kwargs)
self.locks = LazyLoadHandler(self, "locks", LockHandler)
@lazy_property
def locks(self):
return LockHandler(self)
class Meta:
"Define Django meta options"
@ -801,15 +797,33 @@ class TypedObject(SharedMemoryModel):
def __init__(self, *args, **kwargs):
"We must initialize the parent first - important!"
super(TypedObject, self).__init__(*args, **kwargs)
#SharedMemoryModel.__init__(self, *args, **kwargs)
_SA(self, "dbobj", self) # this allows for self-reference
_SA(self, "locks", LazyLoadHandler(self, "locks", LockHandler))
_SA(self, "tags", LazyLoadHandler(self, "tags", TagHandler))
_SA(self, "aliases", LazyLoadHandler(self, "aliases", AliasHandler))
_SA(self, "permissions", LazyLoadHandler(self, "permissions", PermissionHandler))
_SA(self, "attributes", LazyLoadHandler(self, "attributes", AttributeHandler))
_SA(self, "nattributes", NAttributeHandler(self))
#_SA(self, "nattributes", LazyLoadHandler(self, "nattributes", NAttributeHandler))
# initialize all handlers in a lazy fashion
@lazy_property
def attributes(self):
return AttributeHandler(self)
@lazy_property
def locks(self):
return LockHandler(self)
@lazy_property
def tags(self):
return TagHandler(self)
@lazy_property
def aliases(self):
return AliasHandler(self)
@lazy_property
def permissions(self):
return PermissionHandler(self)
@lazy_property
def nattributes(self):
return NAttributeHandler(self)
class Meta:
"""
@ -1276,13 +1290,10 @@ class TypedObject(SharedMemoryModel):
if not TICKER_HANDLER:
from src.scripts.tickerhandler import TICKER_HANDLER
TICKER_HANDLER.remove(self) # removes objects' all ticker subscriptions
if not isinstance(_GA(self, "permissions"), LazyLoadHandler):
_GA(self, "permissions").clear()
if not isinstance(_GA(self, "attributes"), LazyLoadHandler):
_GA(self, "attributes").clear()
if not isinstance(_GA(self, "aliases"), LazyLoadHandler):
_GA(self, "aliases").clear()
if hasattr(self, "nicks") and not isinstance(_GA(self, "nicks"), LazyLoadHandler):
_GA(self, "permissions").clear()
_GA(self, "attributes").clear()
_GA(self, "aliases").clear()
if hasattr(self, "nicks"):
_GA(self, "nicks").clear()
_SA(self, "_cached_typeclass", None)
_GA(self, "flush_from_cache")()

View file

@ -1060,67 +1060,38 @@ def deepsize(obj, max_depth=4):
size = getsizeof(obj) + sum([p[1] for p in sizedict.values()])
return size
# lazy load handlers
import weakref
class LazyLoadHandler(object):
# lazy load handler
_missing = object()
class lazy_property(object):
"""
Load handlers only when they are actually accessed
Delays loading of property until first access. Credit goes to
the Implementation in the werkzeug suite:
http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.cached_property
This should be used as a decorator in a class and is in Evennia
mainly used to lazy-load handlers:
@lazy_property
def attributes(self):
return AttributeHandler(self)
Once initialized, the AttributeHandler will be available
as a property "attributes" on the object.
"""
def __init__(self, obj, name, cls, *args):
"""
Set up a delayed load of a class. The 'name' must be named the
same as the variable to which the LazyLoadHandler is assigned.
"""
_SA(self, "obj", weakref.ref(obj))
_SA(self, "name", name)
_SA(self, "cls", cls)
_SA(self, "args", args)
def __init__(self, func, name=None, doc=None):
"Store all properties for now"
self.__name__ = name or func.__name__
self.__module__ = func.__module__
self.__doc__ = doc or func.__doc__
self.func = func
def _instantiate(self):
"""
Initialize handler as cls(obj, *args)
"""
obj = _GA(self, "obj")()
instance = _GA(self, "cls")(weakref.proxy(obj), *_GA(self, "args"))
_SA(obj, _GA(self, "name"), instance)
return instance
def __getattribute__(self, name):
"""
Access means loading the handler
"""
return getattr(_GA(self, "_instantiate")(), name)
def __setattr__(self, name, value):
"""
Setting means loading the handler
"""
setattr(_GA(self, "_instantiate")(), name, value)
def __delattr__(self, name):
"""
Deleting also triggers loading of handler
"""
delattr(_GA(self, "_instantiate")(), name)
def __repr__(self):
return repr(_GA(self, "_instantiate")())
def __str__(self):
return str(_GA(self, "_instantiate")())
def __unicode__(self):
return str(_GA(self, "_instantiate")())
class NonWeakLazyLoadHandler(LazyLoadHandler):
"""
Variation of LazyLoadHandler that does not
create a weak reference when initiating.
"""
def _instantiate(self):
"""
Initialize handler as cls(obj, *args)
"""
obj = _GA(self, "obj")()
instance = _GA(self, "cls")(obj, *_GA(self, "args"))
_SA(obj, _GA(self, "name"), instance)
return instance
def __get__(self, obj, type=None):
"Triggers initialization"
if obj is None:
return self
value = obj.__dict__.get(self.__name__, _missing)
if value is _missing:
value = self.func(obj)
obj.__dict__[self.__name__] = value
return value