mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Resolve merge conflicts
This commit is contained in:
parent
3e90e0bb14
commit
32d7a4782c
2 changed files with 146 additions and 0 deletions
|
|
@ -385,3 +385,30 @@ class TestPercent(TestCase):
|
|||
self.assertEqual(utils.percent(3, 1, 1), "0.0%")
|
||||
self.assertEqual(utils.percent(3, 0, 1), "100.0%")
|
||||
self.assertEqual(utils.percent(-3, 0, 1), "0.0%")
|
||||
|
||||
|
||||
class ParseArgumentsTest(TestCase):
|
||||
def _run_test(s):
|
||||
return utils.parse_arguments(s)
|
||||
|
||||
def test_happy_flow(self):
|
||||
s = "1, \"The text \\\"Hello, world.\\\" is often used by programmers to test if their code works.\", caller, looker=\"Qwerty\""
|
||||
args, kwargs = ParseArgumentsTest._run_test(s)
|
||||
self.assertEqual(len(args), 3)
|
||||
self.assertEqual(args[0], 1)
|
||||
self.assertEqual(args[1], "The text \"Hello, world.\" is often used by programmers to test if their code works.")
|
||||
#self.assertEqual(args[2], "caller")
|
||||
self.assertEqual(len(kwargs), 1)
|
||||
self.assertEqual(kwargs["looker"], "Qwerty")
|
||||
|
||||
def test_malformed_string(self):
|
||||
s = ",(,),"
|
||||
args, kwargs = ParseArgumentsTest._run_test(s)
|
||||
self.assertEqual(len(args), 4)
|
||||
self.assertEqual(args[0], "")
|
||||
self.assertEqual(args[1].__class__, utils.FunctionArgument)
|
||||
self.assertEqual(args[1].name, "(")
|
||||
self.assertEqual(args[2].__class__, utils.FunctionArgument)
|
||||
self.assertEqual(args[2].name, ")")
|
||||
self.assertEqual(args[3], "")
|
||||
self.assertEqual(len(kwargs), 0)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ ENCODINGS = settings.ENCODINGS
|
|||
_TASK_HANDLER = None
|
||||
_TICKER_HANDLER = None
|
||||
|
||||
_ARG_ESCAPE_SIGN = "\\"
|
||||
|
||||
_GA = object.__getattribute__
|
||||
_SA = object.__setattr__
|
||||
_DA = object.__delattr__
|
||||
|
|
@ -2390,3 +2392,120 @@ def interactive(func):
|
|||
return ret
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
class FunctionArgument(object):
|
||||
def __init__(self, name):
|
||||
self.name = name.strip()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
def parse_arguments(s, **kwargs):
|
||||
"""
|
||||
This method takes a string and parses it as if it were an argument list to a function.
|
||||
It supports both positional and named arguments.
|
||||
|
||||
Values are automatically converted to int or float if possible.
|
||||
Values surrounded by single or double quotes are treated as strings.
|
||||
Any other value is wrapped in a "FunctionArgument" class for later processing.
|
||||
|
||||
Args:
|
||||
s (str): The string to convert.
|
||||
|
||||
Returns:
|
||||
(list, dict): A tuple containing a list of arguments (list) and named arguments (dict).
|
||||
"""
|
||||
global _ARG_ESCAPE_SIGN
|
||||
|
||||
args_list = []
|
||||
args_dict = {}
|
||||
|
||||
# State (general)
|
||||
inside = (False, None) # Are we inside a quoted string? What is the quoted character?
|
||||
skip = False # Skip the current parameter?
|
||||
escape = False # Was the escape key used?
|
||||
is_string = False # Have we been inside a quoted string?
|
||||
temp = "" # Buffer
|
||||
key = None # Key (for named parameter)
|
||||
|
||||
def _parse_value(temp):
|
||||
ret = temp.strip()
|
||||
if not is_string:
|
||||
try:
|
||||
ret = int(ret)
|
||||
except ValueError:
|
||||
try:
|
||||
ret = float(ret)
|
||||
except ValueError:
|
||||
if ret != "":
|
||||
return FunctionArgument(ret)
|
||||
|
||||
return ret
|
||||
|
||||
def _add_value(skip, key, args_list, args_dict, temp):
|
||||
if not skip:
|
||||
# Record value based on whether named parameters mode is set or not.
|
||||
if key is not None:
|
||||
args_dict[key] = _parse_value(temp)
|
||||
key = None
|
||||
else:
|
||||
args_list.append(_parse_value(temp))
|
||||
|
||||
for c in s:
|
||||
if c == _ARG_ESCAPE_SIGN:
|
||||
# Escape sign used.
|
||||
if escape:
|
||||
# Already escaping: print escape sign itself.
|
||||
temp += _ARG_ESCAPE_SIGN
|
||||
escape = False
|
||||
else:
|
||||
# Enter escape mode.
|
||||
escape = True
|
||||
elif escape:
|
||||
# Escape mode: print whatever comes after the symbol.
|
||||
escape = False
|
||||
temp += c
|
||||
elif inside[0] is True:
|
||||
# Inside single quotes or double quotes
|
||||
# Wait for the end symbol, allow everything else through, allow escape sign for typing quotes in strings
|
||||
if c == inside[1]:
|
||||
# Leaving single/double quoted area
|
||||
inside = (False, None)
|
||||
else:
|
||||
temp += c
|
||||
elif c == "\"" or c == "'":
|
||||
# Entering single/double quoted area
|
||||
inside = (True, c)
|
||||
is_string = True
|
||||
continue
|
||||
elif c == "=":
|
||||
if is_string:
|
||||
# Invalid syntax because we don't allow named parameters to be quoted.
|
||||
return None
|
||||
elif key is None:
|
||||
# Named parameters mode and equals sign encountered. Record key and continue with value.
|
||||
key = temp.strip()
|
||||
temp = ""
|
||||
elif c == ",":
|
||||
# Comma encountered outside of quoted area.
|
||||
|
||||
_add_value(skip, key, args_list, args_dict, temp)
|
||||
|
||||
# Reset
|
||||
temp = ""
|
||||
skip = False
|
||||
is_string = False
|
||||
key = None
|
||||
else:
|
||||
# Any other character: add to buffer.
|
||||
temp += c
|
||||
|
||||
if inside[0] is True:
|
||||
# Invalid syntax because we are inside a quoted area.
|
||||
return None
|
||||
else:
|
||||
_add_value(skip, key, args_list, args_dict, temp)
|
||||
|
||||
return args_list, args_dict
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue