Implemented typeclass deleting; you can now do del obj.testval and expect the underlying attribute to be safely deleted from the database. Also fixed some reference errors when assigning to db/ndb properties on objects. Resolves issue 116. Fixed a bug in the command-testing system, so the few command tests that are defined should all work now.

This commit is contained in:
Griatch 2011-02-05 18:06:18 +00:00
parent 19538ff00b
commit 45941e0c69
6 changed files with 76 additions and 33 deletions

View file

@ -43,7 +43,7 @@ class FakeSession(session.Session):
def lineReceived(self, raw_string):
pass
def msg(self, message, data=None):
if VERBOSE:
if VERBOSE:
print message
class CommandTest(TestCase):
@ -60,11 +60,11 @@ class CommandTest(TestCase):
# create a faux player/character for testing.
self.char1 = create.create_player("TestingPlayer", "testplayer@test.com", "testpassword", location=self.room1)
self.char1.player.user.is_superuser = True
self.char1.player.user.is_superuser = True
sess = FakeSession()
sess.connectionMade()
sess.login(self.char1.player)
sess.session_login(self.char1.player)
# create second player and some objects
self.char2 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="char2", location=self.room1)
self.obj1 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj1", location=self.room1)
self.obj2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=self.room1)
@ -90,12 +90,15 @@ class CommandTest(TestCase):
This also mangles the input in various ways to test if the command
will be fooled.
"""
test1 = re.sub(r'\s', '', raw_string) # remove all whitespace inside it
test2 = "%s/åäö öäö;-:$£@*~^' 'test" % raw_string # inserting weird characters in call
test3 = "%s %s" % (raw_string, raw_string) # multiple calls
self.char1.execute_cmd(test1)
self.char1.execute_cmd(test2)
self.char1.execute_cmd(test3)
if not VERBOSE:
# only mangle if not VERBOSE, to make fewer return lines
test1 = re.sub(r'\s', '', raw_string) # remove all whitespace inside it
test2 = "%s/åäö öäö;-:$£@*~^' 'test" % raw_string # inserting weird characters in call
test3 = "%s %s" % (raw_string, raw_string) # multiple calls
self.char1.execute_cmd(test1)
self.char1.execute_cmd(test2)
self.char1.execute_cmd(test3)
# actual call
self.char1.execute_cmd(raw_string)
#------------------------------------------------------------
@ -104,6 +107,7 @@ class CommandTest(TestCase):
class TestHome(CommandTest):
def test_call(self):
self.char1.location = self.room1
self.char1.home = self.room2
self.execute_cmd("home")
self.assertEqual(self.char1.location, self.room2)

View file

@ -133,7 +133,7 @@ class SessionBase(object):
SESSIONS.add_loggedin_session(self)
#call hook
self.at_login()
self.at_login(player)
def session_disconnect(self):
"""

View file

@ -90,12 +90,12 @@ class TelnetProtocol(StatefulTelnetProtocol, session.Session):
string = ansi.parse_ansi(screen.text)
self.at_data_out(string)
def at_login(self):
def at_login(self, player):
"""
Called after authentication. self.logged_in=True at this point.
"""
if self.player.has_attribute('telnet_markup'):
self.telnet_markup = self.player.get_attribute("telnet_markup")
if player.has_attribute('telnet_markup'):
self.telnet_markup = player.get_attribute("telnet_markup")
else:
self.telnet_markup = True

View file

@ -231,12 +231,12 @@ class WebClientSession(session.Session):
#string = parse_html(screen.text)
self.at_data_out(screen.text)
def at_login(self):
def at_login(self, player):
"""
Called after authentication. self.logged_in=True at this point.
"""
if self.player.has_attribute('telnet_markup'):
self.telnet_markup = self.player.get_attribute("telnet_markup")
if player.has_attribute('telnet_markup'):
self.telnet_markup = player.get_attribute("telnet_markup")
else:
self.telnet_markup = True

View file

