diff --git a/src/commands/default/system.py b/src/commands/default/system.py index b563d03ddf..da57433416 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -214,6 +214,7 @@ def format_script_list(scripts): table.align = 'r' for script in scripts: nextrep = script.time_until_next_repeat() + print "@script:", script.key, type(script.key) table.add_row([script.id, script.obj.key if (hasattr(script, 'obj') and script.obj) else "", script.key, diff --git a/src/commands/default/tests.py b/src/commands/default/tests.py index c31019cfbd..3477e0d811 100644 --- a/src/commands/default/tests.py +++ b/src/commands/default/tests.py @@ -33,9 +33,11 @@ _RE = re.compile(r"^\+|-+\+|\+-+|--*|\|", re.MULTILINE) # Command testing # ------------------------------------------------------------ -def dummy_data_out(self, text=None, **kwargs): +def dummy(self, *args, **kwargs): pass -SESSIONS.data_out = dummy_data_out + +SESSIONS.data_out = dummy +SESSIONS.disconnect = dummy class TestObjectClass(Object): def msg(self, text="", **kwargs): @@ -46,6 +48,10 @@ class TestCharacterClass(Character): "test message" if self.player: self.player.msg(text=text, **kwargs) + else: + if not self.ndb.stored_msg: + self.ndb.stored_msg = [] + self.ndb.stored_msg.append(text) class TestPlayerClass(Player): def msg(self, text="", **kwargs): "test message" @@ -116,7 +122,8 @@ class CommandTest(TestCase): cmdobj.func() cmdobj.at_post_cmd() # clean out prettytable sugar - returned_msg = "|".join(_RE.sub("", mess) for mess in self.char1.player.ndb.stored_msg) + stored_msg = self.char1.player.ndb.stored_msg if self.char1.player else self.char1.ndb.stored_msg + returned_msg = "|".join(_RE.sub("", mess) for mess in stored_msg) #returned_msg = "|".join(self.char1.player.ndb.stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() if msg != None: @@ -189,6 +196,8 @@ class TestPlayer(CommandTest): CID = 5 def test_cmds(self): self.call(player.CmdOOCLook(), "", "Account TestPlayer5 (you are OutofCharacter)", caller=self.player) + self.call(player.CmdOOC(), "", "You are already", caller=self.player) + self.call(player.CmdIC(), "Char5","You become Char5.", caller=self.player) self.call(player.CmdPassword(), "testpassword = testpassword", "Password changed.", caller=self.player) self.call(player.CmdEncoding(), "", "Default encoding:", caller=self.player) self.call(player.CmdWho(), "", "Players:", caller=self.player) @@ -197,8 +206,6 @@ class TestPlayer(CommandTest): self.call(player.CmdColorTest(), "ansi", "ANSI colors:", caller=self.player) self.call(player.CmdCharCreate(), "Test1=Test char","Created new character Test1. Use @ic Test1 to enter the game", caller=self.player) self.call(player.CmdQuell(), "", "Quelling Player permissions (immortals). Use @unquell to get them back.", caller=self.player) - self.call(player.CmdIC(), "Char5","Char5 is now acted from another", caller=self.player) - self.call(player.CmdOOC(), "", "You are already", caller=self.player) from src.commands.default import building class TestBuilding(CommandTest): diff --git a/src/comms/models.py b/src/comms/models.py index 593c485c64..2afdb61849 100644 --- a/src/comms/models.py +++ b/src/comms/models.py @@ -523,8 +523,6 @@ class Channel(SharedMemoryModel): logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self) lock_storage = property(lock_storage_get, lock_storage_set, lock_storage_del) - db_model_name = "channel" # used by attributes to safely store objects - class Meta: "Define Django meta options" verbose_name = "Channel" diff --git a/src/server/caches.py b/src/server/caches.py index b5533f31bf..75ea376a27 100644 --- a/src/server/caches.py +++ b/src/server/caches.py @@ -108,6 +108,8 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg # try to see if there is a handler on object that should be triggered when saving. handlername = "_at_%s_save" % fieldname handler = _GA(instance, handlername) if handlername in _GA(instance, '__dict__') else None + #if handlername == "_at_db_location_save": + # print "handler:", handlername, handler, _GA(sender, '__dict__').keys() if callable(handler): #hid = hashid(instance, "-%s" % fieldname) try: diff --git a/src/typeclasses/typeclass.py b/src/typeclasses/typeclass.py index 8bd1c2854b..42a6c73953 100644 --- a/src/typeclasses/typeclass.py +++ b/src/typeclasses/typeclass.py @@ -175,8 +175,8 @@ class TypeClass(object): dbobj.dbid, dbobj.typeclass_path,)) - def __str__(self): - "represent the object" - return self.key - def __unicode__(self): - return u"%s" % self.key + # def __str__(self): + # "represent the object" + # return _GA(self, "key") + # def __unicode__(self): + # return u"%s" % _GA(self, "key") diff --git a/src/utils/idmapper/base.py b/src/utils/idmapper/base.py index 1eab91482f..2be4a52615 100755 --- a/src/utils/idmapper/base.py +++ b/src/utils/idmapper/base.py @@ -14,7 +14,7 @@ from twisted.internet.reactor import callFromThread from django.core.exceptions import ObjectDoesNotExist, FieldError from django.db.models.base import Model, ModelBase from django.db.models.signals import post_save, pre_delete, post_syncdb -from src.utils.utils import dbref, get_evennia_pids +from src.utils.utils import dbref, get_evennia_pids, to_str from manager import SharedMemoryManager @@ -30,7 +30,6 @@ _DA = object.__delattr__ from src import PROC_MODIFIED_OBJS # get info about the current process and thread - _SELF_PID = os.getpid() _SERVER_PID, _PORTAL_PID = get_evennia_pids() _IS_SUBPROCESS = (_SERVER_PID and _PORTAL_PID) and not _SELF_PID in (_SERVER_PID, _PORTAL_PID) @@ -74,7 +73,7 @@ class SharedMemoryModelBase(ModelBase): cls.__instance_cache__ = {} #WeakValueDictionary() super(SharedMemoryModelBase, cls)._prepare() - def __init__(cls, *args, **kwargs): + def __new__(cls, classname, bases, classdict, *args, **kwargs): """ Field shortcut creation: Takes field names db_* and creates property wrappers named without the db_ prefix. So db_key -> key @@ -82,15 +81,15 @@ class SharedMemoryModelBase(ModelBase): already has a wrapper of the given name, the automatic creation is skipped. Note: Remember to document this auto-wrapping in the class header, this could seem very much like magic to the user otherwise. """ - super(SharedMemoryModelBase, cls).__init__(*args, **kwargs) - def create_wrapper(cls, fieldname, wrappername, editable=True): + def create_wrapper(cls, fieldname, wrappername, editable=True, foreignkey=False): "Helper method to create property wrappers with unique names (must be in separate call)" def _get(cls, fname): "Wrapper for getting database field" value = _GA(cls, fieldname) - if type(value) in (basestring, int, float, bool): + if isinstance(value, (basestring, int, float, bool)): return value elif hasattr(value, "typeclass"): + if fieldname == "db_key": print "idmapper _get typeclass:, ", cls.__class__.__name__, fieldname, _GA(value, "typeclass") return _GA(value, "typeclass") return value def _set_nonedit(cls, fname, value): @@ -98,22 +97,32 @@ class SharedMemoryModelBase(ModelBase): raise FieldError("Field %s cannot be edited." % fname) def _set(cls, fname, value): "Wrapper for setting database field" - #print "_set:", fname - if hasattr(value, "dbobj"): + if fname=="db_key": print "db_key _set:", value, type(value) + _SA(cls, fname, value) + # only use explicit update_fields in save if we actually have a + # primary key assigned already (won't be set when first creating object) + update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None + _GA(cls, "save")(update_fields=update_fields) + def _set_foreign(cls, fname, value): + "Setter only used on foreign key relations, allows setting with #dbref" + try: value = _GA(value, "dbobj") - elif isinstance(value, basestring) and (value.isdigit() or value.startswith("#")): - # we also allow setting using dbrefs, if so we try to load the matching object. - # (we assume the object is of the same type as the class holding the field, if - # not a custom handler must be used for that field) - dbid = dbref(value, reqhash=False) - if dbid: - try: - value = cls._default_manager.get(id=dbid) - except ObjectDoesNotExist,e: - # maybe it is just a name that happens to look like a dbid - from src.utils.logger import log_trace - log_trace() - #print "_set wrapper:", fname, value, type(value), cls._get_pk_val(cls._meta) + except AttributeError: + pass + if isinstance(value, (basestring, int)): + value = to_str(value, force_string=True) + if (value.isdigit() or value.startswith("#")): + # we also allow setting using dbrefs, if so we try to load the matching object. + # (we assume the object is of the same type as the class holding the field, if + # not a custom handler must be used for that field) + dbid = dbref(value, reqhash=False) + if dbid: + model = _GA(cls, "_meta").get_field(fname).model + try: + value = model._default_manager.get(id=dbid) + except ObjectDoesNotExist: + # maybe it is just a name that happens to look like a dbid + pass _SA(cls, fname, value) # only use explicit update_fields in save if we actually have a # primary key assigned already (won't be set when first creating object) @@ -128,24 +137,106 @@ class SharedMemoryModelBase(ModelBase): update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None _GA(cls, "save")(update_fields=update_fields) - # create class field wrappers + # wrapper factories fget = lambda cls: _get(cls, fieldname) - fset = lambda cls, val: _set(cls, fieldname, val) if editable else _set_nonedit(cls, fieldname, val) + if not editable: + fset = lambda cls, val: _set_nonedit(cls, fieldname, val) + elif foreignkey: + fset = lambda cls, val: _set_foreign(cls, fieldname, val) + else: + fset = lambda cls, val: _set(cls, fieldname, val) fdel = lambda cls: _del(cls, fieldname) if editable else _del_nonedit(cls,fieldname) - type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel))#, doc)) + # assigning + classdict[wrappername] = property(fget, fset, fdel) + #type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel))#, doc)) # exclude some models that should not auto-create wrapper fields if cls.__name__ in ("ServerConfig", "TypeNick"): return - # dynamically create the wrapper properties for all fields not already handled - for field in cls._meta.fields: - fieldname = field.name - if fieldname.startswith("db_"): - wrappername = "dbid" if fieldname == "id" else fieldname.replace("db_", "") - if not hasattr(cls, wrappername): - # makes sure not to overload manually created wrappers on the model - #print "wrapping %s -> %s" % (fieldname, wrappername) - create_wrapper(cls, fieldname, wrappername, editable=field.editable) + # dynamically create the wrapper properties for all fields not already handled (manytomanyfields are always handlers) + for fieldname, field in ((fname, field) for fname, field in classdict.items() + if fname.startswith("db_") and type(field).__name__ != "ManyToManyField"): + foreignkey = type(field).__name__ == "ForeignKey" + #print fieldname, type(field).__name__, field + wrappername = "dbid" if fieldname == "id" else fieldname.replace("db_", "", 1) + if wrappername not in classdict: + # makes sure not to overload manually created wrappers on the model + #print "wrapping %s -> %s" % (fieldname, wrappername) + create_wrapper(cls, fieldname, wrappername, editable=field.editable, foreignkey=foreignkey) + return super(SharedMemoryModelBase, cls).__new__(cls, classname, bases, classdict, *args, **kwargs) + + #def __init__(cls, *args, **kwargs): + # """ + # Field shortcut creation: + # Takes field names db_* and creates property wrappers named without the db_ prefix. So db_key -> key + # This wrapper happens on the class level, so there is no overhead when creating objects. If a class + # already has a wrapper of the given name, the automatic creation is skipped. Note: Remember to + # document this auto-wrapping in the class header, this could seem very much like magic to the user otherwise. + # """ + # super(SharedMemoryModelBase, cls).__init__(*args, **kwargs) + # def create_wrapper(cls, fieldname, wrappername, editable=True): + # "Helper method to create property wrappers with unique names (must be in separate call)" + # def _get(cls, fname): + # "Wrapper for getting database field" + # value = _GA(cls, fieldname) + # if type(value) in (basestring, int, float, bool): + # return value + # elif hasattr(value, "typeclass"): + # return _GA(value, "typeclass") + # return value + # def _set_nonedit(cls, fname, value): + # "Wrapper for blocking editing of field" + # raise FieldError("Field %s cannot be edited." % fname) + # def _set(cls, fname, value): + # "Wrapper for setting database field" + # #print "_set:", fname + # if hasattr(value, "dbobj"): + # value = _GA(value, "dbobj") + # elif isinstance(value, basestring) and (value.isdigit() or value.startswith("#")): + # # we also allow setting using dbrefs, if so we try to load the matching object. + # # (we assume the object is of the same type as the class holding the field, if + # # not a custom handler must be used for that field) + # dbid = dbref(value, reqhash=False) + # if dbid: + # try: + # value = cls._default_manager.get(id=dbid) + # except ObjectDoesNotExist: + # # maybe it is just a name that happens to look like a dbid + # from src.utils.logger import log_trace + # log_trace() + # #print "_set wrapper:", fname, value, type(value), cls._get_pk_val(cls._meta) + # _SA(cls, fname, value) + # # only use explicit update_fields in save if we actually have a + # # primary key assigned already (won't be set when first creating object) + # update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None + # _GA(cls, "save")(update_fields=update_fields) + # def _del_nonedit(cls, fname): + # "wrapper for not allowing deletion" + # raise FieldError("Field %s cannot be edited." % fname) + # def _del(cls, fname): + # "Wrapper for clearing database field - sets it to None" + # _SA(cls, fname, None) + # update_fields = [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None + # _GA(cls, "save")(update_fields=update_fields) + + # # create class field wrappers + # fget = lambda cls: _get(cls, fieldname) + # fset = lambda cls, val: _set(cls, fieldname, val) if editable else _set_nonedit(cls, fieldname, val) + # fdel = lambda cls: _del(cls, fieldname) if editable else _del_nonedit(cls,fieldname) + # type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel))#, doc)) + + # # exclude some models that should not auto-create wrapper fields + # if cls.__name__ in ("ServerConfig", "TypeNick"): + # return + # # dynamically create the wrapper properties for all fields not already handled + # for field in cls._meta.fields: + # fieldname = field.name + # if fieldname.startswith("db_"): + # wrappername = "dbid" if fieldname == "id" else fieldname.replace("db_", "") + # if not hasattr(cls, wrappername): + # # makes sure not to overload manually created wrappers on the model + # #print "wrapping %s -> %s" % (fieldname, wrappername) + # create_wrapper(cls, fieldname, wrappername, editable=field.editable) class SharedMemoryModel(Model): # CL: setting abstract correctly to allow subclasses to inherit the default diff --git a/src/utils/prettytable.py b/src/utils/prettytable.py index 9a9435f1ce..1b8dfe7c6d 100644 --- a/src/utils/prettytable.py +++ b/src/utils/prettytable.py @@ -1008,6 +1008,8 @@ class PrettyTable(object): if self.rowcount == 0 and (not options["print_empty"] or not options["border"]): return "" + #print "prettytable:", self._rows + # Get the rows we need to print, taking into account slicing, sorting, etc. rows = self._get_rows(options)