-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfield_setting_parser.py
300 lines (207 loc) · 7.5 KB
/
field_setting_parser.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
"""
This module allows to extract from a YAML file the values to write in an ÉTS
club expense report. The YAML file must comply with the format of those
provided in this repository. If this module is executed and given the path to
a YAML file as an argument, it will print the name of the report's fields in
the console with the value they are assigned.
"""
from pathlib import Path
from yaml import FullLoader, load
_CHECKBOX_YES = "/Oui"
_KEY_CHECKED = "Cochée"
def _dict_key_val_str(key, value):
"""
Creates a string representing a dictionary item. The string fits the
format "<key>: <value>".
Args:
key: the key from the dictionary item
value: the value from the dictionary item
Returns:
str: a string representing the dictionary item
"""
return str(key) + ": " + str(value)
def _dict_key_val_type_str(key, value):
"""
Creates a string representing a dictionary item. The string fits this
format: "<key>: <value> <type(value)>".
Args:
key: the key from the dictionary item
value: the value from the dictionary item
Returns:
str: a string representing the dictionary item
"""
return _dict_key_val_str(key, value) + " " + str(type(value))
def _error_for_unexpected_value(key, value):
raise ValueError("Unexpected value for " + str(key) + ": " + str(value))
def filter_values_from_dict(a_dict, unwanted_vals):
"""
Creates a dictionary containing the items from a_dict minus those whose
value is in unwanted_vals. a_dict is not modified.
Args:
a_dict (dict): any dictionary
unwanted_vals: a list, set or tuple containing the values to filter
Returns:
dict: a dictionary containing the items of a_dict except the unwanted
values
"""
wanted_items = dict()
for key, value in a_dict.items():
if value not in unwanted_vals:
wanted_items[key] = value
return wanted_items
def get_yaml_content(yaml_file_path):
"""
Reads a YAML file and returns its content in in a dictionary.
Args:
yaml_file_path (pathlib.Path): the path to a YAML file
Returns:
dict: the YAML file's content
Raises:
ValueError: if the extension of field_setting_path is not "yaml" or
"yml"
"""
if yaml_file_path.suffixes not in ([".yaml"], [".yml"]):
raise ValueError("The file extension must be \".yaml\" or \".yml\".")
with yaml_file_path.open(encoding="utf8") as field_setting_stream:
yaml_content = load(field_setting_stream, FullLoader)
if yaml_content is None:
yaml_content = dict()
return yaml_content
def _parse_codes_comptables(codes_comptables):
fields = dict()
for i in range(len(codes_comptables)):
cc = codes_comptables[i]
ubr = cc.get("UBR")
if ubr is not None:
fields["UBR" + str(i+1)] = ubr
account = cc.get("Compte")
if account is not None:
fields["CC" + str(i+1)] = account
df = cc.get("DemFin")
if df is not None:
fields["DF" + str(i+1)] = df
cbs = cc.get("CBS")
if cbs is not None:
fields["CBS" + str(i+1)] = cbs
amount = cc.get("Montant")
if amount is not None:
fields["ccMontant$" + str(i+1)] = amount
return fields
def _parse_expense_list(expense_list):
fields = dict()
for i, expense in enumerate(expense_list):
if (description := expense.get("Description")) is not None:
fields["Détails" + str(i+1)] = description
amount = expense.get("Montant")
if amount is not None:
fields["Montant$" + str(i+1)] = amount
return fields
def _parse_travel_reasons(travel_reason_dict):
fields = dict()
presentation = travel_reason_dict.get("Présentation")
if presentation is not None:
presentation_checked = presentation.get(_KEY_CHECKED)
if presentation_checked:
fields["Boite1"] = _CHECKBOX_YES
presentation_subject = presentation.get("Sujet")
if presentation_subject is not None:
fields["Présentation"] = presentation_subject
conference = travel_reason_dict.get("Conférence")
if conference is not None:
conference_checked = conference.get(_KEY_CHECKED)
if conference_checked:
fields["Boite2"] = _CHECKBOX_YES
conference_name = conference.get("Nom")
if conference_name is not None:
fields["Conférence"] = conference_name
sabbatical = travel_reason_dict.get("Sabbatique")
if sabbatical:
fields["Boite3"] = _CHECKBOX_YES
others = travel_reason_dict.get("Autres")
if others is not None:
others_checked = others.get(_KEY_CHECKED)
if others_checked:
fields["Boite4"] = _CHECKBOX_YES
others_precision = others.get("Précision")
if others_precision is not None:
fields["Autres"] = others_precision
return fields
def parse_yaml_content(yaml_content):
"""
Parses the content that function get_yaml_content has extracted from a
YAML file and translates it to a dictionary that matches the data with the
fields of expense report rapport_depenses.pdf.
Args:
yaml_content (dict): content of a YAML file returned by
get_yaml_content
Returns:
dict: a dictionary matching the data from the YAML file with the
fields of the expense report.
"""
# Function update_page_fields from library PyPDF2_Fields must be able to
# process the dictionary returned by this function.
field_values = dict()
for key, value in yaml_content.items():
if key == "RaisonVoyage" and value is not None:
field_values.update(_parse_travel_reasons(value))
elif key == "Dépenses" and value is not None:
field_values.update(_parse_expense_list(value))
elif key == "Codes comptables" and value is not None:
field_values.update(_parse_codes_comptables(value))
elif key == "RaisonDépenses" and value is not None:
field_values["Group1"] = value
elif key == "Statut" and value is not None:
field_values["Group2"] = value
elif key == "ModePaiement" and value is not None:
field_values["Group4"] = value
elif key == "Distance" and value is not None:
field_values["KM"] = value
elif value is not None:
field_values[key] = value
return field_values
def print_dictionary(a_dict, print_val_type):
"""
Prints a dictionary's items in the console in the following format:
"<key>: <value>".
Args:
a_dict (dict): any dictionary
print_val_type (bool): if True, the type of each value is also printed.
"""
item_to_str_fnc = _dict_key_val_type_str if print_val_type\
else _dict_key_val_str
for key, value in a_dict.items():
print(item_to_str_fnc(key, value))
def str_to_bool(bool_str):
"""
Converts a string to a Boolean value.
False: "0", "f", "false", "n" or "no"
True: "1", "t", "true", "y" or "yes"
Args:
bool_str (str): a string corresponding to a Boolean value
Returns:
bool: the Boolean value matching bool_str
Raises:
ValueError: if bool_str does not match a boolean value
"""
if bool_str.lower() in ("0", "f", "false", "n", "no"):
return False
if bool_str.lower() in ("1", "t", "true", "y", "yes"):
return True
raise ValueError("\"" + str(bool_str)
+ "\" does not match a boolean value.")
if __name__ == "__main__":
from argparse import ArgumentParser
from path_arg_checks import check_ungenerable_path
parser = ArgumentParser(description=__doc__)
parser.add_argument("-f", "--file", type=Path, required=True,
help="the path to a YAML file that defines values to put in the fields of an expense report")
parser.add_argument("-t", "--types", action="store_true",
help="If this argument is given, the type of the fields' value will be printed.")
args = parser.parse_args()
field_setting_path = args.file
print_val_type = args.types
check_ungenerable_path(
field_setting_path, "-f/--file", ".yml", must_exist=True)
yaml_content = get_yaml_content(field_setting_path)
field_values = parse_yaml_content(yaml_content)
print_dictionary(field_values, print_val_type)