diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index fee4f75214..943c8c2817 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -53,7 +53,8 @@ __all__ = ( # used by set from ast import literal_eval as _LITERAL_EVAL -LIST_APPEND_CHAR = '+' + +LIST_APPEND_CHAR = "+" # used by find CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS @@ -1594,8 +1595,8 @@ class CmdSetAttribute(ObjManipCommand): by you starting your value with one of |c'|n, |c"|n, |c(|n, |c[|n or |c{ |n. - Once you have stored a Python primative as noted above, you can include - |c[]|n in to reference nested values. + Once you have stored a Python primitive as noted above, you can include + |c[]|n in to reference nested values in e.g. a list or dict. Remember that if you use Python primitives like this, you must write proper Python syntax too - notably you must include quotes @@ -1606,7 +1607,7 @@ class CmdSetAttribute(ObjManipCommand): key = "set" locks = "cmd:perm(set) or perm(Builder)" help_category = "Building" - nested_re = re.compile(r'\[.*?\]') + nested_re = re.compile(r"\[.*?\]") not_found = object() def check_obj(self, obj): @@ -1645,10 +1646,10 @@ class CmdSetAttribute(ObjManipCommand): ("nested['asdf'][0]", []), ] """ - quotes = '"\'' + quotes = "\"'" def clean_key(val): - val = val.strip('[]') + val = val.strip("[]") if val[0] in quotes: return val.strip(quotes) if val[0] == LIST_APPEND_CHAR: @@ -1661,9 +1662,9 @@ class CmdSetAttribute(ObjManipCommand): parts = self.nested_re.findall(attr) - base_attr = '' + base_attr = "" if parts: - base_attr = attr[:attr.find(parts[0])] + base_attr = attr[: attr.find(parts[0])] for index, part in enumerate(parts): yield (base_attr, [clean_key(p) for p in parts[index:]]) base_attr += part @@ -1692,7 +1693,7 @@ class CmdSetAttribute(ObjManipCommand): return "\nAttribute %s/%s = %s" % (obj.name, attr, val) error = "\n%s has no attribute '%s'." % (obj.name, attr) if nested: - error += ' (Nested lookups attempted)' + error += " (Nested lookups attempted)" return error def rm_attr(self, obj, attr): @@ -1719,7 +1720,7 @@ class CmdSetAttribute(ObjManipCommand): return "\nDeleted attribute '%s' (= %s) from %s." % (attr, exists, obj.name) error = "\n%s has no attribute '%s'." % (obj.name, attr) if nested: - error += ' (Nested lookups attempted)' + error += " (Nested lookups attempted)" return error def set_attr(self, obj, attr, value): diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index b3148dfa3f..38d5646e04 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -537,138 +537,208 @@ class TestBuilding(CommandTest): def test_nested_attribute_commands(self): # list - adding white space proves real parsing - self.call(building.CmdSetAttribute(), "Obj/test1=[1,2]", "Created attribute Obj/test1 = [1, 2]") + 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") - self.call(building.CmdSetAttribute(), "Obj/test1[0] = 99", "Modified attribute Obj/test1 = [99, 2]") + self.call( + building.CmdSetAttribute(), + "Obj/test1[0] = 99", + "Modified attribute Obj/test1 = [99, 2]", + ) self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 99") # list delete - self.call(building.CmdSetAttribute(), - "Obj/test1[0] =", - "Deleted attribute 'test1[0]' (= nested) from Obj.") + 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]'. (Nested lookups attempted)") + self.call( + building.CmdSetAttribute(), + "Obj/test1[1]", + "Obj has no attribute 'test1[1]'. (Nested lookups attempted)", + ) # Delete non-existent - self.call(building.CmdSetAttribute(), - "Obj/test1[5] =", - "Obj has no attribute 'test1[5]'. (Nested lookups attempted)") + self.call( + building.CmdSetAttribute(), + "Obj/test1[5] =", + "Obj has no attribute 'test1[5]'. (Nested lookups attempted)", + ) # Append - self.call(building.CmdSetAttribute(), - "Obj/test1[+] = 42", - "Modified attribute Obj/test1 = [2, 42]") - self.call(building.CmdSetAttribute(), - "Obj/test1[+0] = -1", - "Modified attribute Obj/test1 = [-1, 2, 42]") + self.call( + building.CmdSetAttribute(), + "Obj/test1[+] = 42", + "Modified attribute Obj/test1 = [2, 42]", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test1[+0] = -1", + "Modified attribute Obj/test1 = [-1, 2, 42]", + ) # dict - removing white space proves real parsing - self.call(building.CmdSetAttribute(), - "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': 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['one']=99", - "Modified attribute Obj/test2 = {'one': 99, 'two': 2}") + self.call( + building.CmdSetAttribute(), + "Obj/test2['one']=99", + "Modified attribute Obj/test2 = {'one': 99, 'two': 2}", + ) self.call(building.CmdSetAttribute(), "Obj/test2['one']", "Attribute Obj/test2['one'] = 99") self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Attribute Obj/test2['two'] = 2") - self.call(building.CmdSetAttribute(), - "Obj/test2[+'three']", - "Obj has no attribute 'test2[+'three']'. (Nested lookups attempted)") - self.call(building.CmdSetAttribute(), - "Obj/test2[+'three'] = 3", - "Modified attribute Obj/test2 = {'one': 99, 'two': 2, \"+'three'\": 3}") - self.call(building.CmdSetAttribute(), - "Obj/test2[+'three'] =", - "Deleted attribute 'test2[+'three']' (= nested) from Obj.") - self.call(building.CmdSetAttribute(), - "Obj/test2['three']=3", - "Modified attribute Obj/test2 = {'one': 99, 'two': 2, 'three': 3}") + self.call( + building.CmdSetAttribute(), + "Obj/test2[+'three']", + "Obj has no attribute 'test2[+'three']'. (Nested lookups attempted)", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2[+'three'] = 3", + "Modified attribute Obj/test2 = {'one': 99, 'two': 2, \"+'three'\": 3}", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2[+'three'] =", + "Deleted attribute 'test2[+'three']' (= nested) from Obj.", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2['three']=3", + "Modified attribute Obj/test2 = {'one': 99, 'two': 2, 'three': 3}", + ) # 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']'. (Nested lookups attempted)") - self.call(building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 99, 'three': 3}") - self.call(building.CmdSetAttribute(), - "Obj/test2[0]", - "Obj has no attribute 'test2[0]'. (Nested lookups attempted)") - self.call(building.CmdSetAttribute(), - "Obj/test2['five'] =", - "Obj has no attribute 'test2['five']'. (Nested lookups attempted)") - self.call(building.CmdSetAttribute(), - "Obj/test2[+]=42", - "Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42}") - self.call(building.CmdSetAttribute(), - "Obj/test2[+1]=33", - "Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42, '+1': 33}") + 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']'. (Nested lookups attempted)", + ) + self.call( + building.CmdSetAttribute(), "Obj/test2", "Attribute Obj/test2 = {'one': 99, 'three': 3}" + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2[0]", + "Obj has no attribute 'test2[0]'. (Nested lookups attempted)", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2['five'] =", + "Obj has no attribute 'test2['five']'. (Nested lookups attempted)", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2[+]=42", + "Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42}", + ) + self.call( + building.CmdSetAttribute(), + "Obj/test2[+1]=33", + "Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42, '+1': 33}", + ) # tuple - self.call(building.CmdSetAttribute(), "Obj/tup = (1,2)", "Created attribute Obj/tup = (1, 2)") - self.call(building.CmdSetAttribute(), - "Obj/tup[1] = 99", - "'tuple' object does not support item assignment - (1, 2)") - self.call(building.CmdSetAttribute(), - "Obj/tup[+] = 99", - "'tuple' object does not support item assignment - (1, 2)") - self.call(building.CmdSetAttribute(), - "Obj/tup[+1] = 99", - "'tuple' object does not support item assignment - (1, 2)") - self.call(building.CmdSetAttribute(), - # Special case for tuple, could have a better message - "Obj/tup[1] = ", - "Obj has no attribute 'tup[1]'. (Nested lookups attempted)") + self.call( + building.CmdSetAttribute(), "Obj/tup = (1,2)", "Created attribute Obj/tup = (1, 2)" + ) + self.call( + building.CmdSetAttribute(), + "Obj/tup[1] = 99", + "'tuple' object does not support item assignment - (1, 2)", + ) + self.call( + building.CmdSetAttribute(), + "Obj/tup[+] = 99", + "'tuple' object does not support item assignment - (1, 2)", + ) + self.call( + building.CmdSetAttribute(), + "Obj/tup[+1] = 99", + "'tuple' object does not support item assignment - (1, 2)", + ) + self.call( + building.CmdSetAttribute(), + # Special case for tuple, could have a better message + "Obj/tup[1] = ", + "Obj has no attribute 'tup[1]'. (Nested lookups attempted)", + ) # Deaper nesting - self.call(building.CmdSetAttribute(), - "Obj/test3=[{'one': 1}]", - "Created attribute Obj/test3 = [{'one': 1}]") - self.call(building.CmdSetAttribute(), "Obj/test3[0]['one']", "Attribute Obj/test3[0]['one'] = 1") + self.call( + building.CmdSetAttribute(), + "Obj/test3=[{'one': 1}]", + "Created attribute Obj/test3 = [{'one': 1}]", + ) + self.call( + building.CmdSetAttribute(), "Obj/test3[0]['one']", "Attribute Obj/test3[0]['one'] = 1" + ) self.call(building.CmdSetAttribute(), "Obj/test3[0]", "Attribute Obj/test3[0] = {'one': 1}") - self.call(building.CmdSetAttribute(), - "Obj/test3[0]['one'] =", - "Deleted attribute 'test3[0]['one']' (= nested) from Obj.") + self.call( + building.CmdSetAttribute(), + "Obj/test3[0]['one'] =", + "Deleted attribute 'test3[0]['one']' (= nested) from Obj.", + ) self.call(building.CmdSetAttribute(), "Obj/test3[0]", "Attribute Obj/test3[0] = {}") self.call(building.CmdSetAttribute(), "Obj/test3", "Attribute Obj/test3 = [{}]") # Naughty keys - self.call(building.CmdSetAttribute(), - "Obj/test4[0]='foo'", - "Created attribute Obj/test4[0] = 'foo'") + self.call( + building.CmdSetAttribute(), + "Obj/test4[0]='foo'", + "Created attribute Obj/test4[0] = 'foo'", + ) self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = foo") - self.call(building.CmdSetAttribute(), - "Obj/test4=[{'one': 1}]", - "Created attribute Obj/test4 = [{'one': 1}]") - self.call(building.CmdSetAttribute(), "Obj/test4[0]['one']", "Attribute Obj/test4[0]['one'] = 1") + self.call( + building.CmdSetAttribute(), + "Obj/test4=[{'one': 1}]", + "Created attribute Obj/test4 = [{'one': 1}]", + ) + self.call( + building.CmdSetAttribute(), "Obj/test4[0]['one']", "Attribute Obj/test4[0]['one'] = 1" + ) # 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.CmdSetAttribute(), "Obj/test4[0]['one']", "Attribute Obj/test4[0]['one'] = 1" + ) # 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']'.") + self.call( + building.CmdSetAttribute(), + "Obj/test4[0]['one']", + "Obj has no attribute 'test4[0]['one']'.", + ) def test_split_nested_attr(self): split_nested_attr = building.CmdSetAttribute().split_nested_attr test_cases = { - 'test1': [('test1', [])], - 'test2["dict"]': [('test2', ['dict']), ('test2["dict"]', [])], + "test1": [("test1", [])], + 'test2["dict"]': [("test2", ["dict"]), ('test2["dict"]', [])], # Quotes not actually required - 'test3[dict]': [('test3', ['dict']), ('test3[dict]', [])], - 'test4["dict]': [('test4', ['dict']), ('test4["dict]', [])], + "test3[dict]": [("test3", ["dict"]), ("test3[dict]", [])], + 'test4["dict]': [("test4", ["dict"]), ('test4["dict]', [])], # duplicate keys don't cause issues - 'test5[0][0]': [('test5', [0, 0]), ('test5[0]', [0]), ('test5[0][0]', [])], + "test5[0][0]": [("test5", [0, 0]), ("test5[0]", [0]), ("test5[0][0]", [])], # String ints preserved - 'test6["0"][0]': [('test6', ['0', 0]), ('test6["0"]', [0]), ('test6["0"][0]', [])], + 'test6["0"][0]': [("test6", ["0", 0]), ('test6["0"]', [0]), ('test6["0"][0]', [])], # Unmatched [] - 'test7[dict': [('test7[dict', [])], + "test7[dict": [("test7[dict", [])], } for attr, result in test_cases.items(): @@ -684,19 +754,19 @@ class TestBuilding(CommandTest): def do_test_multi(value, keys, result): self.assertEqual(do_nested_lookup(value, *keys), result) - do_test_single([], 'test1', not_found) - do_test_single([1], 'test2', not_found) + do_test_single([], "test1", not_found) + do_test_single([1], "test2", not_found) do_test_single([], 0, not_found) - do_test_single([], '0', not_found) + do_test_single([], "0", not_found) do_test_single([1], 2, not_found) do_test_single([1], 0, 1) - do_test_single([1], '0', not_found) # str key is str not int - do_test_single({}, 'test3', not_found) + do_test_single([1], "0", not_found) # str key is str not int + do_test_single({}, "test3", not_found) do_test_single({}, 0, not_found) - do_test_single({'foo': 'bar'}, 'foo', 'bar') + do_test_single({"foo": "bar"}, "foo", "bar") - do_test_multi({'one': [1, 2, 3]}, ('one', 0), 1) - do_test_multi([{}, {'two': 2}, 3], (1, 'two'), 2) + do_test_multi({"one": [1, 2, 3]}, ("one", 0), 1) + do_test_multi([{}, {"two": 2}, 3], (1, "two"), 2) def test_name(self): self.call(building.CmdName(), "", "Usage: ")