Fixes @set to be more accepting of various Python structures. It will now instead convert to string on a ValueError (commonly because a string was not enclosed in quotes) while giving a error string to the user informing of this. This should fix Issue 256.

This commit is contained in:
Griatch 2012-09-22 22:16:30 +02:00
parent 23ba17debe
commit a30029472b

View file

@ -19,6 +19,13 @@ __all__ = ("ObjManipCommand", "CmdSetObjAlias", "CmdCopy",
"CmdLock", "CmdExamine", "CmdFind", "CmdTeleport", "CmdLock", "CmdExamine", "CmdFind", "CmdTeleport",
"CmdScript") "CmdScript")
try:
# used by @set
from ast import literal_eval as _LITERAL_EVAL
except ImportError:
# literal_eval is not available before Python 2.6
_LITERAL_EVAL = None
# used by @find # used by @find
CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
@ -1176,11 +1183,19 @@ class CmdSetAttribute(ObjManipCommand):
def convert_from_string(self, strobj): def convert_from_string(self, strobj):
""" """
Converts a single object in *string form* to its equivalent python Converts a single object in *string form* to its equivalent python
type. Handles floats, ints, and limited nested lists and dicts type.
Python earlier than 2.6:
Handles floats, ints, and limited nested lists and dicts
(can't handle lists in a dict, for example, this is mainly due to (can't handle lists in a dict, for example, this is mainly due to
the complexity of parsing this rather than any technical difficulty - the complexity of parsing this rather than any technical difficulty -
if there is a need for @set-ing such complex structures on the if there is a need for @set-ing such complex structures on the
command line we might consider adding it). command line we might consider adding it).
Python 2.6 and later:
Supports all Python structures through literal_eval as long as they
are valid Python syntax. If they are not (such as [test, test2], ie
withtout the quotes around the strings), the entire structure will
be converted to a string and a warning will be given.
We need to convert like this since all data being sent over the We need to convert like this since all data being sent over the
telnet connection by the Player is text - but we will want to telnet connection by the Player is text - but we will want to
@ -1191,7 +1206,8 @@ class CmdSetAttribute(ObjManipCommand):
def rec_convert(obj): def rec_convert(obj):
""" """
Helper function of recursive conversion calls. Helper function of recursive conversion calls. This is only
used for Python <=2.5. After that literal_eval is available.
""" """
# simple types # simple types
try: return int(obj) try: return int(obj)
@ -1211,18 +1227,20 @@ class CmdSetAttribute(ObjManipCommand):
for pair in obj[1:-1].split(',') if ":" in pair]) for pair in obj[1:-1].split(',') if ":" in pair])
# if nothing matches, return as-is # if nothing matches, return as-is
return obj return obj
if strobj.strip() and strobj.strip()[0] in ("'", '"', "(", "{ ", "["):
# this is a structure starting with a proper python structure, if _LITERAL_EVAL:
# so treat it as such. # Use literal_eval to parse python structure exactly.
try: try:
# under python 2.6, literal_eval can do this for us. return _LITERAL_EVAL(strobj)
from ast import literal_eval except ValueError:
return literal_eval(strobj) # treat as string
except ImportError: string = "{RNote: Value was converted to string. If you don't want this, "
# fall back to old recursive solution (don't support nested lists/dicts) string += "use proper Python syntax, like enclosing strings in quotes.{n"
return rec_convert(strobj.strip()) self.caller.msg(string)
return utils.to_str(strobj)
else: else:
return strobj # fall back to old recursive solution (does not support nested lists/dicts)
return rec_convert(strobj.strip())
def func(self): def func(self):
"Implement the set attribute - a limited form of @py." "Implement the set attribute - a limited form of @py."
@ -1272,10 +1290,9 @@ class CmdSetAttribute(ObjManipCommand):
string += "\nCreated attribute %s/%s = %s" % (obj.name, attr, value) string += "\nCreated attribute %s/%s = %s" % (obj.name, attr, value)
except SyntaxError: except SyntaxError:
# this means literal_eval tried to parse a faulty string # this means literal_eval tried to parse a faulty string
string = "{RPython syntax error in your value. By assigning a value starting with" string = "{RCritical Python syntax error in your value. Only primitive Python structures"
string += "\none of {r'{R, {r\"{R, {r[{R, {r({R or {r{{R we assume you are entering a proper Python" string += "\nare allowed. You also need to use correct Python syntax. Remember especially"
string += "\nprimitive such as a list or a dictionary. You must then also use correct" string += "\nto put quotes around all strings inside lists and dicts.{n"
string += "\nPython syntax. Remember especially to put quotes around all strings.{n"
# send feedback # send feedback
caller.msg(string.strip('\n')) caller.msg(string.strip('\n'))