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, 1, 1), "0.0%")
|
||||||
self.assertEqual(utils.percent(3, 0, 1), "100.0%")
|
self.assertEqual(utils.percent(3, 0, 1), "100.0%")
|
||||||
self.assertEqual(utils.percent(-3, 0, 1), "0.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
|
_TASK_HANDLER = None
|
||||||
_TICKER_HANDLER = None
|
_TICKER_HANDLER = None
|
||||||
|
|
||||||
|
_ARG_ESCAPE_SIGN = "\\"
|
||||||
|
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
_SA = object.__setattr__
|
_SA = object.__setattr__
|
||||||
_DA = object.__delattr__
|
_DA = object.__delattr__
|
||||||
|
|
@ -2390,3 +2392,120 @@ def interactive(func):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return decorator
|
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