diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index de974a7f08..0437260930 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1688,12 +1688,22 @@ class CmdSetAttribute(ObjManipCommand): def rm_attr(self, obj, attr): """ - Remove an attribute from the object, and report back. + Remove an attribute from the object, or a nested data structure, and report back. """ - if obj.attributes.has(attr): - val = obj.attributes.has(attr) - obj.attributes.remove(attr) - return "\nDeleted attribute '%s' (= %s) from %s." % (attr, val, obj.name) + for key, nested_keys in self.split_nested_attr(attr): + if obj.attributes.has(key): + if nested_keys: + del_key = nested_keys[-1] + val = obj.attributes.get(key) + val = self.do_nested_lookup(val, *nested_keys[:-1]) + if val is not self.not_found: + del val[del_key] + obj.attributes.add(key, val) + return "\nDeleted attribute '%s' (= nested) from %s." % (attr, obj.name) + else: + exists = obj.attributes.has(key) + obj.attributes.remove(attr) + return "\nDeleted attribute '%s' (= %s) from %s." % (attr, exists, obj.name) else: return "\n%s has no attribute '%s'." % (obj.name, attr) diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 0f44dcbba8..f54be20150 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -540,13 +540,25 @@ class TestBuilding(CommandTest): self.call(building.CmdSetAttribute(), "Obj/test1=[1,2]", "Created attribute Obj/test1 = [1, 2]") self.call(building.CmdSetAttribute(), "Obj/test1", "Attribute Obj/test1 = [1, 2]") self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 1") + self.call(building.CmdSetAttribute(), "Obj/test1[1]", "Attribute Obj/test1[1] = 2") + # list delete + self.call(building.CmdSetAttribute(), + "Obj/test1[0] =", "Deleted attribute 'test1[0]' (= nested) from Obj.") + self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 2") + self.call(building.CmdSetAttribute(), "Obj/test1[1]", "Obj has no attribute 'test1[1]'.") # removing white space proves real parsing self.call(building.CmdSetAttribute(), - "Obj/test2={ 'one': 1 }", "Created attribute Obj/test2 = {'one': 1}") - self.call(building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 1}") + "Obj/test2={ 'one': 1, 'two': 2 }", "Created attribute Obj/test2 = {'one': 1, 'two': 2}") + self.call(building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 1, 'two': 2}") self.call(building.CmdSetAttribute(), "Obj/test2['one']", "Attribute Obj/test2['one'] = 1") self.call(building.CmdSetAttribute(), "Obj/test2['one]", "Attribute Obj/test2['one] = 1") + self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Attribute Obj/test2['two'] = 2") + # Dict delete + self.call(building.CmdSetAttribute(), + "Obj/test2['two'] =", "Deleted attribute 'test2['two']' (= nested) from Obj.") + self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Obj has no attribute 'test2['two']'.") + self.call(building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 1}") self.call(building.CmdSetAttribute(), "Obj/test2[0]", "Obj has no attribute 'test2[0]'.") # Deaper nesting @@ -565,8 +577,8 @@ class TestBuilding(CommandTest): # Prefer nested items self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = {'one': 1}") self.call(building.CmdSetAttribute(), "Obj/test4[0]['one']", "Attribute Obj/test4[0]['one'] = 1") - self.call(building.CmdWipe(), "Obj/test4", "Wiped attributes test4 on Obj.") # Restored access + self.call(building.CmdWipe(), "Obj/test4", "Wiped attributes test4 on Obj.") self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = foo") self.call(building.CmdSetAttribute(), "Obj/test4[0]['one']", "Obj has no attribute 'test4[0]['one']'.")