[#1928] PR feedback, documentation, error handling

This commit is contained in:
Aaron McMillin 2019-09-29 21:45:33 -04:00
parent 186bc09b4d
commit ba3db1731d
2 changed files with 77 additions and 32 deletions

View file

@ -1570,7 +1570,7 @@ class CmdSetAttribute(ObjManipCommand):
set <obj>/<attr> = <value> set <obj>/<attr> = <value>
set <obj>/<attr> = set <obj>/<attr> =
set <obj>/<attr> set <obj>/<attr>
set *<account>/attr = <value> set *<account>/<attr> = <value>
Switch: Switch:
edit: Open the line editor (string values only) edit: Open the line editor (string values only)
@ -1585,7 +1585,7 @@ class CmdSetAttribute(ObjManipCommand):
Sets attributes on objects. The second example form above clears a Sets attributes on objects. The second example form above clears a
previously set attribute while the third form inspects the current value of previously set attribute while the third form inspects the current value of
the attribute (if any). The last one (with the star) is a shortcut for the attribute (if any). The last one (with the star) is a shortcut for
operatin on a player Account rather than an Object. operating on a player Account rather than an Object.
The most common data to save with this command are strings and The most common data to save with this command are strings and
numbers. You can however also set Python primitives such as lists, numbers. You can however also set Python primitives such as lists,
@ -1593,8 +1593,10 @@ class CmdSetAttribute(ObjManipCommand):
the functionality of certain custom objects). This is indicated the functionality of certain custom objects). This is indicated
by you starting your value with one of |c'|n, |c"|n, |c(|n, |c[|n by you starting your value with one of |c'|n, |c"|n, |c(|n, |c[|n
or |c{ |n. or |c{ |n.
Note that you should leave a space after starting a dictionary ('{ ')
so as to not confuse the dictionary start with a colour code like \{g. Once you have stored a Python primative as noted above, you can include
|c[<key>]|n in <attr> to reference nested values.
Remember that if you use Python primitives like this, you must Remember that if you use Python primitives like this, you must
write proper Python syntax too - notably you must include quotes write proper Python syntax too - notably you must include quotes
around your strings or you will get an error. around your strings or you will get an error.
@ -1680,20 +1682,26 @@ class CmdSetAttribute(ObjManipCommand):
""" """
Look up the value of an attribute and return a string displaying it. Look up the value of an attribute and return a string displaying it.
""" """
nested = False
for key, nested_keys in self.split_nested_attr(attr): for key, nested_keys in self.split_nested_attr(attr):
nested = True
if obj.attributes.has(key): if obj.attributes.has(key):
val = obj.attributes.get(key) val = obj.attributes.get(key)
val = self.do_nested_lookup(val, *nested_keys) val = self.do_nested_lookup(val, *nested_keys)
if val is not self.not_found: if val is not self.not_found:
return "\nAttribute %s/%s = %s" % (obj.name, attr, val) return "\nAttribute %s/%s = %s" % (obj.name, attr, val)
else: error = "\n%s has no attribute '%s'." % (obj.name, attr)
return "\n%s has no attribute '%s'." % (obj.name, attr) if nested:
error += ' (Nested lookups attempted)'
return error
def rm_attr(self, obj, attr): def rm_attr(self, obj, attr):
""" """
Remove an attribute from the object, or a nested data structure, and report back. Remove an attribute from the object, or a nested data structure, and report back.
""" """
nested = False
for key, nested_keys in self.split_nested_attr(attr): for key, nested_keys in self.split_nested_attr(attr):
nested = True
if obj.attributes.has(key): if obj.attributes.has(key):
if nested_keys: if nested_keys:
del_key = nested_keys[-1] del_key = nested_keys[-1]
@ -1709,7 +1717,10 @@ class CmdSetAttribute(ObjManipCommand):
exists = obj.attributes.has(key) exists = obj.attributes.has(key)
obj.attributes.remove(attr) obj.attributes.remove(attr)
return "\nDeleted attribute '%s' (= %s) from %s." % (attr, exists, obj.name) return "\nDeleted attribute '%s' (= %s) from %s." % (attr, exists, obj.name)
return "\n%s has no attribute '%s'." % (obj.name, attr) error = "\n%s has no attribute '%s'." % (obj.name, attr)
if nested:
error += ' (Nested lookups attempted)'
return error
def set_attr(self, obj, attr, value): def set_attr(self, obj, attr, value):
done = False done = False
@ -1720,9 +1731,9 @@ class CmdSetAttribute(ObjManipCommand):
deep = self.do_nested_lookup(lookup_value, *nested_keys[:-1]) deep = self.do_nested_lookup(lookup_value, *nested_keys[:-1])
if deep is not self.not_found: if deep is not self.not_found:
# To support appending and inserting to lists # To support appending and inserting to lists
# a key that starts with @ will insert a new item at that # a key that starts with LIST_APPEND_CHAR will insert a new item at that
# location, and move the other elements down. # location, and move the other elements down.
# Just '@' will append to the list # Using LIST_APPEND_CHAR alone will append to the list
if isinstance(acc_key, str) and acc_key[0] == LIST_APPEND_CHAR: if isinstance(acc_key, str) and acc_key[0] == LIST_APPEND_CHAR:
try: try:
if len(acc_key) > 1: if len(acc_key) > 1:
@ -1730,7 +1741,7 @@ class CmdSetAttribute(ObjManipCommand):
deep.insert(where, value) deep.insert(where, value)
else: else:
deep.append(value) deep.append(value)
except AttributeError: except (ValueError, AttributeError):
pass pass
else: else:
value = lookup_value value = lookup_value

View file

@ -545,40 +545,65 @@ class TestBuilding(CommandTest):
self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 99") self.call(building.CmdSetAttribute(), "Obj/test1[0]", "Attribute Obj/test1[0] = 99")
# list delete # list delete
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test1[0] =", "Deleted attribute 'test1[0]' (= nested) from Obj.") "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[0]", "Attribute Obj/test1[0] = 2")
self.call(building.CmdSetAttribute(), "Obj/test1[1]", "Obj has no attribute 'test1[1]'.") self.call(building.CmdSetAttribute(),
"Obj/test1[1]",
"Obj has no attribute 'test1[1]'. (Nested lookups attempted)")
# Delete non-existent # Delete non-existent
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test1[5] =", "Obj has no attribute 'test1[5]'.") "Obj/test1[5] =",
"Obj has no attribute 'test1[5]'. (Nested lookups attempted)")
# Append # Append
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test1[+] = 42", "Modified attribute Obj/test1 = [2, 42]") "Obj/test1[+] = 42",
"Modified attribute Obj/test1 = [2, 42]")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test1[+0] = -1", "Modified attribute Obj/test1 = [-1, 2, 42]") "Obj/test1[+0] = -1",
"Modified attribute Obj/test1 = [-1, 2, 42]")
# dict - removing white space proves real parsing # dict - removing white space proves real parsing
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test2={ 'one': 1, 'two': 2 }", "Created attribute Obj/test2 = {'one': 1, 'two': 2}") "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", "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]", "Attribute Obj/test2['one] = 1") self.call(building.CmdSetAttribute(), "Obj/test2['one]", "Attribute Obj/test2['one] = 1")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test2['one']=99", "Modified attribute Obj/test2 = {'one': 99, 'two': 2}") "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['one']", "Attribute Obj/test2['one'] = 99")
self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Attribute Obj/test2['two'] = 2") self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Attribute Obj/test2['two'] = 2")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test2['three']=3", "Modified attribute Obj/test2 = {'one': 99, 'two': 2, 'three': 3}") "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 # Dict delete
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test2['two'] =", "Deleted attribute 'test2['two']' (= nested) from Obj.") "Obj/test2['two'] =",
self.call(building.CmdSetAttribute(), "Obj/test2['two']", "Obj has no attribute '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", "Attribute Obj/test2 = {'one': 99, 'three': 3}")
self.call(building.CmdSetAttribute(), "Obj/test2[0]", "Obj has no attribute 'test2[0]'.")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test2['five'] =", "Obj has no attribute 'test2['five']'.") "Obj/test2[0]",
"Obj has no attribute 'test2[0]'. (Nested lookups attempted)")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test2[+]=42", "Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42}") "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(), self.call(building.CmdSetAttribute(),
"Obj/test2[+1]=33", "Obj/test2[+1]=33",
"Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42, '+1': 33}") "Modified attribute Obj/test2 = {'one': 99, 'three': 3, '+': 42, '+1': 33}")
@ -586,31 +611,39 @@ class TestBuilding(CommandTest):
# tuple # tuple
self.call(building.CmdSetAttribute(), "Obj/tup = (1,2)", "Created attribute Obj/tup = (1, 2)") self.call(building.CmdSetAttribute(), "Obj/tup = (1,2)", "Created attribute Obj/tup = (1, 2)")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/tup[1] = 99", "'tuple' object does not support item assignment - (1, 2)") "Obj/tup[1] = 99",
"'tuple' object does not support item assignment - (1, 2)")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/tup[+] = 99", "'tuple' object does not support item assignment - (1, 2)") "Obj/tup[+] = 99",
"'tuple' object does not support item assignment - (1, 2)")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/tup[+1] = 99", "'tuple' object does not support item assignment - (1, 2)") "Obj/tup[+1] = 99",
"'tuple' object does not support item assignment - (1, 2)")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
# Special case for tuple, could have a better message # Special case for tuple, could have a better message
"Obj/tup[1] = ", "Obj has no attribute 'tup[1]'.") "Obj/tup[1] = ",
"Obj has no attribute 'tup[1]'. (Nested lookups attempted)")
# Deaper nesting # Deaper nesting
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test3=[{'one': 1}]", "Created attribute Obj/test3 = [{'one': 1}]") "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]['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]", "Attribute Obj/test3[0] = {'one': 1}")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test3[0]['one'] =", "Deleted attribute 'test3[0]['one']' (= nested) from Obj.") "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[0]", "Attribute Obj/test3[0] = {}")
self.call(building.CmdSetAttribute(), "Obj/test3", "Attribute Obj/test3 = [{}]") self.call(building.CmdSetAttribute(), "Obj/test3", "Attribute Obj/test3 = [{}]")
# Naughty keys # Naughty keys
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test4[0]='foo'", "Created attribute Obj/test4[0] = 'foo'") "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[0]", "Attribute Obj/test4[0] = foo")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test4=[{'one': 1}]", "Created attribute Obj/test4 = [{'one': 1}]") "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[0]['one']", "Attribute Obj/test4[0]['one'] = 1")
# Prefer nested items # Prefer nested items
self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = {'one': 1}") self.call(building.CmdSetAttribute(), "Obj/test4[0]", "Attribute Obj/test4[0] = {'one': 1}")
@ -619,7 +652,8 @@ class TestBuilding(CommandTest):
self.call(building.CmdWipe(), "Obj/test4", "Wiped attributes test4 on Obj.") 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]", "Attribute Obj/test4[0] = foo")
self.call(building.CmdSetAttribute(), self.call(building.CmdSetAttribute(),
"Obj/test4[0]['one']", "Obj has no attribute 'test4[0]['one']'.") "Obj/test4[0]['one']",
"Obj has no attribute 'test4[0]['one']'.")
def test_split_nested_attr(self): def test_split_nested_attr(self):
split_nested_attr = building.CmdSetAttribute().split_nested_attr split_nested_attr = building.CmdSetAttribute().split_nested_attr