Completely refactored the Attribute Refactor into a single fresh branch.

This commit is contained in:
Andrew Bastien 2020-04-13 15:48:38 -07:00
parent 770d2e6b43
commit 43ce2285a5
6 changed files with 733 additions and 517 deletions

View file

@ -32,7 +32,7 @@ from evennia.server.signals import (
SIGNAL_OBJECT_POST_PUPPET, SIGNAL_OBJECT_POST_PUPPET,
SIGNAL_OBJECT_POST_UNPUPPET, SIGNAL_OBJECT_POST_UNPUPPET,
) )
from evennia.typeclasses.attributes import NickHandler from evennia.typeclasses.attributes import NickHandler, ModelAttributeBackend
from evennia.scripts.scripthandler import ScriptHandler from evennia.scripts.scripthandler import ScriptHandler
from evennia.commands.cmdsethandler import CmdSetHandler from evennia.commands.cmdsethandler import CmdSetHandler
from evennia.utils.optionhandler import OptionHandler from evennia.utils.optionhandler import OptionHandler
@ -199,7 +199,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
@lazy_property @lazy_property
def nicks(self): def nicks(self):
return NickHandler(self) return NickHandler(self, ModelAttributeBackend)
@lazy_property @lazy_property
def sessions(self): def sessions(self):

View file

@ -12,7 +12,7 @@ from collections import defaultdict
from django.conf import settings from django.conf import settings
from evennia.typeclasses.models import TypeclassBase from evennia.typeclasses.models import TypeclassBase
from evennia.typeclasses.attributes import NickHandler from evennia.typeclasses.attributes import NickHandler, ModelAttributeBackend
from evennia.objects.manager import ObjectManager from evennia.objects.manager import ObjectManager
from evennia.objects.models import ObjectDB from evennia.objects.models import ObjectDB
from evennia.scripts.scripthandler import ScriptHandler from evennia.scripts.scripthandler import ScriptHandler
@ -225,7 +225,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
@lazy_property @lazy_property
def nicks(self): def nicks(self):
return NickHandler(self) return NickHandler(self, ModelAttributeBackend)
@lazy_property @lazy_property
def sessions(self): def sessions(self):

View file

@ -6,7 +6,6 @@ connection actually happens (so it's the same for telnet, web, ssh etc).
It is stored on the Server side (as opposed to protocol-specific sessions which It is stored on the Server side (as opposed to protocol-specific sessions which
are stored on the Portal side) are stored on the Portal side)
""" """
import weakref
import time import time
from django.utils import timezone from django.utils import timezone
from django.conf import settings from django.conf import settings
@ -16,6 +15,7 @@ from evennia.utils.utils import make_iter, lazy_property
from evennia.commands.cmdsethandler import CmdSetHandler from evennia.commands.cmdsethandler import CmdSetHandler
from evennia.server.session import Session from evennia.server.session import Session
from evennia.scripts.monitorhandler import MONITOR_HANDLER from evennia.scripts.monitorhandler import MONITOR_HANDLER
from evennia.typeclasses.attributes import AttributeHandler, InMemoryAttributeBackend, DbHolder
_GA = object.__getattribute__ _GA = object.__getattribute__
_SA = object.__setattr__ _SA = object.__setattr__
@ -25,124 +25,6 @@ _ANSI = None
# i18n # i18n
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
# Handlers for Session.db/ndb operation
class NDbHolder(object):
"""Holder for allowing property access of attributes"""
def __init__(self, obj, name, manager_name="attributes"):
_SA(self, name, _GA(obj, manager_name))
_SA(self, "name", name)
def __getattribute__(self, attrname):
if attrname == "all":
# we allow to overload our default .all
attr = _GA(self, _GA(self, "name")).get("all")
return attr if attr else _GA(self, "all")
return _GA(self, _GA(self, "name")).get(attrname)
def __setattr__(self, attrname, value):
_GA(self, _GA(self, "name")).add(attrname, value)
def __delattr__(self, attrname):
_GA(self, _GA(self, "name")).remove(attrname)
def get_all(self):
return _GA(self, _GA(self, "name")).all()
all = property(get_all)
class NAttributeHandler(object):
"""
NAttributeHandler version without recache protection.
This stand-alone handler manages non-database saving.
It is similar to `AttributeHandler` and is used
by the `.ndb` handler in the same way as `.db` does
for the `AttributeHandler`.
"""
def __init__(self, obj):
"""
Initialized on the object
"""
self._store = {}
self.obj = weakref.proxy(obj)
def has(self, key):
"""
Check if object has this attribute or not.
Args:
key (str): The Nattribute key to check.
Returns:
has_nattribute (bool): If Nattribute is set or not.
"""
return key in self._store
def get(self, key, default=None):
"""
Get the named key value.
Args:
key (str): The Nattribute key to get.
Returns:
the value of the Nattribute.
"""
return self._store.get(key, default)
def add(self, key, value):
"""
Add new key and value.
Args:
key (str): The name of Nattribute to add.
value (any): The value to store.
"""
self._store[key] = value
def remove(self, key):
"""
Remove Nattribute from storage.
Args:
key (str): The name of the Nattribute to remove.
"""
if key in self._store:
del self._store[key]
def clear(self):
"""
Remove all NAttributes from handler.
"""
self._store = {}
def all(self, return_tuples=False):
"""
List the contents of the handler.
Args:
return_tuples (bool, optional): Defines if the Nattributes
are returns as a list of keys or as a list of `(key, value)`.
Returns:
nattributes (list): A list of keys `[key, key, ...]` or a
list of tuples `[(key, value), ...]` depending on the
setting of `return_tuples`.
"""
if return_tuples:
return [(key, value) for (key, value) in self._store.items() if not key.startswith("_")]
return [key for key in self._store if not key.startswith("_")]
# ------------------------------------------------------------- # -------------------------------------------------------------
# Server Session # Server Session
@ -175,6 +57,10 @@ class ServerSession(Session):
cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set) cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set)
@property
def id(self):
return self.sessid
def at_sync(self): def at_sync(self):
""" """
This is called whenever a session has been resynced with the This is called whenever a session has been resynced with the
@ -490,7 +376,7 @@ class ServerSession(Session):
@lazy_property @lazy_property
def nattributes(self): def nattributes(self):
return NAttributeHandler(self) return AttributeHandler(self, InMemoryAttributeBackend)
@lazy_property @lazy_property
def attributes(self): def attributes(self):
@ -508,7 +394,7 @@ class ServerSession(Session):
try: try:
return self._ndb_holder return self._ndb_holder
except AttributeError: except AttributeError:
self._ndb_holder = NDbHolder(self, "nattrhandler", manager_name="nattributes") self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes")
return self._ndb_holder return self._ndb_holder
# @ndb.setter # @ndb.setter

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,8 @@ from django.urls import reverse
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.text import slugify from django.utils.text import slugify
from evennia.typeclasses.attributes import Attribute, AttributeHandler, NAttributeHandler from evennia.typeclasses.attributes import Attribute, AttributeHandler, ModelAttributeBackend, InMemoryAttributeBackend
from evennia.typeclasses.attributes import DbHolder
from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler
from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase
@ -121,33 +122,6 @@ class TypeclassBase(SharedMemoryModelBase):
signals.pre_delete.connect(remove_attributes_on_delete, sender=new_class) signals.pre_delete.connect(remove_attributes_on_delete, sender=new_class)
return new_class return new_class
class DbHolder(object):
"Holder for allowing property access of attributes"
def __init__(self, obj, name, manager_name="attributes"):
_SA(self, name, _GA(obj, manager_name))
_SA(self, "name", name)
def __getattribute__(self, attrname):
if attrname == "all":
# we allow to overload our default .all
attr = _GA(self, _GA(self, "name")).get("all")
return attr if attr else _GA(self, "all")
return _GA(self, _GA(self, "name")).get(attrname)
def __setattr__(self, attrname, value):
_GA(self, _GA(self, "name")).add(attrname, value)
def __delattr__(self, attrname):
_GA(self, _GA(self, "name")).remove(attrname)
def get_all(self):
return _GA(self, _GA(self, "name")).all()
all = property(get_all)
# #
# Main TypedObject abstraction # Main TypedObject abstraction
# #
@ -301,7 +275,7 @@ class TypedObject(SharedMemoryModel):
# initialize all handlers in a lazy fashion # initialize all handlers in a lazy fashion
@lazy_property @lazy_property
def attributes(self): def attributes(self):
return AttributeHandler(self) return AttributeHandler(self, ModelAttributeBackend)
@lazy_property @lazy_property
def locks(self): def locks(self):
@ -321,7 +295,7 @@ class TypedObject(SharedMemoryModel):
@lazy_property @lazy_property
def nattributes(self): def nattributes(self):
return NAttributeHandler(self) return AttributeHandler(self, InMemoryAttributeBackend)
class Meta(object): class Meta(object):
""" """

View file

@ -26,12 +26,12 @@ class TestAttributes(EvenniaTest):
key = "testattr" key = "testattr"
value = "test attr value " value = "test attr value "
self.obj1.attributes.add(key, value) self.obj1.attributes.add(key, value)
self.assertFalse(self.obj1.attributes._cache) self.assertFalse(self.obj1.attributes.backend._cache)
self.assertEqual(self.obj1.attributes.get(key), value) self.assertEqual(self.obj1.attributes.get(key), value)
self.obj1.db.testattr = value self.obj1.db.testattr = value
self.assertEqual(self.obj1.db.testattr, value) self.assertEqual(self.obj1.db.testattr, value)
self.assertFalse(self.obj1.attributes._cache) self.assertFalse(self.obj1.attributes.backend._cache)
def test_weird_text_save(self): def test_weird_text_save(self):
"test 'weird' text type (different in py2 vs py3)" "test 'weird' text type (different in py2 vs py3)"