@ -789,7 +789,7 @@ class TypedObject(SharedMemoryModel):
logger.log_trace()
return default
return attrib.value
else:
else:
return default
def del_attribute(self, attribute_name):
@ -863,14 +863,14 @@ class TypedObject(SharedMemoryModel):
def __init__(self, obj):
object.__setattr__(self, 'obj', obj)
def __getattribute__(self, attrname):
obj = object.__getattribute__(self, 'obj')
obj = object.__getattribute__(self, 'obj')
if attrname == 'all':
# we allow for overwriting the all() method
# with an attribute named 'all'.
attr = obj.get_attribute("all")
if attr:
return attr
return object.__getattribute__(self, 'all')
return object.__getattribute__(self, 'all')
return obj.get_attribute(attrname)
def __setattr__(self, attrname, value):
obj = object.__getattribute__(self, 'obj')

View file

@ -25,7 +25,6 @@ try:
except AttributeError:
FULL_PERSISTENCE = True
class MetaTypeClass(type):
"""
This metaclass just makes sure the class object gets
@ -116,13 +115,15 @@ class TypeClass(object):
return object.__getattribute__(self, propname)
except AttributeError:
try:
if FULL_PERSISTENCE and propname != 'ndb':
db = object.__getattribute__(dbobj, 'db')
value = object.__getattribute__(db, propname)
if FULL_PERSISTENCE and propname != 'ndb':
if not dbobj.has_attribute(propname):
raise AttributeError
else:
value = dbobj.get_attribute(propname)
else:
# Not FULL_PERSISTENCE
ndb = object.__getattribute__(dbobj, 'ndb')
value = object.__getattribute__(ndb, propname)
value = getattr(ndb, propname)
return value
except AttributeError:
string = "Object: '%s' not found on %s(%s), nor on its typeclass %s."
@ -157,17 +158,14 @@ class TypeClass(object):
if dbobj: # and hasattr(dbobj, propname):
#print " ---> dbobj"
if hasattr(dbobj, propname):
# if attr already exists on dbobj, assign to it.
# only if attr already exists on dbobj, assign to it.
object.__setattr__(dbobj, propname, value)
elif FULL_PERSISTENCE:
#print "full __setattr__1", propname
db = object.__getattribute__(dbobj, 'db')
#print "full __setattr__2", propname
object.__setattr__(db, propname, value)
else:
dbobj.set_attribute(propname, value)
else:
# not FULL_PERSISTENCE
ndb = object.__getattribute__(dbobj, 'ndb')
object.__setattr__(ndb, propname, value)
setattr(ndb, propname, value)
else:
object.__setattr__(self, propname, value)
@ -179,7 +177,48 @@ class TypeClass(object):
return other == self or other == self.dbobj or other == self.dbobj.user
else:
return other == self or other == self.dbobj
def __delattr__(self, propname):
"""
Transparently deletes data from the typeclass or dbobj by first searching on the typeclass,
secondly on the dbobj.db or ndb depending on FULL_PERSISTENCE setting.
Will not allow deletion of properties stored directly on dbobj.
"""
try:
protected = object.__getattribute__(self, '_protected_attrs')
except AttributeError:
protected = PROTECTED
logger.log_trace("Thiis is probably due to an unsafe reload.")
if propname in protected:
string = "%s: '%s' is a protected attribute name."
string += " (protected: [%s])" % (", ".join(protected))
logger.log_errmsg(string % (self.name, propname))
else:
try:
object.__delattr__(self, propname)
except AttributeError:
# not on typeclass, try to delete on db/ndb
try:
dbobj = object.__getattribute__(self, 'dbobj')
except AttributeError:
logger.log_trace("This is probably due to an unsafe reload.")
return # ignore delete
try:
if FULL_PERSISTENCE:
if not dbobj.has_attribute(propname):
raise AttributeError
dbobj.del_attribute(propname)
else:
ndb = object.__getattribute__(dbobj, 'ndb')
ndb.__delattr__(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,))
def __str__(self):
"represent the object"
return self.key