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()) obj = self.caller.search(self.args.strip())
if not obj: if not obj:
return return
print "obj", "self.obj", obj, self
if obj != self.obj: if obj != self.obj:
self.caller.msg("Try as you might, you cannot climb that.") self.caller.msg("Try as you might, you cannot climb that.")
return return

View file

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

View file

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

View file

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

View file

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

View file

@ -27,9 +27,9 @@ Common examples of uses of Scripts:
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.core.exceptions import ObjectDoesNotExist 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.scripts.manager import ScriptManager
from src.utils.utils import dbref, to_str, LazyLoadHandler from src.utils.utils import dbref, to_str
__all__ = ("ScriptDB",) __all__ = ("ScriptDB",)
_GA = object.__getattribute__ _GA = object.__getattribute__
@ -108,13 +108,6 @@ class ScriptDB(TypedObject):
"Define Django meta options" "Define Django meta options"
verbose_name = "Script" 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 # ScriptDB class properties

View file

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

View file

@ -34,7 +34,6 @@ import weakref
from django.db import models from django.db import models
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings from django.conf import settings
from django.db.models import Q
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -48,7 +47,7 @@ from src.typeclasses import managers
from src.locks.lockhandler import LockHandler from src.locks.lockhandler import LockHandler
from src.utils import logger from src.utils import logger
from src.utils.utils import ( 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.dbserialize import to_pickle, from_pickle
from src.utils.picklefield import PickledObjectField from src.utils.picklefield import PickledObjectField
@ -132,12 +131,9 @@ class Attribute(SharedMemoryModel):
# Database manager # Database manager
objects = managers.AttributeManager() objects = managers.AttributeManager()
# Lock handler self.locks @lazy_property
def __init__(self, *args, **kwargs): def locks(self):
"Initializes the parent first -important!" return LockHandler(self)
#SharedMemoryModel.__init__(self, *args, **kwargs)
super(Attribute, self).__init__(*args, **kwargs)
self.locks = LazyLoadHandler(self, "locks", LockHandler)
class Meta: class Meta:
"Define Django meta options" "Define Django meta options"
@ -801,15 +797,33 @@ class TypedObject(SharedMemoryModel):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"We must initialize the parent first - important!" "We must initialize the parent first - important!"
super(TypedObject, self).__init__(*args, **kwargs) super(TypedObject, self).__init__(*args, **kwargs)
#SharedMemoryModel.__init__(self, *args, **kwargs)
_SA(self, "dbobj", self) # this allows for self-reference _SA(self, "dbobj", self) # this allows for self-reference
_SA(self, "locks", LazyLoadHandler(self, "locks", LockHandler))
_SA(self, "tags", LazyLoadHandler(self, "tags", TagHandler)) # initialize all handlers in a lazy fashion
_SA(self, "aliases", LazyLoadHandler(self, "aliases", AliasHandler)) @lazy_property
_SA(self, "permissions", LazyLoadHandler(self, "permissions", PermissionHandler)) def attributes(self):
_SA(self, "attributes", LazyLoadHandler(self, "attributes", AttributeHandler)) return AttributeHandler(self)
_SA(self, "nattributes", NAttributeHandler(self))
#_SA(self, "nattributes", LazyLoadHandler(self, "nattributes", NAttributeHandler)) @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: class Meta:
""" """
@ -1276,13 +1290,10 @@ class TypedObject(SharedMemoryModel):
if not TICKER_HANDLER: if not TICKER_HANDLER:
from src.scripts.tickerhandler import TICKER_HANDLER from src.scripts.tickerhandler import TICKER_HANDLER
TICKER_HANDLER.remove(self) # removes objects' all ticker subscriptions TICKER_HANDLER.remove(self) # removes objects' all ticker subscriptions
if not isinstance(_GA(self, "permissions"), LazyLoadHandler): _GA(self, "permissions").clear()
_GA(self, "permissions").clear() _GA(self, "attributes").clear()
if not isinstance(_GA(self, "attributes"), LazyLoadHandler): _GA(self, "aliases").clear()
_GA(self, "attributes").clear() if hasattr(self, "nicks"):
if not isinstance(_GA(self, "aliases"), LazyLoadHandler):
_GA(self, "aliases").clear()
if hasattr(self, "nicks") and not isinstance(_GA(self, "nicks"), LazyLoadHandler):
_GA(self, "nicks").clear() _GA(self, "nicks").clear()
_SA(self, "_cached_typeclass", None) _SA(self, "_cached_typeclass", None)
_GA(self, "flush_from_cache")() _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()]) size = getsizeof(obj) + sum([p[1] for p in sizedict.values()])
return size return size
# lazy load handlers # lazy load handler
_missing = object()
import weakref class lazy_property(object):
class LazyLoadHandler(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): def __init__(self, func, name=None, doc=None):
""" "Store all properties for now"
Set up a delayed load of a class. The 'name' must be named the self.__name__ = name or func.__name__
same as the variable to which the LazyLoadHandler is assigned. self.__module__ = func.__module__
""" self.__doc__ = doc or func.__doc__
_SA(self, "obj", weakref.ref(obj)) self.func = func
_SA(self, "name", name)
_SA(self, "cls", cls)
_SA(self, "args", args)
def _instantiate(self): def __get__(self, obj, type=None):
""" "Triggers initialization"
Initialize handler as cls(obj, *args) if obj is None:
""" return self
obj = _GA(self, "obj")() value = obj.__dict__.get(self.__name__, _missing)
instance = _GA(self, "cls")(weakref.proxy(obj), *_GA(self, "args")) if value is _missing:
_SA(obj, _GA(self, "name"), instance) value = self.func(obj)
return instance obj.__dict__[self.__name__] = value
return value
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