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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
import re
import string
from test_utils import simple_assert
def if_empty(x, parser):
"""If the field is empty, use `x`, otherwise, call `parser` on it."""
def fn(y):
if y == "":
return x
else:
return parser(y)
return fn
# nullable :: Parser -> Parser
def nullable(parser):
def fn(x):
if x == "":
return None
else:
return parser(x)
return fn
def required(column_name, parser):
def fn(x):
if x == "":
raise Exception(
"\"{}\" is a required field and cannot be empty".format(
column_name))
else:
return parser(x)
return fn
def apply_parser(parser, row):
"""Calls each value in `parser` on the corresponding field in the
dictionary, `row`."""
result = {}
for k, fn in parser.items():
result[k] = fn(row[k])
return result
def raise_parse_error(x, expected):
"""Raises a generic `Exception` when `x` is not a member of the `expected`
set."""
raise Exception("\"{}\" is none of the following: \"{}\"".format(
x, ", ".join(expected)))
def as_hours(x):
match = re.search(r'(\d+) hours', x)
if match:
try:
return int(match[1])
except:
raise Exception('Failed to parse {} as an int'.format(match[1]))
else:
raise Exception('Failed to parse {} as hours'.format(x))
actual = as_hours('24 hours')
expected = 24
simple_assert(actual, expected, name='as_hours')
def as_mapping(mapping):
def fn(x):
if mapping[x]:
return mapping[x]
else:
raise_parse_error(x, set(mapping.keys()))
return fn
# as_yes_no :: String -> Boolean
def as_yes_no(x):
"""Attempt to parse `x`, a Yes or No value, into a boolean."""
if x == "Yes":
return True
elif x == "No":
return False
else:
raise_parse_error(x, {"Yes", "No"})
# as_data_source_type :: String -> String
def as_data_source_type(x):
"""Attempt to parse `x` as the Data Source Type column, which is an enum
defined in the go/consult-types-authwf-auto-consult sheet."""
acceptable = {"Hard-Code", "N/A", "Atlas", "Form"}
if x not in acceptable:
raise_parse_error(x, acceptable)
return x
# as_type :: String -> String
def as_type(x):
"""Attempt to parse `x` as the Type column, which is an enum defined in the
go/consult-types-authwf-auto-consult sheet."""
acceptable = {
"Parent Routing FRD", "Consult Parameter", "Consult Routing FRD",
"Input", "Return Routing FRD"
}
if x not in acceptable:
raise_parse_error(x, acceptable)
return x
def as_int(x):
return int(x)
def as_union_type(x):
if " or " in x:
return [string.trim_surrounding('"', x) for x in x.split(" or ")]
else:
return [x]
simple_assert(as_union_type('Non-Union'), ['Non-Union'], name='as_union_type')
simple_assert(as_union_type(
'"Germany" or "Netherlands" or "Spain" or "Check Republic" or "United Kingdom"'
), ['Germany', 'Netherlands', 'Spain', 'Check Republic', 'United Kingdom'],
name='as_union_type')
# identity :: a -> a
def identity(x):
"""Returns `x` unchanged."""
return x
|