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",
"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
CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
@ -1176,11 +1183,19 @@ class CmdSetAttribute(ObjManipCommand):
def convert_from_string(self, strobj):
"""
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
the complexity of parsing this rather than any technical difficulty -
if there is a need for @set-ing such complex structures on the
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
telnet connection by the Player is text - but we will want to
@ -1191,7 +1206,8 @@ class CmdSetAttribute(ObjManipCommand):
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
try: return int(obj)
@ -1211,18 +1227,20 @@ class CmdSetAttribute(ObjManipCommand):
for pair in obj[1:-1].split(',') if ":" in pair])
# if nothing matches, return as-is
return obj
if strobj.strip() and strobj.strip()[0] in ("'", '"', "(", "{ ", "["):
# this is a structure starting with a proper python structure,
# so treat it as such.
if _LITERAL_EVAL:
# Use literal_eval to parse python structure exactly.
try:
# under python 2.6, literal_eval can do this for us.
from ast import literal_eval
return literal_eval(strobj)
except ImportError:
# fall back to old recursive solution (don't support nested lists/dicts)
return rec_convert(strobj.strip())
return _LITERAL_EVAL(strobj)
except ValueError:
# treat as string
string = "{RNote: Value was converted to string. If you don't want this, "
string += "use proper Python syntax, like enclosing strings in quotes.{n"
self.caller.msg(string)
return utils.to_str(strobj)
else:
return strobj
# fall back to old recursive solution (does not support nested lists/dicts)
return rec_convert(strobj.strip())
def func(self):
"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)
except SyntaxError:
# this means literal_eval tried to parse a faulty string
string = "{RPython syntax error in your value. By assigning a value starting with"
string += "\none of {r'{R, {r\"{R, {r[{R, {r({R or {r{{R we assume you are entering a proper Python"
string += "\nprimitive such as a list or a dictionary. You must then also use correct"
string += "\nPython syntax. Remember especially to put quotes around all strings.{n"
string = "{RCritical Python syntax error in your value. Only primitive Python structures"
string += "\nare allowed. You also need to use correct Python syntax. Remember especially"
string += "\nto put quotes around all strings inside lists and dicts.{n"
# send feedback
caller.msg(string.strip('\n'))