[BUGFIX] Move unescape parsing to separate function (#1108)
Fixes #1107 ``` FunctionRuntimeException: Runtime error occurred when executing the function %from_json: Invalid control character ```
This commit is contained in:
parent
bf64be8a59
commit
6a756cfecf
5 changed files with 55 additions and 18 deletions
|
|
@ -710,6 +710,24 @@ titlecase
|
||||||
:description:
|
:description:
|
||||||
Capitalize each word in the string.
|
Capitalize each word in the string.
|
||||||
|
|
||||||
|
unescape
|
||||||
|
~~~~~~~~
|
||||||
|
:spec: ``unescape(string: String) -> String``
|
||||||
|
|
||||||
|
:description:
|
||||||
|
Unescape symbols like newlines or tabs to their true form.
|
||||||
|
|
||||||
|
:usage:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{
|
||||||
|
%unescape( "Hello\nWorld" )
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hello
|
||||||
|
# World
|
||||||
|
|
||||||
upper
|
upper
|
||||||
~~~~~
|
~~~~~
|
||||||
:spec: ``upper(string: String) -> String``
|
:spec: ``upper(string: String) -> String``
|
||||||
|
|
|
||||||
|
|
@ -143,3 +143,22 @@ class StringFunctions:
|
||||||
length=length,
|
length=length,
|
||||||
char=String("0"),
|
char=String("0"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unescape(string: String) -> String:
|
||||||
|
"""
|
||||||
|
:description:
|
||||||
|
Unescape symbols like newlines or tabs to their true form.
|
||||||
|
|
||||||
|
:usage:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
{
|
||||||
|
%unescape( "Hello\\nWorld" )
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hello
|
||||||
|
# World
|
||||||
|
"""
|
||||||
|
return String(string.value.encode("utf-8").decode("unicode_escape"))
|
||||||
|
|
|
||||||
|
|
@ -301,16 +301,8 @@ class _Parser:
|
||||||
self._pos += len(str_open_token)
|
self._pos += len(str_open_token)
|
||||||
return String(value=string_value)
|
return String(value=string_value)
|
||||||
|
|
||||||
# Read literal "\n" as newlines
|
self._pos += 1
|
||||||
if self._read(increment_pos=False, length=2) == "\\n":
|
string_value += ch
|
||||||
string_value += "\n"
|
|
||||||
self._pos += 2
|
|
||||||
elif self._read(increment_pos=False, length=2) == "\\t":
|
|
||||||
string_value += "\t"
|
|
||||||
self._pos += 2
|
|
||||||
else:
|
|
||||||
self._pos += 1
|
|
||||||
string_value += ch
|
|
||||||
|
|
||||||
raise STRINGS_NOT_CLOSED
|
raise STRINGS_NOT_CLOSED
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,18 +129,18 @@ class TestNumericFunctions:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"input_string, split, max_split, expected_output",
|
"input_string, split, max_split, expected_output",
|
||||||
[
|
[
|
||||||
("no splits", " | ", None, ["no splits"]),
|
("no splits", "' | '", None, ["no splits"]),
|
||||||
("one | split", " | ", None, ["one", "split"]),
|
("one | split", "' | '", None, ["one", "split"]),
|
||||||
("max | split | one", " | ", 1, ["max", "split | one"]),
|
("max | split | one", "' | '", 1, ["max", "split | one"]),
|
||||||
("multiline\ndescription", "\\n", None, ["multiline", "description"]),
|
("multiline\ndescription", "%unescape('\\n')", None, ["multiline", "description"]),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_split(
|
def test_split(
|
||||||
self, input_string: str, split: str, max_split: Optional[int], expected_output: List[str]
|
self, input_string: str, split: str, max_split: Optional[int], expected_output: List[str]
|
||||||
):
|
):
|
||||||
if max_split:
|
if max_split:
|
||||||
output = single_variable_output(f"{{%split('{input_string}', '{split}', {max_split})}}")
|
output = single_variable_output(f"{{%split('{input_string}', {split}, {max_split})}}")
|
||||||
else:
|
else:
|
||||||
output = single_variable_output(f"{{%split('{input_string}', '{split}')}}")
|
output = single_variable_output(f"{{%split('{input_string}', {split})}}")
|
||||||
|
|
||||||
assert output == expected_output
|
assert output == expected_output
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,22 @@ class TestString:
|
||||||
("{%string('backslash \\\\')}", "backslash \\\\"),
|
("{%string('backslash \\\\')}", "backslash \\\\"),
|
||||||
("{%string('''triple quote with \" ' \\''')}", "triple quote with \" ' \\"),
|
("{%string('''triple quote with \" ' \\''')}", "triple quote with \" ' \\"),
|
||||||
('{%string("""triple quote with " \' \\""")}', "triple quote with \" ' \\"),
|
('{%string("""triple quote with " \' \\""")}', "triple quote with \" ' \\"),
|
||||||
("{%string('literal \\n newlines')}", "literal \n newlines"),
|
|
||||||
("{%string('supports \t tabs')}", "supports \t tabs"),
|
("{%string('supports \t tabs')}", "supports \t tabs"),
|
||||||
("{%string('literal \\t tabs')}", "literal \t tabs"),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_string(self, string: str, expected_string: str):
|
def test_string(self, string: str, expected_string: str):
|
||||||
assert single_variable_output(string) == expected_string
|
assert single_variable_output(string) == expected_string
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"string, expected_string",
|
||||||
|
[
|
||||||
|
("{%unescape('literal \\n newlines')}", "literal \n newlines"),
|
||||||
|
("{%unescape('literal \\t tabs')}", "literal \t tabs"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_unescape(self, string: str, expected_string: str):
|
||||||
|
assert single_variable_output(string) == expected_string
|
||||||
|
|
||||||
def test_null_is_empty_string(self):
|
def test_null_is_empty_string(self):
|
||||||
assert Script({"out": "{%string(null)}"}).resolve() == ScriptOutput({"out": String("")})
|
assert Script({"out": "{%string(null)}"}).resolve() == ScriptOutput({"out": String("")})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue