forked from XLSForm/pyxform
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathparameters.py
More file actions
55 lines (41 loc) · 1.63 KB
/
Copy pathparameters.py
File metadata and controls
55 lines (41 loc) · 1.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from lark import Lark, Token, Transformer
from lark.exceptions import LarkError
from pyxform.errors import ErrorCode, PyXFormError
from pyxform.parsing.expression import maybe_strip
# Label and value are used to match against user-specified files so case should be preserved.
CASE_SENSITIVE_VALUES = {"label", "value"}
PARAMETER_GRAMMAR = r"""
start: pair*
pair: TOKEN "=" TOKEN
// Anything that's not a delimiter.
TOKEN: /[^\s=,;]+/
// Delimiters between key-value pairs.
%ignore /[\s,;]+/
"""
_PARAMETER_PARSER = Lark(PARAMETER_GRAMMAR, parser="lalr", start="start")
class ParameterTransformer(Transformer):
@staticmethod
def start(pairs: list[tuple[str, str]]) -> dict[str, str]:
"""Combine (key, value) tuples into a dict"""
return dict(pairs)
@staticmethod
def pair(items: list[Token, Token]) -> tuple[str, str]:
"""Normalise matched (key, value) tokens."""
raw_key, raw_value = items
key = maybe_strip(str(raw_key).lower())
value = maybe_strip(str(raw_value))
if key not in CASE_SENSITIVE_VALUES:
value = value.lower()
return key, value
# No token-specific (ALL_CAPS) methods, so visit_tokens=False.
_PARAMETER_TRANSFORMER = ParameterTransformer(visit_tokens=False)
def parse(
raw_parameters: str,
row_number: int,
) -> dict[str, str]:
if not raw_parameters or not raw_parameters.strip():
return {}
try:
return _PARAMETER_TRANSFORMER.transform(_PARAMETER_PARSER.parse(raw_parameters))
except LarkError as e:
raise PyXFormError(code=ErrorCode.SURVEY_004, context={"row": row_number}) from e